From 1439c2c3a761d530b00fd79336aa096a19547ae8 Mon Sep 17 00:00:00 2001 From: HELYX-OS Date: Fri, 22 Jan 2016 16:57:55 +0100 Subject: [PATCH] Initial Commit --- build_src.xml | 101 + .../application/AbstractApplication.java | 252 ++ src/eu/engys/application/AdPanel.java | 133 + src/eu/engys/application/Application.java | 53 + .../application/ApplicationEventListener.java | 51 + src/eu/engys/application/Batch.java | 35 + src/eu/engys/application/HELYXOS.java | 217 ++ src/eu/engys/application/SupportWindow.java | 198 ++ .../application/modules/HELYXOSModule.java | 285 ++ src/eu/engys/core/Arguments.java | 232 ++ src/eu/engys/core/LoggerUtil.java | 153 + src/eu/engys/core/OpenFOAMEnvironment.java | 417 +++ .../core/controller/AbstractController.java | 541 ++++ .../controller/AbstractScriptFactory.java | 337 ++ .../core/controller/ApplicationActions.java | 44 + .../engys/core/controller/BatchActions.java | 46 + src/eu/engys/core/controller/Client.java | 62 + src/eu/engys/core/controller/ClientInfo.java | 50 + .../core/controller/ClientServerCommand.java | 99 + src/eu/engys/core/controller/Command.java | 59 + src/eu/engys/core/controller/CommandInfo.java | 91 + src/eu/engys/core/controller/Controller.java | 68 + .../core/controller/ControllerListener.java | 60 + .../controller/DefaultNamingConvention.java | 41 + .../core/controller/DefaultScriptFactory.java | 398 +++ .../engys/core/controller/GeometryToMesh.java | 251 ++ .../core/controller/HelyxOSController.java | 428 +++ src/eu/engys/core/controller/ILogServer.java | 40 + src/eu/engys/core/controller/LogClient.java | 41 + .../engys/core/controller/ParsersManager.java | 43 + .../engys/core/controller/QueueConnector.java | 36 + src/eu/engys/core/controller/QueueInfo.java | 41 + .../engys/core/controller/ScriptBuilder.java | 65 + .../engys/core/controller/ScriptFactory.java | 62 + src/eu/engys/core/controller/Server.java | 69 + src/eu/engys/core/controller/ServerInfo.java | 53 + .../engys/core/controller/StateConnector.java | 38 + .../core/controller/StopOrKillCommandOS.java | 59 + .../engys/core/controller/View3DOptions.java | 55 + .../actions/AbstractRunCommand.java | 94 + .../core/controller/actions/CheckMesh.java | 88 + .../controller/actions/CommandException.java | 34 + .../core/controller/actions/DeleteMesh.java | 42 + .../controller/actions/InitialiseFields.java | 69 + .../controller/actions/NamingConvention.java | 35 + .../core/controller/actions/RunCase.java | 134 + .../core/controller/actions/RunCommand.java | 55 + .../core/controller/actions/RunMesh.java | 74 + .../actions/StandardInitialiseFields.java | 80 + .../controller/actions/StandardRunCase.java | 108 + .../controller/actions/StandardRunMesh.java | 77 + .../controller/actions/StopCommandInfo.java | 63 + .../controller/actions/TimeoutException.java | 34 + src/eu/engys/core/dictionary/BeanToDict.java | 274 ++ .../core/dictionary/BlockMeshWriter.java | 120 + .../engys/core/dictionary/DefaultElement.java | 52 + src/eu/engys/core/dictionary/Dictionary.java | 807 +++++ .../core/dictionary/DictionaryBuilder.java | 96 + .../core/dictionary/DictionaryEditor.java | 253 ++ .../core/dictionary/DictionaryException.java | 34 + .../dictionary/DictionaryLinkResolver.java | 116 + .../core/dictionary/DictionaryReader.java | 363 +++ .../core/dictionary/DictionaryUtils.java | 160 + .../core/dictionary/DictionaryWriter.java | 182 ++ .../core/dictionary/DimensionedScalar.java | 145 + .../core/dictionary/FieldChangeListener.java | 36 + .../engys/core/dictionary/FieldElement.java | 62 + .../engys/core/dictionary/FieldListener.java | 31 + src/eu/engys/core/dictionary/FileEditor.java | 254 ++ src/eu/engys/core/dictionary/Finder.java | 32 + src/eu/engys/core/dictionary/FoamFile.java | 65 + src/eu/engys/core/dictionary/ListField.java | 188 ++ src/eu/engys/core/dictionary/ListReader.java | 118 + .../engys/core/dictionary/MatrixReader.java | 98 + .../core/dictionary/StartWithFinder.java | 40 + .../core/dictionary/TableRowElement.java | 100 + .../model/AbstractTableAdapter.java | 233 ++ .../engys/core/dictionary/model/AxisInfo.java | 56 + .../dictionary/model/DictionaryModel.java | 1428 +++++++++ .../model/DictionaryPanelBuilder.java | 206 ++ .../model/DictionaryTableAdapter.java | 62 + .../dictionary/model/EventActionType.java | 42 + .../dictionary/model/LevelsTableAdapter.java | 129 + .../dictionary/model/LinesTableAdapter.java | 191 ++ .../OneDictionaryPerRowTableAdapter.java | 188 ++ .../model/PatchesMapTableAdapter.java | 162 + .../core/dictionary/model/PointInfo.java | 64 + .../dictionary/model/PointTableAdapter.java | 175 + .../dictionary/model/ShowAxisAdapter.java | 112 + .../dictionary/model/ShowLocationAdapter.java | 125 + .../dictionary/parser/DictionaryReader2.java | 443 +++ .../core/dictionary/parser/ListField2.java | 361 +++ .../core/dictionary/parser/ListReader2.java | 420 +++ .../dictionary/parser/ThetaListField2.java | 93 + .../dictionary/parser/ThetaListReader2.java | 72 + .../engys/core/executor/AbstractExecutor.java | 230 ++ .../core/executor/AbstractScriptExecutor.java | 231 ++ .../engys/core/executor/CollapseManager.java | 83 + .../engys/core/executor/CommandExecutor.java | 91 + .../core/executor/ConsoleExecutorMonitor.java | 52 + src/eu/engys/core/executor/Executor.java | 131 + src/eu/engys/core/executor/ExecutorError.java | 63 + src/eu/engys/core/executor/ExecutorHook.java | 32 + .../engys/core/executor/ExecutorListener.java | 52 + .../engys/core/executor/ExecutorMonitor.java | 124 + .../engys/core/executor/ExecutorTerminal.java | 85 + .../core/executor/FileManagerSupport.java | 170 + src/eu/engys/core/executor/JavaExecutor.java | 95 + .../core/executor/MailManagerSupport.java | 136 + .../executor/ProgressExecutorMonitor.java | 116 + .../core/executor/QueueExecutorMonitor.java | 91 + .../QueueTerminalExecutorMonitor.java | 89 + .../engys/core/executor/ScriptExecutor.java | 58 + .../engys/core/executor/StateMapperHook.java | 49 + .../executor/TerminalExecutorMonitor.java | 318 ++ .../engys/core/executor/TerminalManager.java | 256 ++ .../core/executor/TerminalOutputStream.java | 68 + .../engys/core/executor/TerminalSupport.java | 86 + .../core/executor/TerminalTabComponent.java | 82 + .../executor/actions/CloseMonitorAction.java | 53 + .../actions/CopyMonitorToClipboardAction.java | 56 + .../actions/MaximiseMonitorAction.java | 59 + .../executor/actions/SaveLogFileAction.java | 97 + .../executor/actions/ScrollLockAction.java | 63 + .../core/executor/actions/ShowLogAction.java | 65 + .../executor/actions/StopCommandAction.java | 57 + .../engys/core/modules/ApplicationModule.java | 91 + .../modules/ApplicationModuleAdapter.java | 124 + .../engys/core/modules/CaseSetupReader.java | 41 + .../engys/core/modules/CaseSetupWriter.java | 39 + .../modules/FieldsInitialisationView.java | 38 + src/eu/engys/core/modules/ModuleDefaults.java | 72 + src/eu/engys/core/modules/ModulePanel.java | 40 + src/eu/engys/core/modules/ModulesUtil.java | 275 ++ .../BoundaryConditionsView.java | 38 + .../boundaryconditions/BoundaryTypePanel.java | 68 + .../IBoundaryConditionsPanel.java | 34 + .../boundaryconditions/ParametersPanel.java | 51 + .../core/modules/cellzones/CellZonePanel.java | 81 + .../core/modules/cellzones/CellZonesView.java | 41 + .../modules/materials/MaterialsBuilder.java | 42 + .../modules/materials/MaterialsDatabase.java | 93 + .../core/modules/materials/MaterialsView.java | 42 + .../AbstractSolutionView.java | 86 + .../solutionmodelling/MultiphaseBuilder.java | 41 + .../SolutionModellingPanel.java | 44 + .../solutionmodelling/SolutionView.java | 59 + .../core/modules/tree/ModuleElementPanel.java | 35 + src/eu/engys/core/modules/tree/TreeView.java | 32 + src/eu/engys/core/parameters/Parameter.java | 55 + src/eu/engys/core/parameters/Parameters.java | 96 + src/eu/engys/core/presentation/Action.java | 44 + .../core/presentation/ActionContainer.java | 31 + .../core/presentation/ActionManager.java | 140 + .../engys/core/presentation/ActionToggle.java | 44 + .../core/project/AbstractProjectReader.java | 59 + .../core/project/AbstractProjectWriter.java | 64 + src/eu/engys/core/project/CaseParameters.java | 73 + src/eu/engys/core/project/CreateCase.java | 160 + .../core/project/DefaultProjectReader.java | 159 + .../core/project/DefaultProjectWriter.java | 182 ++ .../core/project/InvalidProjectException.java | 34 + src/eu/engys/core/project/Model.java | 342 ++ .../engys/core/project/NullProjectReader.java | 47 + .../engys/core/project/NullProjectWriter.java | 52 + .../project/Project200To210Converter.java | 438 +++ .../core/project/ProjectFolderAnalyzer.java | 276 ++ .../core/project/ProjectFolderStructure.java | 54 + src/eu/engys/core/project/ProjectReader.java | 36 + src/eu/engys/core/project/ProjectWriter.java | 38 + src/eu/engys/core/project/SolverModel.java | 156 + .../engys/core/project/SolverModelReader.java | 230 ++ .../engys/core/project/SolverModelWriter.java | 61 + src/eu/engys/core/project/SolverState.java | 68 + .../engys/core/project/TurbulenceModel.java | 125 + .../core/project/TurbulenceModelType.java | 50 + .../engys/core/project/TurbulenceModels.java | 214 ++ .../core/project/constant/ConstantFolder.java | 217 ++ .../core/project/constant/PolyMeshFolder.java | 48 + .../constant/ThermophysicalProperties.java | 117 + .../project/constant/TransportProperties.java | 119 + .../project/constant/TriSurfaceFolder.java | 48 + .../constant/TurbulenceProperties.java | 52 + src/eu/engys/core/project/custom/Custom.java | 225 ++ .../engys/core/project/custom/CustomFile.java | 261 ++ .../core/project/custom/CustomFileType.java | 82 + .../core/project/custom/CustomUtils.java | 143 + .../defaults/AbstractDefaultsProvider.java | 140 + .../defaults/DefaultDictDataFolder.java | 53 + .../engys/core/project/defaults/Defaults.java | 142 + .../project/defaults/DefaultsProvider.java | 48 + .../core/project/defaults/DictDataFolder.java | 36 + .../project/defaults/JarDictDataFolder.java | 118 + .../project/files/DefaultFileManager.java | 136 + .../engys/core/project/files/FileManager.java | 42 + src/eu/engys/core/project/files/Folder.java | 33 + .../core/project/geometry/BlockReader.java | 221 ++ .../core/project/geometry/BlockSaver.java | 169 + .../core/project/geometry/BoundingBox.java | 140 + .../core/project/geometry/FeatureLine.java | 178 + .../core/project/geometry/FeatureLines.java | 70 + .../engys/core/project/geometry/Geometry.java | 335 ++ .../core/project/geometry/GeometryReader.java | 304 ++ .../core/project/geometry/GeometrySaver.java | 345 ++ .../core/project/geometry/GeometryWriter.java | 63 + .../engys/core/project/geometry/Surface.java | 374 +++ .../core/project/geometry/TransfromMode.java | 31 + src/eu/engys/core/project/geometry/Type.java | 77 + .../factory/DefaultGeometryFactory.java | 311 ++ .../project/geometry/factory/EMESHReader.java | 94 + .../project/geometry/factory/EMESHWriter.java | 88 + .../factory/EngysGeometryFactory.java | 104 + .../geometry/factory/GeometryFactory.java | 51 + .../project/geometry/stl/AffineTransform.java | 356 ++ .../core/project/geometry/stl/ImportIGES.java | 124 + .../project/geometry/stl/NastranReader.java | 105 + .../geometry/stl/RemoveDuplicates.java | 162 + .../core/project/geometry/stl/STLJoiner.java | 122 + .../core/project/geometry/stl/STLManager.java | 76 + .../core/project/geometry/stl/STLReader.java | 470 +++ .../project/geometry/stl/STLReplacer.java | 204 ++ .../core/project/geometry/stl/STLWriter.java | 132 + .../project/geometry/stl/SolidWriter.java | 91 + .../project/geometry/surface/BaseSurface.java | 78 + .../core/project/geometry/surface/Box.java | 84 + .../project/geometry/surface/Cylinder.java | 102 + .../project/geometry/surface/MultiPlane.java | 137 + .../project/geometry/surface/MultiRegion.java | 134 + .../project/geometry/surface/NullSurface.java | 96 + .../core/project/geometry/surface/Plane.java | 112 + .../project/geometry/surface/PlaneRegion.java | 117 + .../core/project/geometry/surface/Region.java | 69 + .../core/project/geometry/surface/Ring.java | 159 + .../core/project/geometry/surface/Solid.java | 87 + .../core/project/geometry/surface/Sphere.java | 88 + .../core/project/geometry/surface/Stl.java | 151 + .../core/project/materials/Material.java | 62 + .../core/project/materials/Materials.java | 98 + .../materials/Materials200To210Converter.java | 262 ++ .../project/materials/MaterialsReader.java | 38 + .../project/materials/MaterialsWriter.java | 37 + .../engys/core/project/materials/Phase.java | 62 + src/eu/engys/core/project/mesh/FieldItem.java | 133 + src/eu/engys/core/project/mesh/Mesh.java | 201 ++ .../core/project/mesh/ScalarBarType.java | 350 ++ .../engys/core/project/openFOAMProject.java | 159 + .../project/runtimefields/RuntimeField.java | 40 + .../project/runtimefields/RuntimeFields.java | 95 + .../core/project/state/BuoyancyBuilder.java | 54 + .../core/project/state/EngysTable15.java | 129 + src/eu/engys/core/project/state/Flow.java | 53 + src/eu/engys/core/project/state/Mach.java | 53 + src/eu/engys/core/project/state/Method.java | 53 + .../core/project/state/MultiphaseModel.java | 81 + .../core/project/state/PhaseBuilder.java | 99 + .../core/project/state/PhasesNumber.java | 45 + .../engys/core/project/state/ServerState.java | 100 + .../core/project/state/SolutionState.java | 122 + src/eu/engys/core/project/state/Solver.java | 63 + .../core/project/state/SolverFamily.java | 75 + .../engys/core/project/state/SolverType.java | 53 + src/eu/engys/core/project/state/State.java | 405 +++ .../core/project/state/StateBuilder.java | 542 ++++ .../core/project/state/StateComposer.java | 175 + src/eu/engys/core/project/state/Table15.java | 48 + .../core/project/state/ThermalState.java | 62 + src/eu/engys/core/project/state/Time.java | 53 + .../core/project/state/TurbulenceBuilder.java | 113 + .../core/project/system/BlockMeshDict.java | 198 ++ .../core/project/system/CaseSetupDict.java | 48 + .../core/project/system/ControlDict.java | 202 ++ .../core/project/system/CustomNodeDict.java | 52 + .../core/project/system/DecomposeParDict.java | 96 + .../engys/core/project/system/FvOptions.java | 44 + .../engys/core/project/system/FvSchemes.java | 111 + .../engys/core/project/system/FvSolution.java | 67 + .../core/project/system/MapFieldsDict.java | 128 + src/eu/engys/core/project/system/RunDict.java | 71 + .../core/project/system/SetFieldsDict.java | 72 + .../project/system/SnappyHexMeshDict.java | 288 ++ .../core/project/system/SystemFolder.java | 463 +++ .../FieldManipulationFunctionObject.java | 61 + .../FieldManipulationFunctionObjectPanel.java | 47 + .../FieldManipulationFunctionObjectType.java | 40 + .../FieldManipulationFunctionObjects.java | 165 + .../monitoringfunctionobjects/FakeParser.java | 74 + .../MonitoringFunctionObject.java | 70 + .../MonitoringFunctionObjectPanel.java | 49 + .../MonitoringFunctionObjectType.java | 42 + .../MonitoringFunctionObjects.java | 198 ++ .../monitoringfunctionobjects/Parser.java | 51 + .../ParserFactory.java | 39 + .../monitoringfunctionobjects/ParserView.java | 73 + .../monitoringfunctionobjects/TimeBlock.java | 67 + .../TimeBlockUnit.java | 52 + .../monitoringfunctionobjects/TimeBlocks.java | 158 + .../engys/core/project/zero/MeshRegion.java | 51 + .../project/zero/ParallelZeroFileManager.java | 276 ++ .../project/zero/SerialZeroFileManager.java | 237 ++ .../core/project/zero/ZeroFileManager.java | 63 + .../engys/core/project/zero/ZeroFolder.java | 438 +++ .../project/zero/ZeroFolderStructure.java | 49 + .../core/project/zero/ZeroFolderUtil.java | 311 ++ .../core/project/zero/cellzones/CellZone.java | 137 + .../project/zero/cellzones/CellZoneType.java | 53 + .../project/zero/cellzones/CellZones.java | 96 + .../cellzones/CellZones200To210Converter.java | 226 ++ .../zero/cellzones/CellZonesBuilder.java | 50 + .../zero/cellzones/CellZonesReader.java | 164 + .../zero/cellzones/CellZonesUtils.java | 108 + .../zero/cellzones/CellZonesWriter.java | 141 + .../core/project/zero/facezones/FaceZone.java | 98 + .../project/zero/facezones/FaceZones.java | 60 + .../zero/facezones/FaceZonesReader.java | 142 + .../zero/fields/AbstractInitialisations.java | 80 + .../zero/fields/ArrayInternalField.java | 60 + .../engys/core/project/zero/fields/Field.java | 281 ++ .../core/project/zero/fields/FieldFilter.java | 32 + .../core/project/zero/fields/FieldReader.java | 245 ++ .../core/project/zero/fields/FieldWriter.java | 78 + .../core/project/zero/fields/Fields.java | 232 ++ .../project/zero/fields/FieldsDefaults.java | 247 ++ .../project/zero/fields/FieldsReader.java | 109 + .../project/zero/fields/FieldsWriter.java | 117 + .../project/zero/fields/Initialisations.java | 49 + .../project/zero/fields/InternalField.java | 42 + .../zero/fields/MatrixInternalField.java | 68 + .../zero/fields/ScalarInternalField.java | 60 + .../zero/fields/VectorInternalField.java | 67 + .../zero/patches/BoundaryConditions.java | 357 +++ .../patches/BoundaryConditionsDefaults.java | 211 ++ .../project/zero/patches/BoundaryType.java | 225 ++ .../zero/patches/MergeBoundaryConditions.java | 317 ++ .../core/project/zero/patches/Patch.java | 154 + .../core/project/zero/patches/Patches.java | 163 + .../project/zero/patches/PatchesReader.java | 183 ++ .../project/zero/patches/PatchesWriter.java | 189 ++ .../zero/patches/SplitBoundaryConditions.java | 192 ++ src/eu/engys/core/report/Exporter.java | 143 + .../engys/core/report/excel/CSVExporter.java | 70 + .../core/report/excel/ExcelExporter.java | 83 + .../engys/core/report/excel/ExcelUtils.java | 84 + src/eu/engys/core/report/pdf/PDFImage.java | 46 + src/eu/engys/core/report/pdf/PDFPage.java | 36 + .../engys/core/report/pdf/PDFPageEvent.java | 79 + src/eu/engys/core/report/pdf/PDFReport.java | 107 + src/eu/engys/core/report/pdf/PDFUtils.java | 213 ++ src/eu/engys/gui/AboutWindow.java | 166 + src/eu/engys/gui/AbstractGUIPanel.java | 235 ++ src/eu/engys/gui/Actions.java | 37 + src/eu/engys/gui/CreateCaseDialog.java | 366 +++ src/eu/engys/gui/DefaultGUIPanel.java | 47 + src/eu/engys/gui/GUIError.java | 35 + src/eu/engys/gui/GUIPanel.java | 63 + src/eu/engys/gui/GlassPane.java | 78 + src/eu/engys/gui/ListBuilderFactory.java | 152 + src/eu/engys/gui/MenuBar.java | 167 + src/eu/engys/gui/ModelObserver.java | 47 + src/eu/engys/gui/PreferencesDialog.java | 595 ++++ src/eu/engys/gui/RecentItems.java | 129 + src/eu/engys/gui/StandardScriptFactory.java | 104 + src/eu/engys/gui/StartPanel.java | 214 ++ src/eu/engys/gui/casesetup/CaseSetup.java | 42 + .../gui/casesetup/CaseSetup3DElement.java | 50 + .../engys/gui/casesetup/CaseSetupElement.java | 118 + .../gui/casesetup/RuntimeControlsPanel.java | 346 ++ .../gui/casesetup/actions/DecomposeCase.java | 139 + .../actions/DecomposeCaseAction.java | 129 + .../casesetup/actions/DecomposeCasePanel.java | 286 ++ .../actions/DefaultCaseSetupActions.java | 73 + .../casesetup/actions/ReconstructCase.java | 128 + .../actions/StandardCaseSetupActions.java | 58 + .../AbstractInterpolationTable.java | 405 +++ .../BoundaryConditionsPanel.java | 382 +++ .../BoundaryConditionsTreeNodeManager.java | 336 ++ .../InterpolationChartPanel.java | 100 + .../NonUniformComboBoxController.java | 71 + .../NonUniformInterpolationTable.java | 76 + .../TimeVaryingComboBoxController.java | 92 + .../TimeVaryingInterpolationTable.java | 73 + .../factories/CyclicFactory.java | 141 + .../factories/PressureFactory.java | 135 + .../factories/StandardPhaseFactory.java | 60 + .../factories/StandardPressureFactory.java | 43 + .../factories/StandardVelocityFactory.java | 32 + .../factories/TemperatureFactory.java | 173 + .../factories/TurbulenceFactory.java | 303 ++ .../factories/VelocityFactory.java | 245 ++ .../panels/AbstractBoundaryTypePanel.java | 341 ++ .../AbstractCyclicAMISettingsPanel.java | 333 ++ .../panels/AbstractParametersPanel.java | 162 + .../panels/CyclicSettingsPanel.java | 168 + .../panels/MomentumParametersPanel.java | 60 + .../panels/PhaseParametersPanel.java | 63 + .../StandardCyclicAMISettingsPanel.java | 108 + .../panels/ThermalParametersPanel.java | 54 + .../panels/TurbulenceParametersPanel.java | 81 + .../panels/patch/MomentumPatch.java | 421 +++ .../panels/patch/PatchSettingsPanel.java | 62 + .../panels/patch/PhasePatch.java | 140 + .../panels/patch/ThermalPatch.java | 124 + .../panels/patch/TurbulencePatch.java | 197 ++ .../panels/wall/StandardMomentumWall.java | 151 + .../panels/wall/StandardThermalWall.java | 140 + .../wall/StandardWallSettingsPanel.java | 56 + .../utils/BoundaryConditionsUtils.java | 350 ++ .../utils/ThermalUtils.java | 64 + .../utils/TurbulenceUtils.java | 222 ++ .../cellzones/CellZoneComparator.java | 50 + .../casesetup/cellzones/CellZonesFactory.java | 188 ++ .../casesetup/cellzones/CellZonesPanel.java | 224 ++ .../cellzones/CellZonesTreeNodeManager.java | 270 ++ .../cellzones/SourcePanelContainer.java | 114 + .../cellzones/SourceTypeSelectionPanel.java | 135 + .../cellzones/StandardCellZonesBuilder.java | 328 ++ .../mrf/StandardCellZoneMRFPanel.java | 90 + .../casesetup/cellzones/mrf/StandardMRF.java | 92 + .../porous/StandardCellZonePorousPanel.java | 105 + .../cellzones/porous/StandardPorous.java | 92 + .../thermal/StandardCellZoneThermalPanel.java | 92 + .../cellzones/thermal/StandardThermal.java | 100 + .../AbstractFieldsInitialisationPanel.java | 365 +++ .../gui/casesetup/fields/CellSetDialog.java | 259 ++ .../gui/casesetup/fields/CellSetRow.java | 515 +++ .../fields/SetFieldsDictConverter.java | 123 + .../StandardFieldsInitialisationPanel.java | 75 + .../fields/StandardInitialisations.java | 162 + .../AbstractIncompressibleMaterialsPanel.java | 159 + .../materials/AbstractMaterialsBuilder.java | 113 + .../materials/AbstractMaterialsReader.java | 66 + .../materials/AbstractMaterialsWriter.java | 58 + .../materials/CompressibleMaterialsPanel.java | 144 + .../IncompressibleMaterialsPanel.java | 54 + .../materials/MaterialsTreeNodeManager.java | 212 ++ .../StandardCompressibleMaterialsPanel.java | 196 ++ .../StandardIncompressibleMaterialsPanel.java | 110 + .../materials/StandardMaterialsBuilder.java | 222 ++ .../materials/StandardMaterialsReader.java | 87 + .../materials/StandardMaterialsWriter.java | 69 + .../panels/MaterialParametersPanel.java | 131 + .../panels/MaterialsDatabasePanel.java | 444 +++ .../materials/panels/MaterialsPanel.java | 359 +++ .../gui/casesetup/phases/PhasesPanel.java | 93 + .../gui/casesetup/phases/PhasesView.java | 39 + .../gui/casesetup/run/StandardTable15.java | 123 + .../casesetup/schemes/AdvectionSchemes.java | 300 ++ .../schemes/NumericalSchemesPanel.java | 261 ++ .../gui/casesetup/schemes/SchemePanel.java | 136 + .../AbstractSolutionModellingPanel.java | 419 +++ .../StandardSolutionModellingPanel.java | 109 + .../solution/StandardThermalPanel.java | 72 + .../solution/panels/AbstractThermalPanel.java | 164 + .../casesetup/solution/panels/FlowPanel.java | 71 + .../gui/casesetup/solution/panels/GPanel.java | 102 + .../casesetup/solution/panels/MachPanel.java | 70 + .../solution/panels/MethodPanel.java | 70 + .../panels/MultiphaseChooserPanel.java | 101 + .../solution/panels/MultiphasePanel.java | 159 + .../solution/panels/SolutionStatePanel.java | 225 ++ .../solution/panels/SolverTypePanel.java | 71 + .../casesetup/solution/panels/TimePanel.java | 70 + .../solution/panels/TurbulencePanel.java | 119 + .../solver/SolverSettingsBuilder.java | 200 ++ .../casesetup/solver/SolverSettingsPanel.java | 357 +++ .../solver/panels/CentralSettingsPanel.java | 76 + .../solver/panels/CoupledSettingsPanel.java | 74 + .../solver/panels/PimpleSettingsPanel.java | 238 ++ .../solver/panels/PisoSettingsPanel.java | 154 + .../solver/panels/SimpleSettingsPanel.java | 147 + .../casesetup/solver/panels/SolverPanel.java | 57 + src/eu/engys/gui/custom/CustomFileDialog.java | 501 +++ src/eu/engys/gui/custom/CustomNodePanel.java | 365 +++ .../gui/custom/CustomTreeNodeManager.java | 293 ++ src/eu/engys/gui/events/EventManager.java | 287 ++ src/eu/engys/gui/events/EventObject.java | 45 + .../engys/gui/events/EventSubscription.java | 60 + src/eu/engys/gui/events/EventWatcher.java | 120 + .../events/application/ApplicationEvent.java | 33 + .../application/BaseMeshTypeChangedEvent.java | 37 + .../events/application/OpenMonitorEvent.java | 37 + .../gui/events/view3D/ActorExtractEvent.java | 49 + .../gui/events/view3D/ActorPopUpEvent.java | 60 + .../events/view3D/ActorSelectionEvent.java | 57 + .../events/view3D/ActorVisibilityEvent.java | 44 + .../engys/gui/events/view3D/AddSTLEvent.java | 46 + .../gui/events/view3D/AddSurfaceEvent.java | 54 + src/eu/engys/gui/events/view3D/AxisEvent.java | 44 + src/eu/engys/gui/events/view3D/BoxEvent.java | 68 + .../gui/events/view3D/ChangeSurfaceEvent.java | 51 + .../gui/events/view3D/ColorSurfaceEvent.java | 52 + .../events/view3D/LayersCoverageEvent.java | 64 + .../gui/events/view3D/MeshQualityEvent.java | 56 + .../engys/gui/events/view3D/PlaneEvent.java | 86 + .../engys/gui/events/view3D/PointEvent.java | 66 + .../gui/events/view3D/RemoveSurfaceEvent.java | 54 + .../gui/events/view3D/RenameSurfaceEvent.java | 56 + .../events/view3D/ScalarBarWidgetEvent.java | 43 + .../events/view3D/SelectCellZonesEvent.java | 44 + .../gui/events/view3D/SelectPatchesEvent.java | 44 + .../gui/events/view3D/SelectSurfaceEvent.java | 44 + .../gui/events/view3D/SelectionEvent.java | 60 + .../events/view3D/TransformSurfaceEvent.java | 57 + .../engys/gui/events/view3D/View3DEvent.java | 33 + .../gui/events/view3D/VisibleItemEvent.java | 51 + .../gui/events/view3D/VolumeReportEvent.java | 58 + .../view3D/VolumeReportVisibilityEvent.java | 68 + src/eu/engys/gui/mesh/GeometryPanel.java | 55 + src/eu/engys/gui/mesh/Mesh.java | 42 + src/eu/engys/gui/mesh/Mesh3DElement.java | 50 + src/eu/engys/gui/mesh/MeshElement.java | 115 + src/eu/engys/gui/mesh/actions/AddIGES.java | 153 + src/eu/engys/gui/mesh/actions/AddSTL.java | 107 + .../gui/mesh/actions/DefaultMeshActions.java | 164 + .../engys/gui/mesh/actions/IGESAccessory.java | 62 + .../mesh/actions/IGESFileChooserWrapper.java | 78 + .../engys/gui/mesh/actions/RunBlockMesh.java | 143 + .../gui/mesh/actions/RunBlockMeshAction.java | 85 + .../engys/gui/mesh/actions/STLAccessory.java | 292 ++ .../mesh/actions/STLFileChooserWrapper.java | 79 + .../gui/mesh/actions/StandardMeshActions.java | 63 + .../actions/geometry/CloneSurfaceAction.java | 95 + .../actions/geometry/CopySurfaceAction.java | 79 + .../actions/geometry/ExtractLineAction.java | 72 + .../actions/geometry/ExtractLinesDialog.java | 446 +++ .../actions/geometry/PasteSurfaceAction.java | 95 + .../actions/geometry/RemoveSurfaceAction.java | 97 + .../mesh/panels/AbstractBaseMeshPanel.java | 281 ++ .../mesh/panels/AbstractGeometryPanel.java | 502 +++ .../mesh/panels/BaseMeshTreeNodeManager.java | 267 ++ .../panels/BoundaryMeshTreeNodeManager.java | 263 ++ .../mesh/panels/DefaultBoundaryMeshPanel.java | 232 ++ .../mesh/panels/DefaultGeometryActions.java | 163 + .../DefaultMeshAdvancedOptionsPanel.java | 319 ++ .../gui/mesh/panels/FeatureLinesPanel.java | 213 ++ .../panels/FeatureLinesTreeNodeManager.java | 365 +++ .../mesh/panels/GeometriesPanelBuilder.java | 517 +++ .../gui/mesh/panels/GeometryBuilder.java | 182 ++ .../mesh/panels/GeometryTreeNodeManager.java | 353 ++ .../gui/mesh/panels/MaterialPointsPanel.java | 124 + .../mesh/panels/SolverBoundaryMeshPanel.java | 207 ++ .../mesh/panels/StandardBaseMeshPanel.java | 81 + .../panels/StandardFeatureLinesPanel.java | 44 + .../mesh/panels/StandardGeometryPanel.java | 169 + .../StandardMeshAdvancedOptionsPanel.java | 199 ++ .../panels/lines/AutomaticBaseMeshPanel.java | 84 + .../panels/lines/BoundingBoxFacesPanel.java | 131 + .../panels/lines/ColorFeatureLineAction.java | 73 + .../lines/FeatureLinesRefinementTable.java | 176 + .../panels/lines/FromFileBaseMeshPanel.java | 192 ++ .../panels/lines/ImportFeatureLineAction.java | 117 + .../lines/UserDefinedBaseMeshPanel.java | 240 ++ .../gui/solver/DefaultRunOptionsPanel.java | 168 + src/eu/engys/gui/solver/ReloadOnFinish.java | 51 + .../engys/gui/solver/ReopenOnInitialised.java | 53 + src/eu/engys/gui/solver/ReopenOnMeshed.java | 53 + src/eu/engys/gui/solver/Solver.java | 42 + src/eu/engys/gui/solver/Solver3DElement.java | 60 + src/eu/engys/gui/solver/SolverElement.java | 114 + .../solver/SolverRuntimeControlsPanel.java | 373 +++ .../engys/gui/solver/UpdateClientState.java | 45 + .../solver/actions/DefaultSolverActions.java | 86 + .../solver/actions/EditRunSolverAction.java | 46 + .../solver/actions/OpenParaviewAction.java | 108 + .../gui/solver/actions/RunSolverAction.java | 55 + .../solver/actions/StandardSolverActions.java | 47 + .../solver/postprocessing/ParsersHandler.java | 182 ++ .../postprocessing/ParsersViewHandler.java | 232 ++ .../solver/postprocessing/ServerListener.java | 34 + .../postprocessing/ServerStateMonitor.java | 279 ++ .../data/DoubleListTimeBlockUnit.java | 54 + .../data/DoubleTimeBlockUnit.java | 52 + .../data/PointTimeBlockUnit.java | 54 + .../panels/AbstractChartPanel.java | 148 + .../panels/AbstractParserView.java | 266 ++ .../panels/HistoryChartPanel.java | 87 + .../panels/MovingAverageChartPanel.java | 235 ++ .../panels/actions/ExportToCSVAction.java | 52 + .../panels/actions/ExportToExcelAction.java | 51 + .../panels/actions/ExportToPNGAction.java | 52 + .../panels/actions/ShowCrosshairAction.java | 56 + .../ShowCrosshairForResidualsAction.java | 53 + .../panels/actions/ShowLogFileAction.java | 51 + .../panels/residuals/ResidualsChartPanel.java | 94 + .../panels/residuals/ResidualsExporter.java | 193 ++ .../panels/residuals/ResidualsPanel.java | 99 + .../panels/residuals/ResidualsView.java | 101 + .../panels/utils/MovingAverageCalculator.java | 161 + .../panels/utils/MovingAveragePanel.java | 105 + .../panels/utils/MovingAverageType.java | 57 + .../panels/utils/SelectedViewProvider.java | 32 + .../panels/utils/SeriesPanel.java | 136 + .../panels/utils/WaitLayerUI.java | 288 ++ .../parsers/AbstractParser.java | 169 + .../postprocessing/parsers/ParserUtils.java | 52 + .../parsers/ResidualsParser.java | 234 ++ .../parsers/ResidualsUtils.java | 61 + .../gui/tree/AbstractSelectionHandler.java | 47 + .../gui/tree/DefaultTreeNodeManager.java | 118 + src/eu/engys/gui/tree/GUIPanelHandler.java | 41 + src/eu/engys/gui/tree/SelectionHandler.java | 48 + src/eu/engys/gui/tree/Tree.java | 581 ++++ src/eu/engys/gui/tree/TreeNodeManager.java | 57 + src/eu/engys/gui/tree/TreeSelectionModel.java | 78 + .../engys/gui/view/AbstractView3DElement.java | 70 + .../engys/gui/view/AbstractViewElement.java | 225 ++ src/eu/engys/gui/view/ApplicationToolBar.java | 102 + .../gui/view/DefaultControllerListener.java | 174 + src/eu/engys/gui/view/ElementSelector.java | 154 + src/eu/engys/gui/view/MainPanel.java | 271 ++ src/eu/engys/gui/view/StatusBar.java | 184 ++ src/eu/engys/gui/view/SurfacesCombo.java | 102 + src/eu/engys/gui/view/View.java | 430 +++ src/eu/engys/gui/view/View3DElement.java | 41 + src/eu/engys/gui/view/ViewElement.java | 80 + .../engys/gui/view/ViewElementNavigator.java | 106 + src/eu/engys/gui/view/ViewElementPanel.java | 223 ++ .../view/ViewElementPanelTopNavigator.java | 132 + .../gui/view/ViewElementTopNavigator.java | 83 + .../view/fallback/FallbackViewElement.java | 134 + src/eu/engys/gui/view3D/Actor.java | 86 + src/eu/engys/gui/view3D/Axis.java | 43 + src/eu/engys/gui/view3D/BoxEventButton.java | 66 + src/eu/engys/gui/view3D/CameraManager.java | 35 + src/eu/engys/gui/view3D/CanvasPanel.java | 92 + src/eu/engys/gui/view3D/CellPicker.java | 33 + src/eu/engys/gui/view3D/Context.java | 45 + src/eu/engys/gui/view3D/Controller3D.java | 55 + .../gui/view3D/Geometry3DController.java | 69 + .../gui/view3D/Geometry3DEventListener.java | 136 + src/eu/engys/gui/view3D/Interactor.java | 48 + src/eu/engys/gui/view3D/LayerInfo.java | 46 + src/eu/engys/gui/view3D/Mesh3DController.java | 81 + .../engys/gui/view3D/Mesh3DEventListener.java | 81 + src/eu/engys/gui/view3D/PickInfo.java | 43 + src/eu/engys/gui/view3D/PickManager.java | 43 + src/eu/engys/gui/view3D/Picker.java | 35 + src/eu/engys/gui/view3D/QualityInfo.java | 102 + src/eu/engys/gui/view3D/RenderPanel.java | 94 + src/eu/engys/gui/view3D/Representation.java | 31 + src/eu/engys/gui/view3D/Selection.java | 120 + .../engys/gui/view3D/View3DEventListener.java | 33 + .../view3D/fallback/Fallback3DElement.java | 59 + .../FallbackGeometry3DController.java | 149 + .../fallback/FallbackMesh3DController.java | 198 ++ .../gui/view3D/fallback/FallbackView3D.java | 251 ++ src/eu/engys/gui/view3D/widget/Widget.java | 57 + .../gui/view3D/widget/WidgetComponent.java | 41 + .../launcher/AbstractApplicationLauncher.java | 96 + .../engys/launcher/ApplicationLauncher.java | 44 + src/eu/engys/launcher/HELYXOSLauncher.java | 50 + src/eu/engys/launcher/Launcher.java | 138 + src/eu/engys/launcher/LocaleUtil.java | 37 + src/eu/engys/launcher/StartUpMonitor.java | 224 ++ src/eu/engys/launcher/modules/Modules.java | 188 ++ src/eu/engys/resources/application.properties | 34 + src/eu/engys/resources/bundle.properties | 604 ++++ src/eu/engys/resources/driver.pbs | 12 + src/eu/engys/resources/elementsBox.png | Bin 0 -> 9180 bytes src/eu/engys/resources/elements_logo_full.png | Bin 0 -> 6214 bytes src/eu/engys/resources/engys_logo.png | Bin 0 -> 1631 bytes src/eu/engys/resources/engys_logo_big.png | Bin 0 -> 6030 bytes src/eu/engys/resources/engys_logo_full.png | Bin 0 -> 2956 bytes src/eu/engys/resources/engys_logo_medium.png | Bin 0 -> 5603 bytes src/eu/engys/resources/helyxBox.png | Bin 0 -> 9067 bytes src/eu/engys/resources/helyxosBox.png | Bin 0 -> 10464 bytes src/eu/engys/resources/helyxos_banner.png | Bin 0 -> 10976 bytes src/eu/engys/resources/helyxos_faq.png | Bin 0 -> 245357 bytes src/eu/engys/resources/helyxos_products.png | Bin 0 -> 145329 bytes src/eu/engys/resources/helyxos_startup.png | Bin 0 -> 26532 bytes src/eu/engys/resources/images/XNeg16.png | Bin 0 -> 594 bytes src/eu/engys/resources/images/XPos16.png | Bin 0 -> 604 bytes src/eu/engys/resources/images/YNeg16.png | Bin 0 -> 609 bytes src/eu/engys/resources/images/YPos16.png | Bin 0 -> 602 bytes src/eu/engys/resources/images/ZNeg16.png | Bin 0 -> 603 bytes src/eu/engys/resources/images/ZPos16.png | Bin 0 -> 612 bytes .../images/application_view_list16.png | Bin 0 -> 554 bytes .../engys/resources/images/arrow-turn16.png | Bin 0 -> 708 bytes .../engys/resources/images/arrow_down16.png | Bin 0 -> 328 bytes .../engys/resources/images/browseFile16.png | Bin 0 -> 672 bytes .../engys/resources/images/browseFolder16.png | Bin 0 -> 815 bytes .../engys/resources/images/calculator16.png | Bin 0 -> 663 bytes src/eu/engys/resources/images/cellField16.png | Bin 0 -> 718 bytes src/eu/engys/resources/images/clip24.png | Bin 0 -> 1431 bytes src/eu/engys/resources/images/cog16.png | Bin 0 -> 777 bytes src/eu/engys/resources/images/computer16.png | Bin 0 -> 715 bytes src/eu/engys/resources/images/console16.png | Bin 0 -> 504 bytes src/eu/engys/resources/images/copy16.png | Bin 0 -> 1437 bytes src/eu/engys/resources/images/crinkle24.png | Bin 0 -> 1405 bytes src/eu/engys/resources/images/crosshair16.png | Bin 0 -> 270 bytes src/eu/engys/resources/images/cube24.png | Bin 0 -> 961 bytes src/eu/engys/resources/images/cursor16.png | Bin 0 -> 554 bytes src/eu/engys/resources/images/cyclic16.png | Bin 0 -> 723 bytes src/eu/engys/resources/images/cyclicAMI16.png | Bin 0 -> 653 bytes src/eu/engys/resources/images/cylinder24.png | Bin 0 -> 1017 bytes src/eu/engys/resources/images/decompose16.png | Bin 0 -> 651 bytes src/eu/engys/resources/images/desktop16.png | Bin 0 -> 1590 bytes src/eu/engys/resources/images/documents16.png | Bin 0 -> 711 bytes src/eu/engys/resources/images/download16.png | Bin 0 -> 761 bytes .../engys/resources/images/downloadZip16.png | Bin 0 -> 734 bytes src/eu/engys/resources/images/drive16.png | Bin 0 -> 430 bytes src/eu/engys/resources/images/edit16.png | Bin 0 -> 1185 bytes src/eu/engys/resources/images/email16.png | Bin 0 -> 530 bytes src/eu/engys/resources/images/empty16.png | Bin 0 -> 1180 bytes src/eu/engys/resources/images/engys16.png | Bin 0 -> 1774 bytes src/eu/engys/resources/images/ensight16.png | Bin 0 -> 867 bytes src/eu/engys/resources/images/erase16.png | Bin 0 -> 718 bytes src/eu/engys/resources/images/excel16.png | Bin 0 -> 725 bytes src/eu/engys/resources/images/exit16.png | Bin 0 -> 773 bytes src/eu/engys/resources/images/exit32.png | Bin 0 -> 1382 bytes src/eu/engys/resources/images/export16.png | Bin 0 -> 402 bytes .../engys/resources/images/exportImage16.png | Bin 0 -> 389 bytes .../resources/images/exportResults16.png | Bin 0 -> 625 bytes .../engys/resources/images/externalMesh16.png | Bin 0 -> 534 bytes src/eu/engys/resources/images/extract16.png | Bin 0 -> 609 bytes src/eu/engys/resources/images/extrude16.png | Bin 0 -> 874 bytes src/eu/engys/resources/images/eye16.png | Bin 0 -> 493 bytes src/eu/engys/resources/images/eye_no16.png | Bin 0 -> 423 bytes .../engys/resources/images/favourites16.png | Bin 0 -> 830 bytes .../resources/images/favouritesAdd16.png | Bin 0 -> 611 bytes src/eu/engys/resources/images/fieldview16.png | Bin 0 -> 1447 bytes src/eu/engys/resources/images/file16.png | Bin 0 -> 594 bytes src/eu/engys/resources/images/fileSave16.png | Bin 0 -> 710 bytes src/eu/engys/resources/images/first16.png | Bin 0 -> 741 bytes .../engys/resources/images/first_grey16.png | Bin 0 -> 609 bytes src/eu/engys/resources/images/fit16.png | Bin 0 -> 638 bytes src/eu/engys/resources/images/fluent16.png | Bin 0 -> 737 bytes .../engys/resources/images/folder-open16.png | Bin 0 -> 632 bytes .../engys/resources/images/folder_add16.png | Bin 0 -> 772 bytes .../resources/images/folder_delete16.png | Bin 0 -> 767 bytes .../engys/resources/images/freeSurface16.png | Bin 0 -> 1166 bytes src/eu/engys/resources/images/gridgen16.png | Bin 0 -> 891 bytes .../engys/resources/images/homeFolder16.png | Bin 0 -> 887 bytes src/eu/engys/resources/images/igs24.png | Bin 0 -> 350 bytes src/eu/engys/resources/images/import16.png | Bin 0 -> 381 bytes .../engys/resources/images/import_disk16.png | Bin 0 -> 746 bytes src/eu/engys/resources/images/info16.png | Bin 0 -> 764 bytes src/eu/engys/resources/images/inlet16.png | Bin 0 -> 405 bytes src/eu/engys/resources/images/jar16.png | Bin 0 -> 593 bytes src/eu/engys/resources/images/last16.png | Bin 0 -> 741 bytes src/eu/engys/resources/images/last_grey16.png | Bin 0 -> 616 bytes src/eu/engys/resources/images/license16.png | Bin 0 -> 756 bytes src/eu/engys/resources/images/lightbulb16.png | Bin 0 -> 685 bytes .../resources/images/lightbulb_off16.png | Bin 0 -> 658 bytes src/eu/engys/resources/images/lightning.png | Bin 0 -> 683 bytes src/eu/engys/resources/images/lockClose16.png | Bin 0 -> 689 bytes src/eu/engys/resources/images/lockOpen16.png | Bin 0 -> 687 bytes src/eu/engys/resources/images/merge16.png | Bin 0 -> 508 bytes .../engys/resources/images/merge_disk16.png | Bin 0 -> 829 bytes src/eu/engys/resources/images/monitor16.png | Bin 0 -> 850 bytes .../resources/images/monitoringFunction16.png | Bin 0 -> 759 bytes .../resources/images/network-cloud16.png | Bin 0 -> 1417 bytes src/eu/engys/resources/images/new16.png | Bin 0 -> 487 bytes src/eu/engys/resources/images/next16.png | Bin 0 -> 742 bytes src/eu/engys/resources/images/next_grey16.png | Bin 0 -> 627 bytes src/eu/engys/resources/images/open16.png | Bin 0 -> 632 bytes src/eu/engys/resources/images/openFoam16.png | Bin 0 -> 493 bytes src/eu/engys/resources/images/opening16.png | Bin 0 -> 420 bytes src/eu/engys/resources/images/outlet16.png | Bin 0 -> 398 bytes src/eu/engys/resources/images/parMap16.png | Bin 0 -> 598 bytes src/eu/engys/resources/images/paraview16.png | Bin 0 -> 1318 bytes src/eu/engys/resources/images/patch16.png | Bin 0 -> 420 bytes src/eu/engys/resources/images/pdf16.png | Bin 0 -> 657 bytes src/eu/engys/resources/images/pencil16.png | Bin 0 -> 474 bytes src/eu/engys/resources/images/plane24.png | Bin 0 -> 1070 bytes .../engys/resources/images/planeWidget16.png | Bin 0 -> 825 bytes src/eu/engys/resources/images/png16.png | Bin 0 -> 1361 bytes .../engys/resources/images/pointField16.png | Bin 0 -> 321 bytes .../engys/resources/images/preferences16.png | Bin 0 -> 707 bytes src/eu/engys/resources/images/prev_grey16.png | Bin 0 -> 611 bytes .../engys/resources/images/reconstruct16.png | Bin 0 -> 556 bytes src/eu/engys/resources/images/refresh16.png | Bin 0 -> 753 bytes .../resources/images/refreshChartGray32.png | Bin 0 -> 846 bytes .../resources/images/refreshChartWhite32.png | Bin 0 -> 796 bytes .../engys/resources/images/refresh_grey16.png | Bin 0 -> 464 bytes src/eu/engys/resources/images/ring24.png | Bin 0 -> 1460 bytes .../engys/resources/images/rulerWidget16.png | Bin 0 -> 697 bytes src/eu/engys/resources/images/runMode16.png | Bin 0 -> 459 bytes src/eu/engys/resources/images/save16.png | Bin 0 -> 730 bytes src/eu/engys/resources/images/saveAs16.png | Bin 0 -> 858 bytes .../images/scalarbar/DIVBlueToRed16.png | Bin 0 -> 309 bytes .../images/scalarbar/DIVBlueToYellow16.png | Bin 0 -> 291 bytes .../images/scalarbar/DIVRedToBlue16.png | Bin 0 -> 295 bytes .../images/scalarbar/DIVYellowToBlue16.png | Bin 0 -> 285 bytes .../images/scalarbar/HSVBlueToRed16.png | Bin 0 -> 264 bytes .../images/scalarbar/HSVBlueToYellow16.png | Bin 0 -> 283 bytes .../images/scalarbar/HSVRedToBlue16.png | Bin 0 -> 270 bytes .../images/scalarbar/HSVYellowToBlue16.png | Bin 0 -> 289 bytes .../images/scalarbar/RGBBlueToRed16.png | Bin 0 -> 298 bytes .../images/scalarbar/RGBBlueToYellow16.png | Bin 0 -> 394 bytes .../images/scalarbar/RGBRedToBlue16.png | Bin 0 -> 293 bytes .../images/scalarbar/RGBYellowToBlue16.png | Bin 0 -> 391 bytes .../images/scalarbar/blackToWhite16.png | Bin 0 -> 381 bytes .../resources/images/scalarbar/rainbow16.png | Bin 0 -> 279 bytes .../images/scalarbar/rainbowInverted16.png | Bin 0 -> 270 bytes .../images/scalarbar/whiteToBlack16.png | Bin 0 -> 366 bytes src/eu/engys/resources/images/scalarbar16.png | Bin 0 -> 252 bytes .../resources/images/scalarbarEdit16.png | Bin 0 -> 547 bytes .../engys/resources/images/scroll_pane16.png | Bin 0 -> 1284 bytes .../resources/images/scroll_pane_lock16.png | Bin 0 -> 645 bytes .../engys/resources/images/searchTable16.png | Bin 0 -> 771 bytes .../images/shape_boundary_edges16.png | Bin 0 -> 393 bytes .../resources/images/shape_outline16.png | Bin 0 -> 396 bytes .../resources/images/shape_surface16.png | Bin 0 -> 379 bytes .../images/shape_surface_edges16.png | Bin 0 -> 636 bytes .../resources/images/shape_wireframe16.png | Bin 0 -> 532 bytes src/eu/engys/resources/images/share16.png | Bin 0 -> 553 bytes src/eu/engys/resources/images/shortcut16.png | Bin 0 -> 1572 bytes .../engys/resources/images/showResults16.png | Bin 0 -> 789 bytes src/eu/engys/resources/images/slice24.png | Bin 0 -> 1283 bytes .../engys/resources/images/sliderLock16.png | Bin 0 -> 1323 bytes .../engys/resources/images/sliderUnlock16.png | Bin 0 -> 1241 bytes src/eu/engys/resources/images/sphere24.png | Bin 0 -> 1186 bytes src/eu/engys/resources/images/starcd16.png | Bin 0 -> 854 bytes src/eu/engys/resources/images/start16.png | Bin 0 -> 742 bytes src/eu/engys/resources/images/startAll16.png | Bin 0 -> 746 bytes src/eu/engys/resources/images/stl24.png | Bin 0 -> 290 bytes src/eu/engys/resources/images/stop16.png | Bin 0 -> 739 bytes .../images/streamlinesolutions16.png | Bin 0 -> 980 bytes src/eu/engys/resources/images/symmetry16.png | Bin 0 -> 652 bytes .../resources/images/symmetryPlane16.png | Bin 0 -> 630 bytes .../resources/images/table_select_big.png | Bin 0 -> 581 bytes src/eu/engys/resources/images/terminal16.png | Bin 0 -> 669 bytes src/eu/engys/resources/images/tick16.png | Bin 0 -> 451 bytes src/eu/engys/resources/images/toolbox16.png | Bin 0 -> 779 bytes .../resources/images/transform_parallel16.png | Bin 0 -> 616 bytes .../images/transform_perspective16.png | Bin 0 -> 578 bytes src/eu/engys/resources/images/update16.png | Bin 0 -> 814 bytes src/eu/engys/resources/images/upload16.png | Bin 0 -> 743 bytes src/eu/engys/resources/images/uploadZip16.png | Bin 0 -> 746 bytes src/eu/engys/resources/images/wall16.png | Bin 0 -> 597 bytes src/eu/engys/resources/images/wedge16.png | Bin 0 -> 3302 bytes src/eu/engys/resources/images/win_close16.png | Bin 0 -> 448 bytes .../engys/resources/images/win_closeAll16.png | Bin 0 -> 545 bytes .../engys/resources/images/win_maximize16.png | Bin 0 -> 281 bytes .../engys/resources/images/win_restore16.png | Bin 0 -> 363 bytes src/eu/engys/resources/images/zip16.png | Bin 0 -> 704 bytes src/eu/engys/resources/images/zoomIn16.png | Bin 0 -> 792 bytes src/eu/engys/resources/images/zoomOut16.png | Bin 0 -> 790 bytes src/eu/engys/resources/images/zoomReset16.png | Bin 0 -> 846 bytes .../engys/resources/images/zoomToArea16.png | Bin 0 -> 779 bytes src/eu/engys/resources/old/splash.png | Bin 0 -> 18963 bytes src/eu/engys/resources/old/splash_HelyxOS.gif | Bin 0 -> 9536 bytes src/eu/engys/resources/pbs.run | 173 + .../StandardVOFBoundaryConditionsView.java | 81 + .../engys/standardVOF/StandardVOFModule.java | 194 ++ .../standardVOF/StandardVOFPhasesView.java | 96 + .../engys/standardVOF/StandardVOFReader.java | 139 + .../standardVOF/StandardVOFSolutionView.java | 75 + .../standardVOF/StandardVOFTreeView.java | 52 + .../engys/standardVOF/StandardVOFWriter.java | 101 + .../standardVOF/resources/standardVOF.fields | 130 + .../resources/standardVOF.stateData | 470 +++ src/eu/engys/suite/Suite.java | 138 + src/eu/engys/suite/SuitePanel.java | 141 + src/eu/engys/util/ApplicationInfo.java | 257 ++ src/eu/engys/util/ArchiveUtils.java | 363 +++ src/eu/engys/util/ColorUtil.java | 60 + src/eu/engys/util/CompactCharSequence.java | 96 + src/eu/engys/util/CompactStringBuilder.java | 107 + src/eu/engys/util/DimensionalUnits.java | 59 + src/eu/engys/util/FormatUtil.java | 115 + src/eu/engys/util/IOUtils.java | 108 + src/eu/engys/util/LineSeparator.java | 64 + src/eu/engys/util/MemoryWidget.java | 153 + src/eu/engys/util/OpenFOAMCommands.java | 249 ++ src/eu/engys/util/PDFFileFilter.java | 53 + src/eu/engys/util/PrefUtil.java | 257 ++ src/eu/engys/util/RegexpUtils.java | 44 + src/eu/engys/util/Symbols.java | 123 + src/eu/engys/util/TempFolder.java | 80 + src/eu/engys/util/TooltipUtils.java | 62 + src/eu/engys/util/Util.java | 595 ++++ src/eu/engys/util/VTKSettings.java | 156 + src/eu/engys/util/VersionChecker.java | 140 + src/eu/engys/util/bean/AbstractBean.java | 74 + src/eu/engys/util/bean/Bindings.java | 64 + .../util/connection/QueueParameters.java | 79 + .../engys/util/connection/SshParameters.java | 186 ++ src/eu/engys/util/connection/SshUtils.java | 618 ++++ .../util/filechooser/AbstractFileChooser.java | 174 + .../filechooser/FileChooserEventListener.java | 32 + .../util/filechooser/HelyxFileChooser.java | 163 + .../util/filechooser/LinkFileObject.java | 60 + .../util/filechooser/ParentFileObject.java | 69 + .../util/filechooser/RemoteFileChooser.java | 111 + .../filechooser/actions/DeleteFileAction.java | 82 + .../actions/ExtractArchiveAction.java | 122 + .../filechooser/actions/NewFolderAction.java | 112 + .../actions/favorite/AddFavorite.java | 91 + .../actions/favorite/EditFavorite.java | 167 + .../actions/favorite/OpenFavorite.java | 87 + .../pathnavigation/BaseNavigateAction.java | 175 + .../BaseNavigateActionGoUp.java | 82 + .../BaseNavigateActionOpen.java | 89 + .../BaseNavigateActionRefresh.java | 76 + .../filechooser/authentication/AuthStore.java | 59 + .../authentication/AuthStoreUtils.java | 306 ++ .../AuthorisationCancelledException.java | 59 + .../authentication/CompositeAuthStore.java | 110 + .../DialogPasswordProvider.java | 67 + .../authentication/MemoryAuthStore.java | 101 + .../authentication/PasswordProvider.java | 47 + .../StaticPasswordProvider.java | 56 + .../UserAuthenticationDataWrapper.java | 102 + .../UserAuthenticationInfo.java | 109 + .../UserAuthenticatorFactory.java | 66 + .../AbstractUiUserAuthenticator.java | 131 + .../OtrosStaticUserAuthenticator.java | 83 + .../authenticator/OtrosUserAuthenticator.java | 53 + ...eCentralsFromSessionUserAuthenticator.java | 101 + .../depot/FTPUserAuthenticator.java | 169 + .../filechooser/depot/OriginalVfsBrowser.java | 519 +++ .../depot/SftpUserAuthenticator.java | 140 + .../depot/SmbUserAuthenticator.java | 111 + .../util/filechooser/favorites/Favorite.java | 100 + .../filechooser/favorites/FavoritesUtils.java | 135 + .../filechooser/favorites/PopupListener.java | 116 + .../list/MutableListDragListener.java | 87 + .../list/MutableListDropHandler.java | 95 + .../favorites/list/MutableListModel.java | 98 + .../list/SelectFirstElementFocusAdapter.java | 63 + .../renderer/FavoriteListCellRenderer.java | 93 + .../engys/util/filechooser/gui/Accessory.java | 36 + .../filechooser/gui/BreadCrumbsPanel.java | 159 + .../util/filechooser/gui/BrowserFactory.java | 65 + .../util/filechooser/gui/ButtonsPanel.java | 208 ++ .../util/filechooser/gui/FavoritesPanel.java | 294 ++ .../gui/FileChooserController.java | 234 ++ .../filechooser/gui/FileChooserPanel.java | 337 ++ .../util/filechooser/gui/FileSystemPanel.java | 416 +++ .../util/filechooser/gui/LoadingPanel.java | 94 + .../engys/util/filechooser/gui/Options.java | 36 + .../engys/util/filechooser/gui/URIPanel.java | 219 ++ .../filechooser/table/FileNameWithType.java | 79 + .../table/FileNameWithTypeComparator.java | 96 + .../table/FileObjectComparator.java | 78 + .../util/filechooser/table/FileSize.java | 166 + .../table/FileSystemTableModel.java | 173 + .../table/QuickSearchKeyAdapter.java | 93 + .../table/renderer/DateTableCellRenderer.java | 83 + .../FileNameWithTypeTableCellRenderer.java | 134 + .../renderer/FileSizeTableCellRenderer.java | 65 + .../renderer/FileTypeTableCellRenderer.java | 63 + .../renderer/MixedDateTableCellRenderer.java | 66 + .../RelativeDateTableCellRenderer.java | 81 + .../engys/util/filechooser/uri/Protocol.java | 113 + .../util/filechooser/uri/VFSURIParser.java | 157 + .../util/filechooser/uri/VFSURIValidator.java | 2854 +++++++++++++++++ .../util/CompositeTaskContext.java | 79 + .../util/EngysFileSystemManager.java | 48 + .../filechooser/util/FileNameWrapper.java | 153 + .../filechooser/util/FileObjectWrapper.java | 176 + .../filechooser/util/HelyxFileFilter.java | 84 + .../filechooser/util/InvalidFileName.java | 55 + .../util/filechooser/util/SelectionMode.java | 79 + .../util/filechooser/util/TaskContext.java | 94 + .../engys/util/filechooser/util/VFSUtils.java | 547 ++++ .../engys/util/plaf/HelyxOSLookAndFeel.java | 81 + src/eu/engys/util/plaf/ILookAndFeel.java | 42 + src/eu/engys/util/plaf/TestLookAndFeel.java | 66 + .../engys/util/progress/ConsoleMonitor.java | 181 ++ src/eu/engys/util/progress/ProgressBar.java | 62 + .../engys/util/progress/ProgressDialog.java | 261 ++ .../engys/util/progress/ProgressMonitor.java | 79 + .../util/progress/ProgressMonitorImpl.java | 358 +++ src/eu/engys/util/progress/SilentMonitor.java | 162 + .../progress/VTKProgressConsoleWrapper.java | 52 + .../progress/VTKProgressMonitorWrapper.java | 54 + src/eu/engys/util/ui/ASCIIArt.java | 65 + src/eu/engys/util/ui/BigButton.java | 40 + src/eu/engys/util/ui/ButtonBar.java | 207 ++ src/eu/engys/util/ui/CheckBoxPanel.java | 95 + src/eu/engys/util/ui/ChooseFileAction.java | 80 + src/eu/engys/util/ui/ChooserPanel.java | 168 + .../engys/util/ui/ComponentTitledBorder.java | 202 ++ src/eu/engys/util/ui/ComponentsFactory.java | 445 +++ src/eu/engys/util/ui/CopyPasteSupport.java | 224 ++ src/eu/engys/util/ui/DoubleListAction.java | 116 + src/eu/engys/util/ui/DualList.java | 258 ++ src/eu/engys/util/ui/ExecUtil.java | 91 + src/eu/engys/util/ui/FileChooserUtils.java | 134 + src/eu/engys/util/ui/FileFieldPanel.java | 108 + .../util/ui/JComboBoxWithItemsSupport.java | 121 + src/eu/engys/util/ui/ListBuilder.java | 37 + src/eu/engys/util/ui/ListFieldPanel.java | 99 + .../util/ui/NoneSelectedButtonGroup.java | 40 + src/eu/engys/util/ui/RadioFieldPanel.java | 113 + src/eu/engys/util/ui/ResourcesUtil.java | 113 + src/eu/engys/util/ui/ScriptEditor.java | 367 +++ .../util/ui/SelectionValueConfigurator.java | 32 + src/eu/engys/util/ui/TableUtil.java | 43 + src/eu/engys/util/ui/TreeUtil.java | 154 + src/eu/engys/util/ui/UiUtil.java | 891 +++++ src/eu/engys/util/ui/ViewAction.java | 90 + src/eu/engys/util/ui/WrappedFlowLayout.java | 131 + .../util/ui/builder/GroupController.java | 51 + .../engys/util/ui/builder/HideController.java | 101 + .../util/ui/builder/JCheckBoxController.java | 103 + .../util/ui/builder/JComboBoxController.java | 95 + .../engys/util/ui/builder/PanelBuilder.java | 628 ++++ .../ui/checkboxtree/AddCheckBoxToTree.java | 646 ++++ .../util/ui/checkboxtree/FileTreeViewer.java | 366 +++ .../util/ui/checkboxtree/LoadableItem.java | 36 + .../util/ui/checkboxtree/RootVisibleItem.java | 58 + .../checkboxtree/RootVisibleLoadableItem.java | 46 + .../RootVisibleLoadableTreeNode.java | 62 + .../ui/checkboxtree/TristateCheckBox.java | 295 ++ .../util/ui/checkboxtree/VisibleItem.java | 35 + .../ui/groupcolumnheader/ColumnGroup.java | 143 + .../GroupableTableColumnModel.java | 68 + .../GroupableTableHeader.java | 50 + .../GroupableTableHeaderUI.java | 157 + .../util/ui/stepcomponent/FlatButtonUI.java | 173 + .../util/ui/stepcomponent/MultiLineLabel.java | 698 ++++ .../util/ui/stepcomponent/RichJLabel.java | 142 + .../util/ui/stepcomponent/StepButton.java | 160 + .../util/ui/stepcomponent/StepButtonUI.java | 156 + .../util/ui/stepcomponent/StepComponent.java | 141 + .../ui/stepcomponent/StepComponentLayout.java | 180 ++ .../util/ui/textfields/AdaptativeFormat.java | 67 + .../engys/util/ui/textfields/DoubleField.java | 245 ++ .../util/ui/textfields/FileTextField.java | 80 + .../util/ui/textfields/IntegerField.java | 153 + .../textfields/NullableNumberFormatter.java | 61 + .../util/ui/textfields/PromptTextField.java | 156 + .../util/ui/textfields/SpinnerField.java | 86 + .../engys/util/ui/textfields/StringField.java | 94 + .../verifiers/AbstractVerifier.java | 158 + .../textfields/verifiers/DoubleVerifier.java | 74 + .../ui/textfields/verifiers/FileVerifier.java | 57 + .../textfields/verifiers/IntegerVerifier.java | 82 + .../textfields/verifiers/StringVerifier.java | 76 + .../ui/treetable/AbstractTreeTableModel.java | 129 + .../engys/util/ui/treetable/JTreeTable.java | 196 ++ .../engys/util/ui/treetable/TableFilter.java | 70 + .../ui/treetable/TreeTableCellEditor.java | 107 + .../util/ui/treetable/TreeTableModel.java | 46 + .../ui/treetable/TreeTableModelAdapter.java | 120 + .../tree/JTreeTableCellRenderer.java | 82 + .../tree/ListToTreeSelectionModelWrapper.java | 95 + .../treetable/tree/TreeTableCellRenderer.java | 95 + .../ui/treetable/tree/TreeTableTreeModel.java | 121 + .../ui/treetable/tree/TreeTableTreeNode.java | 39 + src/eu/engys/vtk/ActorsMap.java | 87 + src/eu/engys/vtk/CellZoneActor.java | 55 + src/eu/engys/vtk/GeometryContext.java | 81 + .../engys/vtk/HelyxView3DEventListener.java | 121 + src/eu/engys/vtk/InteractorStyle.java | 105 + src/eu/engys/vtk/MeshContext.java | 111 + src/eu/engys/vtk/PatchActor.java | 45 + src/eu/engys/vtk/ReaderProgress.java | 44 + src/eu/engys/vtk/RenderPanelAdapter.java | 179 ++ src/eu/engys/vtk/VTK3DActionsToolBar.java | 182 ++ src/eu/engys/vtk/VTKActors.java | 43 + src/eu/engys/vtk/VTKCameraManager.java | 78 + src/eu/engys/vtk/VTKCellZones.java | 200 ++ src/eu/engys/vtk/VTKColors.java | 192 ++ src/eu/engys/vtk/VTKEmptyView3D.java | 290 ++ src/eu/engys/vtk/VTKGeometry3DController.java | 535 +++ src/eu/engys/vtk/VTKInteractor.java | 101 + src/eu/engys/vtk/VTKInternalMesh.java | 268 ++ src/eu/engys/vtk/VTKMesh3DController.java | 518 +++ src/eu/engys/vtk/VTKMouseHandler.java | 245 ++ src/eu/engys/vtk/VTKOpenFOAMDataset.java | 436 +++ src/eu/engys/vtk/VTKOpenFOAMReader.java | 256 ++ src/eu/engys/vtk/VTKPatches.java | 202 ++ src/eu/engys/vtk/VTKPickManager.java | 222 ++ src/eu/engys/vtk/VTKRangeCalculator.java | 96 + src/eu/engys/vtk/VTKRenderPanel.java | 595 ++++ src/eu/engys/vtk/VTKUtil.java | 395 +++ src/eu/engys/vtk/VTKView3D.java | 584 ++++ src/eu/engys/vtk/VTKView3DController.java | 181 ++ src/eu/engys/vtk/VTKView3DProvider.java | 82 + src/eu/engys/vtk/WidgetPanel.java | 106 + src/eu/engys/vtk/WidgetToolBar.java | 70 + src/eu/engys/vtk/actions/ExtractLines.java | 172 + .../engys/vtk/actions/ExtractSelection.java | 377 +++ .../engys/vtk/actions/IntersectSurfaces.java | 111 + src/eu/engys/vtk/actors/BoxActor.java | 36 + src/eu/engys/vtk/actors/CylinderActor.java | 38 + src/eu/engys/vtk/actors/DefaultActor.java | 592 ++++ src/eu/engys/vtk/actors/HelyxActor.java | 516 +++ .../engys/vtk/actors/InternalMeshActor.java | 46 + src/eu/engys/vtk/actors/LineActor.java | 47 + src/eu/engys/vtk/actors/PlaneActor.java | 36 + src/eu/engys/vtk/actors/PlaneRegionActor.java | 70 + src/eu/engys/vtk/actors/RingActor.java | 36 + src/eu/engys/vtk/actors/SolidActor.java | 38 + src/eu/engys/vtk/actors/SphereActor.java | 36 + src/eu/engys/vtk/actors/StlActor.java | 56 + src/eu/engys/vtk/actors/SurfaceActor.java | 43 + src/eu/engys/vtk/actors/SurfaceToActor.java | 183 ++ .../engys/vtk/info/VTKArrayInformation.java | 647 ++++ .../vtk/info/VTKCompositeDataInformation.java | 419 +++ src/eu/engys/vtk/info/VTKConstants.java | 68 + src/eu/engys/vtk/info/VTKDataInformation.java | 1240 +++++++ .../info/VTKDataSetAttributesInformation.java | 371 +++ .../info/VTKGenericAttributeInformation.java | 54 + src/eu/engys/vtk/widgets/AxesWidget.java | 67 + src/eu/engys/vtk/widgets/AxisWidget.java | 217 ++ .../engys/vtk/widgets/AxisWidgetManager.java | 70 + src/eu/engys/vtk/widgets/CORWidget.java | 125 + .../vtk/widgets/ExtractSelectionWidget.java | 223 ++ .../vtk/widgets/LayersCoverageWidget.java | 223 ++ src/eu/engys/vtk/widgets/LogoWidget.java | 119 + .../engys/vtk/widgets/MinMaxPointWidget.java | 117 + .../vtk/widgets/MinMaxPointWidgetManager.java | 74 + .../engys/vtk/widgets/PlaneDisplayWidget.java | 113 + src/eu/engys/vtk/widgets/PlaneWidget.java | 171 + src/eu/engys/vtk/widgets/PointWidget.java | 139 + .../engys/vtk/widgets/PointWidgetManager.java | 69 + src/eu/engys/vtk/widgets/QualityWidget.java | 223 ++ .../vtk/widgets/fake/FakeClipperWidget.java | 55 + .../widgets/fake/FakeExportImageWidget.java | 55 + .../vtk/widgets/fake/FakeFieldsWidget.java | 64 + .../vtk/widgets/fake/FakeRulerWidget.java | 55 + .../vtk/widgets/fake/FakeScalarBarWidget.java | 70 + .../vtk/widgets/fake/FakeSelectionWidget.java | 56 + .../vtk/widgets/fake/FakeTimeStepsWidget.java | 114 + src/eu/engys/vtk/widgets/fake/FakeWidget.java | 118 + .../vtk/widgets/panels/BoundingBoxBar.java | 120 + .../engys/vtk/widgets/shapes/BoxWidget.java | 192 ++ .../vtk/widgets/shapes/CylinderWidget.java | 207 ++ .../vtk/widgets/shapes/SphereWidget.java | 228 ++ src/vtk/vtkPanel.java | 194 ++ 1125 files changed, 134775 insertions(+) create mode 100644 build_src.xml create mode 100644 src/eu/engys/application/AbstractApplication.java create mode 100644 src/eu/engys/application/AdPanel.java create mode 100644 src/eu/engys/application/Application.java create mode 100644 src/eu/engys/application/ApplicationEventListener.java create mode 100644 src/eu/engys/application/Batch.java create mode 100644 src/eu/engys/application/HELYXOS.java create mode 100644 src/eu/engys/application/SupportWindow.java create mode 100644 src/eu/engys/application/modules/HELYXOSModule.java create mode 100644 src/eu/engys/core/Arguments.java create mode 100644 src/eu/engys/core/LoggerUtil.java create mode 100644 src/eu/engys/core/OpenFOAMEnvironment.java create mode 100644 src/eu/engys/core/controller/AbstractController.java create mode 100644 src/eu/engys/core/controller/AbstractScriptFactory.java create mode 100644 src/eu/engys/core/controller/ApplicationActions.java create mode 100644 src/eu/engys/core/controller/BatchActions.java create mode 100644 src/eu/engys/core/controller/Client.java create mode 100644 src/eu/engys/core/controller/ClientInfo.java create mode 100644 src/eu/engys/core/controller/ClientServerCommand.java create mode 100644 src/eu/engys/core/controller/Command.java create mode 100644 src/eu/engys/core/controller/CommandInfo.java create mode 100644 src/eu/engys/core/controller/Controller.java create mode 100644 src/eu/engys/core/controller/ControllerListener.java create mode 100644 src/eu/engys/core/controller/DefaultNamingConvention.java create mode 100644 src/eu/engys/core/controller/DefaultScriptFactory.java create mode 100644 src/eu/engys/core/controller/GeometryToMesh.java create mode 100644 src/eu/engys/core/controller/HelyxOSController.java create mode 100644 src/eu/engys/core/controller/ILogServer.java create mode 100644 src/eu/engys/core/controller/LogClient.java create mode 100644 src/eu/engys/core/controller/ParsersManager.java create mode 100644 src/eu/engys/core/controller/QueueConnector.java create mode 100644 src/eu/engys/core/controller/QueueInfo.java create mode 100644 src/eu/engys/core/controller/ScriptBuilder.java create mode 100644 src/eu/engys/core/controller/ScriptFactory.java create mode 100644 src/eu/engys/core/controller/Server.java create mode 100644 src/eu/engys/core/controller/ServerInfo.java create mode 100644 src/eu/engys/core/controller/StateConnector.java create mode 100644 src/eu/engys/core/controller/StopOrKillCommandOS.java create mode 100644 src/eu/engys/core/controller/View3DOptions.java create mode 100644 src/eu/engys/core/controller/actions/AbstractRunCommand.java create mode 100644 src/eu/engys/core/controller/actions/CheckMesh.java create mode 100644 src/eu/engys/core/controller/actions/CommandException.java create mode 100644 src/eu/engys/core/controller/actions/DeleteMesh.java create mode 100644 src/eu/engys/core/controller/actions/InitialiseFields.java create mode 100644 src/eu/engys/core/controller/actions/NamingConvention.java create mode 100644 src/eu/engys/core/controller/actions/RunCase.java create mode 100644 src/eu/engys/core/controller/actions/RunCommand.java create mode 100644 src/eu/engys/core/controller/actions/RunMesh.java create mode 100644 src/eu/engys/core/controller/actions/StandardInitialiseFields.java create mode 100644 src/eu/engys/core/controller/actions/StandardRunCase.java create mode 100644 src/eu/engys/core/controller/actions/StandardRunMesh.java create mode 100644 src/eu/engys/core/controller/actions/StopCommandInfo.java create mode 100644 src/eu/engys/core/controller/actions/TimeoutException.java create mode 100644 src/eu/engys/core/dictionary/BeanToDict.java create mode 100644 src/eu/engys/core/dictionary/BlockMeshWriter.java create mode 100644 src/eu/engys/core/dictionary/DefaultElement.java create mode 100644 src/eu/engys/core/dictionary/Dictionary.java create mode 100644 src/eu/engys/core/dictionary/DictionaryBuilder.java create mode 100644 src/eu/engys/core/dictionary/DictionaryEditor.java create mode 100644 src/eu/engys/core/dictionary/DictionaryException.java create mode 100644 src/eu/engys/core/dictionary/DictionaryLinkResolver.java create mode 100644 src/eu/engys/core/dictionary/DictionaryReader.java create mode 100644 src/eu/engys/core/dictionary/DictionaryUtils.java create mode 100644 src/eu/engys/core/dictionary/DictionaryWriter.java create mode 100644 src/eu/engys/core/dictionary/DimensionedScalar.java create mode 100644 src/eu/engys/core/dictionary/FieldChangeListener.java create mode 100644 src/eu/engys/core/dictionary/FieldElement.java create mode 100644 src/eu/engys/core/dictionary/FieldListener.java create mode 100644 src/eu/engys/core/dictionary/FileEditor.java create mode 100644 src/eu/engys/core/dictionary/Finder.java create mode 100644 src/eu/engys/core/dictionary/FoamFile.java create mode 100644 src/eu/engys/core/dictionary/ListField.java create mode 100644 src/eu/engys/core/dictionary/ListReader.java create mode 100644 src/eu/engys/core/dictionary/MatrixReader.java create mode 100644 src/eu/engys/core/dictionary/StartWithFinder.java create mode 100644 src/eu/engys/core/dictionary/TableRowElement.java create mode 100644 src/eu/engys/core/dictionary/model/AbstractTableAdapter.java create mode 100644 src/eu/engys/core/dictionary/model/AxisInfo.java create mode 100644 src/eu/engys/core/dictionary/model/DictionaryModel.java create mode 100644 src/eu/engys/core/dictionary/model/DictionaryPanelBuilder.java create mode 100644 src/eu/engys/core/dictionary/model/DictionaryTableAdapter.java create mode 100644 src/eu/engys/core/dictionary/model/EventActionType.java create mode 100644 src/eu/engys/core/dictionary/model/LevelsTableAdapter.java create mode 100644 src/eu/engys/core/dictionary/model/LinesTableAdapter.java create mode 100644 src/eu/engys/core/dictionary/model/OneDictionaryPerRowTableAdapter.java create mode 100644 src/eu/engys/core/dictionary/model/PatchesMapTableAdapter.java create mode 100644 src/eu/engys/core/dictionary/model/PointInfo.java create mode 100644 src/eu/engys/core/dictionary/model/PointTableAdapter.java create mode 100644 src/eu/engys/core/dictionary/model/ShowAxisAdapter.java create mode 100644 src/eu/engys/core/dictionary/model/ShowLocationAdapter.java create mode 100644 src/eu/engys/core/dictionary/parser/DictionaryReader2.java create mode 100644 src/eu/engys/core/dictionary/parser/ListField2.java create mode 100644 src/eu/engys/core/dictionary/parser/ListReader2.java create mode 100644 src/eu/engys/core/dictionary/parser/ThetaListField2.java create mode 100644 src/eu/engys/core/dictionary/parser/ThetaListReader2.java create mode 100644 src/eu/engys/core/executor/AbstractExecutor.java create mode 100644 src/eu/engys/core/executor/AbstractScriptExecutor.java create mode 100644 src/eu/engys/core/executor/CollapseManager.java create mode 100644 src/eu/engys/core/executor/CommandExecutor.java create mode 100644 src/eu/engys/core/executor/ConsoleExecutorMonitor.java create mode 100644 src/eu/engys/core/executor/Executor.java create mode 100644 src/eu/engys/core/executor/ExecutorError.java create mode 100644 src/eu/engys/core/executor/ExecutorHook.java create mode 100644 src/eu/engys/core/executor/ExecutorListener.java create mode 100644 src/eu/engys/core/executor/ExecutorMonitor.java create mode 100644 src/eu/engys/core/executor/ExecutorTerminal.java create mode 100644 src/eu/engys/core/executor/FileManagerSupport.java create mode 100644 src/eu/engys/core/executor/JavaExecutor.java create mode 100644 src/eu/engys/core/executor/MailManagerSupport.java create mode 100644 src/eu/engys/core/executor/ProgressExecutorMonitor.java create mode 100644 src/eu/engys/core/executor/QueueExecutorMonitor.java create mode 100644 src/eu/engys/core/executor/QueueTerminalExecutorMonitor.java create mode 100644 src/eu/engys/core/executor/ScriptExecutor.java create mode 100644 src/eu/engys/core/executor/StateMapperHook.java create mode 100644 src/eu/engys/core/executor/TerminalExecutorMonitor.java create mode 100644 src/eu/engys/core/executor/TerminalManager.java create mode 100644 src/eu/engys/core/executor/TerminalOutputStream.java create mode 100644 src/eu/engys/core/executor/TerminalSupport.java create mode 100644 src/eu/engys/core/executor/TerminalTabComponent.java create mode 100644 src/eu/engys/core/executor/actions/CloseMonitorAction.java create mode 100644 src/eu/engys/core/executor/actions/CopyMonitorToClipboardAction.java create mode 100644 src/eu/engys/core/executor/actions/MaximiseMonitorAction.java create mode 100644 src/eu/engys/core/executor/actions/SaveLogFileAction.java create mode 100644 src/eu/engys/core/executor/actions/ScrollLockAction.java create mode 100644 src/eu/engys/core/executor/actions/ShowLogAction.java create mode 100644 src/eu/engys/core/executor/actions/StopCommandAction.java create mode 100644 src/eu/engys/core/modules/ApplicationModule.java create mode 100644 src/eu/engys/core/modules/ApplicationModuleAdapter.java create mode 100644 src/eu/engys/core/modules/CaseSetupReader.java create mode 100644 src/eu/engys/core/modules/CaseSetupWriter.java create mode 100644 src/eu/engys/core/modules/FieldsInitialisationView.java create mode 100644 src/eu/engys/core/modules/ModuleDefaults.java create mode 100644 src/eu/engys/core/modules/ModulePanel.java create mode 100644 src/eu/engys/core/modules/ModulesUtil.java create mode 100644 src/eu/engys/core/modules/boundaryconditions/BoundaryConditionsView.java create mode 100644 src/eu/engys/core/modules/boundaryconditions/BoundaryTypePanel.java create mode 100644 src/eu/engys/core/modules/boundaryconditions/IBoundaryConditionsPanel.java create mode 100644 src/eu/engys/core/modules/boundaryconditions/ParametersPanel.java create mode 100644 src/eu/engys/core/modules/cellzones/CellZonePanel.java create mode 100644 src/eu/engys/core/modules/cellzones/CellZonesView.java create mode 100644 src/eu/engys/core/modules/materials/MaterialsBuilder.java create mode 100644 src/eu/engys/core/modules/materials/MaterialsDatabase.java create mode 100644 src/eu/engys/core/modules/materials/MaterialsView.java create mode 100644 src/eu/engys/core/modules/solutionmodelling/AbstractSolutionView.java create mode 100644 src/eu/engys/core/modules/solutionmodelling/MultiphaseBuilder.java create mode 100644 src/eu/engys/core/modules/solutionmodelling/SolutionModellingPanel.java create mode 100644 src/eu/engys/core/modules/solutionmodelling/SolutionView.java create mode 100644 src/eu/engys/core/modules/tree/ModuleElementPanel.java create mode 100644 src/eu/engys/core/modules/tree/TreeView.java create mode 100644 src/eu/engys/core/parameters/Parameter.java create mode 100644 src/eu/engys/core/parameters/Parameters.java create mode 100644 src/eu/engys/core/presentation/Action.java create mode 100644 src/eu/engys/core/presentation/ActionContainer.java create mode 100644 src/eu/engys/core/presentation/ActionManager.java create mode 100644 src/eu/engys/core/presentation/ActionToggle.java create mode 100644 src/eu/engys/core/project/AbstractProjectReader.java create mode 100644 src/eu/engys/core/project/AbstractProjectWriter.java create mode 100644 src/eu/engys/core/project/CaseParameters.java create mode 100644 src/eu/engys/core/project/CreateCase.java create mode 100644 src/eu/engys/core/project/DefaultProjectReader.java create mode 100644 src/eu/engys/core/project/DefaultProjectWriter.java create mode 100644 src/eu/engys/core/project/InvalidProjectException.java create mode 100644 src/eu/engys/core/project/Model.java create mode 100644 src/eu/engys/core/project/NullProjectReader.java create mode 100644 src/eu/engys/core/project/NullProjectWriter.java create mode 100644 src/eu/engys/core/project/Project200To210Converter.java create mode 100644 src/eu/engys/core/project/ProjectFolderAnalyzer.java create mode 100644 src/eu/engys/core/project/ProjectFolderStructure.java create mode 100644 src/eu/engys/core/project/ProjectReader.java create mode 100644 src/eu/engys/core/project/ProjectWriter.java create mode 100644 src/eu/engys/core/project/SolverModel.java create mode 100644 src/eu/engys/core/project/SolverModelReader.java create mode 100644 src/eu/engys/core/project/SolverModelWriter.java create mode 100644 src/eu/engys/core/project/SolverState.java create mode 100644 src/eu/engys/core/project/TurbulenceModel.java create mode 100644 src/eu/engys/core/project/TurbulenceModelType.java create mode 100644 src/eu/engys/core/project/TurbulenceModels.java create mode 100644 src/eu/engys/core/project/constant/ConstantFolder.java create mode 100644 src/eu/engys/core/project/constant/PolyMeshFolder.java create mode 100644 src/eu/engys/core/project/constant/ThermophysicalProperties.java create mode 100644 src/eu/engys/core/project/constant/TransportProperties.java create mode 100644 src/eu/engys/core/project/constant/TriSurfaceFolder.java create mode 100644 src/eu/engys/core/project/constant/TurbulenceProperties.java create mode 100644 src/eu/engys/core/project/custom/Custom.java create mode 100644 src/eu/engys/core/project/custom/CustomFile.java create mode 100644 src/eu/engys/core/project/custom/CustomFileType.java create mode 100644 src/eu/engys/core/project/custom/CustomUtils.java create mode 100644 src/eu/engys/core/project/defaults/AbstractDefaultsProvider.java create mode 100644 src/eu/engys/core/project/defaults/DefaultDictDataFolder.java create mode 100644 src/eu/engys/core/project/defaults/Defaults.java create mode 100644 src/eu/engys/core/project/defaults/DefaultsProvider.java create mode 100644 src/eu/engys/core/project/defaults/DictDataFolder.java create mode 100644 src/eu/engys/core/project/defaults/JarDictDataFolder.java create mode 100644 src/eu/engys/core/project/files/DefaultFileManager.java create mode 100644 src/eu/engys/core/project/files/FileManager.java create mode 100644 src/eu/engys/core/project/files/Folder.java create mode 100644 src/eu/engys/core/project/geometry/BlockReader.java create mode 100644 src/eu/engys/core/project/geometry/BlockSaver.java create mode 100644 src/eu/engys/core/project/geometry/BoundingBox.java create mode 100644 src/eu/engys/core/project/geometry/FeatureLine.java create mode 100644 src/eu/engys/core/project/geometry/FeatureLines.java create mode 100644 src/eu/engys/core/project/geometry/Geometry.java create mode 100644 src/eu/engys/core/project/geometry/GeometryReader.java create mode 100644 src/eu/engys/core/project/geometry/GeometrySaver.java create mode 100644 src/eu/engys/core/project/geometry/GeometryWriter.java create mode 100644 src/eu/engys/core/project/geometry/Surface.java create mode 100644 src/eu/engys/core/project/geometry/TransfromMode.java create mode 100644 src/eu/engys/core/project/geometry/Type.java create mode 100644 src/eu/engys/core/project/geometry/factory/DefaultGeometryFactory.java create mode 100644 src/eu/engys/core/project/geometry/factory/EMESHReader.java create mode 100644 src/eu/engys/core/project/geometry/factory/EMESHWriter.java create mode 100644 src/eu/engys/core/project/geometry/factory/EngysGeometryFactory.java create mode 100644 src/eu/engys/core/project/geometry/factory/GeometryFactory.java create mode 100644 src/eu/engys/core/project/geometry/stl/AffineTransform.java create mode 100644 src/eu/engys/core/project/geometry/stl/ImportIGES.java create mode 100644 src/eu/engys/core/project/geometry/stl/NastranReader.java create mode 100644 src/eu/engys/core/project/geometry/stl/RemoveDuplicates.java create mode 100644 src/eu/engys/core/project/geometry/stl/STLJoiner.java create mode 100644 src/eu/engys/core/project/geometry/stl/STLManager.java create mode 100644 src/eu/engys/core/project/geometry/stl/STLReader.java create mode 100644 src/eu/engys/core/project/geometry/stl/STLReplacer.java create mode 100644 src/eu/engys/core/project/geometry/stl/STLWriter.java create mode 100644 src/eu/engys/core/project/geometry/stl/SolidWriter.java create mode 100644 src/eu/engys/core/project/geometry/surface/BaseSurface.java create mode 100644 src/eu/engys/core/project/geometry/surface/Box.java create mode 100644 src/eu/engys/core/project/geometry/surface/Cylinder.java create mode 100644 src/eu/engys/core/project/geometry/surface/MultiPlane.java create mode 100644 src/eu/engys/core/project/geometry/surface/MultiRegion.java create mode 100644 src/eu/engys/core/project/geometry/surface/NullSurface.java create mode 100644 src/eu/engys/core/project/geometry/surface/Plane.java create mode 100644 src/eu/engys/core/project/geometry/surface/PlaneRegion.java create mode 100644 src/eu/engys/core/project/geometry/surface/Region.java create mode 100644 src/eu/engys/core/project/geometry/surface/Ring.java create mode 100644 src/eu/engys/core/project/geometry/surface/Solid.java create mode 100644 src/eu/engys/core/project/geometry/surface/Sphere.java create mode 100644 src/eu/engys/core/project/geometry/surface/Stl.java create mode 100644 src/eu/engys/core/project/materials/Material.java create mode 100644 src/eu/engys/core/project/materials/Materials.java create mode 100644 src/eu/engys/core/project/materials/Materials200To210Converter.java create mode 100644 src/eu/engys/core/project/materials/MaterialsReader.java create mode 100644 src/eu/engys/core/project/materials/MaterialsWriter.java create mode 100644 src/eu/engys/core/project/materials/Phase.java create mode 100644 src/eu/engys/core/project/mesh/FieldItem.java create mode 100644 src/eu/engys/core/project/mesh/Mesh.java create mode 100644 src/eu/engys/core/project/mesh/ScalarBarType.java create mode 100644 src/eu/engys/core/project/openFOAMProject.java create mode 100644 src/eu/engys/core/project/runtimefields/RuntimeField.java create mode 100644 src/eu/engys/core/project/runtimefields/RuntimeFields.java create mode 100644 src/eu/engys/core/project/state/BuoyancyBuilder.java create mode 100644 src/eu/engys/core/project/state/EngysTable15.java create mode 100644 src/eu/engys/core/project/state/Flow.java create mode 100644 src/eu/engys/core/project/state/Mach.java create mode 100644 src/eu/engys/core/project/state/Method.java create mode 100644 src/eu/engys/core/project/state/MultiphaseModel.java create mode 100644 src/eu/engys/core/project/state/PhaseBuilder.java create mode 100644 src/eu/engys/core/project/state/PhasesNumber.java create mode 100644 src/eu/engys/core/project/state/ServerState.java create mode 100644 src/eu/engys/core/project/state/SolutionState.java create mode 100644 src/eu/engys/core/project/state/Solver.java create mode 100644 src/eu/engys/core/project/state/SolverFamily.java create mode 100644 src/eu/engys/core/project/state/SolverType.java create mode 100644 src/eu/engys/core/project/state/State.java create mode 100644 src/eu/engys/core/project/state/StateBuilder.java create mode 100644 src/eu/engys/core/project/state/StateComposer.java create mode 100644 src/eu/engys/core/project/state/Table15.java create mode 100644 src/eu/engys/core/project/state/ThermalState.java create mode 100644 src/eu/engys/core/project/state/Time.java create mode 100644 src/eu/engys/core/project/state/TurbulenceBuilder.java create mode 100644 src/eu/engys/core/project/system/BlockMeshDict.java create mode 100644 src/eu/engys/core/project/system/CaseSetupDict.java create mode 100644 src/eu/engys/core/project/system/ControlDict.java create mode 100644 src/eu/engys/core/project/system/CustomNodeDict.java create mode 100644 src/eu/engys/core/project/system/DecomposeParDict.java create mode 100644 src/eu/engys/core/project/system/FvOptions.java create mode 100644 src/eu/engys/core/project/system/FvSchemes.java create mode 100644 src/eu/engys/core/project/system/FvSolution.java create mode 100644 src/eu/engys/core/project/system/MapFieldsDict.java create mode 100644 src/eu/engys/core/project/system/RunDict.java create mode 100644 src/eu/engys/core/project/system/SetFieldsDict.java create mode 100644 src/eu/engys/core/project/system/SnappyHexMeshDict.java create mode 100644 src/eu/engys/core/project/system/SystemFolder.java create mode 100644 src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObject.java create mode 100644 src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjectPanel.java create mode 100644 src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjectType.java create mode 100644 src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjects.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/FakeParser.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObject.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjectPanel.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjectType.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjects.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/Parser.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/ParserFactory.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/ParserView.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlock.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlockUnit.java create mode 100644 src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlocks.java create mode 100644 src/eu/engys/core/project/zero/MeshRegion.java create mode 100644 src/eu/engys/core/project/zero/ParallelZeroFileManager.java create mode 100644 src/eu/engys/core/project/zero/SerialZeroFileManager.java create mode 100644 src/eu/engys/core/project/zero/ZeroFileManager.java create mode 100644 src/eu/engys/core/project/zero/ZeroFolder.java create mode 100644 src/eu/engys/core/project/zero/ZeroFolderStructure.java create mode 100644 src/eu/engys/core/project/zero/ZeroFolderUtil.java create mode 100644 src/eu/engys/core/project/zero/cellzones/CellZone.java create mode 100644 src/eu/engys/core/project/zero/cellzones/CellZoneType.java create mode 100644 src/eu/engys/core/project/zero/cellzones/CellZones.java create mode 100644 src/eu/engys/core/project/zero/cellzones/CellZones200To210Converter.java create mode 100644 src/eu/engys/core/project/zero/cellzones/CellZonesBuilder.java create mode 100644 src/eu/engys/core/project/zero/cellzones/CellZonesReader.java create mode 100644 src/eu/engys/core/project/zero/cellzones/CellZonesUtils.java create mode 100644 src/eu/engys/core/project/zero/cellzones/CellZonesWriter.java create mode 100644 src/eu/engys/core/project/zero/facezones/FaceZone.java create mode 100644 src/eu/engys/core/project/zero/facezones/FaceZones.java create mode 100644 src/eu/engys/core/project/zero/facezones/FaceZonesReader.java create mode 100644 src/eu/engys/core/project/zero/fields/AbstractInitialisations.java create mode 100644 src/eu/engys/core/project/zero/fields/ArrayInternalField.java create mode 100644 src/eu/engys/core/project/zero/fields/Field.java create mode 100644 src/eu/engys/core/project/zero/fields/FieldFilter.java create mode 100644 src/eu/engys/core/project/zero/fields/FieldReader.java create mode 100644 src/eu/engys/core/project/zero/fields/FieldWriter.java create mode 100644 src/eu/engys/core/project/zero/fields/Fields.java create mode 100644 src/eu/engys/core/project/zero/fields/FieldsDefaults.java create mode 100644 src/eu/engys/core/project/zero/fields/FieldsReader.java create mode 100644 src/eu/engys/core/project/zero/fields/FieldsWriter.java create mode 100644 src/eu/engys/core/project/zero/fields/Initialisations.java create mode 100644 src/eu/engys/core/project/zero/fields/InternalField.java create mode 100644 src/eu/engys/core/project/zero/fields/MatrixInternalField.java create mode 100644 src/eu/engys/core/project/zero/fields/ScalarInternalField.java create mode 100644 src/eu/engys/core/project/zero/fields/VectorInternalField.java create mode 100644 src/eu/engys/core/project/zero/patches/BoundaryConditions.java create mode 100644 src/eu/engys/core/project/zero/patches/BoundaryConditionsDefaults.java create mode 100644 src/eu/engys/core/project/zero/patches/BoundaryType.java create mode 100644 src/eu/engys/core/project/zero/patches/MergeBoundaryConditions.java create mode 100644 src/eu/engys/core/project/zero/patches/Patch.java create mode 100644 src/eu/engys/core/project/zero/patches/Patches.java create mode 100644 src/eu/engys/core/project/zero/patches/PatchesReader.java create mode 100644 src/eu/engys/core/project/zero/patches/PatchesWriter.java create mode 100644 src/eu/engys/core/project/zero/patches/SplitBoundaryConditions.java create mode 100644 src/eu/engys/core/report/Exporter.java create mode 100644 src/eu/engys/core/report/excel/CSVExporter.java create mode 100644 src/eu/engys/core/report/excel/ExcelExporter.java create mode 100644 src/eu/engys/core/report/excel/ExcelUtils.java create mode 100644 src/eu/engys/core/report/pdf/PDFImage.java create mode 100644 src/eu/engys/core/report/pdf/PDFPage.java create mode 100644 src/eu/engys/core/report/pdf/PDFPageEvent.java create mode 100644 src/eu/engys/core/report/pdf/PDFReport.java create mode 100644 src/eu/engys/core/report/pdf/PDFUtils.java create mode 100644 src/eu/engys/gui/AboutWindow.java create mode 100644 src/eu/engys/gui/AbstractGUIPanel.java create mode 100644 src/eu/engys/gui/Actions.java create mode 100644 src/eu/engys/gui/CreateCaseDialog.java create mode 100644 src/eu/engys/gui/DefaultGUIPanel.java create mode 100644 src/eu/engys/gui/GUIError.java create mode 100644 src/eu/engys/gui/GUIPanel.java create mode 100644 src/eu/engys/gui/GlassPane.java create mode 100644 src/eu/engys/gui/ListBuilderFactory.java create mode 100644 src/eu/engys/gui/MenuBar.java create mode 100644 src/eu/engys/gui/ModelObserver.java create mode 100644 src/eu/engys/gui/PreferencesDialog.java create mode 100644 src/eu/engys/gui/RecentItems.java create mode 100644 src/eu/engys/gui/StandardScriptFactory.java create mode 100644 src/eu/engys/gui/StartPanel.java create mode 100644 src/eu/engys/gui/casesetup/CaseSetup.java create mode 100644 src/eu/engys/gui/casesetup/CaseSetup3DElement.java create mode 100644 src/eu/engys/gui/casesetup/CaseSetupElement.java create mode 100644 src/eu/engys/gui/casesetup/RuntimeControlsPanel.java create mode 100644 src/eu/engys/gui/casesetup/actions/DecomposeCase.java create mode 100644 src/eu/engys/gui/casesetup/actions/DecomposeCaseAction.java create mode 100644 src/eu/engys/gui/casesetup/actions/DecomposeCasePanel.java create mode 100644 src/eu/engys/gui/casesetup/actions/DefaultCaseSetupActions.java create mode 100644 src/eu/engys/gui/casesetup/actions/ReconstructCase.java create mode 100644 src/eu/engys/gui/casesetup/actions/StandardCaseSetupActions.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/AbstractInterpolationTable.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/BoundaryConditionsPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/BoundaryConditionsTreeNodeManager.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/InterpolationChartPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/NonUniformComboBoxController.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/NonUniformInterpolationTable.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/TimeVaryingComboBoxController.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/TimeVaryingInterpolationTable.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/factories/CyclicFactory.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/factories/PressureFactory.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardPhaseFactory.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardPressureFactory.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardVelocityFactory.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/factories/TemperatureFactory.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/factories/TurbulenceFactory.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/factories/VelocityFactory.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractBoundaryTypePanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractCyclicAMISettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractParametersPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/CyclicSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/MomentumParametersPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/PhaseParametersPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/StandardCyclicAMISettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/ThermalParametersPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/TurbulenceParametersPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/MomentumPatch.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/PatchSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/PhasePatch.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/ThermalPatch.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/TurbulencePatch.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardMomentumWall.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardThermalWall.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardWallSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/utils/BoundaryConditionsUtils.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/utils/ThermalUtils.java create mode 100644 src/eu/engys/gui/casesetup/boundaryconditions/utils/TurbulenceUtils.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/CellZoneComparator.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/CellZonesFactory.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/CellZonesPanel.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/CellZonesTreeNodeManager.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/SourcePanelContainer.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/SourceTypeSelectionPanel.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/StandardCellZonesBuilder.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/mrf/StandardCellZoneMRFPanel.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/mrf/StandardMRF.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/porous/StandardCellZonePorousPanel.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/porous/StandardPorous.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/thermal/StandardCellZoneThermalPanel.java create mode 100644 src/eu/engys/gui/casesetup/cellzones/thermal/StandardThermal.java create mode 100644 src/eu/engys/gui/casesetup/fields/AbstractFieldsInitialisationPanel.java create mode 100644 src/eu/engys/gui/casesetup/fields/CellSetDialog.java create mode 100644 src/eu/engys/gui/casesetup/fields/CellSetRow.java create mode 100644 src/eu/engys/gui/casesetup/fields/SetFieldsDictConverter.java create mode 100644 src/eu/engys/gui/casesetup/fields/StandardFieldsInitialisationPanel.java create mode 100644 src/eu/engys/gui/casesetup/fields/StandardInitialisations.java create mode 100644 src/eu/engys/gui/casesetup/materials/AbstractIncompressibleMaterialsPanel.java create mode 100644 src/eu/engys/gui/casesetup/materials/AbstractMaterialsBuilder.java create mode 100644 src/eu/engys/gui/casesetup/materials/AbstractMaterialsReader.java create mode 100644 src/eu/engys/gui/casesetup/materials/AbstractMaterialsWriter.java create mode 100644 src/eu/engys/gui/casesetup/materials/CompressibleMaterialsPanel.java create mode 100644 src/eu/engys/gui/casesetup/materials/IncompressibleMaterialsPanel.java create mode 100644 src/eu/engys/gui/casesetup/materials/MaterialsTreeNodeManager.java create mode 100644 src/eu/engys/gui/casesetup/materials/StandardCompressibleMaterialsPanel.java create mode 100644 src/eu/engys/gui/casesetup/materials/StandardIncompressibleMaterialsPanel.java create mode 100644 src/eu/engys/gui/casesetup/materials/StandardMaterialsBuilder.java create mode 100644 src/eu/engys/gui/casesetup/materials/StandardMaterialsReader.java create mode 100644 src/eu/engys/gui/casesetup/materials/StandardMaterialsWriter.java create mode 100644 src/eu/engys/gui/casesetup/materials/panels/MaterialParametersPanel.java create mode 100644 src/eu/engys/gui/casesetup/materials/panels/MaterialsDatabasePanel.java create mode 100644 src/eu/engys/gui/casesetup/materials/panels/MaterialsPanel.java create mode 100644 src/eu/engys/gui/casesetup/phases/PhasesPanel.java create mode 100644 src/eu/engys/gui/casesetup/phases/PhasesView.java create mode 100644 src/eu/engys/gui/casesetup/run/StandardTable15.java create mode 100644 src/eu/engys/gui/casesetup/schemes/AdvectionSchemes.java create mode 100644 src/eu/engys/gui/casesetup/schemes/NumericalSchemesPanel.java create mode 100644 src/eu/engys/gui/casesetup/schemes/SchemePanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/AbstractSolutionModellingPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/StandardSolutionModellingPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/StandardThermalPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/AbstractThermalPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/FlowPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/GPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/MachPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/MethodPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/MultiphaseChooserPanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/MultiphasePanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/SolutionStatePanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/SolverTypePanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/TimePanel.java create mode 100644 src/eu/engys/gui/casesetup/solution/panels/TurbulencePanel.java create mode 100644 src/eu/engys/gui/casesetup/solver/SolverSettingsBuilder.java create mode 100644 src/eu/engys/gui/casesetup/solver/SolverSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/solver/panels/CentralSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/solver/panels/CoupledSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/solver/panels/PimpleSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/solver/panels/PisoSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/solver/panels/SimpleSettingsPanel.java create mode 100644 src/eu/engys/gui/casesetup/solver/panels/SolverPanel.java create mode 100644 src/eu/engys/gui/custom/CustomFileDialog.java create mode 100644 src/eu/engys/gui/custom/CustomNodePanel.java create mode 100644 src/eu/engys/gui/custom/CustomTreeNodeManager.java create mode 100644 src/eu/engys/gui/events/EventManager.java create mode 100644 src/eu/engys/gui/events/EventObject.java create mode 100644 src/eu/engys/gui/events/EventSubscription.java create mode 100644 src/eu/engys/gui/events/EventWatcher.java create mode 100644 src/eu/engys/gui/events/application/ApplicationEvent.java create mode 100644 src/eu/engys/gui/events/application/BaseMeshTypeChangedEvent.java create mode 100644 src/eu/engys/gui/events/application/OpenMonitorEvent.java create mode 100644 src/eu/engys/gui/events/view3D/ActorExtractEvent.java create mode 100644 src/eu/engys/gui/events/view3D/ActorPopUpEvent.java create mode 100644 src/eu/engys/gui/events/view3D/ActorSelectionEvent.java create mode 100644 src/eu/engys/gui/events/view3D/ActorVisibilityEvent.java create mode 100644 src/eu/engys/gui/events/view3D/AddSTLEvent.java create mode 100644 src/eu/engys/gui/events/view3D/AddSurfaceEvent.java create mode 100644 src/eu/engys/gui/events/view3D/AxisEvent.java create mode 100644 src/eu/engys/gui/events/view3D/BoxEvent.java create mode 100644 src/eu/engys/gui/events/view3D/ChangeSurfaceEvent.java create mode 100644 src/eu/engys/gui/events/view3D/ColorSurfaceEvent.java create mode 100644 src/eu/engys/gui/events/view3D/LayersCoverageEvent.java create mode 100644 src/eu/engys/gui/events/view3D/MeshQualityEvent.java create mode 100644 src/eu/engys/gui/events/view3D/PlaneEvent.java create mode 100644 src/eu/engys/gui/events/view3D/PointEvent.java create mode 100644 src/eu/engys/gui/events/view3D/RemoveSurfaceEvent.java create mode 100644 src/eu/engys/gui/events/view3D/RenameSurfaceEvent.java create mode 100644 src/eu/engys/gui/events/view3D/ScalarBarWidgetEvent.java create mode 100644 src/eu/engys/gui/events/view3D/SelectCellZonesEvent.java create mode 100644 src/eu/engys/gui/events/view3D/SelectPatchesEvent.java create mode 100644 src/eu/engys/gui/events/view3D/SelectSurfaceEvent.java create mode 100644 src/eu/engys/gui/events/view3D/SelectionEvent.java create mode 100644 src/eu/engys/gui/events/view3D/TransformSurfaceEvent.java create mode 100644 src/eu/engys/gui/events/view3D/View3DEvent.java create mode 100644 src/eu/engys/gui/events/view3D/VisibleItemEvent.java create mode 100644 src/eu/engys/gui/events/view3D/VolumeReportEvent.java create mode 100644 src/eu/engys/gui/events/view3D/VolumeReportVisibilityEvent.java create mode 100644 src/eu/engys/gui/mesh/GeometryPanel.java create mode 100644 src/eu/engys/gui/mesh/Mesh.java create mode 100644 src/eu/engys/gui/mesh/Mesh3DElement.java create mode 100644 src/eu/engys/gui/mesh/MeshElement.java create mode 100644 src/eu/engys/gui/mesh/actions/AddIGES.java create mode 100644 src/eu/engys/gui/mesh/actions/AddSTL.java create mode 100644 src/eu/engys/gui/mesh/actions/DefaultMeshActions.java create mode 100644 src/eu/engys/gui/mesh/actions/IGESAccessory.java create mode 100644 src/eu/engys/gui/mesh/actions/IGESFileChooserWrapper.java create mode 100644 src/eu/engys/gui/mesh/actions/RunBlockMesh.java create mode 100644 src/eu/engys/gui/mesh/actions/RunBlockMeshAction.java create mode 100644 src/eu/engys/gui/mesh/actions/STLAccessory.java create mode 100644 src/eu/engys/gui/mesh/actions/STLFileChooserWrapper.java create mode 100644 src/eu/engys/gui/mesh/actions/StandardMeshActions.java create mode 100644 src/eu/engys/gui/mesh/actions/geometry/CloneSurfaceAction.java create mode 100644 src/eu/engys/gui/mesh/actions/geometry/CopySurfaceAction.java create mode 100644 src/eu/engys/gui/mesh/actions/geometry/ExtractLineAction.java create mode 100644 src/eu/engys/gui/mesh/actions/geometry/ExtractLinesDialog.java create mode 100644 src/eu/engys/gui/mesh/actions/geometry/PasteSurfaceAction.java create mode 100644 src/eu/engys/gui/mesh/actions/geometry/RemoveSurfaceAction.java create mode 100644 src/eu/engys/gui/mesh/panels/AbstractBaseMeshPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/AbstractGeometryPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/BaseMeshTreeNodeManager.java create mode 100644 src/eu/engys/gui/mesh/panels/BoundaryMeshTreeNodeManager.java create mode 100644 src/eu/engys/gui/mesh/panels/DefaultBoundaryMeshPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/DefaultGeometryActions.java create mode 100644 src/eu/engys/gui/mesh/panels/DefaultMeshAdvancedOptionsPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/FeatureLinesPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/FeatureLinesTreeNodeManager.java create mode 100644 src/eu/engys/gui/mesh/panels/GeometriesPanelBuilder.java create mode 100644 src/eu/engys/gui/mesh/panels/GeometryBuilder.java create mode 100644 src/eu/engys/gui/mesh/panels/GeometryTreeNodeManager.java create mode 100644 src/eu/engys/gui/mesh/panels/MaterialPointsPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/SolverBoundaryMeshPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/StandardBaseMeshPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/StandardFeatureLinesPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/StandardGeometryPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/StandardMeshAdvancedOptionsPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/lines/AutomaticBaseMeshPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/lines/BoundingBoxFacesPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/lines/ColorFeatureLineAction.java create mode 100644 src/eu/engys/gui/mesh/panels/lines/FeatureLinesRefinementTable.java create mode 100644 src/eu/engys/gui/mesh/panels/lines/FromFileBaseMeshPanel.java create mode 100644 src/eu/engys/gui/mesh/panels/lines/ImportFeatureLineAction.java create mode 100644 src/eu/engys/gui/mesh/panels/lines/UserDefinedBaseMeshPanel.java create mode 100644 src/eu/engys/gui/solver/DefaultRunOptionsPanel.java create mode 100644 src/eu/engys/gui/solver/ReloadOnFinish.java create mode 100644 src/eu/engys/gui/solver/ReopenOnInitialised.java create mode 100644 src/eu/engys/gui/solver/ReopenOnMeshed.java create mode 100644 src/eu/engys/gui/solver/Solver.java create mode 100644 src/eu/engys/gui/solver/Solver3DElement.java create mode 100644 src/eu/engys/gui/solver/SolverElement.java create mode 100644 src/eu/engys/gui/solver/SolverRuntimeControlsPanel.java create mode 100644 src/eu/engys/gui/solver/UpdateClientState.java create mode 100644 src/eu/engys/gui/solver/actions/DefaultSolverActions.java create mode 100644 src/eu/engys/gui/solver/actions/EditRunSolverAction.java create mode 100644 src/eu/engys/gui/solver/actions/OpenParaviewAction.java create mode 100644 src/eu/engys/gui/solver/actions/RunSolverAction.java create mode 100644 src/eu/engys/gui/solver/actions/StandardSolverActions.java create mode 100644 src/eu/engys/gui/solver/postprocessing/ParsersHandler.java create mode 100644 src/eu/engys/gui/solver/postprocessing/ParsersViewHandler.java create mode 100644 src/eu/engys/gui/solver/postprocessing/ServerListener.java create mode 100644 src/eu/engys/gui/solver/postprocessing/ServerStateMonitor.java create mode 100644 src/eu/engys/gui/solver/postprocessing/data/DoubleListTimeBlockUnit.java create mode 100644 src/eu/engys/gui/solver/postprocessing/data/DoubleTimeBlockUnit.java create mode 100644 src/eu/engys/gui/solver/postprocessing/data/PointTimeBlockUnit.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/AbstractChartPanel.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/AbstractParserView.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/HistoryChartPanel.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/MovingAverageChartPanel.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToCSVAction.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToExcelAction.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToPNGAction.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/actions/ShowCrosshairAction.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/actions/ShowCrosshairForResidualsAction.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/actions/ShowLogFileAction.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsChartPanel.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsExporter.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsPanel.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsView.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAverageCalculator.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAveragePanel.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAverageType.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/utils/SelectedViewProvider.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/utils/SeriesPanel.java create mode 100644 src/eu/engys/gui/solver/postprocessing/panels/utils/WaitLayerUI.java create mode 100644 src/eu/engys/gui/solver/postprocessing/parsers/AbstractParser.java create mode 100644 src/eu/engys/gui/solver/postprocessing/parsers/ParserUtils.java create mode 100644 src/eu/engys/gui/solver/postprocessing/parsers/ResidualsParser.java create mode 100644 src/eu/engys/gui/solver/postprocessing/parsers/ResidualsUtils.java create mode 100644 src/eu/engys/gui/tree/AbstractSelectionHandler.java create mode 100644 src/eu/engys/gui/tree/DefaultTreeNodeManager.java create mode 100644 src/eu/engys/gui/tree/GUIPanelHandler.java create mode 100644 src/eu/engys/gui/tree/SelectionHandler.java create mode 100644 src/eu/engys/gui/tree/Tree.java create mode 100644 src/eu/engys/gui/tree/TreeNodeManager.java create mode 100644 src/eu/engys/gui/tree/TreeSelectionModel.java create mode 100644 src/eu/engys/gui/view/AbstractView3DElement.java create mode 100644 src/eu/engys/gui/view/AbstractViewElement.java create mode 100644 src/eu/engys/gui/view/ApplicationToolBar.java create mode 100644 src/eu/engys/gui/view/DefaultControllerListener.java create mode 100644 src/eu/engys/gui/view/ElementSelector.java create mode 100644 src/eu/engys/gui/view/MainPanel.java create mode 100644 src/eu/engys/gui/view/StatusBar.java create mode 100644 src/eu/engys/gui/view/SurfacesCombo.java create mode 100644 src/eu/engys/gui/view/View.java create mode 100644 src/eu/engys/gui/view/View3DElement.java create mode 100644 src/eu/engys/gui/view/ViewElement.java create mode 100644 src/eu/engys/gui/view/ViewElementNavigator.java create mode 100644 src/eu/engys/gui/view/ViewElementPanel.java create mode 100644 src/eu/engys/gui/view/ViewElementPanelTopNavigator.java create mode 100644 src/eu/engys/gui/view/ViewElementTopNavigator.java create mode 100644 src/eu/engys/gui/view/fallback/FallbackViewElement.java create mode 100644 src/eu/engys/gui/view3D/Actor.java create mode 100644 src/eu/engys/gui/view3D/Axis.java create mode 100644 src/eu/engys/gui/view3D/BoxEventButton.java create mode 100644 src/eu/engys/gui/view3D/CameraManager.java create mode 100644 src/eu/engys/gui/view3D/CanvasPanel.java create mode 100644 src/eu/engys/gui/view3D/CellPicker.java create mode 100644 src/eu/engys/gui/view3D/Context.java create mode 100644 src/eu/engys/gui/view3D/Controller3D.java create mode 100644 src/eu/engys/gui/view3D/Geometry3DController.java create mode 100644 src/eu/engys/gui/view3D/Geometry3DEventListener.java create mode 100644 src/eu/engys/gui/view3D/Interactor.java create mode 100644 src/eu/engys/gui/view3D/LayerInfo.java create mode 100644 src/eu/engys/gui/view3D/Mesh3DController.java create mode 100644 src/eu/engys/gui/view3D/Mesh3DEventListener.java create mode 100644 src/eu/engys/gui/view3D/PickInfo.java create mode 100644 src/eu/engys/gui/view3D/PickManager.java create mode 100644 src/eu/engys/gui/view3D/Picker.java create mode 100644 src/eu/engys/gui/view3D/QualityInfo.java create mode 100644 src/eu/engys/gui/view3D/RenderPanel.java create mode 100644 src/eu/engys/gui/view3D/Representation.java create mode 100644 src/eu/engys/gui/view3D/Selection.java create mode 100644 src/eu/engys/gui/view3D/View3DEventListener.java create mode 100644 src/eu/engys/gui/view3D/fallback/Fallback3DElement.java create mode 100644 src/eu/engys/gui/view3D/fallback/FallbackGeometry3DController.java create mode 100644 src/eu/engys/gui/view3D/fallback/FallbackMesh3DController.java create mode 100644 src/eu/engys/gui/view3D/fallback/FallbackView3D.java create mode 100644 src/eu/engys/gui/view3D/widget/Widget.java create mode 100644 src/eu/engys/gui/view3D/widget/WidgetComponent.java create mode 100644 src/eu/engys/launcher/AbstractApplicationLauncher.java create mode 100644 src/eu/engys/launcher/ApplicationLauncher.java create mode 100644 src/eu/engys/launcher/HELYXOSLauncher.java create mode 100644 src/eu/engys/launcher/Launcher.java create mode 100644 src/eu/engys/launcher/LocaleUtil.java create mode 100644 src/eu/engys/launcher/StartUpMonitor.java create mode 100644 src/eu/engys/launcher/modules/Modules.java create mode 100644 src/eu/engys/resources/application.properties create mode 100644 src/eu/engys/resources/bundle.properties create mode 100644 src/eu/engys/resources/driver.pbs create mode 100644 src/eu/engys/resources/elementsBox.png create mode 100644 src/eu/engys/resources/elements_logo_full.png create mode 100644 src/eu/engys/resources/engys_logo.png create mode 100644 src/eu/engys/resources/engys_logo_big.png create mode 100644 src/eu/engys/resources/engys_logo_full.png create mode 100644 src/eu/engys/resources/engys_logo_medium.png create mode 100644 src/eu/engys/resources/helyxBox.png create mode 100644 src/eu/engys/resources/helyxosBox.png create mode 100644 src/eu/engys/resources/helyxos_banner.png create mode 100644 src/eu/engys/resources/helyxos_faq.png create mode 100644 src/eu/engys/resources/helyxos_products.png create mode 100644 src/eu/engys/resources/helyxos_startup.png create mode 100644 src/eu/engys/resources/images/XNeg16.png create mode 100644 src/eu/engys/resources/images/XPos16.png create mode 100644 src/eu/engys/resources/images/YNeg16.png create mode 100644 src/eu/engys/resources/images/YPos16.png create mode 100644 src/eu/engys/resources/images/ZNeg16.png create mode 100644 src/eu/engys/resources/images/ZPos16.png create mode 100644 src/eu/engys/resources/images/application_view_list16.png create mode 100644 src/eu/engys/resources/images/arrow-turn16.png create mode 100644 src/eu/engys/resources/images/arrow_down16.png create mode 100644 src/eu/engys/resources/images/browseFile16.png create mode 100644 src/eu/engys/resources/images/browseFolder16.png create mode 100644 src/eu/engys/resources/images/calculator16.png create mode 100644 src/eu/engys/resources/images/cellField16.png create mode 100644 src/eu/engys/resources/images/clip24.png create mode 100644 src/eu/engys/resources/images/cog16.png create mode 100644 src/eu/engys/resources/images/computer16.png create mode 100644 src/eu/engys/resources/images/console16.png create mode 100644 src/eu/engys/resources/images/copy16.png create mode 100644 src/eu/engys/resources/images/crinkle24.png create mode 100644 src/eu/engys/resources/images/crosshair16.png create mode 100644 src/eu/engys/resources/images/cube24.png create mode 100644 src/eu/engys/resources/images/cursor16.png create mode 100644 src/eu/engys/resources/images/cyclic16.png create mode 100644 src/eu/engys/resources/images/cyclicAMI16.png create mode 100644 src/eu/engys/resources/images/cylinder24.png create mode 100644 src/eu/engys/resources/images/decompose16.png create mode 100644 src/eu/engys/resources/images/desktop16.png create mode 100644 src/eu/engys/resources/images/documents16.png create mode 100644 src/eu/engys/resources/images/download16.png create mode 100644 src/eu/engys/resources/images/downloadZip16.png create mode 100644 src/eu/engys/resources/images/drive16.png create mode 100644 src/eu/engys/resources/images/edit16.png create mode 100644 src/eu/engys/resources/images/email16.png create mode 100644 src/eu/engys/resources/images/empty16.png create mode 100644 src/eu/engys/resources/images/engys16.png create mode 100644 src/eu/engys/resources/images/ensight16.png create mode 100644 src/eu/engys/resources/images/erase16.png create mode 100644 src/eu/engys/resources/images/excel16.png create mode 100644 src/eu/engys/resources/images/exit16.png create mode 100644 src/eu/engys/resources/images/exit32.png create mode 100644 src/eu/engys/resources/images/export16.png create mode 100644 src/eu/engys/resources/images/exportImage16.png create mode 100644 src/eu/engys/resources/images/exportResults16.png create mode 100644 src/eu/engys/resources/images/externalMesh16.png create mode 100644 src/eu/engys/resources/images/extract16.png create mode 100644 src/eu/engys/resources/images/extrude16.png create mode 100644 src/eu/engys/resources/images/eye16.png create mode 100644 src/eu/engys/resources/images/eye_no16.png create mode 100644 src/eu/engys/resources/images/favourites16.png create mode 100644 src/eu/engys/resources/images/favouritesAdd16.png create mode 100644 src/eu/engys/resources/images/fieldview16.png create mode 100644 src/eu/engys/resources/images/file16.png create mode 100644 src/eu/engys/resources/images/fileSave16.png create mode 100644 src/eu/engys/resources/images/first16.png create mode 100644 src/eu/engys/resources/images/first_grey16.png create mode 100644 src/eu/engys/resources/images/fit16.png create mode 100644 src/eu/engys/resources/images/fluent16.png create mode 100644 src/eu/engys/resources/images/folder-open16.png create mode 100644 src/eu/engys/resources/images/folder_add16.png create mode 100644 src/eu/engys/resources/images/folder_delete16.png create mode 100644 src/eu/engys/resources/images/freeSurface16.png create mode 100644 src/eu/engys/resources/images/gridgen16.png create mode 100644 src/eu/engys/resources/images/homeFolder16.png create mode 100644 src/eu/engys/resources/images/igs24.png create mode 100644 src/eu/engys/resources/images/import16.png create mode 100644 src/eu/engys/resources/images/import_disk16.png create mode 100644 src/eu/engys/resources/images/info16.png create mode 100644 src/eu/engys/resources/images/inlet16.png create mode 100644 src/eu/engys/resources/images/jar16.png create mode 100644 src/eu/engys/resources/images/last16.png create mode 100644 src/eu/engys/resources/images/last_grey16.png create mode 100644 src/eu/engys/resources/images/license16.png create mode 100644 src/eu/engys/resources/images/lightbulb16.png create mode 100644 src/eu/engys/resources/images/lightbulb_off16.png create mode 100644 src/eu/engys/resources/images/lightning.png create mode 100644 src/eu/engys/resources/images/lockClose16.png create mode 100644 src/eu/engys/resources/images/lockOpen16.png create mode 100644 src/eu/engys/resources/images/merge16.png create mode 100644 src/eu/engys/resources/images/merge_disk16.png create mode 100644 src/eu/engys/resources/images/monitor16.png create mode 100644 src/eu/engys/resources/images/monitoringFunction16.png create mode 100644 src/eu/engys/resources/images/network-cloud16.png create mode 100644 src/eu/engys/resources/images/new16.png create mode 100644 src/eu/engys/resources/images/next16.png create mode 100644 src/eu/engys/resources/images/next_grey16.png create mode 100644 src/eu/engys/resources/images/open16.png create mode 100644 src/eu/engys/resources/images/openFoam16.png create mode 100644 src/eu/engys/resources/images/opening16.png create mode 100644 src/eu/engys/resources/images/outlet16.png create mode 100644 src/eu/engys/resources/images/parMap16.png create mode 100644 src/eu/engys/resources/images/paraview16.png create mode 100644 src/eu/engys/resources/images/patch16.png create mode 100644 src/eu/engys/resources/images/pdf16.png create mode 100644 src/eu/engys/resources/images/pencil16.png create mode 100644 src/eu/engys/resources/images/plane24.png create mode 100644 src/eu/engys/resources/images/planeWidget16.png create mode 100644 src/eu/engys/resources/images/png16.png create mode 100644 src/eu/engys/resources/images/pointField16.png create mode 100644 src/eu/engys/resources/images/preferences16.png create mode 100644 src/eu/engys/resources/images/prev_grey16.png create mode 100644 src/eu/engys/resources/images/reconstruct16.png create mode 100644 src/eu/engys/resources/images/refresh16.png create mode 100644 src/eu/engys/resources/images/refreshChartGray32.png create mode 100644 src/eu/engys/resources/images/refreshChartWhite32.png create mode 100644 src/eu/engys/resources/images/refresh_grey16.png create mode 100644 src/eu/engys/resources/images/ring24.png create mode 100644 src/eu/engys/resources/images/rulerWidget16.png create mode 100644 src/eu/engys/resources/images/runMode16.png create mode 100644 src/eu/engys/resources/images/save16.png create mode 100644 src/eu/engys/resources/images/saveAs16.png create mode 100644 src/eu/engys/resources/images/scalarbar/DIVBlueToRed16.png create mode 100644 src/eu/engys/resources/images/scalarbar/DIVBlueToYellow16.png create mode 100644 src/eu/engys/resources/images/scalarbar/DIVRedToBlue16.png create mode 100644 src/eu/engys/resources/images/scalarbar/DIVYellowToBlue16.png create mode 100644 src/eu/engys/resources/images/scalarbar/HSVBlueToRed16.png create mode 100644 src/eu/engys/resources/images/scalarbar/HSVBlueToYellow16.png create mode 100644 src/eu/engys/resources/images/scalarbar/HSVRedToBlue16.png create mode 100644 src/eu/engys/resources/images/scalarbar/HSVYellowToBlue16.png create mode 100644 src/eu/engys/resources/images/scalarbar/RGBBlueToRed16.png create mode 100644 src/eu/engys/resources/images/scalarbar/RGBBlueToYellow16.png create mode 100644 src/eu/engys/resources/images/scalarbar/RGBRedToBlue16.png create mode 100644 src/eu/engys/resources/images/scalarbar/RGBYellowToBlue16.png create mode 100644 src/eu/engys/resources/images/scalarbar/blackToWhite16.png create mode 100644 src/eu/engys/resources/images/scalarbar/rainbow16.png create mode 100644 src/eu/engys/resources/images/scalarbar/rainbowInverted16.png create mode 100644 src/eu/engys/resources/images/scalarbar/whiteToBlack16.png create mode 100644 src/eu/engys/resources/images/scalarbar16.png create mode 100644 src/eu/engys/resources/images/scalarbarEdit16.png create mode 100644 src/eu/engys/resources/images/scroll_pane16.png create mode 100644 src/eu/engys/resources/images/scroll_pane_lock16.png create mode 100644 src/eu/engys/resources/images/searchTable16.png create mode 100644 src/eu/engys/resources/images/shape_boundary_edges16.png create mode 100644 src/eu/engys/resources/images/shape_outline16.png create mode 100644 src/eu/engys/resources/images/shape_surface16.png create mode 100644 src/eu/engys/resources/images/shape_surface_edges16.png create mode 100644 src/eu/engys/resources/images/shape_wireframe16.png create mode 100644 src/eu/engys/resources/images/share16.png create mode 100644 src/eu/engys/resources/images/shortcut16.png create mode 100644 src/eu/engys/resources/images/showResults16.png create mode 100644 src/eu/engys/resources/images/slice24.png create mode 100644 src/eu/engys/resources/images/sliderLock16.png create mode 100644 src/eu/engys/resources/images/sliderUnlock16.png create mode 100644 src/eu/engys/resources/images/sphere24.png create mode 100644 src/eu/engys/resources/images/starcd16.png create mode 100644 src/eu/engys/resources/images/start16.png create mode 100644 src/eu/engys/resources/images/startAll16.png create mode 100644 src/eu/engys/resources/images/stl24.png create mode 100644 src/eu/engys/resources/images/stop16.png create mode 100644 src/eu/engys/resources/images/streamlinesolutions16.png create mode 100644 src/eu/engys/resources/images/symmetry16.png create mode 100644 src/eu/engys/resources/images/symmetryPlane16.png create mode 100644 src/eu/engys/resources/images/table_select_big.png create mode 100644 src/eu/engys/resources/images/terminal16.png create mode 100644 src/eu/engys/resources/images/tick16.png create mode 100644 src/eu/engys/resources/images/toolbox16.png create mode 100644 src/eu/engys/resources/images/transform_parallel16.png create mode 100644 src/eu/engys/resources/images/transform_perspective16.png create mode 100644 src/eu/engys/resources/images/update16.png create mode 100644 src/eu/engys/resources/images/upload16.png create mode 100644 src/eu/engys/resources/images/uploadZip16.png create mode 100644 src/eu/engys/resources/images/wall16.png create mode 100644 src/eu/engys/resources/images/wedge16.png create mode 100644 src/eu/engys/resources/images/win_close16.png create mode 100644 src/eu/engys/resources/images/win_closeAll16.png create mode 100644 src/eu/engys/resources/images/win_maximize16.png create mode 100644 src/eu/engys/resources/images/win_restore16.png create mode 100644 src/eu/engys/resources/images/zip16.png create mode 100644 src/eu/engys/resources/images/zoomIn16.png create mode 100644 src/eu/engys/resources/images/zoomOut16.png create mode 100644 src/eu/engys/resources/images/zoomReset16.png create mode 100644 src/eu/engys/resources/images/zoomToArea16.png create mode 100644 src/eu/engys/resources/old/splash.png create mode 100644 src/eu/engys/resources/old/splash_HelyxOS.gif create mode 100644 src/eu/engys/resources/pbs.run create mode 100644 src/eu/engys/standardVOF/StandardVOFBoundaryConditionsView.java create mode 100644 src/eu/engys/standardVOF/StandardVOFModule.java create mode 100644 src/eu/engys/standardVOF/StandardVOFPhasesView.java create mode 100644 src/eu/engys/standardVOF/StandardVOFReader.java create mode 100644 src/eu/engys/standardVOF/StandardVOFSolutionView.java create mode 100644 src/eu/engys/standardVOF/StandardVOFTreeView.java create mode 100644 src/eu/engys/standardVOF/StandardVOFWriter.java create mode 100644 src/eu/engys/standardVOF/resources/standardVOF.fields create mode 100644 src/eu/engys/standardVOF/resources/standardVOF.stateData create mode 100644 src/eu/engys/suite/Suite.java create mode 100644 src/eu/engys/suite/SuitePanel.java create mode 100644 src/eu/engys/util/ApplicationInfo.java create mode 100644 src/eu/engys/util/ArchiveUtils.java create mode 100644 src/eu/engys/util/ColorUtil.java create mode 100644 src/eu/engys/util/CompactCharSequence.java create mode 100644 src/eu/engys/util/CompactStringBuilder.java create mode 100644 src/eu/engys/util/DimensionalUnits.java create mode 100644 src/eu/engys/util/FormatUtil.java create mode 100644 src/eu/engys/util/IOUtils.java create mode 100644 src/eu/engys/util/LineSeparator.java create mode 100644 src/eu/engys/util/MemoryWidget.java create mode 100644 src/eu/engys/util/OpenFOAMCommands.java create mode 100644 src/eu/engys/util/PDFFileFilter.java create mode 100644 src/eu/engys/util/PrefUtil.java create mode 100644 src/eu/engys/util/RegexpUtils.java create mode 100644 src/eu/engys/util/Symbols.java create mode 100644 src/eu/engys/util/TempFolder.java create mode 100644 src/eu/engys/util/TooltipUtils.java create mode 100644 src/eu/engys/util/Util.java create mode 100644 src/eu/engys/util/VTKSettings.java create mode 100644 src/eu/engys/util/VersionChecker.java create mode 100644 src/eu/engys/util/bean/AbstractBean.java create mode 100644 src/eu/engys/util/bean/Bindings.java create mode 100644 src/eu/engys/util/connection/QueueParameters.java create mode 100644 src/eu/engys/util/connection/SshParameters.java create mode 100644 src/eu/engys/util/connection/SshUtils.java create mode 100644 src/eu/engys/util/filechooser/AbstractFileChooser.java create mode 100644 src/eu/engys/util/filechooser/FileChooserEventListener.java create mode 100644 src/eu/engys/util/filechooser/HelyxFileChooser.java create mode 100644 src/eu/engys/util/filechooser/LinkFileObject.java create mode 100644 src/eu/engys/util/filechooser/ParentFileObject.java create mode 100644 src/eu/engys/util/filechooser/RemoteFileChooser.java create mode 100644 src/eu/engys/util/filechooser/actions/DeleteFileAction.java create mode 100644 src/eu/engys/util/filechooser/actions/ExtractArchiveAction.java create mode 100644 src/eu/engys/util/filechooser/actions/NewFolderAction.java create mode 100644 src/eu/engys/util/filechooser/actions/favorite/AddFavorite.java create mode 100644 src/eu/engys/util/filechooser/actions/favorite/EditFavorite.java create mode 100644 src/eu/engys/util/filechooser/actions/favorite/OpenFavorite.java create mode 100644 src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateAction.java create mode 100644 src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionGoUp.java create mode 100644 src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionOpen.java create mode 100644 src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionRefresh.java create mode 100644 src/eu/engys/util/filechooser/authentication/AuthStore.java create mode 100644 src/eu/engys/util/filechooser/authentication/AuthStoreUtils.java create mode 100644 src/eu/engys/util/filechooser/authentication/AuthorisationCancelledException.java create mode 100644 src/eu/engys/util/filechooser/authentication/CompositeAuthStore.java create mode 100644 src/eu/engys/util/filechooser/authentication/DialogPasswordProvider.java create mode 100644 src/eu/engys/util/filechooser/authentication/MemoryAuthStore.java create mode 100644 src/eu/engys/util/filechooser/authentication/PasswordProvider.java create mode 100644 src/eu/engys/util/filechooser/authentication/StaticPasswordProvider.java create mode 100644 src/eu/engys/util/filechooser/authentication/UserAuthenticationDataWrapper.java create mode 100644 src/eu/engys/util/filechooser/authentication/UserAuthenticationInfo.java create mode 100644 src/eu/engys/util/filechooser/authentication/UserAuthenticatorFactory.java create mode 100644 src/eu/engys/util/filechooser/authentication/authenticator/AbstractUiUserAuthenticator.java create mode 100644 src/eu/engys/util/filechooser/authentication/authenticator/OtrosStaticUserAuthenticator.java create mode 100644 src/eu/engys/util/filechooser/authentication/authenticator/OtrosUserAuthenticator.java create mode 100644 src/eu/engys/util/filechooser/authentication/authenticator/UseCentralsFromSessionUserAuthenticator.java create mode 100644 src/eu/engys/util/filechooser/depot/FTPUserAuthenticator.java create mode 100644 src/eu/engys/util/filechooser/depot/OriginalVfsBrowser.java create mode 100644 src/eu/engys/util/filechooser/depot/SftpUserAuthenticator.java create mode 100644 src/eu/engys/util/filechooser/depot/SmbUserAuthenticator.java create mode 100644 src/eu/engys/util/filechooser/favorites/Favorite.java create mode 100644 src/eu/engys/util/filechooser/favorites/FavoritesUtils.java create mode 100644 src/eu/engys/util/filechooser/favorites/PopupListener.java create mode 100644 src/eu/engys/util/filechooser/favorites/list/MutableListDragListener.java create mode 100644 src/eu/engys/util/filechooser/favorites/list/MutableListDropHandler.java create mode 100644 src/eu/engys/util/filechooser/favorites/list/MutableListModel.java create mode 100644 src/eu/engys/util/filechooser/favorites/list/SelectFirstElementFocusAdapter.java create mode 100644 src/eu/engys/util/filechooser/favorites/renderer/FavoriteListCellRenderer.java create mode 100644 src/eu/engys/util/filechooser/gui/Accessory.java create mode 100644 src/eu/engys/util/filechooser/gui/BreadCrumbsPanel.java create mode 100644 src/eu/engys/util/filechooser/gui/BrowserFactory.java create mode 100644 src/eu/engys/util/filechooser/gui/ButtonsPanel.java create mode 100644 src/eu/engys/util/filechooser/gui/FavoritesPanel.java create mode 100644 src/eu/engys/util/filechooser/gui/FileChooserController.java create mode 100644 src/eu/engys/util/filechooser/gui/FileChooserPanel.java create mode 100644 src/eu/engys/util/filechooser/gui/FileSystemPanel.java create mode 100644 src/eu/engys/util/filechooser/gui/LoadingPanel.java create mode 100644 src/eu/engys/util/filechooser/gui/Options.java create mode 100644 src/eu/engys/util/filechooser/gui/URIPanel.java create mode 100644 src/eu/engys/util/filechooser/table/FileNameWithType.java create mode 100644 src/eu/engys/util/filechooser/table/FileNameWithTypeComparator.java create mode 100644 src/eu/engys/util/filechooser/table/FileObjectComparator.java create mode 100644 src/eu/engys/util/filechooser/table/FileSize.java create mode 100644 src/eu/engys/util/filechooser/table/FileSystemTableModel.java create mode 100644 src/eu/engys/util/filechooser/table/QuickSearchKeyAdapter.java create mode 100644 src/eu/engys/util/filechooser/table/renderer/DateTableCellRenderer.java create mode 100644 src/eu/engys/util/filechooser/table/renderer/FileNameWithTypeTableCellRenderer.java create mode 100644 src/eu/engys/util/filechooser/table/renderer/FileSizeTableCellRenderer.java create mode 100644 src/eu/engys/util/filechooser/table/renderer/FileTypeTableCellRenderer.java create mode 100644 src/eu/engys/util/filechooser/table/renderer/MixedDateTableCellRenderer.java create mode 100644 src/eu/engys/util/filechooser/table/renderer/RelativeDateTableCellRenderer.java create mode 100644 src/eu/engys/util/filechooser/uri/Protocol.java create mode 100644 src/eu/engys/util/filechooser/uri/VFSURIParser.java create mode 100644 src/eu/engys/util/filechooser/uri/VFSURIValidator.java create mode 100644 src/eu/engys/util/filechooser/util/CompositeTaskContext.java create mode 100644 src/eu/engys/util/filechooser/util/EngysFileSystemManager.java create mode 100644 src/eu/engys/util/filechooser/util/FileNameWrapper.java create mode 100644 src/eu/engys/util/filechooser/util/FileObjectWrapper.java create mode 100644 src/eu/engys/util/filechooser/util/HelyxFileFilter.java create mode 100644 src/eu/engys/util/filechooser/util/InvalidFileName.java create mode 100644 src/eu/engys/util/filechooser/util/SelectionMode.java create mode 100644 src/eu/engys/util/filechooser/util/TaskContext.java create mode 100644 src/eu/engys/util/filechooser/util/VFSUtils.java create mode 100644 src/eu/engys/util/plaf/HelyxOSLookAndFeel.java create mode 100644 src/eu/engys/util/plaf/ILookAndFeel.java create mode 100644 src/eu/engys/util/plaf/TestLookAndFeel.java create mode 100644 src/eu/engys/util/progress/ConsoleMonitor.java create mode 100644 src/eu/engys/util/progress/ProgressBar.java create mode 100644 src/eu/engys/util/progress/ProgressDialog.java create mode 100644 src/eu/engys/util/progress/ProgressMonitor.java create mode 100644 src/eu/engys/util/progress/ProgressMonitorImpl.java create mode 100644 src/eu/engys/util/progress/SilentMonitor.java create mode 100644 src/eu/engys/util/progress/VTKProgressConsoleWrapper.java create mode 100644 src/eu/engys/util/progress/VTKProgressMonitorWrapper.java create mode 100644 src/eu/engys/util/ui/ASCIIArt.java create mode 100644 src/eu/engys/util/ui/BigButton.java create mode 100644 src/eu/engys/util/ui/ButtonBar.java create mode 100644 src/eu/engys/util/ui/CheckBoxPanel.java create mode 100644 src/eu/engys/util/ui/ChooseFileAction.java create mode 100644 src/eu/engys/util/ui/ChooserPanel.java create mode 100644 src/eu/engys/util/ui/ComponentTitledBorder.java create mode 100644 src/eu/engys/util/ui/ComponentsFactory.java create mode 100644 src/eu/engys/util/ui/CopyPasteSupport.java create mode 100644 src/eu/engys/util/ui/DoubleListAction.java create mode 100644 src/eu/engys/util/ui/DualList.java create mode 100644 src/eu/engys/util/ui/ExecUtil.java create mode 100644 src/eu/engys/util/ui/FileChooserUtils.java create mode 100644 src/eu/engys/util/ui/FileFieldPanel.java create mode 100644 src/eu/engys/util/ui/JComboBoxWithItemsSupport.java create mode 100644 src/eu/engys/util/ui/ListBuilder.java create mode 100644 src/eu/engys/util/ui/ListFieldPanel.java create mode 100644 src/eu/engys/util/ui/NoneSelectedButtonGroup.java create mode 100644 src/eu/engys/util/ui/RadioFieldPanel.java create mode 100644 src/eu/engys/util/ui/ResourcesUtil.java create mode 100644 src/eu/engys/util/ui/ScriptEditor.java create mode 100644 src/eu/engys/util/ui/SelectionValueConfigurator.java create mode 100644 src/eu/engys/util/ui/TableUtil.java create mode 100644 src/eu/engys/util/ui/TreeUtil.java create mode 100644 src/eu/engys/util/ui/UiUtil.java create mode 100644 src/eu/engys/util/ui/ViewAction.java create mode 100644 src/eu/engys/util/ui/WrappedFlowLayout.java create mode 100644 src/eu/engys/util/ui/builder/GroupController.java create mode 100644 src/eu/engys/util/ui/builder/HideController.java create mode 100644 src/eu/engys/util/ui/builder/JCheckBoxController.java create mode 100644 src/eu/engys/util/ui/builder/JComboBoxController.java create mode 100644 src/eu/engys/util/ui/builder/PanelBuilder.java create mode 100644 src/eu/engys/util/ui/checkboxtree/AddCheckBoxToTree.java create mode 100644 src/eu/engys/util/ui/checkboxtree/FileTreeViewer.java create mode 100644 src/eu/engys/util/ui/checkboxtree/LoadableItem.java create mode 100644 src/eu/engys/util/ui/checkboxtree/RootVisibleItem.java create mode 100644 src/eu/engys/util/ui/checkboxtree/RootVisibleLoadableItem.java create mode 100644 src/eu/engys/util/ui/checkboxtree/RootVisibleLoadableTreeNode.java create mode 100644 src/eu/engys/util/ui/checkboxtree/TristateCheckBox.java create mode 100644 src/eu/engys/util/ui/checkboxtree/VisibleItem.java create mode 100644 src/eu/engys/util/ui/groupcolumnheader/ColumnGroup.java create mode 100644 src/eu/engys/util/ui/groupcolumnheader/GroupableTableColumnModel.java create mode 100644 src/eu/engys/util/ui/groupcolumnheader/GroupableTableHeader.java create mode 100644 src/eu/engys/util/ui/groupcolumnheader/GroupableTableHeaderUI.java create mode 100644 src/eu/engys/util/ui/stepcomponent/FlatButtonUI.java create mode 100644 src/eu/engys/util/ui/stepcomponent/MultiLineLabel.java create mode 100644 src/eu/engys/util/ui/stepcomponent/RichJLabel.java create mode 100644 src/eu/engys/util/ui/stepcomponent/StepButton.java create mode 100644 src/eu/engys/util/ui/stepcomponent/StepButtonUI.java create mode 100644 src/eu/engys/util/ui/stepcomponent/StepComponent.java create mode 100644 src/eu/engys/util/ui/stepcomponent/StepComponentLayout.java create mode 100644 src/eu/engys/util/ui/textfields/AdaptativeFormat.java create mode 100644 src/eu/engys/util/ui/textfields/DoubleField.java create mode 100644 src/eu/engys/util/ui/textfields/FileTextField.java create mode 100644 src/eu/engys/util/ui/textfields/IntegerField.java create mode 100644 src/eu/engys/util/ui/textfields/NullableNumberFormatter.java create mode 100644 src/eu/engys/util/ui/textfields/PromptTextField.java create mode 100644 src/eu/engys/util/ui/textfields/SpinnerField.java create mode 100644 src/eu/engys/util/ui/textfields/StringField.java create mode 100644 src/eu/engys/util/ui/textfields/verifiers/AbstractVerifier.java create mode 100644 src/eu/engys/util/ui/textfields/verifiers/DoubleVerifier.java create mode 100644 src/eu/engys/util/ui/textfields/verifiers/FileVerifier.java create mode 100644 src/eu/engys/util/ui/textfields/verifiers/IntegerVerifier.java create mode 100644 src/eu/engys/util/ui/textfields/verifiers/StringVerifier.java create mode 100644 src/eu/engys/util/ui/treetable/AbstractTreeTableModel.java create mode 100644 src/eu/engys/util/ui/treetable/JTreeTable.java create mode 100644 src/eu/engys/util/ui/treetable/TableFilter.java create mode 100644 src/eu/engys/util/ui/treetable/TreeTableCellEditor.java create mode 100644 src/eu/engys/util/ui/treetable/TreeTableModel.java create mode 100644 src/eu/engys/util/ui/treetable/TreeTableModelAdapter.java create mode 100644 src/eu/engys/util/ui/treetable/tree/JTreeTableCellRenderer.java create mode 100644 src/eu/engys/util/ui/treetable/tree/ListToTreeSelectionModelWrapper.java create mode 100644 src/eu/engys/util/ui/treetable/tree/TreeTableCellRenderer.java create mode 100644 src/eu/engys/util/ui/treetable/tree/TreeTableTreeModel.java create mode 100644 src/eu/engys/util/ui/treetable/tree/TreeTableTreeNode.java create mode 100644 src/eu/engys/vtk/ActorsMap.java create mode 100644 src/eu/engys/vtk/CellZoneActor.java create mode 100644 src/eu/engys/vtk/GeometryContext.java create mode 100644 src/eu/engys/vtk/HelyxView3DEventListener.java create mode 100644 src/eu/engys/vtk/InteractorStyle.java create mode 100644 src/eu/engys/vtk/MeshContext.java create mode 100644 src/eu/engys/vtk/PatchActor.java create mode 100644 src/eu/engys/vtk/ReaderProgress.java create mode 100644 src/eu/engys/vtk/RenderPanelAdapter.java create mode 100644 src/eu/engys/vtk/VTK3DActionsToolBar.java create mode 100644 src/eu/engys/vtk/VTKActors.java create mode 100644 src/eu/engys/vtk/VTKCameraManager.java create mode 100644 src/eu/engys/vtk/VTKCellZones.java create mode 100644 src/eu/engys/vtk/VTKColors.java create mode 100644 src/eu/engys/vtk/VTKEmptyView3D.java create mode 100644 src/eu/engys/vtk/VTKGeometry3DController.java create mode 100644 src/eu/engys/vtk/VTKInteractor.java create mode 100644 src/eu/engys/vtk/VTKInternalMesh.java create mode 100644 src/eu/engys/vtk/VTKMesh3DController.java create mode 100644 src/eu/engys/vtk/VTKMouseHandler.java create mode 100644 src/eu/engys/vtk/VTKOpenFOAMDataset.java create mode 100644 src/eu/engys/vtk/VTKOpenFOAMReader.java create mode 100644 src/eu/engys/vtk/VTKPatches.java create mode 100644 src/eu/engys/vtk/VTKPickManager.java create mode 100644 src/eu/engys/vtk/VTKRangeCalculator.java create mode 100644 src/eu/engys/vtk/VTKRenderPanel.java create mode 100644 src/eu/engys/vtk/VTKUtil.java create mode 100644 src/eu/engys/vtk/VTKView3D.java create mode 100644 src/eu/engys/vtk/VTKView3DController.java create mode 100644 src/eu/engys/vtk/VTKView3DProvider.java create mode 100644 src/eu/engys/vtk/WidgetPanel.java create mode 100644 src/eu/engys/vtk/WidgetToolBar.java create mode 100644 src/eu/engys/vtk/actions/ExtractLines.java create mode 100644 src/eu/engys/vtk/actions/ExtractSelection.java create mode 100644 src/eu/engys/vtk/actions/IntersectSurfaces.java create mode 100644 src/eu/engys/vtk/actors/BoxActor.java create mode 100644 src/eu/engys/vtk/actors/CylinderActor.java create mode 100644 src/eu/engys/vtk/actors/DefaultActor.java create mode 100644 src/eu/engys/vtk/actors/HelyxActor.java create mode 100644 src/eu/engys/vtk/actors/InternalMeshActor.java create mode 100644 src/eu/engys/vtk/actors/LineActor.java create mode 100644 src/eu/engys/vtk/actors/PlaneActor.java create mode 100644 src/eu/engys/vtk/actors/PlaneRegionActor.java create mode 100644 src/eu/engys/vtk/actors/RingActor.java create mode 100644 src/eu/engys/vtk/actors/SolidActor.java create mode 100644 src/eu/engys/vtk/actors/SphereActor.java create mode 100644 src/eu/engys/vtk/actors/StlActor.java create mode 100644 src/eu/engys/vtk/actors/SurfaceActor.java create mode 100644 src/eu/engys/vtk/actors/SurfaceToActor.java create mode 100644 src/eu/engys/vtk/info/VTKArrayInformation.java create mode 100644 src/eu/engys/vtk/info/VTKCompositeDataInformation.java create mode 100644 src/eu/engys/vtk/info/VTKConstants.java create mode 100644 src/eu/engys/vtk/info/VTKDataInformation.java create mode 100644 src/eu/engys/vtk/info/VTKDataSetAttributesInformation.java create mode 100644 src/eu/engys/vtk/info/VTKGenericAttributeInformation.java create mode 100644 src/eu/engys/vtk/widgets/AxesWidget.java create mode 100644 src/eu/engys/vtk/widgets/AxisWidget.java create mode 100644 src/eu/engys/vtk/widgets/AxisWidgetManager.java create mode 100644 src/eu/engys/vtk/widgets/CORWidget.java create mode 100644 src/eu/engys/vtk/widgets/ExtractSelectionWidget.java create mode 100644 src/eu/engys/vtk/widgets/LayersCoverageWidget.java create mode 100644 src/eu/engys/vtk/widgets/LogoWidget.java create mode 100644 src/eu/engys/vtk/widgets/MinMaxPointWidget.java create mode 100644 src/eu/engys/vtk/widgets/MinMaxPointWidgetManager.java create mode 100644 src/eu/engys/vtk/widgets/PlaneDisplayWidget.java create mode 100644 src/eu/engys/vtk/widgets/PlaneWidget.java create mode 100644 src/eu/engys/vtk/widgets/PointWidget.java create mode 100644 src/eu/engys/vtk/widgets/PointWidgetManager.java create mode 100644 src/eu/engys/vtk/widgets/QualityWidget.java create mode 100644 src/eu/engys/vtk/widgets/fake/FakeClipperWidget.java create mode 100644 src/eu/engys/vtk/widgets/fake/FakeExportImageWidget.java create mode 100644 src/eu/engys/vtk/widgets/fake/FakeFieldsWidget.java create mode 100644 src/eu/engys/vtk/widgets/fake/FakeRulerWidget.java create mode 100644 src/eu/engys/vtk/widgets/fake/FakeScalarBarWidget.java create mode 100644 src/eu/engys/vtk/widgets/fake/FakeSelectionWidget.java create mode 100644 src/eu/engys/vtk/widgets/fake/FakeTimeStepsWidget.java create mode 100644 src/eu/engys/vtk/widgets/fake/FakeWidget.java create mode 100644 src/eu/engys/vtk/widgets/panels/BoundingBoxBar.java create mode 100644 src/eu/engys/vtk/widgets/shapes/BoxWidget.java create mode 100644 src/eu/engys/vtk/widgets/shapes/CylinderWidget.java create mode 100644 src/eu/engys/vtk/widgets/shapes/SphereWidget.java create mode 100644 src/vtk/vtkPanel.java diff --git a/build_src.xml b/build_src.xml new file mode 100644 index 0000000..b5a4d2d --- /dev/null +++ b/build_src.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/eu/engys/application/AbstractApplication.java b/src/eu/engys/application/AbstractApplication.java new file mode 100644 index 0000000..b8c087f --- /dev/null +++ b/src/eu/engys/application/AbstractApplication.java @@ -0,0 +1,252 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.application; + +import static eu.engys.launcher.StartUpMonitor.close; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GraphicsDevice; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Arrays; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JPanel; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.Arguments; +import eu.engys.core.OpenFOAMEnvironment; +import eu.engys.core.controller.Controller; +import eu.engys.core.presentation.ActionContainer; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.gui.AboutWindow; +import eu.engys.gui.GlassPane; +import eu.engys.gui.PreferencesDialog; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.view.View; +import eu.engys.gui.view3D.View3DEventListener; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; + +public abstract class AbstractApplication implements Application, ActionContainer { + + private static final Logger logger = LoggerFactory.getLogger(AbstractApplication.class); + + protected JFrame frame; + public View view; + protected Model model; + public Controller controller; + protected View3DEventListener view3dListener; + + public AbstractApplication(Model model, View view, Controller controller) { + this.model = model; + this.view = view; + this.controller = controller; + } + + @Override + public JFrame getFrame() { + return frame; + } + + @Override + public boolean isDemo() { + return false; + } + + @Override + public void checkVersion() { + } + + @Override + public void run() { + initFrame(); + frame.setVisible(true); + trySettingOpenFoamFolder(); + + if (Arguments.stlFiles != null) { + if (Arguments.baseDir != null) { + ActionManager.getInstance().invoke("application.open"); + } else { + ActionManager.getInstance().invoke("application.create"); + } + } else { + if (Arguments.baseDir != null) { + controller.openCase(Arguments.baseDir); + } else { + view.showStartupDialog(this); + } + } + close(); + } + + protected void trySettingOpenFoamFolder() { + OpenFOAMEnvironment.trySettingOpenFoamFolder(frame); + } + + @Override + public void initFrame() { + view.layoutComponents(); + frame = new JFrame(getTitle()) { + @Override + public void dispose() { + EventManager.unregisterAllEventSubscriptions(); + super.dispose(); + } + + /** + * This method fixes the Synthetica laf bug that causes incorrect + * fullscreen window size on secondary monitor. + */ + @Override + public void setMaximizedBounds(Rectangle bounds) { + GraphicsDevice currentFrame = getGraphicsConfiguration().getDevice(); + if (UiUtil.isSecondaryScreen(currentFrame) && getExtendedState() == JFrame.NORMAL) { + super.setMaximizedBounds(UiUtil.getCurrentScreenSize(frame)); + } else { + super.setMaximizedBounds(bounds); + } + } + }; + view.setProgressMonitorParent(frame); + + Dimension preferredDimension = UiUtil.getPreferredScreenSize(); + logger.info("Set dimendions to {}", preferredDimension); + frame.setSize(preferredDimension); + frame.setLocationRelativeTo(null); + + UiUtil.center(frame); + + frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + + frame.setIconImages(Arrays.asList(new Image[] { ((ImageIcon) getSmallIcon()).getImage(), ((ImageIcon) getBigIcon()).getImage() })); + + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + ActionManager.getInstance().invoke("application.exit"); + } + }); + frame.setName("MainFrame"); + frame.getRootPane().updateUI(); + frame.setJMenuBar(view.getMenuBar()); + + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(view, BorderLayout.CENTER); + frame.getContentPane().add(view.getStatusBar(), BorderLayout.SOUTH); + + GlassPane glassPane = new GlassPane(); + frame.setGlassPane(glassPane); + glassPane.setVisible(false); + + + customizeGUIFrame(view); + } + + public View getView() { + return view; + } + + public Model getModel() { + return model; + } + + public abstract String getTitle(); + + protected abstract void customizeGUIFrame(View view); + + protected void addPreferencesItem(final View view) { + JMenuItem preferencesItem = new JMenuItem(new AbstractAction("Preferences", PREFERENCES_ICON) { + @Override + public void actionPerformed(ActionEvent e) { + new PreferencesDialog(isOS(), hasParaview(), hasFieldView(), hasEnsight(), hasSolverPreferences(), model.getDefaults().getDictDataFolder()).show(); + } + }); + preferencesItem.setName("Application Preferences"); + view.getMenuBar().getEditMenu().add(preferencesItem); + } + + protected abstract boolean hasParaview(); + + protected abstract boolean hasFieldView(); + + protected abstract boolean hasEnsight(); + + protected boolean hasSolverPreferences() { + return true; + } + + protected boolean isOS() { + return false; + } + + protected void addHelpItem(final View view) { + view.getMenuBar().getHelpMenu().add(new AbstractAction("About", INFO_ICON) { + @Override + public void actionPerformed(ActionEvent e) { + new AboutWindow(getMediumIcon(), getBannerIcon()); + } + }); + } + + + @Override + public JPanel createAdPanel() { + return new JPanel(); + } + + @Override + public JPanel createVersionPanel() { + return new JPanel(); + } + + /** + * RESOURCES + */ + + public static final Icon PREFERENCES_ICON = ResourcesUtil.getIcon("preferences.icon"); + public static final Icon LICENSE_ICON = ResourcesUtil.getIcon("license.icon"); + public static final Icon INFO_ICON = ResourcesUtil.getIcon("info.icon"); + public static final Icon PDF_ICON = ResourcesUtil.getIcon("file.pdf"); + public static final Icon FOLDER_ICON = ResourcesUtil.getIcon("application.open.icon"); + + public static final Icon SMALL_LOGO = ResourcesUtil.getIcon("engys.logo"); + public static final Icon BIG_LOGO = ResourcesUtil.getIcon("engys.logo.big"); + public static final Icon MEDIUM_LOGO = ResourcesUtil.getIcon("engys.logo.medium"); + public static final Icon FULL_LOGO = ResourcesUtil.getIcon("engys.logo.full"); +} diff --git a/src/eu/engys/application/AdPanel.java b/src/eu/engys/application/AdPanel.java new file mode 100644 index 0000000..ecba263 --- /dev/null +++ b/src/eu/engys/application/AdPanel.java @@ -0,0 +1,133 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.application; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import eu.engys.util.Symbols; +import eu.engys.util.Util; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; + +public class AdPanel extends JPanel { + + private static final String ENGYS = "ENGYS" + Symbols.REGISTERED; + + public static final Icon FAQ = ResourcesUtil.getIcon("helyxos.faq"); + public static final Icon ENGYS_PRODUCTS = ResourcesUtil.getIcon("helyxos.products"); + public static final Icon HELYX_BOX = ResourcesUtil.getIcon("helyxos.helyx.box"); + public static final Icon HELYX_OS_BOX = ResourcesUtil.getIcon("helyxos.helyxos.box"); + public static final Icon ELEMENTS_BOX = ResourcesUtil.getIcon("helyxos.elements.box"); + public static final Icon FULL_LOGO = ResourcesUtil.getIcon("engys.logo.full"); + + public AdPanel() { + super(new BorderLayout()); + layoutComponents(); + + setBorder(BorderFactory.createTitledBorder(ENGYS + " products")); + } + + private void layoutComponents() { + createCentralPanel(); + createSouthPanel(); + } + + private void createCentralPanel() { + JPanel productsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + productsPanel.add(new JLabel(HELYX_BOX)); + productsPanel.add(new JLabel(HELYX_OS_BOX)); + productsPanel.add(new JLabel(ELEMENTS_BOX)); + + add(productsPanel, BorderLayout.CENTER); + } + + private void createSouthPanel() { + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + buttonsPanel.add(createShowImageButton("FAQ", FAQ)); + buttonsPanel.add(createShowImageButton("Products Comparison", ENGYS_PRODUCTS)); + buttonsPanel.add(createOpenEngysSiteButton()); + + JPanel southPanel = new JPanel(new GridLayout(2, 1)); + southPanel.add(new JLabel(FULL_LOGO, JLabel.CENTER)); + southPanel.add(buttonsPanel); + + add(southPanel, BorderLayout.SOUTH); + + } + + private JButton createShowImageButton(final String title, final Icon image) { + return new JButton(new AbstractAction(title) { + + @Override + public void actionPerformed(ActionEvent e) { + JDialog dialog = new JDialog(UiUtil.getActiveWindow(), title); + dialog.setModal(true); + dialog.setSize(1000, 600); + dialog.setLocationRelativeTo(null); + dialog.getContentPane().setLayout(new BorderLayout()); + + JLabel label = new JLabel(image); + label.setBackground(Color.WHITE); + + JScrollPane jsp = new JScrollPane(label); + jsp.setOpaque(false); + jsp.getViewport().setOpaque(false); + jsp.getVerticalScrollBar().setUnitIncrement(20); + dialog.getContentPane().add(jsp, BorderLayout.CENTER); + + dialog.setVisible(true); + } + }); + } + + private JButton createOpenEngysSiteButton() { + return new JButton(new AbstractAction(ENGYS + " Website") { + @Override + public void actionPerformed(ActionEvent e) { + try { + Util.openWebpage(new URL("http://www.engys.com")); + } catch (MalformedURLException e1) { + e1.printStackTrace(); + } + } + }); + } +} diff --git a/src/eu/engys/application/Application.java b/src/eu/engys/application/Application.java new file mode 100644 index 0000000..41278b3 --- /dev/null +++ b/src/eu/engys/application/Application.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.application; + +import javax.swing.Icon; +import javax.swing.JFrame; +import javax.swing.JPanel; + +public interface Application extends Runnable { + + public JFrame getFrame(); + public void initFrame(); + + public abstract String getTitle(); + + public abstract Icon getSmallIcon(); + public abstract Icon getMediumIcon(); + public abstract Icon getBigIcon(); + public abstract Icon getFullLogo(); + + public abstract Icon getBannerIcon(); + public abstract Icon getBgIcon(); + + public abstract JPanel createAdPanel(); + public abstract JPanel createVersionPanel(); + + public void checkVersion(); + +} diff --git a/src/eu/engys/application/ApplicationEventListener.java b/src/eu/engys/application/ApplicationEventListener.java new file mode 100644 index 0000000..21dec04 --- /dev/null +++ b/src/eu/engys/application/ApplicationEventListener.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.application; + +import java.io.File; + +import eu.engys.core.project.CaseParameters; +import eu.engys.gui.events.EventManager.GenericEventListener; + +public interface ApplicationEventListener extends GenericEventListener { + + void createCase(CaseParameters params); + + void openCase(File file); + + void saveCase(File file); + + void setupMesh(); + + void runMesh(); + + void setupCase(); + + void runCase(); + + +} diff --git a/src/eu/engys/application/Batch.java b/src/eu/engys/application/Batch.java new file mode 100644 index 0000000..66e8147 --- /dev/null +++ b/src/eu/engys/application/Batch.java @@ -0,0 +1,35 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.application; + + +public interface Batch extends Runnable { + + public abstract String getTitle(); + +} + diff --git a/src/eu/engys/application/HELYXOS.java b/src/eu/engys/application/HELYXOS.java new file mode 100644 index 0000000..3e70ead --- /dev/null +++ b/src/eu/engys/application/HELYXOS.java @@ -0,0 +1,217 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.application; + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Inject; + +import eu.engys.core.OpenFOAMEnvironment; +import eu.engys.core.controller.Controller; +import eu.engys.core.presentation.Action; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.gui.view.View; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.Symbols; +import eu.engys.util.Util; +import eu.engys.util.VersionChecker; +import eu.engys.util.VersionChecker.VersionType; +import eu.engys.util.ui.ResourcesUtil; + +public class HELYXOS extends AbstractApplication { + + private static final Logger logger = LoggerFactory.getLogger(HELYXOS.class); + private static final String DISCLAIMER = "This offering is not approved or endorsed by OpenCFD" + Symbols.COPYRIGHT + " Limited, the producer of the OPENFOAM" + Symbols.COPYRIGHT + " software and owner of the OPENFOAM" + Symbols.COPYRIGHT + " and OpenCFD" + Symbols.COPYRIGHT + " trade marks."; + + private JLabel versionLabel; + private JButton versionButton; + + @Inject + public HELYXOS(Model model, View view, Controller controller) { + super(model, view, controller); + ActionManager.getInstance().parseActions(this); + + BoundaryType.registerBoundaryType(BoundaryType.PATCH); + BoundaryType.registerBoundaryType(BoundaryType.WALL); + BoundaryType.registerBoundaryType(BoundaryType.EMPTY); + BoundaryType.registerBoundaryType(BoundaryType.CYCLIC_AMI); + BoundaryType.registerBoundaryType(BoundaryType.CYCLIC); + BoundaryType.registerBoundaryType(BoundaryType.SYMMETRY_PLANE); + BoundaryType.registerBoundaryType(BoundaryType.SYMMETRY); + BoundaryType.registerBoundaryType(BoundaryType.WEDGE); + } + + @Override + public String getTitle() { + return ApplicationInfo.getName() + " - powered by " + ApplicationInfo.getVendor() + Symbols.REGISTERED; + } + + @Override + protected void customizeGUIFrame(final View view) { + addPreferencesItem(view); + addHelpItem(view); + addSupportItem(view); + } + + @Override + protected void trySettingOpenFoamFolder() { + OpenFOAMEnvironment.trySettingOpenFoamFolderOS(frame); + } + + private void addSupportItem(final View view) { + view.getMenuBar().getHelpMenu().add(new AbstractAction("Support", INFO_ICON) { + @Override + public void actionPerformed(ActionEvent e) { + showSupportWindow(); + } + }); + } + + @Action(key = "application.support.window") + public void showSupportWindow() { + new SupportWindow(getMediumIcon(), getBannerIcon(), DISCLAIMER); + } + + @Override + public void checkVersion() { + new Thread(new Runnable() { + @Override + public void run() { + VersionType versionType = VersionChecker.isNewVersionAvailable(); + if (versionType.isUpdated()) { + versionLabel.setText("Your version is up to date!"); + versionLabel.setForeground(Color.GREEN.darker()); + versionButton.setVisible(false); + } else if (versionType.isOld()) { + versionLabel.setText("Version " + VersionChecker.getOnlineVersion() + " is available for download!"); + versionLabel.setForeground(Color.RED); + versionButton.setVisible(true); + } else if (versionType.isNotAvailable()) { + versionLabel.setText("Version not available!"); + versionButton.setVisible(false); + } + } + }).start(); + } + + @Override + public JPanel createAdPanel() { + return new AdPanel(); + } + + @Override + public JPanel createVersionPanel() { + JPanel panel = new JPanel(new FlowLayout()); + panel.add(versionLabel = new JLabel("Checking for updates...")); + versionLabel.setFont(new Font(versionLabel.getFont().getFontName(), Font.BOLD, versionLabel.getFont().getSize())); + + panel.add(versionButton = new JButton(new AbstractAction("Download") { + @Override + public void actionPerformed(ActionEvent e) { + String downloadPage = ApplicationInfo.getSite() + "/files"; + try { + Util.openWebpage(new URL(downloadPage)); + } catch (MalformedURLException e1) { + logger.error("Cannot open " + downloadPage); + } + } + })); + versionButton.setVisible(false); + panel.setBorder(BorderFactory.createTitledBorder("Version")); + return panel; + } + + @Override + protected boolean isOS() { + return true; + } + + @Override + protected boolean hasParaview() { + return true; + } + + @Override + protected boolean hasFieldView() { + return false; + } + + @Override + protected boolean hasEnsight() { + return false; + } + + @Override + public Icon getSmallIcon() { + return SMALL_LOGO; + } + + @Override + public Icon getBigIcon() { + return BIG_LOGO; + } + + @Override + public Icon getBannerIcon() { + return BANNER; + } + + @Override + public Icon getBgIcon() { + return STARTUP_BACKGROUND; + } + + @Override + public Icon getMediumIcon() { + return MEDIUM_LOGO; + } + + @Override + public Icon getFullLogo() { + return null; + } + + public static final Icon BANNER = ResourcesUtil.getIcon("helyxos.banner"); + public static final Icon STARTUP_BACKGROUND = ResourcesUtil.getIcon("helyxos.startup"); + +} diff --git a/src/eu/engys/application/SupportWindow.java b/src/eu/engys/application/SupportWindow.java new file mode 100644 index 0000000..946395d --- /dev/null +++ b/src/eu/engys/application/SupportWindow.java @@ -0,0 +1,198 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.application; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; +import javax.swing.JWindow; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledDocument; + +import eu.engys.util.ApplicationInfo; +import eu.engys.util.Symbols; +import eu.engys.util.ui.UiUtil; + +public class SupportWindow { + + private static final String MESSAGE = "If you require technical assistance with HELYX-OS and OPENFOAM" + Symbols.COPYRIGHT + ", ENGYS offers a dedicated user support package. For more information please contact "; + private static final String SUBJECT = "HELYX-OS%20Info%20Request"; + private final String disclaimer; + + private JWindow window; + private final Icon vendorIcon; + private final Icon applicationIcon; + + public SupportWindow(Icon vendorIcon, Icon applicationIcon, String disclaimer) { + this.vendorIcon = vendorIcon; + this.applicationIcon = applicationIcon; + this.disclaimer = disclaimer; + createWindow(); + } + + private void createWindow() { + window = new JWindow(UiUtil.getActiveWindow()); + window.getContentPane().setLayout(new BorderLayout()); + window.getContentPane().add(createMainPanel(), BorderLayout.CENTER); + window.setSize(420, 320); + window.setLocationRelativeTo(null); + window.setVisible(true); + } + + private JPanel createMainPanel() { + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.setBackground(Color.WHITE); + mainPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + mainPanel.add(createNorthPanel(), BorderLayout.NORTH); + mainPanel.add(createCenterPanel(), BorderLayout.CENTER); + mainPanel.add(createCloseButtonPanel(), BorderLayout.SOUTH); + return mainPanel; + } + + private JPanel createNorthPanel() { + JPanel panel = new JPanel(new BorderLayout()); + panel.setBackground(Color.WHITE); + panel.add(getImage(vendorIcon), BorderLayout.WEST); + panel.add(getImage(applicationIcon), BorderLayout.CENTER); + panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + return panel; + } + + private JLabel getImage(Icon imageIcon) { + JLabel label = new JLabel(imageIcon); + label.setOpaque(true); + label.setBackground(Color.WHITE); + return label; + } + + private JPanel createCloseButtonPanel() { + JPanel panel = new JPanel(new FlowLayout()); + panel.setBackground(Color.WHITE); + panel.add(new JButton(new AbstractAction("Close") { + @Override + public void actionPerformed(ActionEvent e) { + window.dispose(); + } + })); + return panel; + } + + private JPanel createCenterPanel() { + JLabel vers = center("" + ApplicationInfo.getVersion() + "", 20f, Color.BLACK); + JLabel copy = left("" + ApplicationInfo.getCopyright() + "", 10f, Color.BLACK); + + JPanel infoPanel = new JPanel(new GridBagLayout()); + infoPanel.setBackground(Color.WHITE); + infoPanel.add(vers, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(30, 10, 0, 10), 0, 0)); + infoPanel.add(copy, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 10, 30, 10), 0, 0)); + + JTextPane textPane = createTextPane(); + JScrollPane scrollPane = new JScrollPane(textPane); + + JPanel textPanePanel = new JPanel(new BorderLayout()); + textPanePanel.setBackground(Color.WHITE); + textPanePanel.add(scrollPane, BorderLayout.CENTER); + textPanePanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(infoPanel, BorderLayout.NORTH); + mainPanel.add(textPanePanel, BorderLayout.CENTER); + return mainPanel; + } + + private JTextPane createTextPane() { + JTextPane textPane = new JTextPane(); + textPane.setText(MESSAGE + ApplicationInfo.getMail() + ".\n\n" + disclaimer); + StyledDocument doc = textPane.getStyledDocument(); + SimpleAttributeSet center = new SimpleAttributeSet(); + StyleConstants.setAlignment(center, StyleConstants.ALIGN_LEFT); + doc.setParagraphAttributes(0, doc.getLength(), center, false); + textPane.setCaretPosition(0); + return textPane; + } + + private JButton createMailButton() { + final JButton button = new JButton(new AbstractAction(ApplicationInfo.getMail()) { + + @Override + public void actionPerformed(ActionEvent e) { + // MailManagerSupport.mail(TO, SUBJECT); + } + }); + button.setForeground(Color.BLUE); + return button; + } + + private JLabel center(String text, float size, Color color) { + JLabel label = new JLabel(text) { + @Override + public void paintComponent(Graphics g) { + Graphics2D graphics2d = (Graphics2D) g; + graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + super.paintComponent(g); + } + }; + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + label.setHorizontalAlignment(JLabel.CENTER); + label.setFont(label.getFont().deriveFont(size)); + label.setForeground(color); + return label; + } + + private JLabel left(String text, float size, Color color) { + JLabel label = new JLabel(text) { + @Override + public void paintComponent(Graphics g) { + Graphics2D graphics2d = (Graphics2D) g; + graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + super.paintComponent(g); + } + }; + label.setAlignmentX(JLabel.LEFT_ALIGNMENT); + label.setHorizontalAlignment(JLabel.LEFT); + label.setFont(label.getFont().deriveFont(size)); + label.setForeground(color); + return label; + } +} diff --git a/src/eu/engys/application/modules/HELYXOSModule.java b/src/eu/engys/application/modules/HELYXOSModule.java new file mode 100644 index 0000000..68a9b81 --- /dev/null +++ b/src/eu/engys/application/modules/HELYXOSModule.java @@ -0,0 +1,285 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.application.modules; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Names; + +import eu.engys.application.Application; +import eu.engys.application.HELYXOS; +import eu.engys.core.Arguments; +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.HelyxOSController; +import eu.engys.core.controller.ScriptFactory; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.DefaultProjectReader; +import eu.engys.core.project.DefaultProjectWriter; +import eu.engys.core.project.Model; +import eu.engys.core.project.NullProjectReader; +import eu.engys.core.project.NullProjectWriter; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.core.project.defaults.Defaults; +import eu.engys.core.project.defaults.DictDataFolder; +import eu.engys.core.project.defaults.JarDictDataFolder; +import eu.engys.core.project.geometry.factory.DefaultGeometryFactory; +import eu.engys.core.project.geometry.factory.GeometryFactory; +import eu.engys.core.project.materials.MaterialsReader; +import eu.engys.core.project.materials.MaterialsWriter; +import eu.engys.core.project.state.Table15; +import eu.engys.core.project.system.fieldmanipulationfunctionobjects.FieldManipulationFunctionObjectType; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObjectType; +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; +import eu.engys.core.project.zero.fields.Initialisations; +import eu.engys.gui.Actions; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.StandardScriptFactory; +import eu.engys.gui.casesetup.CaseSetup; +import eu.engys.gui.casesetup.CaseSetup3DElement; +import eu.engys.gui.casesetup.CaseSetupElement; +import eu.engys.gui.casesetup.RuntimeControlsPanel; +import eu.engys.gui.casesetup.actions.StandardCaseSetupActions; +import eu.engys.gui.casesetup.boundaryconditions.BoundaryConditionsPanel; +import eu.engys.gui.casesetup.boundaryconditions.panels.CyclicSettingsPanel; +import eu.engys.gui.casesetup.boundaryconditions.panels.StandardCyclicAMISettingsPanel; +import eu.engys.gui.casesetup.boundaryconditions.panels.patch.PatchSettingsPanel; +import eu.engys.gui.casesetup.boundaryconditions.panels.wall.StandardWallSettingsPanel; +import eu.engys.gui.casesetup.cellzones.CellZonesPanel; +import eu.engys.gui.casesetup.cellzones.StandardCellZonesBuilder; +import eu.engys.gui.casesetup.cellzones.mrf.StandardMRF; +import eu.engys.gui.casesetup.cellzones.porous.StandardPorous; +import eu.engys.gui.casesetup.cellzones.thermal.StandardThermal; +import eu.engys.gui.casesetup.fields.StandardFieldsInitialisationPanel; +import eu.engys.gui.casesetup.fields.StandardInitialisations; +import eu.engys.gui.casesetup.materials.CompressibleMaterialsPanel; +import eu.engys.gui.casesetup.materials.IncompressibleMaterialsPanel; +import eu.engys.gui.casesetup.materials.StandardCompressibleMaterialsPanel; +import eu.engys.gui.casesetup.materials.StandardIncompressibleMaterialsPanel; +import eu.engys.gui.casesetup.materials.StandardMaterialsReader; +import eu.engys.gui.casesetup.materials.StandardMaterialsWriter; +import eu.engys.gui.casesetup.materials.panels.MaterialsDatabasePanel; +import eu.engys.gui.casesetup.materials.panels.MaterialsPanel; +import eu.engys.gui.casesetup.run.StandardTable15; +import eu.engys.gui.casesetup.schemes.NumericalSchemesPanel; +import eu.engys.gui.casesetup.solution.StandardSolutionModellingPanel; +import eu.engys.gui.casesetup.solver.SolverSettingsPanel; +import eu.engys.gui.custom.CustomNodePanel; +import eu.engys.gui.mesh.Mesh; +import eu.engys.gui.mesh.Mesh3DElement; +import eu.engys.gui.mesh.MeshElement; +import eu.engys.gui.mesh.actions.StandardMeshActions; +import eu.engys.gui.mesh.panels.DefaultBoundaryMeshPanel; +import eu.engys.gui.mesh.panels.DefaultMeshAdvancedOptionsPanel; +import eu.engys.gui.mesh.panels.MaterialPointsPanel; +import eu.engys.gui.mesh.panels.SolverBoundaryMeshPanel; +import eu.engys.gui.mesh.panels.StandardBaseMeshPanel; +import eu.engys.gui.mesh.panels.StandardFeatureLinesPanel; +import eu.engys.gui.mesh.panels.StandardGeometryPanel; +import eu.engys.gui.mesh.panels.StandardMeshAdvancedOptionsPanel; +import eu.engys.gui.solver.DefaultRunOptionsPanel; +import eu.engys.gui.solver.Solver; +import eu.engys.gui.solver.Solver3DElement; +import eu.engys.gui.solver.SolverElement; +import eu.engys.gui.solver.SolverRuntimeControlsPanel; +import eu.engys.gui.solver.actions.StandardSolverActions; +import eu.engys.gui.solver.postprocessing.panels.residuals.ResidualsPanel; +import eu.engys.gui.view.View; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElement; +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.gui.view3D.Controller3D; +import eu.engys.gui.view3D.Geometry3DController; +import eu.engys.gui.view3D.Mesh3DController; +import eu.engys.gui.view3D.fallback.FallbackGeometry3DController; +import eu.engys.gui.view3D.fallback.FallbackMesh3DController; +import eu.engys.gui.view3D.fallback.FallbackView3D; +import eu.engys.gui.view3D.widget.Widget; +import eu.engys.launcher.ApplicationLauncher; +import eu.engys.launcher.HELYXOSLauncher; +import eu.engys.standardVOF.StandardVOFModule; +import eu.engys.util.VTKSettings; +import eu.engys.util.plaf.HelyxOSLookAndFeel; +import eu.engys.util.plaf.ILookAndFeel; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.progress.ProgressMonitorImpl; +import eu.engys.vtk.VTKEmptyView3D; +import eu.engys.vtk.VTKGeometry3DController; +import eu.engys.vtk.VTKMesh3DController; +import eu.engys.vtk.VTKView3D; +import eu.engys.vtk.WidgetPanel; + +public class HELYXOSModule extends AbstractModule { + + @Override + protected void configure() { + configureApp(); + configureMVC(); + configureModules(); + configure3D(); + configurePanels(); + configureBoundaryConditions(); + configureCellZones(); + configureFunctionObjects(); + } + + protected void configureApp() { + bind(ILookAndFeel.class).to(HelyxOSLookAndFeel.class).in(Singleton.class); + bind(ApplicationLauncher.class).to(HELYXOSLauncher.class).in(Singleton.class); + bind(String.class).annotatedWith(Names.named("Application")).toInstance("HELYX-OS"); + bind(Application.class).to(HELYXOS.class).in(Singleton.class); + } + + private void configureMVC() { + bind(DictDataFolder.class).to(JarDictDataFolder.class).in(Singleton.class); + bind(Defaults.class).in(Singleton.class); + bind(Model.class).in(Singleton.class); + bind(View.class).in(Singleton.class); + bind(Controller.class).to(HelyxOSController.class).in(Singleton.class); + bind(ProgressMonitor.class).to(ProgressMonitorImpl.class).in(Singleton.class); + + bind(Initialisations.class).to(StandardInitialisations.class).in(Singleton.class); + + bind(ProjectWriter.class).to(DefaultProjectWriter.class); + bind(ProjectReader.class).to(DefaultProjectReader.class); + bind(ProjectWriter.class).annotatedWith(CaseSetup.class).to(NullProjectWriter.class); + bind(ProjectReader.class).annotatedWith(CaseSetup.class).to(NullProjectReader.class); + + bind(CellZonesBuilder.class).to(StandardCellZonesBuilder.class); + + bind(MaterialsReader.class).to(StandardMaterialsReader.class); + bind(MaterialsWriter.class).to(StandardMaterialsWriter.class); + bind(CompressibleMaterialsPanel.class).to(StandardCompressibleMaterialsPanel.class); + + bind(Table15.class).to(StandardTable15.class).in(Singleton.class); + bind(ScriptFactory.class).to(StandardScriptFactory.class).in(Singleton.class); + } + + private void configureModules() { + Multibinder applicationModules = Multibinder.newSetBinder(binder(), ApplicationModule.class); + applicationModules.addBinding().to(StandardVOFModule.class).in(Singleton.class); + } + + protected void configure3D() { + bind(WidgetPanel.class).in(Singleton.class); + if (!VTKSettings.librariesAreLoaded()) { + VTKSettings.LoadAllNativeLibraries(); + } + if (VTKSettings.librariesAreLoaded()) { + if (Arguments.no3D) { + bind(CanvasPanel.class).to(VTKEmptyView3D.class).in(Singleton.class); + } else { + bind(CanvasPanel.class).to(VTKView3D.class).in(Singleton.class); + } + bind(Geometry3DController.class).to(VTKGeometry3DController.class).in(Singleton.class); + bind(Mesh3DController.class).to(VTKMesh3DController.class).in(Singleton.class); + } else { + bind(CanvasPanel.class).to(FallbackView3D.class).in(Singleton.class); + bind(Geometry3DController.class).to(FallbackGeometry3DController.class).in(Singleton.class); + bind(Mesh3DController.class).to(FallbackMesh3DController.class).in(Singleton.class); + } + + Multibinder controllers = Multibinder.newSetBinder(binder(), Controller3D.class); + controllers.addBinding().to(Geometry3DController.class).in(Singleton.class); + controllers.addBinding().to(Mesh3DController.class).in(Singleton.class); + + Multibinder.newSetBinder(binder(), Widget.class); + } + + private void configurePanels() { + bind(String.class).annotatedWith(Mesh.class).toInstance("Mesh"); + bind(String.class).annotatedWith(CaseSetup.class).toInstance("Case Setup"); + bind(String.class).annotatedWith(Solver.class).toInstance("Solver"); + + bind(View3DElement.class).annotatedWith(Mesh.class).to(Mesh3DElement.class); + bind(View3DElement.class).annotatedWith(CaseSetup.class).to(CaseSetup3DElement.class); + bind(View3DElement.class).annotatedWith(Solver.class).to(Solver3DElement.class); + + bind(Actions.class).annotatedWith(Mesh.class).to(StandardMeshActions.class).in(Singleton.class); + bind(Actions.class).annotatedWith(CaseSetup.class).to(StandardCaseSetupActions.class).in(Singleton.class); + bind(Actions.class).annotatedWith(Solver.class).to(StandardSolverActions.class).in(Singleton.class); + + bind(GeometryFactory.class).to(DefaultGeometryFactory.class); + bind(DefaultMeshAdvancedOptionsPanel.class).to(StandardMeshAdvancedOptionsPanel.class); + + bind(MaterialsDatabasePanel.class).in(Singleton.class); + bind(CompressibleMaterialsPanel.class).to(StandardCompressibleMaterialsPanel.class); + bind(IncompressibleMaterialsPanel.class).to(StandardIncompressibleMaterialsPanel.class); + + Multibinder binder = Multibinder.newSetBinder(binder(), ViewElement.class); + binder.addBinding().to(MeshElement.class).in(Singleton.class); + binder.addBinding().to(CaseSetupElement.class).in(Singleton.class); + binder.addBinding().to(SolverElement.class).in(Singleton.class); + + Multibinder panelsMesh = Multibinder.newSetBinder(binder(), GUIPanel.class, Mesh.class); + panelsMesh.addBinding().to(StandardBaseMeshPanel.class).in(Singleton.class); + panelsMesh.addBinding().to(StandardGeometryPanel.class).in(Singleton.class); + panelsMesh.addBinding().to(StandardFeatureLinesPanel.class).in(Singleton.class); + panelsMesh.addBinding().to(MaterialPointsPanel.class).in(Singleton.class); + panelsMesh.addBinding().to(DefaultBoundaryMeshPanel.class).in(Singleton.class); + panelsMesh.addBinding().to(CustomNodePanel.class).in(Singleton.class); + + Multibinder panelsCaseSetup = Multibinder.newSetBinder(binder(), GUIPanel.class, CaseSetup.class); + panelsCaseSetup.addBinding().to(StandardSolutionModellingPanel.class).in(Singleton.class); + panelsCaseSetup.addBinding().to(MaterialsPanel.class).in(Singleton.class); + panelsCaseSetup.addBinding().to(BoundaryConditionsPanel.class).in(Singleton.class); + panelsCaseSetup.addBinding().to(CellZonesPanel.class).in(Singleton.class); + panelsCaseSetup.addBinding().to(NumericalSchemesPanel.class).in(Singleton.class); + panelsCaseSetup.addBinding().to(SolverSettingsPanel.class).in(Singleton.class); + panelsCaseSetup.addBinding().to(RuntimeControlsPanel.class).in(Singleton.class); + panelsCaseSetup.addBinding().to(StandardFieldsInitialisationPanel.class).in(Singleton.class); + panelsCaseSetup.addBinding().to(CustomNodePanel.class).in(Singleton.class); + + Multibinder panelsSolver = Multibinder.newSetBinder(binder(), GUIPanel.class, Solver.class); + panelsSolver.addBinding().to(DefaultRunOptionsPanel.class).in(Singleton.class); + panelsSolver.addBinding().to(SolverRuntimeControlsPanel.class).in(Singleton.class); + panelsSolver.addBinding().to(ResidualsPanel.class).in(Singleton.class); + panelsSolver.addBinding().to(SolverBoundaryMeshPanel.class).in(Singleton.class); + } + + private void configureBoundaryConditions() { + Multibinder bcMultibinder = Multibinder.newSetBinder(binder(), BoundaryTypePanel.class); + bcMultibinder.addBinding().to(PatchSettingsPanel.class).in(Singleton.class); + bcMultibinder.addBinding().to(StandardWallSettingsPanel.class).in(Singleton.class); + bcMultibinder.addBinding().to(CyclicSettingsPanel.class).in(Singleton.class); + bcMultibinder.addBinding().to(StandardCyclicAMISettingsPanel.class).in(Singleton.class); + } + + private void configureCellZones() { + Multibinder zonesMultibinder = Multibinder.newSetBinder(binder(), CellZoneType.class); + zonesMultibinder.addBinding().to(StandardMRF.class).in(Singleton.class); + zonesMultibinder.addBinding().to(StandardPorous.class).in(Singleton.class); + zonesMultibinder.addBinding().to(StandardThermal.class).in(Singleton.class); + } + + private void configureFunctionObjects() { + Multibinder.newSetBinder(binder(), FieldManipulationFunctionObjectType.class); + Multibinder.newSetBinder(binder(), MonitoringFunctionObjectType.class); + } +} diff --git a/src/eu/engys/core/Arguments.java b/src/eu/engys/core/Arguments.java new file mode 100644 index 0000000..90ca5a5 --- /dev/null +++ b/src/eu/engys/core/Arguments.java @@ -0,0 +1,232 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core; + +import java.io.File; +import java.io.FilenameFilter; + +import org.apache.log4j.Level; + +import eu.engys.util.ApplicationInfo; +import eu.engys.util.Util; + +public class Arguments { + + private static final String LINE = " ********************************"; + private static final String TAB = " "; + + public enum CaseType { + SERIAL, PARALLEL + } + + public static boolean verbose = false; + public static boolean no3D = false; + public static boolean load3Dmesh = true; + public static boolean load3Dgeometry = true; + public static Level logLevel = Level.ERROR; + + public static File baseDir = null; + + public static boolean mesh = false; + public static boolean run = false; + public static boolean setup = false; + public static boolean all = false; + public static boolean initialise = false; + + public static boolean server = false; + public static CaseType caseType = null; + public static File[] stlFiles = null; +// public static long timeout = -1L; + + private static final String OPTION_V = "-v"; + private static final String OPTION_VV = "-V"; + private static final String OPTION_HELP = "-help"; + private static final String OPTION_NO3D = "-no3D"; + private static final String OPTION_CASE = "-case"; + + public static final String OPTION_MESH = "-mesh"; + public static final String OPTION_RUN = "-run"; + public static final String OPTION_SETUP = "-setup"; + public static final String OPTION_ALL = "-all"; + public static final String OPTION_INITIALISE = "-initialise"; + + private static final String OPTION_SERVER = "-server"; /* INTERNAL */ + private static final String OPTION_IMPORT = "-import"; /* INTERNAL */ + private static final String OPTION_NOMESH = "-no3Dmesh"; /* INTERNAL */ + private static final String OPTION_NOGEOM = "-no3DGeom"; /* INTERNAL */ +// private static final String OPTION_CORE = "-core"; /* INTERNAL */ +// private static final String OPTION_TIMEOUT = "-timeout"; /* INTERNAL */ + + public static void init(final String[] argv) { + for (int i = 0; i < argv.length; i++) { + final String arg = argv[i]; + + if (arg.charAt(0) == '-') { + switch (arg) { + case OPTION_V: logLevel = Level.INFO; verbose = true; break; + case OPTION_VV: logLevel = Level.DEBUG; verbose = true; break; + case OPTION_NO3D: no3D = true; break; + + case OPTION_CASE: + if (i == argv.length - 1) { + fatal("Missing case folder"); + printUsage(); + exit(-1); + } + String baseDirPath = argv[++i]; + final File baseDir = new File(baseDirPath); + if (!baseDir.exists()) { + warning("Case Folder \"" + baseDir.getAbsolutePath() + "\" Does Not Exist!"); + } else { + Arguments.baseDir = baseDir; + } + break; + + case OPTION_MESH: mesh = true; break; + case OPTION_RUN: run = true; break; + case OPTION_SETUP: setup = true; break; + case OPTION_ALL: all = true; break; + case OPTION_INITIALISE: initialise = true; break; + case OPTION_SERVER: server = true; break; + + case OPTION_NOGEOM: load3Dgeometry = false; break; + case OPTION_NOMESH: load3Dmesh = false; break; + + case OPTION_IMPORT: + if (i == argv.length - 1) { + fatal("Missing import folder"); + printUsage(); + exit(-1); + } + String importPath = argv[++i]; + final File importFolder = new File(importPath); + if (!importFolder.exists()) { + fatal("Import Folder Does Not Exist!"); + exit(-1); + } else if (importFolder.isFile()) { + String name = importFolder.getName(); + if (name.endsWith("stl") || name.endsWith("STL")) { + Arguments.stlFiles = new File[]{importFolder}; + } else { + fatal("Import Folder Does Not Exist!"); + exit(-1); + } + } else { + File[] stls = importFolder.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith("stl") || name.endsWith("STL"); + } + }); + if (stls.length == 0) { + fatal("No files to import!"); + exit(-1); + } else { + Arguments.stlFiles = stls; + } + } + break; + case OPTION_HELP: + printUsage(); + exit(0); + break; + default: + fatal("Unknown Option " + arg); + printUsage(); + exit(0); + break; + } + } + } + checkCase(); + } + + private static void checkCase() { + if (hasCommand()) { + if (Arguments.baseDir == null) { + fatal("Missing case folder"); + printUsage(); + exit(-1); + } + } + } + + private static void fatal(String msg) { + System.err.println(); + System.err.println(LINE); + System.err.println(" " + TAB + "FATAL ERROR:"); + System.err.println(" " + TAB + TAB + msg); + System.err.println(LINE); + } + + private static void warning(String msg) { + System.err.println(); + System.err.println(LINE); + System.err.println(" " + TAB+"WARNING:"); + System.err.println(" " + TAB + TAB + msg); + System.err.println(TAB+LINE); + } + + private static void exit(int status) { + System.exit(status); + } + + private static void printUsage() { + + System.err.println(" USAGE"); + System.err.println(" -----------------------------------------------------"); + if (Util.isWindows()) + System.err.println(" "+ApplicationInfo.getName()+".bat ["+OPTION_V+"] ["+OPTION_VV+"] [-case ] [command] "); + else + System.err.println(" "+ApplicationInfo.getName()+".sh ["+OPTION_V+"] ["+OPTION_VV+"] [-case ] [command] "); + + System.err.println(); + System.err.println(" Options:"); + System.err.println(" " + Util.padWithSpaces(OPTION_HELP, 12) + " Print this help screen."); + System.err.println(" " + Util.padWithSpaces(OPTION_V, 12) + " The verbose output."); + System.err.println(" " + Util.padWithSpaces(OPTION_VV, 12) + " The very verbose output."); + System.err.println(" " + Util.padWithSpaces(OPTION_CASE, 12) + " Specify the case directory for the application."); + System.err.println(" " + Util.padWithSpaces(OPTION_NO3D, 12) + " Does not display 3D window."); + System.err.println(); + System.err.println(" Commands:"); + System.err.println(" " + Util.padWithSpaces(OPTION_MESH, 12) + " Launch mesh creation according to system/snappyHexMeshDict."); + System.err.println(" " + Util.padWithSpaces(OPTION_SETUP, 12) + " Setup the cfd case according to system/caseSetupDict."); + System.err.println(" " + Util.padWithSpaces(OPTION_INITIALISE, 12) + " Initialise the fields according to system/caseSetupDict."); + System.err.println(" " + Util.padWithSpaces(OPTION_RUN, 12) + " Launch the solver."); + System.err.println(" " + Util.padWithSpaces(OPTION_ALL, 12) + " Launch mesh + setup + run."); + System.err.println(" -----------------------------------------------------"); + } + + public static boolean isBatch() { + return Arguments.server || hasCommand(); + } + + private static boolean hasCommand() { + return Arguments.mesh || Arguments.setup || Arguments.run || Arguments.all || Arguments.initialise; + } + +} diff --git a/src/eu/engys/core/LoggerUtil.java b/src/eu/engys/core/LoggerUtil.java new file mode 100644 index 0000000..3e9eec8 --- /dev/null +++ b/src/eu/engys/core/LoggerUtil.java @@ -0,0 +1,153 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core; + +import java.io.File; +import java.io.IOException; + +import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.FileAppender; +import org.apache.log4j.Layout; +import org.apache.log4j.Level; +import org.apache.log4j.PatternLayout; +import org.apache.log4j.Priority; +import org.apache.log4j.spi.LoggingEvent; + +import eu.engys.util.Symbols; +import eu.engys.util.Util; + +public class LoggerUtil { + + public static void initLogger() { + if (Util.isWindows()) { + initNormalLogger(); + } else { + initColorLogger(); + } + } + + private static void initColorLogger() { + org.apache.log4j.Logger.getRootLogger().addAppender(new ColorConsoleAppender(new PatternLayout("%6r - %-30.30t - %-5p %-30.30c{1} %x - %m%n"))); + org.apache.log4j.Logger.getRootLogger().setLevel(Arguments.logLevel); + } + + private static void initNormalLogger() { + org.apache.log4j.Logger.getRootLogger().addAppender(new ConsoleAppender(new PatternLayout("%6r - %-30.30t - %-5p %-30.30c{1} %x - %m%n"))); + org.apache.log4j.Logger.getRootLogger().setLevel(Arguments.logLevel); + } + + public static void initFlatLogger() { + org.apache.log4j.Logger.getRootLogger().addAppender(new ConsoleAppender(new PatternLayout("%-5p %m%n"))); + org.apache.log4j.Logger.getRootLogger().setLevel(Arguments.logLevel); + } + + public static void initTestLogger() { + org.apache.log4j.Logger.getRootLogger().addAppender(new ConsoleAppender(new PatternLayout("%r [%t] %p %c %x - %m%n"))); + org.apache.log4j.Logger.getRootLogger().setLevel(Level.INFO); + } + + public static void initTestLogger(Level level) { + org.apache.log4j.Logger.getRootLogger().addAppender(new ConsoleAppender(new PatternLayout("%r [%t] %p %c %x - %m%n"))); + org.apache.log4j.Logger.getRootLogger().setLevel(level); + } + + public static void initFileLogger(String file, Level level) throws IOException { + org.apache.log4j.Logger.getRootLogger().removeAllAppenders(); + org.apache.log4j.Logger.getRootLogger().addAppender(new FileAppender(new PatternLayout("%r [%t] %p %c %x - %m%n"), file, false)); + org.apache.log4j.Logger.getRootLogger().setLevel(level); + } + + private static final String LOG_FILE_NAME = "log"; + private static final String TXT_EXT = ".txt"; + + public static void redirectLog(File tempDirectory) { + File log = new File(tempDirectory, LOG_FILE_NAME + TXT_EXT); + try { + initFileLogger(log.getAbsolutePath(), Level.DEBUG); + } catch (Exception e) { + System.out.println("ERROR : Unable to open logger file!"); + System.exit(-1); + } + } + + static class ColorConsoleAppender extends ConsoleAppender { + private static final int NORMAL = 0; + private static final int BRIGHT = 1; + // private static final int FOREGROUND_BLACK = 30; + private static final int FOREGROUND_RED = 31; + private static final int FOREGROUND_GREEN = 32; + private static final int FOREGROUND_YELLOW = 33; + private static final int FOREGROUND_BLUE = 34; + // private static final int FOREGROUND_MAGENTA = 35; + private static final int FOREGROUND_CYAN = 36; + // private static final int FOREGROUND_WHITE = 37; + + private static final String PREFIX = Symbols.ESC + "["; + private static final String SUFFIX = "m"; + private static final char SEPARATOR = ';'; + private static final String END_COLOUR = PREFIX + SUFFIX; + + private static final String FATAL_COLOUR = PREFIX + BRIGHT + SEPARATOR + FOREGROUND_RED + SUFFIX; + private static final String ERROR_COLOUR = PREFIX + NORMAL + SEPARATOR + FOREGROUND_RED + SUFFIX; + private static final String WARN_COLOUR = PREFIX + NORMAL + SEPARATOR + FOREGROUND_YELLOW + SUFFIX; + private static final String INFO_COLOUR = PREFIX + NORMAL + SEPARATOR + FOREGROUND_GREEN + SUFFIX; + private static final String DEBUG_COLOUR = PREFIX + NORMAL + SEPARATOR + FOREGROUND_CYAN + SUFFIX; + private static final String TRACE_COLOUR = PREFIX + NORMAL + SEPARATOR + FOREGROUND_BLUE + SUFFIX; + + public ColorConsoleAppender(Layout layout) { + super(layout); + } + + @Override + protected void subAppend(LoggingEvent event) { + this.qw.write(getColour(event.getLevel())); + super.subAppend(event); + this.qw.write(END_COLOUR); + + if (this.immediateFlush) { + this.qw.flush(); + } + } + + private String getColour(Level level) { + switch (level.toInt()) { + case Priority.FATAL_INT: + return FATAL_COLOUR; + case Priority.ERROR_INT: + return ERROR_COLOUR; + case Priority.WARN_INT: + return WARN_COLOUR; + case Priority.INFO_INT: + return INFO_COLOUR; + case Priority.DEBUG_INT: + return DEBUG_COLOUR; + default: + return TRACE_COLOUR; + } + } + } +} diff --git a/src/eu/engys/core/OpenFOAMEnvironment.java b/src/eu/engys/core/OpenFOAMEnvironment.java new file mode 100644 index 0000000..ca14fd9 --- /dev/null +++ b/src/eu/engys/core/OpenFOAMEnvironment.java @@ -0,0 +1,417 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core; + +import static eu.engys.core.project.openFOAMProject.LOG; + +import java.io.File; +import java.io.FileFilter; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.JFrame; + +import org.apache.commons.exec.CommandLine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.ScriptBuilder; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.JavaExecutor; +import eu.engys.core.project.Model; +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.ui.UiUtil; + +public class OpenFOAMEnvironment { + + private static final Logger logger = LoggerFactory.getLogger(OpenFOAMEnvironment.class); + + private static final String[] VARIABLES_TO_UNSET = new String[] { "LD_LIBRARY_PATH", "WM_COMPILER", "WM_PROJECT_VERSION", "WM_THIRDPARTY_VERSION", "ParaView_MAJOR", "ParaView_VERSION", "WM_MPLIB", "FOAM_MPI" }; + + public static void loadEnvironment(ScriptBuilder sb) { + cleanEnvironment(sb); + sb.newLine(); + if (Util.isWindowsScriptStyle()) { + sb.append("call \"%ENV_LOADER%\""); + } else { + sb.append("export ParaView_VERSION=$PV_VERSION"); + sb.append("export FOAM_INST_DIR=$VENDOR_HOME"); + sb.append(". $ENV_LOADER"); + sb.newLine(); + sb.append("set -e"); + sb.append("set -o pipefail"); + } + sb.newLine(); + } + + public static void cleanEnvironment(ScriptBuilder sb) { + for (String var : VARIABLES_TO_UNSET) { + if (Util.isWindowsScriptStyle()) { + sb.append("set " + var + "="); + } else { + sb.append("unset " + var); + } + } + } + + public static void printVariables(ScriptBuilder sb) { + if (Util.isWindowsScriptStyle()) { + sb.append("echo \"Case : %CASE%\""); + sb.append("echo \"Procs : %NP%\""); + sb.append("echo \"Log : %LOG%\""); + sb.append("echo \"Env : %ENV_LOADER%\""); + sb.append("echo \"MachineFile : %MACHINEFILE%\""); + sb.append("echo \"Solver : %SOLVER%\""); + } else { + sb.append("echo \"Case : $CASE\""); + sb.append("echo \"Procs : $NP\""); + sb.append("echo \"Log : $LOG\""); + sb.append("echo \"Env : $ENV_LOADER\""); + sb.append("echo \"Vendor : $VENDOR_HOME\""); + sb.append("echo \"Paraview : $PV_VERSION\""); + sb.append("echo \"MachineFile : $MACHINEFILE\""); + sb.append("echo \"Solver : $SOLVER\""); + } + sb.newLine(); + } + + public static Map getEnvironment(Model model) { + return getEnvironment(model, ""); + } + +// public static Map getEnvironment(Model model, File baseDir) { +// return getEnvironment(model, baseDir, null, null); +// } + + public static Map getEnvironment(Model model, String logFileName) { + return getEnvironment(model, model.getProject().getBaseDir(), logFileName, null); + } + + public static Map getEnvironment(Model model, File baseDir, String logFileName) { + return getEnvironment(model, baseDir, logFileName, null); + } + + public static Map getEnvironment(Model model, String logFileName, String option) { + return getEnvironment(model, model.getProject().getBaseDir(), logFileName, option); + } + + private static Map getEnvironment(Model model, File baseDir, String logFileName, String option) { + Map map = new HashMap<>(); + + Path hostfilePath = Paths.get(model.getProject().getBaseDir().getAbsolutePath()).resolve(model.getSolverModel().getHostfilePath()); + + map.put("CASE", baseDir.getAbsolutePath()); + + map.put("NP", String.valueOf(model.getProject().getProcessors())); + + map.put("SOLVER", model.getState().getSolver().getName()); + + if (logFileName != null) { + map.put("LOG", Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, logFileName).toString()); + } + + map.put("VENDOR_HOME", getVendorHome().getAbsolutePath()); + + map.put("PV_VERSION", getParaviewVersion()); + + map.put("ENV_LOADER", getEnvLoader().getAbsolutePath()); + + if (option != null) { + JavaExecutor executor = Executor.jvm("eu.engys.launcher.Launcher", option, "-V"); + executor.inFolder(baseDir); + + CommandLine cmdLine = executor.getCommandLine(); + map.put("APPLICATION", cmdLine.toString()); + } + + // DPC + if (model.getSolverModel().isQueue()) { + map.put("MACHINEFILE", "-machinefile " + System.getenv("HOSTFILE")); + } else { + map.put("MACHINEFILE", model.getSolverModel().getMultiMachine() ? "-machinefile " + hostfilePath : ""); + } + + return map; + } + + public static Map getTestEnvironment() { + Map map = new HashMap<>(); + map.put("VENDOR_HOME", getVendorHome().getAbsolutePath()); + map.put("ENV_LOADER", getEnvLoader().getAbsolutePath()); + return map; + } + + public static void printHeader(ScriptBuilder sb, String header) { + if (Util.isWindowsScriptStyle()) { + sb.append("@echo off"); + } else { + sb.append("#!/bin/bash"); + } + sb.append(getHeaderDelimiter(header.length())); + sb.append(getHeaderTitle(header)); + sb.append(getHeaderDelimiter(header.length())); + sb.newLine(); + } + + private static String getHeaderTitle(String header) { + StringBuilder sb = new StringBuilder("echo \""); + sb.append("*"); + sb.append(" "); + sb.append(" "); + sb.append(" "); + sb.append(" "); + sb.append(header); + sb.append(" "); + sb.append(" "); + sb.append(" "); + sb.append(" "); + sb.append("*"); + sb.append("\""); + return sb.toString(); + } + + private static String getHeaderDelimiter(int headerLength) { + StringBuilder sb = new StringBuilder("echo \""); + for (int i = 0; i < headerLength + 10; i++) { + sb.append("*"); + } + sb.append("\""); + return sb.toString(); + } + + /* + * Other + */ + + public static void trySettingOpenFoamFolder(JFrame frame) { + if (!OpenFOAMEnvironment.isEnvironementLoaded()) { + File[] openFoamDir = getOpenFoamDir(); + if (Util.isVarArgsNotNullAndOfSize(1, openFoamDir)) { + PrefUtil.setOpenFoamEntry(openFoamDir[0]); + logger.info("Environment set to {}", PrefUtil.getOpenFoamEntry()); + } else { + UiUtil.showCoreEnvironmentNotLoadedWarning(frame); + } + } + } + + public static void trySettingOpenFoamFolderOS(JFrame frame) { + if (!OpenFOAMEnvironment.isEnvironementLoaded()) { + File[] openFoamDir = null; + if (Util.isUnix()) { + openFoamDir = getOpenFoamDirOS_onUnix(); + } else { + openFoamDir = getOpenFoamDir(); + } + if (Util.isVarArgsNotNullAndOfSize(1, openFoamDir)) { + PrefUtil.setOpenFoamEntry(openFoamDir[0]); + logger.info("Environment set to {}", PrefUtil.getOpenFoamEntry()); + } else { + UiUtil.showCoreEnvironmentNotLoadedWarning(frame); + } + } + } + + public static void trySettingParaviewExecutable() { + if (!OpenFOAMEnvironment.isParaviewPathSet() && OpenFOAMEnvironment.isEnvironementLoaded()) { + File paraviewExecutable = getParaViewExecutablePath(); + if (paraviewExecutable != null) { + PrefUtil.setParaViewEntry(paraviewExecutable); + logger.info("ParaView path set to {}", PrefUtil.getParaViewEntry()); + } else { + logger.warn("ParaView path NOT set"); + } + } + } + + public static File[] getOpenFoamDir() { + File[] openFoamFolders = new File[0]; + String jarPath = ""; + try { + jarPath = new File(OpenFOAMEnvironment.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getAbsolutePath(); + File vendorHome = Paths.get(jarPath).getParent().getParent().getParent().getParent().toFile(); + logger.info("Check for valid OpenFOAM folder in {}", vendorHome); + openFoamFolders = vendorHome.listFiles(new FileFilter() { + + @Override + public boolean accept(File file) { + return file.isDirectory() && file.getName().startsWith("OpenFOAM"); + } + }); + } catch (URISyntaxException e) { + logger.error("JarPath {}", jarPath); + } + return openFoamFolders; + } + + private static File getParaViewExecutablePath() { + File[] paraviewFolders = new File[0]; + File[] thirdPartyDirs = getThirdPartyDir(); + if (Util.isVarArgsNotNullAndOfSize(1, thirdPartyDirs)) { + File thirdPartyDir = thirdPartyDirs[0]; + logger.info("Check for valid ParaView folder in {}", thirdPartyDir); + paraviewFolders = thirdPartyDir.listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + return file.isDirectory() && file.getName().startsWith("ParaView"); + } + }); + } + if (Util.isVarArgsNotNull(paraviewFolders)) { + for (File pvFolder : paraviewFolders) { + File pvExecutable = Paths.get(pvFolder.getAbsolutePath(), "platforms", "linux64Gcc", "bin", "paraview").toFile(); + if (pvExecutable.exists()) { + return pvExecutable; + } + } + } + return null; + } + + private static File[] getThirdPartyDir() { + File[] openFoamFolders = getOpenFoamDir(); + File[] thirdPartyFolders = new File[0]; + if (Util.isVarArgsNotNullAndOfSize(1, openFoamFolders)) { + File vendorHome = getOpenFoamDir()[0].getParentFile(); + logger.info("Check for valid ThirdParty folder in {}", vendorHome); + thirdPartyFolders = vendorHome.listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + return file.isDirectory() && file.getName().startsWith("ThirdParty"); + } + }); + } + return thirdPartyFolders; + } + + private static File[] getOpenFoamDirOS_onUnix() { + File[] openFoamFolders = new File[0]; + File optFolder = new File("/opt"); + logger.info("Check for valid OpenFOAM folder in {}", optFolder); + openFoamFolders = optFolder.listFiles(new FileFilter() { + + @Override + public boolean accept(File file) { + boolean isDir = file.isDirectory(); + String fileName = file.getName(); + boolean ubuntuNameCheck = fileName.startsWith("openfoam"); + boolean fedoraNameCheck = fileName.startsWith("OpenFOAM") && !fileName.contains("ParaView") && !fileName.contains("scotch"); + boolean suseNameCheck = fileName.startsWith("OpenFOAM") && !fileName.contains("ParaView") && !fileName.contains("scotch"); + return isDir && (ubuntuNameCheck || fedoraNameCheck || suseNameCheck); + } + }); + return openFoamFolders; + } + + public static File[] getDocumentationDir() { + File[] documentationFolders = new File[0]; + String jarPath = ""; + try { + jarPath = new File(OpenFOAMEnvironment.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getAbsolutePath(); + File vendorHome = Paths.get(jarPath).getParent().getParent().getParent().getParent().toFile(); + logger.info("Check for valid documentation folder in {}", vendorHome); + documentationFolders = vendorHome.listFiles(new FileFilter() { + + @Override + public boolean accept(File file) { + return file.isDirectory() && file.getName().equals("doc"); + } + }); + } catch (URISyntaxException e) { + logger.error("JarPath {}", jarPath); + } + return documentationFolders; + } + + public static boolean isEnvironementLoaded() { + File openFoamDir = PrefUtil.getOpenFoamEntry(); + if (openFoamDir == null || !openFoamDir.exists() || !openFoamDir.isDirectory()) { + return false; + } + return true; + } + + public static boolean isParaviewPathSet() { + File paraView = PrefUtil.getParaViewEntry(); + if (paraView == null || !paraView.exists() || !paraView.isFile() || !paraView.canExecute()) { + return false; + } + return true; + } + + public static boolean isFieldViewPathSet() { + File fieldView = PrefUtil.getFieldViewEntry(); + if (fieldView == null || !fieldView.exists() || !fieldView.isFile() || !fieldView.canExecute()) { + return false; + } + return true; + } + + public static boolean isEnSightPathSet() { + File enSight = PrefUtil.getEnsightEntry(); + if (enSight == null || !enSight.exists() || !enSight.isFile() || !enSight.canExecute()) { + return false; + } + return true; + } + + private static File getEnvLoader() { + File openFoamEntry = PrefUtil.getOpenFoamEntry(); + if (openFoamEntry != null) { + if (Util.isWindowsScriptStyle()) { + return openFoamEntry.toPath().resolve("etc").resolve("batchrc.bat").toFile(); + } else { + return openFoamEntry.toPath().resolve("etc").resolve("bashrc").toFile(); + } + } + return new File(""); + } + + public static File getVendorHome() { + File openFoamEntry = PrefUtil.getOpenFoamEntry(); + if (openFoamEntry != null) { + return openFoamEntry.getParentFile(); + } + return new File(""); + } + + public static String getParaviewVersion() { + File pvHome = PrefUtil.getParaViewEntry(); + if (pvHome != null && pvHome.exists()) { + String name = pvHome.getName(); + if (name.startsWith("ParaView-")) { + String version = name.substring("ParaView-".length()); + return version; + } + } + return ""; + } + +} diff --git a/src/eu/engys/core/controller/AbstractController.java b/src/eu/engys/core/controller/AbstractController.java new file mode 100644 index 0000000..9c322da --- /dev/null +++ b/src/eu/engys/core/controller/AbstractController.java @@ -0,0 +1,541 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.File; +import java.rmi.RemoteException; +import java.util.Set; + +import javax.swing.Icon; +import javax.swing.JOptionPane; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.Arguments; +import eu.engys.core.controller.actions.CommandException; +import eu.engys.core.controller.actions.DeleteMesh; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.presentation.Action; +import eu.engys.core.presentation.ActionContainer; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.CaseParameters; +import eu.engys.core.project.InvalidProjectException; +import eu.engys.core.project.Model; +import eu.engys.core.project.Project200To210Converter; +import eu.engys.core.project.ProjectFolderAnalyzer; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.core.project.SolverState; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.system.monitoringfunctionobjects.ParserView; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.PrefUtil; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; + +public abstract class AbstractController implements Controller, ActionContainer { + + public static final String STOP_SOLVER = "Stop Solver"; + public static final String KILL_SOLVER = "Kill Solver"; + + public static final String STOP_EXECUTION = "Stop Execution"; + public static final String KILL_PROCESS = "Kill Process"; + + public static final String STOP_FIELDS_INITIALISATION = "Stop Fields Initialisation"; + public static final String STOP_MESH_GENERATOR = "Stop Mesh Generator"; + + public static final String CANCEL = "Cancel"; + public static final String CONTINUE_IN_BATCH = "Continue in Batch"; + + private static final Icon EXIT_BIG_ICON = ResourcesUtil.getIcon("application.exit.big.icon"); + private static final String EXIT_LABEL = ResourcesUtil.getString("application.exit.label"); + private static final Logger logger = LoggerFactory.getLogger(Controller.class); + + protected final Model model; + protected final Set modules; + protected final ProjectReader reader; + protected final ProjectWriter writer; + protected final ProgressMonitor monitor; + protected final ScriptFactory scriptFactory; + protected ControllerListener listener; + protected CellZonesBuilder cellZonesBuilder; + + public AbstractController(Model model, Set modules, ProjectReader reader, ProjectWriter writer, CellZonesBuilder cellZonesBuilder, ProgressMonitor monitor, ScriptFactory scriptFactory) { + this.cellZonesBuilder = cellZonesBuilder; + logger.info("Loading {}", getClass().getSimpleName()); + this.model = model; + this.modules = modules; + this.reader = reader; + this.writer = writer; + this.monitor = monitor; + this.scriptFactory = scriptFactory; + } + + /* + * NEW CASE + */ + + @Override + public void createCase(CaseParameters params) { + if (params != null) { + newCaseInAThread(params); + } + } + + private void newCaseInAThread(final CaseParameters params) { + monitor.setTotal(10); + monitor.start(String.format("Creating %s", params), false, new Runnable() { + @Override + public void run() { + create(params); + PrefUtil.putFile(PrefUtil.WORK_DIR, model.getProject().getBaseDir().getParentFile()); + monitor.end(); + } + }); + } + + @Override + public void create(final CaseParameters params) { + if (listener != null) { + listener.beforeNewCase(); + } + clearModel(); + writer.create(params); + if (listener != null) { + listener.afterNewCase(); + } + } + + /* + * OPEN + */ + + @Override + public void openCase(File file) { + if (file == null) { + file = fileToOpenOrNull(); + } + if (file != null) { + ActionManager.getInstance().invoke("application.startup.hide"); + openInAThread(file); + } + Arguments.load3Dgeometry = true; + Arguments.load3Dmesh = true; + } + + private File fileToOpenOrNull() { + final File[] openFile = new File[1]; + Runnable r = new Runnable() { + @Override + public void run() { + File workDir = PrefUtil.getWorkDir(PrefUtil.WORK_DIR); + HelyxFileChooser fileChooser = new HelyxFileChooser(workDir.getAbsolutePath()); + fileChooser.setTitle("Open"); + fileChooser.setSelectionMode(SelectionMode.DIRS_AND_ARCHIVES); + + View3DOptions options = new View3DOptions(); + ReturnValue returnValue = fileChooser.showOpenDialog(options); + if (returnValue.isApprove()) { + File selectedCase = fileChooser.getSelectedFile(); + if (isSuitable(selectedCase)) { + PrefUtil.putFile(PrefUtil.WORK_DIR, selectedCase.getParentFile()); + Arguments.load3Dgeometry = true; + Arguments.load3Dmesh = options.loadMesh(); + openFile[0] = selectedCase; + return; + } + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), selectedCase + "\n appears not to be a valid case folder", "File System Error", JOptionPane.ERROR_MESSAGE); + } + openFile[0] = null; + return; + } + }; + ExecUtil.invokeAndWait(r); + return openFile[0]; + } + + private void openInAThread(final File file) { + monitor.setTotal(10); + monitor.start("Open " + file.getName(), false, new Runnable() { + @Override + public void run() { + open(file); + monitor.end(); + } + }); + } + + @Override + public void open(File file) { + final File baseDir = file.isAbsolute() ? file : file.getAbsoluteFile(); + logger.debug("OPEN file {}", baseDir.getAbsolutePath()); + if (listener != null) { + listener.beforeLoadCase(); + } + clearModel(); + + model.setProject(openFOAMProject.createProject(baseDir, monitor)); + + new Project200To210Converter(model.getProject(), cellZonesBuilder).convert(); + + _read(); + + if (listener != null) { + listener.afterLoadCase(); + } + + logger.debug("OPEN file {} done.", baseDir.getName()); + } + + @Override + public void reopen(OpenOptions options) { + File baseDir = model.getProject().getBaseDir(); + int np = model.getProject().getProcessors(); + boolean parallel = model.getProject().isParallel(); + + logger.debug("REOPEN file {} with option {}", baseDir.getAbsolutePath(), options); + if (listener != null) { + listener.beforeReopenCase(); + } + + if (options == OpenOptions.MESH_ONLY) { + reader.readMesh(); + if (listener != null) { + listener.afterReopenCase(); + } + return; + } + clearModel(); + + switch (options) { + case SERIAL: + model.setProject(openFOAMProject.newSerialProject(baseDir)); + break; + case PARALLEL: + model.setProject(openFOAMProject.newParallelProject(baseDir)); + break; + case CHECK_FOLDER: + model.setProject(openFOAMProject.createProject(baseDir, monitor)); + break; + case CURRENT_SETTINGS: + model.setProject(parallel ? openFOAMProject.newParallelProject(baseDir, np) : openFOAMProject.newSerialProject(baseDir)); + break; + case MESH_ONLY: + break; + default: + break; + } + + reader.read(); + + if (listener != null) { + listener.afterReopenCase(); + } + logger.debug("Open file {} done.", baseDir.getName()); + } + + private void _read() { + try { + reader.read(); + } catch (InvalidProjectException e) { + logger.error(e.getMessage()); + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), e.getMessage(), "Project error", JOptionPane.ERROR_MESSAGE); + clearModel(); + } + } + + @Override + public void reopenCase(final OpenOptions options) { + monitor.start("Reopen " + model.getProject().getBaseDir(), false, new Runnable() { + @Override + public void run() { + reopen(options); + monitor.end(); + } + }); + } + + /* + * SAVE + */ + + @Override + public void saveCase(File file) { + if (file == null) { + file = fileToSaveOrNull(); + } + if (file != null) { + saveInAThread(file); + } + } + + protected void saveInAThread(final File baseDir) { + monitor.info(""); + monitor.start("Save: " + baseDir.getAbsolutePath(), false, new Runnable() { + @Override + public void run() { + save(baseDir); + monitor.end(); + } + }); + } + + @Override + public void save(File baseDir) { + if (baseDir == null) { + baseDir = model.getProject().getBaseDir(); + } + logger.debug("Save file {}", baseDir.getAbsolutePath()); + if (listener != null) + listener.beforeSaveCase(); + writer.write(baseDir); + writeScripts(); + if (listener != null) { + listener.afterSaveCase(); + } + logger.debug("Save file {} done.", baseDir.getName()); + } + + private File fileToSaveOrNull() { + final File[] file = new File[1]; + Runnable r = new Runnable() { + @Override + public void run() { + File workDir = PrefUtil.getWorkDir(PrefUtil.WORK_DIR); + + HelyxFileChooser fileChooser = new HelyxFileChooser(workDir.getAbsolutePath()); + if (model.getProject().getBaseDir().getAbsoluteFile().getParentFile().equals(workDir)) { + fileChooser.selectFile(model.getProject().getBaseDir()); + } + fileChooser.setTitle("Save As"); + fileChooser.setSelectionMode(SelectionMode.DIRS_ONLY); + + ReturnValue returnValue = fileChooser.showSaveAsDialog(); + if (returnValue.isApprove()) { + File baseDir = fileChooser.getSelectedFile(); + if (baseDir != null) { + if (baseDir.exists() && !baseDir.equals(model.getProject().getBaseDir())) { + int retVal = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "Folder already exists. Continue anyway?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (retVal == JOptionPane.NO_OPTION) { + file[0] = fileToSaveOrNull(); + return; + } + } + PrefUtil.putFile(PrefUtil.WORK_DIR, baseDir.getParentFile()); + } + file[0] = baseDir; + return; + } + file[0] = null; + return; + } + }; + ExecUtil.invokeAndWait(r); + return file[0]; + } + + /* + * MESH + */ + + @Action(key = "mesh.delete") + public void deleteMesh() { + int retVal = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "This action will delete the existing mesh.\nContinue?", "Delete Mesh", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (retVal == JOptionPane.YES_OPTION) { + saveInAThread(model.getProject().getBaseDir()); + new DeleteMesh(model, this).executeClient(); + reopenCase(OpenOptions.CURRENT_SETTINGS); + } + } + + private void writeScripts() { + scriptFactory.getMeshScript(model); + scriptFactory.getInitialiseScript(model); + scriptFactory.getSolverScript(model); + if (model.getSolverModel().isQueue()) { + scriptFactory.getQueueDriver(model); + scriptFactory.getQueueLauncher(model); + } + } + + /* + * OTHER + */ + + @Override + public void createReport() { + } + + protected void clearModel() { + logger.info("--- CLEAR MODEL ---"); + model.init(); + model.setProject(null); + System.gc(); + } + + @Override + public ProjectReader getReader() { + return reader; + } + + @Override + public ProjectWriter getWriter() { + return writer; + } + + public boolean isSuitable(File file) { + return ProjectFolderAnalyzer.isSuitable(file); + } + + @Override + public boolean allowActionsOnRunning(boolean exit) { + if (model != null && model.getSolverModel() != null) { + SolverState solverState = model.getSolverModel().getServerState().getSolverState(); + if (solverState.isMeshing()) { + return handleExitOnMeshRunning(); + } else if (solverState.isInitialising()) { + return handleExitOnFieldsInitialising(); + } else if (solverState.isRunning()) { + return handleExitOnSolverRunning(); + } else if (exit) { + int option = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), EXIT_LABEL + " " + ApplicationInfo.getName() + "?", EXIT_LABEL, JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE, EXIT_BIG_ICON); + if (option == JOptionPane.CANCEL_OPTION) { + return false; + } else { + if (getClient() != null && getClient().getServer() != null) { + shutdownServer(); + } + return true; + } + } else if (getClient() != null && getClient().getServer() != null) { + shutdownServer(); + return true; + } + } else if (exit) {// If no case has been loaded yet + int option = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), EXIT_LABEL + " " + ApplicationInfo.getName() + "?", EXIT_LABEL, JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE, EXIT_BIG_ICON); + if (option == JOptionPane.CANCEL_OPTION) { + return false; + } + } + return true; + } + + private void shutdownServer() { + try { + getClient().getServer().shutdown(); + } catch (RemoteException e) { + logger.error("Error shutting down server: {}" + e.getMessage()); + } catch (Exception e) { + logger.error("Error shutting down server: {}" + e.getMessage()); + } + } + + protected boolean handleExitOnMeshRunning() { + Object[] options = new Object[] { STOP_MESH_GENERATOR, CONTINUE_IN_BATCH, CANCEL }; + int option = JOptionPane.showOptionDialog(UiUtil.getActiveWindow(), "Mesh Generator is Running. Select an action to perform.", "Mesh Generator Running", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + + if (getClient() != null && option == JOptionPane.YES_OPTION) { + kill(); + return true; + } else if (getClient() != null && option == JOptionPane.NO_OPTION) { + getClient().goToBatch(); + return true; + } else { + return false; + } + } + + protected boolean handleExitOnFieldsInitialising() { + Object[] options = new Object[] { STOP_FIELDS_INITIALISATION, CONTINUE_IN_BATCH, CANCEL }; + int option = JOptionPane.showOptionDialog(UiUtil.getActiveWindow(), "Fields Initialisation is Running. Select an action to perform.", "Fields Initialisation Running", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + + if (getClient() != null && option == JOptionPane.YES_OPTION) { + kill(); + return true; + } else if (getClient() != null && option == JOptionPane.NO_OPTION) { + getClient().goToBatch(); + return true; + } else { + return false; + } + } + + protected boolean handleExitOnSolverRunning() { + Object[] options = new Object[] { STOP_SOLVER, CONTINUE_IN_BATCH, CANCEL }; + int option = JOptionPane.showOptionDialog(UiUtil.getActiveWindow(), "Solver is Running. Select an action to perform.", "Solver Running", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + + if (getClient() != null && option == JOptionPane.YES_OPTION) { + getClient().stopCommand(Command.ANY); + return true; + } else if (getClient() != null && option == JOptionPane.NO_OPTION) { + getClient().goToBatch(); + return true; + } else { + return false; + } + } + + @Override + public void addListener(ControllerListener listener) { + this.listener = listener; + } + + @Override + public ControllerListener getListener() { + return listener; + } + + @Override + public void executeCommand(Command command) throws CommandException { + } + + @Override + public void executeCommands(Command... commands) throws CommandException { + } + + @Override + public boolean isRunningCommand() { + return false; + } + + @Override + public String submitCommand(Command command) throws CommandException { + return null; + } + + @Override + public ParserView getResidualView() { + return null; + } + +} diff --git a/src/eu/engys/core/controller/AbstractScriptFactory.java b/src/eu/engys/core/controller/AbstractScriptFactory.java new file mode 100644 index 0000000..f38e7c3 --- /dev/null +++ b/src/eu/engys/core/controller/AbstractScriptFactory.java @@ -0,0 +1,337 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.File; +import java.util.List; + +import eu.engys.core.project.Model; +import eu.engys.util.IOUtils; +import eu.engys.util.Util; + +public abstract class AbstractScriptFactory implements ScriptFactory { + + protected static final String RUN_MESH = "Run Mesh"; + public static final String MESH_SERIAL_RUN = "mesh_serial.run"; + public static final String MESH_SERIAL_BAT = "mesh_serial.bat"; + public static final String MESH_PARALLEL_RUN = "mesh_parallel.run"; + public static final String MESH_PARALLEL_BAT = "mesh_parallel.bat"; + + protected static final String CHECK_MESH = "Check Mesh"; + public static final String CHECK_MESH_SERIAL_RUN = "check_mesh_serial.run"; + public static final String CHECK_MESH_SERIAL_BAT = "check_mesh_serial.bat"; + public static final String CHECK_MESH_PARALLEL_RUN = "check_mesh_parallel.run"; + public static final String CHECK_MESH_PARALLEL_BAT = "check_mesh_parallel.bat"; + + protected static final String RUN_CASE = "Run Case"; + public static final String SOLVER_SERIAL_RUN = "solver_serial.run"; + public static final String SOLVER_SERIAL_BAT = "solver_serial.bat"; + public static final String SOLVER_PARALLEL_RUN = "solver_parallel.run"; + public static final String SOLVER_PARALLEL_BAT = "solver_parallel.bat"; + + protected static final String INITIALISE_FIELDS = "Initialise Fields"; + public static final String INITIALISE_FIELDS_SERIAL_RUN = "initialiseFields_serial.run"; + public static final String INITIALISE_FIELDS_SERIAL_BAT = "initialiseFields_serial.bat"; + public static final String INITIALISE_FIELDS_PARALLEL_RUN = "initialiseFields_parallel.run"; + public static final String INITIALISE_FIELDS_PARALLEL_BAT = "initialiseFields_parallel.bat"; + + protected static final String EXTRUDEMESH = "Extrude To Region"; + private static final String EXTRUDEMESH_SERIAL_RUN = "extrudeMesh_serial.run"; + private static final String EXTRUDEMESH_SERIAL_BAT = "extrudeMesh_serial.bat"; + private static final String EXTRUDEMESH_PARALLEL_RUN = "extrudeMesh_parallel.run"; + private static final String EXTRUDEMESH_PARALLEL_BAT = "extrudeMesh_parallel.bat"; + + /* + * MESH + */ + @Override + public File getMeshScript(Model model) { + File parallelScript = getMeshParallelScript(model); + File serialScript = getMeshSerialScript(model); + + if (model.getProject().isParallel()) { + return parallelScript; + } else { + return serialScript; + } + } + + @Override + public void deleteMeshScripts(Model model) { + File serialFile = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? MESH_SERIAL_BAT : MESH_SERIAL_RUN); + if (serialFile.exists()) { + serialFile.delete(); + } + File parallelFile = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? MESH_PARALLEL_BAT : MESH_PARALLEL_RUN); + if (parallelFile.exists()) { + parallelFile.delete(); + } + } + + @Override + public List getDefaultMeshScript(Model model) { + List script = null; + if (model.getProject().isParallel()) { + script = getParallelMeshScript(); + } else { + script = getSerialMeshScript(); + } + return script; + } + + private File getMeshParallelScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? MESH_PARALLEL_BAT : MESH_PARALLEL_RUN); + writeFileIfNeeded(file, getParallelMeshScript()); + file.setExecutable(true); + return file; + } + + private File getMeshSerialScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? MESH_SERIAL_BAT : MESH_SERIAL_RUN); + writeFileIfNeeded(file, getSerialMeshScript()); + file.setExecutable(true); + return file; + } + + protected abstract List getParallelMeshScript(); + + protected abstract List getSerialMeshScript(); + + @Override + public File getCheckMeshScript(Model model) { + File parallelScript = getCheckMeshParallelScript(model); + File serialScript = getCheckMeshSerialScript(model); + + if (model.getProject().isParallel()) { + return parallelScript; + } else { + return serialScript; + } + } + + @Override + public List getDefaultCheckMeshScript(Model model) { + List script = null; + if (model.getProject().isParallel()) { + script = getParallelMeshScript(); + } else { + script = getSerialMeshScript(); + } + return script; + } + + private File getCheckMeshParallelScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? CHECK_MESH_PARALLEL_BAT : CHECK_MESH_PARALLEL_RUN); + writeFileIfNeeded(file, getParallelCheckMeshScript()); + file.setExecutable(true); + return file; + } + + private File getCheckMeshSerialScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? CHECK_MESH_SERIAL_BAT : CHECK_MESH_SERIAL_RUN); + writeFileIfNeeded(file, getSerialCheckMeshScript()); + file.setExecutable(true); + return file; + } + + protected abstract List getParallelCheckMeshScript(); + + protected abstract List getSerialCheckMeshScript(); + + /* + * SOLVER + */ + + @Override + public File getSolverScript(Model model) { + File parallelScript = getSolverParallelScript(model); + File serialScript = getSolverSerialScript(model); + + if (model.getProject().isParallel()) { + return parallelScript; + } else { + return serialScript; + } + } + + @Override + public List getDefaultSolverScript(Model model) { + List script = null; + if (model.getProject().isParallel()) { + script = getParallelSolverScript(); + } else { + script = getSerialSolverScript(); + } + return script; + } + + protected File getSolverParallelScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? SOLVER_PARALLEL_BAT : SOLVER_PARALLEL_RUN); + writeFileIfNeeded(file, getParallelSolverScript()); + file.setExecutable(true); + return file; + } + + protected File getSolverSerialScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? SOLVER_SERIAL_BAT : SOLVER_SERIAL_RUN); + writeFileIfNeeded(file, getSerialSolverScript()); + file.setExecutable(true); + return file; + } + + protected abstract List getParallelSolverScript(); + + protected abstract List getSerialSolverScript(); + + @Override + public File getInitialiseScript(Model model) { + File parallelScript = getInitialiseParallelScript(model); + File serialScript = getInitialiseSerialScript(model); + + if (model.getProject().isParallel()) { + return parallelScript; + } else { + return serialScript; + } + } + + protected File getInitialiseParallelScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? INITIALISE_FIELDS_PARALLEL_BAT : INITIALISE_FIELDS_PARALLEL_RUN); + writeFileIfNeeded(file, getParallelInitialiseScript()); + file.setExecutable(true); + return file; + } + + protected File getInitialiseSerialScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? INITIALISE_FIELDS_SERIAL_BAT : INITIALISE_FIELDS_SERIAL_RUN); + writeFileIfNeeded(file, getSerialInitialiseScript()); + file.setExecutable(true); + return file; + } + + protected abstract List getParallelInitialiseScript(); + + protected abstract List getSerialInitialiseScript(); + + @Override + public List getDefaultInitialiseScript(Model model) { + List script = null; + if (model.getProject().isParallel()) { + script = getParallelInitialiseScript(); + } else { + script = getSerialInitialiseScript(); + } + return script; + } + + @Override + public File getExtrudeScript(Model model) { + File parallelScript = getExtrudeParallelScript(model); + File serialScript = getExtrudeSerialScript(model); + + if (model.getProject().isParallel()) { + return parallelScript; + } else { + return serialScript; + } + } + + protected File getExtrudeParallelScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? EXTRUDEMESH_PARALLEL_BAT : EXTRUDEMESH_PARALLEL_RUN); + writeFileIfNeeded(file, getParallelExtrudeScript()); + file.setExecutable(true); + return file; + } + + protected File getExtrudeSerialScript(Model model) { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? EXTRUDEMESH_SERIAL_BAT : EXTRUDEMESH_SERIAL_RUN); + writeFileIfNeeded(file, getSerialExtrudeScript()); + file.setExecutable(true); + return file; + } + + protected abstract List getParallelExtrudeScript(); + + protected abstract List getSerialExtrudeScript(); + + @Override + public List getDefaultExtrudeScript(Model model) { + List script = null; + if (model.getProject().isParallel()) { + script = getParallelExtrudeScript(); + } else { + script = getSerialExtrudeScript(); + } + return script; + } + + @Override + public File getQueueLauncher(Model model) { + // if (Util.isWindowsScriptStyle()) { + // File file = new File(model.getProject().getBaseDir(), "driver.pbs"); + // writeFileIfNeeded(file, getWindowsQueueLauncher()); + // return file; + // } else { + File file = new File(model.getProject().getBaseDir(), "pbs.run"); + writeFileIfNeeded(file, getLinuxQueueLauncher()); + return file; + // } + } + + protected abstract List getWindowsQueueLauncher(); + + protected abstract List getLinuxQueueLauncher(); + + @Override + public List getDefaultQueueLauncher(Model model) { + return getLinuxQueueLauncher(); + } + + protected abstract List getWindowsSetupCaseScript(); + + protected abstract List getLinuxSetupCaseScript(); + + @Override + public File getExportScript(Model model) { + File file = new File(model.getProject().getBaseDir(), "export.py"); + writeFileIfNeeded(file, getExportScript()); + return file; + } + + @Override + public List getDefaultExportScript(Model model) { + return getExportScript(); + } + + protected abstract List getExportScript(); + + protected void writeFileIfNeeded(File file, List script) { + if (!file.exists()) { + IOUtils.writeLinesToFile(file, script); + file.setExecutable(true); + } + } +} diff --git a/src/eu/engys/core/controller/ApplicationActions.java b/src/eu/engys/core/controller/ApplicationActions.java new file mode 100644 index 0000000..6c5f5ef --- /dev/null +++ b/src/eu/engys/core/controller/ApplicationActions.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.controller; + +import java.io.File; + +import eu.engys.core.controller.Controller.OpenOptions; +import eu.engys.core.project.CaseParameters; + +public interface ApplicationActions { + + void createCase(CaseParameters params); + + void openCase(File file); + + void reopenCase(OpenOptions options); + + void saveCase(File file); + +} diff --git a/src/eu/engys/core/controller/BatchActions.java b/src/eu/engys/core/controller/BatchActions.java new file mode 100644 index 0000000..1dccc86 --- /dev/null +++ b/src/eu/engys/core/controller/BatchActions.java @@ -0,0 +1,46 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.controller; + +import java.io.File; + +import eu.engys.core.controller.Controller.OpenOptions; +import eu.engys.core.controller.actions.TimeoutException; +import eu.engys.core.project.CaseParameters; + +public interface BatchActions { + + void create(CaseParameters params); + void open(File file); + void reopen(OpenOptions options); + void save(File file); + + void setupCase(); + void stopCase() throws TimeoutException; + void kill(); + +} diff --git a/src/eu/engys/core/controller/Client.java b/src/eu/engys/core/controller/Client.java new file mode 100644 index 0000000..a5aa530 --- /dev/null +++ b/src/eu/engys/core/controller/Client.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import javax.swing.JComponent; + +import eu.engys.core.project.system.monitoringfunctionobjects.ParserView; + +public interface Client { + + void executeCommand(Command command); + + void executeCommands(Command... command); + + ParserView getResidualView(); + + void refreshOnce(); + + void loadState(); + + void stopCommand(Command command); + + void killCommand(Command command); + + void goToBatch(); + + void reset(); + + Server getServer(); + + void createReport(); + + JComponent getServerPanel(); + + JComponent getQueuePanel(); + + void waitForFinished(); + +} diff --git a/src/eu/engys/core/controller/ClientInfo.java b/src/eu/engys/core/controller/ClientInfo.java new file mode 100644 index 0000000..719c8b3 --- /dev/null +++ b/src/eu/engys/core/controller/ClientInfo.java @@ -0,0 +1,50 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.Serializable; + +public class ClientInfo implements Serializable { + + private boolean connected; + + private ClientInfo(boolean connected) { + this.connected = connected; + } + + public boolean isConnected() { + return connected; + } + + public static ClientInfo clientConnected() { + return new ClientInfo(true); + } + + public static ClientInfo clientDisconnected() { + return new ClientInfo(false); + } + +} diff --git a/src/eu/engys/core/controller/ClientServerCommand.java b/src/eu/engys/core/controller/ClientServerCommand.java new file mode 100644 index 0000000..4ecee38 --- /dev/null +++ b/src/eu/engys/core/controller/ClientServerCommand.java @@ -0,0 +1,99 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.Serializable; + +public class ClientServerCommand implements Serializable { + + private Command[] commands; + private String open; + private boolean parallel; + private boolean startParsers; + private boolean queue; + + public ClientServerCommand(Command... commands) { + this.commands = commands; + this.open = null; + this.parallel = false; + this.startParsers = false; + } + + public ClientServerCommand(Command command, String open, boolean parallel, boolean startParsers) { + this.commands = new Command[]{command}; + this.open = open; + this.parallel = parallel; + this.startParsers = startParsers; + } + + public Command getCommand() { + return commands[0]; + } + + public Command[] getCommands() { + return commands; + } + + public void setCommands(Command[] commands) { + this.commands = commands; + } + + public String getOpen() { + return open; + } + + public void setOpen(String open) { + this.open = open; + } + + public boolean isParallel() { + return parallel; + } + + public void setParallel(boolean parallel) { + this.parallel = parallel; + } + + public boolean isStartParsers() { + return startParsers; + } + + public void setStartParsers(boolean startParsers) { + this.startParsers = startParsers; + } + + public boolean isCommandSequence() { + return commands.length > 1; + } + + public void setQueue(boolean queue) { + this.queue = queue; + } + + public boolean isQueue() { + return queue; + } +} diff --git a/src/eu/engys/core/controller/Command.java b/src/eu/engys/core/controller/Command.java new file mode 100644 index 0000000..fbbc050 --- /dev/null +++ b/src/eu/engys/core/controller/Command.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +public enum Command { + + CREATE_MESH("", ""), + RUN_CASE("", ""), + INITIALISE_FIELDS("", ""), + RUN_ALL("", ""), + EXTRUDE_TO_REGION("", ""), + ANY("any", "Any"), + NONE("none", "None"); + + private String key; + private String label; + + private Command(String key, String label) { + this.key = key; + this.label = label; + } + + public String label() { + return label; + } + + public String key() { + return key; + } + + public boolean isRunCase(){ + return this == RUN_CASE || this == RUN_ALL; + } + + +} diff --git a/src/eu/engys/core/controller/CommandInfo.java b/src/eu/engys/core/controller/CommandInfo.java new file mode 100644 index 0000000..81afbf7 --- /dev/null +++ b/src/eu/engys/core/controller/CommandInfo.java @@ -0,0 +1,91 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.Serializable; +import java.rmi.RemoteException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CommandInfo implements Serializable { + + private static final Logger logger = LoggerFactory.getLogger(CommandInfo.class); + + public boolean success; + public String message; + public Exception exception; + public String jobID; + + public static CommandInfo remoteException(RemoteException e) { + logger.warn(">>> SERVER REMOTE ERROR", e); + CommandInfo ci = new CommandInfo(); + ci.message = "Error"; + ci.exception = e; + ci.success = false; + return ci; + } + + public static CommandInfo genericException(Exception e) { + logger.error(">>> SERVER GENERIC ERROR", e); + CommandInfo ci = new CommandInfo(); + ci.message = "Error"; + ci.exception = e; + ci.success = false; + return ci; + } + + public static CommandInfo error(String message) { + logger.warn(">>> SERVER WARNING: {}", message); + CommandInfo ci = new CommandInfo(); + ci.message = message; + ci.exception = null; + ci.success = false; + return ci; + } + + public static CommandInfo notConnected() { + CommandInfo ci = new CommandInfo(); + ci.message = "Not Connected"; + ci.exception = null; + ci.success = false; + return ci; + } + + public static CommandInfo success() { + return success("Success"); + } + + public static CommandInfo success(String message) { + logger.info(">>> SERVER: {}", message); + CommandInfo ci = new CommandInfo(); + ci.message = message; + ci.exception = null; + ci.success = true; + return ci; + } + +} diff --git a/src/eu/engys/core/controller/Controller.java b/src/eu/engys/core/controller/Controller.java new file mode 100644 index 0000000..a8aedc9 --- /dev/null +++ b/src/eu/engys/core/controller/Controller.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.controller; + +import eu.engys.core.controller.actions.CommandException; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.core.project.system.monitoringfunctionobjects.ParserView; + +public interface Controller extends ApplicationActions, BatchActions { + + public enum CloseOptions { + EXIT, CONTINUE, NONE + } + + public enum OpenOptions { + SERIAL, PARALLEL, CURRENT_SETTINGS, CHECK_FOLDER, MESH_ONLY + } + + boolean isDemo(); + + ProjectWriter getWriter(); + ProjectReader getReader(); + + void addListener(ControllerListener l); + ControllerListener getListener(); + + public Client getClient(); + public Server getServer(); + public ParserView getResidualView(); + + boolean allowActionsOnRunning(boolean exit); + + void createReport(); + + void executeCommand(Command command) throws CommandException; + + void executeCommands(Command... commands) throws CommandException; + + String submitCommand(Command command) throws CommandException; + + boolean isRunningCommand(); + +} diff --git a/src/eu/engys/core/controller/ControllerListener.java b/src/eu/engys/core/controller/ControllerListener.java new file mode 100644 index 0000000..6225c74 --- /dev/null +++ b/src/eu/engys/core/controller/ControllerListener.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.controller; + + +public interface ControllerListener { + + void beforeNewCase(); + void afterNewCase(); + + void beforeLoadCase(); + void afterLoadCase(); + + void beforeReopenCase(); + void afterReopenCase(); + + void beforeSaveCase(); + void afterSaveCase(); + + void beforeRunCase(); + void afterRunCase(); + + void beforeVirtualise(); + void afterVirtualise(GeometryToMesh g2m); + + void beforeCheckMesh(); + void afterCheckMesh(); + + void selectDestinationAndGo(); + + void saveLocation(); + void goToLocation(); + + void afterBlockMesh(); + +} diff --git a/src/eu/engys/core/controller/DefaultNamingConvention.java b/src/eu/engys/core/controller/DefaultNamingConvention.java new file mode 100644 index 0000000..b8a8bdd --- /dev/null +++ b/src/eu/engys/core/controller/DefaultNamingConvention.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import eu.engys.core.controller.actions.NamingConvention; +import eu.engys.core.project.geometry.Surface; + +public class DefaultNamingConvention implements NamingConvention { + @Override + public String getCellZoneName(Surface surface) { + return surface.getZoneName(); + } + + @Override + public String getPatchName(Surface surface) { + return surface.getPatchName(); + } +} diff --git a/src/eu/engys/core/controller/DefaultScriptFactory.java b/src/eu/engys/core/controller/DefaultScriptFactory.java new file mode 100644 index 0000000..03fb1d2 --- /dev/null +++ b/src/eu/engys/core/controller/DefaultScriptFactory.java @@ -0,0 +1,398 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.controller; + +import static eu.engys.core.OpenFOAMEnvironment.loadEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.printHeader; +import static eu.engys.core.OpenFOAMEnvironment.printVariables; +import static eu.engys.util.OpenFOAMCommands.BLOCK_MESH; +import static eu.engys.util.OpenFOAMCommands.DECOMPOSE_PAR; +import static eu.engys.util.OpenFOAMCommands.DECOMPOSE_PAR_ALLREGIONS; +import static eu.engys.util.OpenFOAMCommands.DECOMPOSE_PAR_CONSTANT_ALLREGIONS; +import static eu.engys.util.OpenFOAMCommands.EXTRUDE_REGION_TO_MESH; +import static eu.engys.util.OpenFOAMCommands.INITIALISE_FIELDS_PARALLEL; +import static eu.engys.util.OpenFOAMCommands.INITIALISE_FIELDS_SERIAL; +import static eu.engys.util.OpenFOAMCommands.RECONSTRUCT_PAR_MESH; +import static eu.engys.util.OpenFOAMCommands.RECONSTRUCT_PAR_MESH_CONSTANT; +import static eu.engys.util.OpenFOAMCommands.RUN_CASE_PARALLEL; +import static eu.engys.util.OpenFOAMCommands.RUN_CASE_SERIAL; +import static eu.engys.util.OpenFOAMCommands.RUN_MESH_PARALLEL; +import static eu.engys.util.OpenFOAMCommands.RUN_MESH_SERIAL; +//import static eu.engys.util.OpenFOAMCommands.CHECK_MESH_PARALLEL; +//import static eu.engys.util.OpenFOAMCommands.CHECK_MESH_SERIAL; +import static eu.engys.util.OpenFOAMCommands.SNAPPY_CHECK_MESH_PARALLEL; +import static eu.engys.util.OpenFOAMCommands.SNAPPY_CHECK_MESH_SERIAL; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.commons.io.FileUtils; + +import eu.engys.core.project.Model; +import eu.engys.util.IOUtils; +import eu.engys.util.Util; +import eu.engys.util.connection.QueueParameters; + +public class DefaultScriptFactory extends AbstractScriptFactory { + + private static final String DO_NOT_EDIT_BELOW_THIS_LINE = "# DO NOT EDIT BELOW THIS LINE"; + private static final String DO_NOT_EDIT_ABOVE_THIS_LINE = "# DO NOT EDIT ABOVE THIS LINE"; + protected Model model; + + @Inject + public DefaultScriptFactory(Model model) { + this.model = model; + } + + /* + * MESH + */ + + @Override + protected List getSerialMeshScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, RUN_MESH); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.appendIf(performBlockMesh(), BLOCK_MESH()); + sb.newLine(); + sb.append(RUN_MESH_SERIAL()); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getParallelMeshScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, RUN_MESH); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.appendIf(performBlockMesh(), BLOCK_MESH()); + sb.newLine(); + sb.appendIf(performBlockMesh(), DECOMPOSE_PAR()); + sb.newLine(); + sb.append(RUN_MESH_PARALLEL()); + sb.newLine(); + sb.appendIf(performBlockMesh() && Util.isUnixScriptStyle(), "rm -rf constant/polyMesh"); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getSerialCheckMeshScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, CHECK_MESH); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(SNAPPY_CHECK_MESH_SERIAL()); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getParallelCheckMeshScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, CHECK_MESH); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(SNAPPY_CHECK_MESH_PARALLEL()); + sb.newLine(); + return sb.getLines(); + } + + /* + * SOLVER + */ + + @Override + protected List getSerialSolverScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, RUN_CASE); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(RUN_CASE_SERIAL()); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getParallelSolverScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, RUN_CASE); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(RUN_CASE_PARALLEL()); + sb.newLine(); + return sb.getLines(); + } + + /* + * INITIALISE + */ + + @Override + protected List getSerialInitialiseScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, INITIALISE_FIELDS.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(INITIALISE_FIELDS_SERIAL()); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getParallelInitialiseScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, INITIALISE_FIELDS.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(INITIALISE_FIELDS_PARALLEL()); + sb.newLine(); + return sb.getLines(); + } + + /* + * EXTRUDE REGION + */ + + @Override + protected List getSerialExtrudeScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, EXTRUDEMESH.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(EXTRUDE_REGION_TO_MESH()); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getParallelExtrudeScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, EXTRUDEMESH.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.appendIf(meshOnZero(), RECONSTRUCT_PAR_MESH(), RECONSTRUCT_PAR_MESH_CONSTANT()); + sb.append(EXTRUDE_REGION_TO_MESH()); + sb.appendIf(meshOnZero(), DECOMPOSE_PAR_ALLREGIONS(), DECOMPOSE_PAR_CONSTANT_ALLREGIONS()); + sb.newLine(); + return sb.getLines(); + } + + private boolean meshOnZero() { + return model.getProject().isMeshOnZero(); + } + + /* + * QUEUE + */ + + @Override + public List getDefaultQueueDriver(Model model) { + return getLinuxQueueDriver(defaultBody()); + } + + @Override + public File getQueueDriver(Model model) { + File file = new File(model.getProject().getBaseDir(), "driver.pbs"); + List lines = null; + if (file.exists()) { + lines = getLinuxQueueDriver(extractBody(file)); + } else { + lines = getLinuxQueueDriver(defaultBody()); + } + + IOUtils.writeLinesToFile(file, lines); + return file; + } + + private List extractBody(File file) { + try { + return extractLine(file, DO_NOT_EDIT_ABOVE_THIS_LINE, DO_NOT_EDIT_BELOW_THIS_LINE); + } catch (IOException e) { + e.printStackTrace(); + return Collections.emptyList(); + } + } + + public static List extractLine(File file, String start, String end) throws IOException { + List lines = FileUtils.readLines(file); + List support = new LinkedList(); + + boolean copy = false; + for (String l : lines) { + if(l.startsWith(end)){ + break; + } + if(copy){ + support.add(l); + } + if(l.startsWith(start)){ + copy = true; + } + } + return support; + } + + private List defaultBody() { + InputStream inputStream = DefaultScriptFactory.class.getClassLoader().getResourceAsStream("eu/engys/resources/driver.pbs"); + try { + String body = IOUtils.readStringFromStream(inputStream); + return Arrays.asList(body.split(IOUtils.EOL)); + } catch (IOException e) { + e.printStackTrace(); + return Collections.emptyList(); + } + } + + private List getWindowsQueueDriver() { + throw new RuntimeException("NOT IMPLEMENTED"); + } + + private List getLinuxQueueDriver(List body) { + + String name = model.getProject().getBaseDir().getName(); + QueueParameters queueParameters = model.getSolverModel().getQueueParameters(); + int nodes = queueParameters.getNumberOfNodes(); + int cpus = queueParameters.getCpuPerNode(); + int timeout = queueParameters.getTimeout(); + String feature = queueParameters.getFeature(); + String names = queueParameters.getNodeNames(); + + ScriptBuilder sb = new ScriptBuilder(); + sb.append("#PBS -o " + name + ".out"); + // sb.append("#PBS -e " + name + ".err"); + sb.append("#PBS -j oe"); + // sb.append("#PBS -k oe"); + sb.append("#PBS -N " + name); + if (names == null || names.isEmpty()) { + sb.append("#PBS -l nodes=" + nodes + ":ppn=" + cpus + (feature.isEmpty() ? "" : (":" + feature))); + } else { + sb.append("#PBS -l nodes=" + names + ":ppn=" + cpus + (feature.isEmpty() ? "" : (":" + feature))); + } + sb.append("#PBS -l walltime=" + timeout + ":00:00"); + sb.append("#PBS -V"); + sb.newLine(); + sb.append(DO_NOT_EDIT_ABOVE_THIS_LINE); + sb.newLine(); + for (String line : body) { + sb.append(line); + } + sb.newLine(); + sb.append(DO_NOT_EDIT_BELOW_THIS_LINE); + sb.newLine(); + sb.append("echo \" Environment\""); + sb.append("echo \"---------------------------------\""); + sb.append("echo \" APPLICATION = $APPLICATION\""); + sb.append("echo \" ENV_LOADER = $ENV_LOADER\""); + sb.append("echo \" HOSTFILE = $HOSTFILE\""); + sb.append("echo \" CASE = $CASE\""); + sb.append("echo \" LOG = $LOG\""); + sb.append("echo \" NP = $NP\""); + sb.append("echo \"---------------------------------\""); + sb.append("echo \" PBS_O_WORKDIR = $PBS_O_WORKDIR\""); + sb.append("echo \" PBS_NODEFILE = $PBS_NODEFILE\""); + sb.append("echo \"---------------------------------\""); + sb.append("echo \" HOSTNAME = `hostname`\""); + sb.append("echo \" TIME = `date`\""); + sb.append("echo \" PWD = `pwd`\""); + sb.append("echo \"---------------------------------\""); + sb.newLine(); + sb.append("unset DISPLAY"); + sb.append("export HOSTFILE=$PBS_NODEFILE"); + sb.append("NPROCS=`wc -l < $HOSTFILE`"); + sb.append("NNODES=`uniq $HOSTFILE | wc -l`"); + sb.append("echo \" Using $NPROCS processors across $NNODES nodes\""); + sb.newLine(); + sb.append("cd $PBS_O_WORKDIR"); + sb.newLine(); + sb.append("$APPLICATION -case $CASE &> $LOG"); + sb.newLine(); + sb.append("exit $?"); + + return sb.getLines(); + } + + @Override + protected List getLinuxSetupCaseScript() { + throw new RuntimeException("NOT IMPLEMENTED"); + } + + @Override + protected List getWindowsSetupCaseScript() { + throw new RuntimeException("NOT IMPLEMENTED"); + } + + @Override + protected List getExportScript() { + throw new RuntimeException("NOT IMPLEMENTED"); + } + + @Override + protected List getLinuxQueueLauncher() { + InputStream inputStream = DefaultScriptFactory.class.getClassLoader().getResourceAsStream("eu/engys/resources/pbs.run"); + String driverString = ""; + try { + driverString = IOUtils.readStringFromStream(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + + return Arrays.asList(driverString.split(IOUtils.EOL)); + } + + @Override + protected List getWindowsQueueLauncher() { + throw new RuntimeException("NOT IMPLEMENTED"); + } + + /* + * UTILS + */ + + protected boolean performBlockMesh() { + return !model.getGeometry().isAutoBoundingBox(); + } +} diff --git a/src/eu/engys/core/controller/GeometryToMesh.java b/src/eu/engys/core/controller/GeometryToMesh.java new file mode 100644 index 0000000..be0d799 --- /dev/null +++ b/src/eu/engys/core/controller/GeometryToMesh.java @@ -0,0 +1,251 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import static eu.engys.core.project.system.SnappyHexMeshDict.BAFFLE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.BOUNDARY_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_TYPE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_ZONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.INSIDE; +import static eu.engys.core.project.system.SnappyHexMeshDict.LEVELS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MODE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.NONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.OUTSIDE_KEY; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.actions.NamingConvention; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.Region; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.core.project.zero.patches.Patch; + +public class GeometryToMesh { + + private static final Logger logger = LoggerFactory.getLogger(GeometryToMesh.class); + + private Model model; + private List patches = new ArrayList<>(); + private List cellZones = new ArrayList<>(); + + private List willBePatches = new ArrayList<>(); + private List willBeCellZones = new ArrayList<>(); + + private NamingConvention naming; + + public GeometryToMesh(Model model) { + this.model = model; + this.naming = new DefaultNamingConvention(); + } + + public String[] listPatches() { + extractPatchesFromGeometry(); + + String[] names = new String[patches.size()]; + for (int i = 0; i < names.length; i++) { + names[i] = patches.get(i).getName(); + } + + return names; + } + + public void execute() { + model.getPatches().clear(); + model.getCellZones().clear(); + + extractPatchesFromGeometry(); + + model.getPatches().addPatches(patches); + model.getCellZones().addZones(cellZones); + } + + public List getWillBePatches() { + return willBePatches; + } + + public List getWillBeCellZones() { + return willBeCellZones; + } + + private void extractPatchesFromGeometry() { + for (Surface surface : model.getGeometry().getSurfaces()) { + logger.debug("Surface {}: {} {} {}", surface.getName(), surface.getSurfaceDictionary(), surface.getVolumeDictionary(), surface.getZoneDictionary()); + surfaceToPatch(surface); + surfaceToCellZone(surface); + } + + if (model.getGeometry().hasBlock()) { + surfaceToPatch(model.getGeometry().getBlock()); + } + } + + private void surfaceToCellZone(Surface surface) { + if (willBeACellZone(surface)) { + if (willCreatePatches(surface)) { + zoneToPatches(surface); + } else { + logger.debug("'{}' does NOT become a PATCH+SLAVE", surface.getName()); + } + String zoneName = naming.getCellZoneName(surface); + CellZone zone = new CellZone(zoneName); + zone.setName(zoneName); + zone.setVisible(true); + zone.setLoaded(true); + + logger.debug("'{}' becomes a ZONE with name {}", surface.getName(), zoneName); + + cellZones.add(zone); + willBeCellZones.add(surface); + } else { + logger.debug("'{}' does NOT become a ZONE", surface.getName()); + } + } + + private void zoneToPatches(Surface surface) { + if (surface.hasRegions()) { + if (surface.isSingleton()) { + addPatchAndSlave(surface.getRegions()[0]); + } else if (isBaffle(surface)) { + addPatchAndSlave(surface.getRegions()[0]); + } else if (isBoundary(surface)) { + for (Region region : surface.getRegions()) { + addPatchAndSlave(region); + } + } + } else { + addPatchAndSlave(surface); + } + } + + private boolean willBeACellZone(Surface surface) { + Dictionary zoneDictionary = surface.getZoneDictionary(); + return zoneDictionary != null && !zoneDictionary.isEmpty() && zoneDictionary.isField(FACE_ZONE_KEY) && zoneDictionary.found(FACE_TYPE_KEY) && !zoneDictionary.lookup(FACE_TYPE_KEY).equals(NONE_KEY); + } + + private boolean willCreatePatches(Surface surface) { + Dictionary zoneDictionary = surface.getZoneDictionary(); + return zoneDictionary.found(FACE_TYPE_KEY) && (zoneDictionary.lookup(FACE_TYPE_KEY).equals(BOUNDARY_KEY) || zoneDictionary.lookup(FACE_TYPE_KEY).equals(BAFFLE_KEY)); + } + + private boolean isBoundary(Surface surface) { + Dictionary zoneDictionary = surface.getZoneDictionary(); + return zoneDictionary.lookup(FACE_TYPE_KEY).equals(BOUNDARY_KEY); + } + + private boolean isBaffle(Surface surface) { + Dictionary zoneDictionary = surface.getZoneDictionary(); + return zoneDictionary.lookup(FACE_TYPE_KEY).equals(BAFFLE_KEY); + } + + private void surfaceToPatch(Surface surface) { + if (surface.isSingleton()) { + addPatch(surface); + } else if (surface.hasRegions()) { + for (Region region : surface.getRegions()) { + addPatch(region); + } + } else { + addPatch(surface); + } + } + + private void addPatch(Surface surface) { + if (willBeAPatch(surface)) { + String patchName = naming.getPatchName(surface); + logger.debug("'{}' becomes a PATCH with name {}, {}", surface.getName(), patchName, surface.getSurfaceDictionary()); + patches.add(newPatch(patchName)); + willBePatches.add(surface); + } else { + logger.debug("'{}' does NOT become a PATCH", surface.getName()); + } + } + + private void addPatchAndSlave(Surface surface) { + String patchName = naming.getPatchName(surface); + String slaveName = patchName + "_slave"; + logger.debug("'{}' becomes 2 PATCHES with name {} and {}", surface.getName(), patchName, slaveName); + patches.add(newPatch(patchName)); + willBePatches.add(surface); + patches.add(newPatch(slaveName)); + willBePatches.add(surface); + } + + private Patch newPatch(String name) { + Patch patch = new Patch(name); + patch.setName(name); + patch.setDictionary(new Dictionary(name)); + patch.setVisible(true); + patch.setLoaded(true); + patch.setEmpty(false); + patch.setPhisicalType(BoundaryType.getDefaultType()); + patch.setBoundaryConditions(new BoundaryConditions()); + return patch; + } + + private boolean willBeAPatch(Surface surface) { + return surface.getType().isPlane() + || (surface.getType().isStl() && surface.isSingleton() && isSurfaceRefinementOnly(surface)) + || (surface.getType().isSolid() && willBeAPatch(((Solid)surface).getParent()) ) + || (!surface.getType().isSolid() && isSurfaceRefinementOnly(surface)); + } + + private boolean isSurfaceRefinementOnly(Surface surface) { + boolean surfaceRefinement = isSurfaceRefinement(surface); + boolean volumeRefinement = isVolumeRefinement(surface); + boolean willBeACellZone = willBeACellZone(surface); + + // System.err.println("GeometryToMesh.isSurfaceRefinementOnly() surfaceRefinement: "+surfaceRefinement+", volumeRefinement: "+volumeRefinement+", willBeACellZone: "+willBeACellZone); + return surfaceRefinement && !volumeRefinement && !willBeACellZone; + } + + private boolean isVolumeRefinement(Surface surface) { + Dictionary volumeDictionary = surface.getVolumeDictionary(); + return volumeDictionary != null && !volumeDictionary.isEmpty() && volumeDictionary.isField(LEVELS_KEY) && volumeDictionary.isField(MODE_KEY) && (volumeDictionary.lookup(MODE_KEY).equals(INSIDE) || volumeDictionary.lookup(MODE_KEY).equals(OUTSIDE_KEY)); + } + + private boolean isSurfaceRefinement(Surface surface) { + Dictionary surfaceDictionary = surface.getSurfaceDictionary(); + return surfaceDictionary != null && !surfaceDictionary.isEmpty() && surfaceDictionary.isField("level"); + } + + public String getPatchName(Surface surface) { + return naming.getPatchName(surface); + } + + public String getCellZoneName(Surface surface) { + return naming.getCellZoneName(surface); + } + +} diff --git a/src/eu/engys/core/controller/HelyxOSController.java b/src/eu/engys/core/controller/HelyxOSController.java new file mode 100644 index 0000000..26c3443 --- /dev/null +++ b/src/eu/engys/core/controller/HelyxOSController.java @@ -0,0 +1,428 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import static eu.engys.core.project.system.SetFieldsDict.CELL_SET_KEY; + +import java.io.File; +import java.util.List; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ThreadPoolExecutor; + +import javax.swing.JOptionPane; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Inject; + +import eu.engys.core.controller.actions.CheckMesh; +import eu.engys.core.controller.actions.InitialiseFields; +import eu.engys.core.controller.actions.RunCommand; +import eu.engys.core.controller.actions.StandardInitialiseFields; +import eu.engys.core.controller.actions.StandardRunCase; +import eu.engys.core.controller.actions.StandardRunMesh; +import eu.engys.core.controller.actions.TimeoutException; +import eu.engys.core.executor.Executor; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.presentation.Action; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.core.project.state.ServerState; +import eu.engys.core.project.system.monitoringfunctionobjects.ParserView; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.gui.casesetup.fields.StandardInitialisations; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.EventManager.Event; +import eu.engys.gui.events.EventManager.GenericEventListener; +import eu.engys.gui.events.application.ApplicationEvent; +import eu.engys.gui.events.application.BaseMeshTypeChangedEvent; +import eu.engys.gui.events.application.OpenMonitorEvent; +import eu.engys.gui.solver.postprocessing.ParsersHandler; +import eu.engys.gui.solver.postprocessing.ParsersViewHandler; +import eu.engys.gui.solver.postprocessing.panels.residuals.ResidualsView; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ScriptEditor; +import eu.engys.util.ui.UiUtil; + +public class HelyxOSController extends AbstractController implements GenericEventListener, ParsersManager { + + private static final long TIMER_INITIAL_DELAY = 500L; + private static final long TIMER_REFRESH_RATE = 1000L; + + private static final Logger logger = LoggerFactory.getLogger(HelyxOSController.class); + private ResidualsView residualsView; + private RunCommand command; + + private Timer timer; + private ParsersHandler parsersHandler; + private ParsersViewHandler viewHandler; + private ThreadPoolExecutor executor; + + @Inject + public HelyxOSController(Model model, CellZonesBuilder cellZonesBuilder, Set modules, ProjectReader reader, ProjectWriter writer, CellZonesBuilder zonesBuilder, ProgressMonitor monitor, ScriptFactory scriptFactory) { + super(model, modules, reader, writer, zonesBuilder, monitor, scriptFactory); + this.residualsView = new ResidualsView(model, monitor); + EventManager.registerEventListener(this, ApplicationEvent.class); + ActionManager.getInstance().parseActions(this); + } + + @Override + public void eventTriggered(Object obj, Event e) { + logger.info("Event triggered {}", e.getClass().getName()); + if (e instanceof OpenMonitorEvent) { + monitor.start(null); + } else if (e instanceof BaseMeshTypeChangedEvent) { + scriptFactory.getMeshScript(model).delete(); + } + } + + /* + * MESH + */ + + @Action(key = "mesh.create", checkEnv = true) + public void runMesh() { + save(model.getProject().getBaseDir()); + + command = new StandardRunMesh(model, this, scriptFactory); + command.beforeExecute(); + command.executeClient(); + } + + @Action(key = "mesh.check", checkEnv = true) + public void checkMesh() { + model.getProject().getSystemFolder().write(model, null); + RunCommand checkMesh = new CheckMesh(model, this, scriptFactory); + checkMesh.beforeExecute(); + checkMesh.executeClient(); + } + + /* + * CASE SETUP + */ + @Override + public void setupCase() { + /* JUST REOPEN IN THIS CASE */ + monitor.start("Open " + model.getProject().getBaseDir(), false, new Runnable() { + @Override + public void run() { + reopen(OpenOptions.CURRENT_SETTINGS); + monitor.end(); + } + }); + } + + @Action(key = "initialise.fields", checkEnv = true) + public void initialiseFields() { + if (model.getProject().getZeroFolder().hasNonZeroTimeFolders()) { + int retVal = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "This action will DELETE all the time folders. Continue?", "Initialise Fields", JOptionPane.YES_NO_OPTION); + if (retVal == JOptionPane.YES_OPTION) { + model.getProject().getSystemFolder().getControlDict().startFromZero(); + model.projectChanged(); + } else { + return; + } + } + monitor.start(InitialiseFields.ACTION_NAME, false, new Runnable() { + @Override + public void run() { + save(null); + monitor.end(); + } + }); + + new StandardInitialisations(model, cellZonesBuilder, modules).initializeFields(); + if (cellSetFieldPresent()) { + save(model.getProject().getBaseDir()); + + command = new StandardInitialiseFields(model, this, scriptFactory); + command.beforeExecute(); + command.executeClient(); + } + } + + public boolean cellSetFieldPresent() { + for (Field f : model.getFields().values()) { + if (f.getInitialisationType().equals(CELL_SET_KEY)) { + return true; + } + } + return false; + } + + /* + * SOLVER + */ + + private void startTimer() { + startParsers(); + viewHandler = new ParsersViewHandler(model, this, residualsView); + + executor = Executor.newExecutor("ServerStateMonitor"); + if (timer == null) { + timer = new Timer("- Client Monitor -", true); + } + timer.schedule(new TimerTask() { + @Override + public void run() { + if (executor.getQueue().isEmpty()) { + executor.submit(new Runnable() { + @Override + public void run() { + runTimer(); + } + + }); + } else { + logger.debug("Timer running..."); + } + } + }, TIMER_INITIAL_DELAY, TIMER_REFRESH_RATE); + } + + private void runTimer() { + ServerState state = model.getSolverModel().getServerState(); + Command c = state.getCommand(); + logger.debug("RUN TIMER, STATE IS {}", state.getSolverState()); + if (c.isRunCase()) { + viewHandler.serverChanged(state); + if (state.getSolverState().isFinished() || state.getSolverState().isError()) { + stopTimer(); + } + } + } + + private void stopTimer() { + logger.debug("STOP TIMER"); + if (viewHandler != null) { + viewHandler = null; + } + if (executor != null) { + executor.shutdown(); + executor = null; + } + if (timer != null) { + timer.cancel(); + timer.purge(); + timer = null; + } + } + + @Action(key = "solver.run", checkEnv = true) + public void runCase() { + save(model.getProject().getBaseDir()); + + listener.beforeRunCase(); + command = new StandardRunCase(model, this, scriptFactory); + command.beforeExecute(); + command.executeClient(); + + startTimer(); + } + + @Action(key = "solver.refresh.once") + public void refreshOnce() { + ParsersViewHandler viewHandler = new ParsersViewHandler(model, this, residualsView); + viewHandler.refreshOnce(); + } + + @Override + @Action(key = "solver.stop") + public void stopCase() { + monitor.setIndeterminate(true); + monitor.start("Stop Solver", false, new Runnable() { + @Override + public void run() { + _stopCase(); + monitor.info("DONE"); + monitor.end(); + } + + }); + } + + private void _stopCase() { + try { + command.stop(); + } catch (TimeoutException e) { + Object[] options = new Object[] { "Wait", "Kill Process" }; + int option = JOptionPane.showOptionDialog(monitor.getDialog(), "Solver has not finished yet.\nSelect an action to perform.", "Stop Execution", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); + if (timer != null) { + if (option == JOptionPane.YES_OPTION) { + _stopCase(); + } else { + _kill(); + } + + } + } + } + + @Override + public void kill() { + monitor.setIndeterminate(true); + monitor.start("Killing Command", false, new Runnable() { + @Override + public void run() { + _kill(); + monitor.info("DONE"); + monitor.end(); + } + + }); + } + + private void _kill() { + command.kill(); + } + + /* + * EDIT SCRIPTS + */ + + @Action(key = "solver.run.edit") + public void editRunCaseScript() { + ScriptEditor.getInstance().show(scriptFactory.getSolverScript(model).toPath(), scriptFactory.getDefaultSolverScript(model)); + } + + @Action(key = "mesh.create.edit") + public void editRunMeshScript() { + ScriptEditor.getInstance().show(scriptFactory.getMeshScript(model).toPath(), scriptFactory.getDefaultMeshScript(model)); + } + + @Action(key = "mesh.check.edit") + public void editCheckMeshScript() { + ScriptEditor.getInstance().show(scriptFactory.getCheckMeshScript(model).toPath(), scriptFactory.getDefaultCheckMeshScript(model)); + } + + @Action(key = "initialise.fields.edit") + public void editInitialiseScript() { + ScriptEditor.getInstance().show(scriptFactory.getInitialiseScript(model).toPath(), scriptFactory.getDefaultInitialiseScript(model)); + } + + /* + * Parsers + */ + @Override + public void startParsers() { + logger.info("[SERVER] START PARSERS"); + parsersHandler = new ParsersHandler(model); + parsersHandler.deleteUselessLogFiles(); + } + + @Override + public void endParsers() { + logger.info("[SERVER] END PARSERS"); + if (parsersHandler != null) { + parsersHandler.endParsers(); + parsersHandler = null; + } + } + + @Override + public List updateParser(String foName) { + logger.info("[SERVER] UPDATE PARSERS"); + return parsersHandler.refreshParsersForFunctionObject(foName); + } + + @Override + public List updateParserOnce(String foName) { + logger.info("[SERVER] UPDATE PARSERS ONCE"); + ParsersHandler ph = new ParsersHandler(model); + return ph.refreshOnceForFunctionObject(foName); + } + + /* + * OTHER + */ + + @Override + public ParserView getResidualView() { + return residualsView; + } + + @Override + public void open(File baseDir) { + super.open(baseDir); + if (listener != null) { + // client.loadState(); + listener.selectDestinationAndGo(); + } + } + + @Override + public void reopen(OpenOptions options) { + if (listener != null) { + listener.saveLocation(); + } + + super.reopen(options); + + if (listener != null) { + // client.loadState(); + listener.goToLocation(); + } + + } + + @Override + public Client getClient() { + return null; + } + + @Override + public Server getServer() { + return null; + } + + @Override + public boolean isDemo() { + return false; + } + + @Override + protected boolean handleExitOnSolverRunning() { + Object[] options = new Object[] { STOP_SOLVER, KILL_SOLVER, CANCEL }; + int option = JOptionPane.showOptionDialog(UiUtil.getActiveWindow(), "Solver is Running. Select an action to perform.", STOP_SOLVER, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + + if (option == JOptionPane.YES_OPTION) { + stopCase(); + return true; + } else if (option == JOptionPane.NO_OPTION) { + kill(); + return true; + } else { + return false; + } + } +} diff --git a/src/eu/engys/core/controller/ILogServer.java b/src/eu/engys/core/controller/ILogServer.java new file mode 100644 index 0000000..0f5708d --- /dev/null +++ b/src/eu/engys/core/controller/ILogServer.java @@ -0,0 +1,40 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.Serializable; + +public interface ILogServer extends Serializable { + + void start(String key); + + void pump(String key, String lines); + + void close(); + + void stop(String key); + +} diff --git a/src/eu/engys/core/controller/LogClient.java b/src/eu/engys/core/controller/LogClient.java new file mode 100644 index 0000000..97ea61f --- /dev/null +++ b/src/eu/engys/core/controller/LogClient.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.OutputStream; +import java.io.Serializable; + +public interface LogClient extends Serializable { + + void start(String key, OutputStream out, OutputStream err); + + void pump(String key, String lines); + + void close(); + + void stop(String key); + +} diff --git a/src/eu/engys/core/controller/ParsersManager.java b/src/eu/engys/core/controller/ParsersManager.java new file mode 100644 index 0000000..eaefad8 --- /dev/null +++ b/src/eu/engys/core/controller/ParsersManager.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.rmi.RemoteException; +import java.util.List; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; + +public interface ParsersManager { + + void startParsers() throws RemoteException; + + List updateParser(String functionObjectName) throws RemoteException; + + List updateParserOnce(String functionObjectName) throws RemoteException; + + void endParsers() throws RemoteException; + +} diff --git a/src/eu/engys/core/controller/QueueConnector.java b/src/eu/engys/core/controller/QueueConnector.java new file mode 100644 index 0000000..0ecf225 --- /dev/null +++ b/src/eu/engys/core/controller/QueueConnector.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.util.Map; + +public interface QueueConnector { + + String submit(Map env); + + void kill(); + +} diff --git a/src/eu/engys/core/controller/QueueInfo.java b/src/eu/engys/core/controller/QueueInfo.java new file mode 100644 index 0000000..c18d168 --- /dev/null +++ b/src/eu/engys/core/controller/QueueInfo.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.Serializable; +import java.util.List; + +import com.tupilabs.pbs.model.Job; +import com.tupilabs.pbs.model.Node; +import com.tupilabs.pbs.model.Queue; + +public class QueueInfo implements Serializable { + + public List nodes; + public List queues; + public List jobs; + +} diff --git a/src/eu/engys/core/controller/ScriptBuilder.java b/src/eu/engys/core/controller/ScriptBuilder.java new file mode 100644 index 0000000..4195303 --- /dev/null +++ b/src/eu/engys/core/controller/ScriptBuilder.java @@ -0,0 +1,65 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.util.LinkedList; +import java.util.List; + +public class ScriptBuilder { + + private List lines; + + public ScriptBuilder() { + lines = new LinkedList(); + } + + public void append(String s) { + lines.add(s); + } + + public void appendIf(boolean b, String s) { + if (b) { + lines.add(s); + } + } + + public void appendIf(boolean b, String s1, String s2) { + if (b) { + lines.add(s1); + } else { + lines.add(s2); + } + } + + public void newLine() { + lines.add(""); + } + + public List getLines() { + return lines; + } + +} diff --git a/src/eu/engys/core/controller/ScriptFactory.java b/src/eu/engys/core/controller/ScriptFactory.java new file mode 100644 index 0000000..511cf80 --- /dev/null +++ b/src/eu/engys/core/controller/ScriptFactory.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.controller; + +import java.io.File; +import java.util.List; + +import eu.engys.core.project.Model; + +public interface ScriptFactory { + + File getMeshScript(Model model); + List getDefaultMeshScript(Model model); + + File getCheckMeshScript(Model model); + List getDefaultCheckMeshScript(Model model); + + File getSolverScript(Model model); + List getDefaultSolverScript(Model model); + + File getInitialiseScript(Model model); + List getDefaultInitialiseScript(Model model); + + File getExtrudeScript(Model model); + List getDefaultExtrudeScript(Model model); + + void deleteMeshScripts(Model model); + + File getQueueDriver(Model model); + List getDefaultQueueDriver(Model model); + + File getQueueLauncher(Model model); + List getDefaultQueueLauncher(Model model); + + File getExportScript(Model model); + List getDefaultExportScript(Model model); + +} diff --git a/src/eu/engys/core/controller/Server.java b/src/eu/engys/core/controller/Server.java new file mode 100644 index 0000000..8dfbff2 --- /dev/null +++ b/src/eu/engys/core/controller/Server.java @@ -0,0 +1,69 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.List; + +import eu.engys.core.controller.actions.StopCommandInfo; +import eu.engys.core.project.state.ServerState; + +public interface Server extends Remote, ParsersManager { + + void heartBeat() throws RemoteException; + + CommandInfo executeCommand(ClientServerCommand command) throws RemoteException; + + StopCommandInfo stopCommand(Command command) throws RemoteException; + + CommandInfo killCommand(Command command) throws RemoteException; + + StateConnector getStateConnector() throws RemoteException; + + ILogServer getLogConnector() throws RemoteException; + + QueueConnector getQueueConnector() throws RemoteException; + + List getStates() throws RemoteException; + + ServerInfo start() throws Exception; + + void stop() throws RemoteException; + + void shutdown() throws RemoteException; + + String test() throws RemoteException; + + void disconnect() throws RemoteException; + + QueueInfo getQueueInfo() throws RemoteException; + + void goToBatch() throws RemoteException; + + void connect(ClientInfo clientInfo) throws RemoteException; + +} diff --git a/src/eu/engys/core/controller/ServerInfo.java b/src/eu/engys/core/controller/ServerInfo.java new file mode 100644 index 0000000..f5ffb23 --- /dev/null +++ b/src/eu/engys/core/controller/ServerInfo.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.util.Scanner; + +public class ServerInfo { + + public boolean success; + public String message; + public int port1; + public int port2; + public String date; + public String id; + + public void decodePorts(String payload) { + if (payload != null && !payload.isEmpty()) { + Scanner scanner = new Scanner(payload); + String date = scanner.hasNextLine() ? scanner.nextLine() : ""; + this.port1 = scanner.hasNextInt() ? scanner.nextInt() : 0; + this.port2 = scanner.hasNextInt() ? scanner.nextInt() : 0; + scanner.close(); + } + } + + @Override + public String toString() { + return "ServerInfo - ID: " + id + ", msg: " + message + ", port1: " + port1 + ", port2: " + port2 + ", succes: " + success + "date: " + date; + } +} diff --git a/src/eu/engys/core/controller/StateConnector.java b/src/eu/engys/core/controller/StateConnector.java new file mode 100644 index 0000000..59d1d29 --- /dev/null +++ b/src/eu/engys/core/controller/StateConnector.java @@ -0,0 +1,38 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import java.io.Serializable; + +import eu.engys.core.project.state.ServerState; + +public interface StateConnector extends Serializable { + + void offer(ServerState serverState); + ServerState take(); + ServerState peek(); + +} diff --git a/src/eu/engys/core/controller/StopOrKillCommandOS.java b/src/eu/engys/core/controller/StopOrKillCommandOS.java new file mode 100644 index 0000000..7110cdb --- /dev/null +++ b/src/eu/engys/core/controller/StopOrKillCommandOS.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import static eu.engys.core.controller.AbstractController.CANCEL; +import static eu.engys.core.controller.AbstractController.KILL_SOLVER; +import static eu.engys.core.controller.AbstractController.STOP_SOLVER; + +import javax.swing.JOptionPane; + +import eu.engys.core.controller.actions.TimeoutException; +import eu.engys.util.ui.UiUtil; + +public class StopOrKillCommandOS implements Runnable { + + private Controller controller; + + public StopOrKillCommandOS(Controller controller) { + this.controller = controller; + } + + @Override + public void run() { + Object[] options = new Object[] { STOP_SOLVER, KILL_SOLVER, CANCEL }; + int option = JOptionPane.showOptionDialog(UiUtil.getActiveWindow(), "Select an action to perform.", STOP_SOLVER, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + if (option == JOptionPane.YES_OPTION) { + try { + controller.stopCase(); + } catch (TimeoutException e) { + // should never pass here + } + } else if (option == JOptionPane.NO_OPTION) { + controller.kill(); + } + } +} diff --git a/src/eu/engys/core/controller/View3DOptions.java b/src/eu/engys/core/controller/View3DOptions.java new file mode 100644 index 0000000..f1e380a --- /dev/null +++ b/src/eu/engys/core/controller/View3DOptions.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JPanel; + +import eu.engys.util.filechooser.gui.Options; +import eu.engys.util.ui.builder.PanelBuilder; + +public class View3DOptions implements Options { + + private JCheckBox loadMesh = new JCheckBox("Display Mesh After Reading", true); + + @Override + public void onSelectionChanged() { + } + + @Override + public JPanel getPanel() { + PanelBuilder builder = new PanelBuilder(); + builder.addLeft(loadMesh); + builder.getPanel().setBorder(BorderFactory.createTitledBorder("Display Options")); + return builder.getPanel(); + } + + public boolean loadMesh() { + return loadMesh.isSelected(); + } + +} diff --git a/src/eu/engys/core/controller/actions/AbstractRunCommand.java b/src/eu/engys/core/controller/actions/AbstractRunCommand.java new file mode 100644 index 0000000..7f7e23f --- /dev/null +++ b/src/eu/engys/core/controller/actions/AbstractRunCommand.java @@ -0,0 +1,94 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import java.util.concurrent.ExecutorService; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.Server; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorTerminal; +import eu.engys.core.project.Model; + +public abstract class AbstractRunCommand implements RunCommand { + + protected Model model; + protected Executor executor; + protected Controller controller; + protected ExecutorService service; + protected ExecutorTerminal terminal; + + public AbstractRunCommand(Model model, Controller controller) { + this.model = model; + this.controller = controller; + } + + @Override + public void inService(ExecutorService service) { + this.service = service; + } + + @Override + public void inTerminal(ExecutorTerminal terminal) { + this.terminal = terminal; + } + + @Override + public boolean isRunning() { + return executor != null && executor.getState().isDoingSomething(); + } + + @Override + public void kill() { + executor.getService().shutdownNow(); + } + + @Override + public void beforeExecute() { + } + + @Override + public void stop() throws TimeoutException { + } + + @Override + public void executeClient() { + } + + @Override + public void executeServer(Server server) throws CommandException { + } + + @Override + public String executeQueue(Server server) throws CommandException { + return null; + } + + @Override + public void executeBatch() { + } + +} diff --git a/src/eu/engys/core/controller/actions/CheckMesh.java b/src/eu/engys/core/controller/actions/CheckMesh.java new file mode 100644 index 0000000..c844f55 --- /dev/null +++ b/src/eu/engys/core/controller/actions/CheckMesh.java @@ -0,0 +1,88 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; +import static eu.engys.core.project.openFOAMProject.LOG; + +import java.io.File; +import java.nio.file.Paths; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.Controller.OpenOptions; +import eu.engys.core.controller.ScriptFactory; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorHook; +import eu.engys.core.executor.ExecutorListener.ExecutorState; +import eu.engys.core.executor.ExecutorMonitor; +import eu.engys.core.executor.ExecutorTerminal; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.util.IOUtils; + +public class CheckMesh extends AbstractRunCommand { + + public static final String ACTION_NAME = "Check Mesh"; + public static final String LOG_NAME = "checkMesh.log"; + + private File logFile; + private ScriptFactory scriptFactory; + + public CheckMesh(Model model, Controller controller, ScriptFactory scriptFactory) { + super(model, controller); + this.scriptFactory = scriptFactory; + this.logFile = Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, LOG_NAME).toFile(); + } + + @Override + public void beforeExecute() { + IOUtils.clearFile(logFile); + if (controller.getListener() != null) { + controller.getListener().beforeCheckMesh(); + } + } + + @Override + public void executeClient() { + ExecutorTerminal terminal = new TerminalExecutorMonitor(logFile); + ExecutorMonitor monitor = new ExecutorMonitor(); + monitor.addHook(ExecutorState.FINISH, new FinishHook()); + + this.executor = Executor.script(scriptFactory.getCheckMeshScript(model)).description(ACTION_NAME).inFolder(model.getProject().getBaseDir()).inTerminal(terminal).withMonitors(monitor).env(getEnvironment(model, LOG_NAME)).keepFileOnEnd(); + executor.exec(); + } + + private class FinishHook implements ExecutorHook { + + @Override + public void run(ExecutorMonitor monitor) { + if (controller.getListener() != null) { + controller.reopenCase(OpenOptions.MESH_ONLY); + controller.getListener().afterCheckMesh(); + } + } + } +} diff --git a/src/eu/engys/core/controller/actions/CommandException.java b/src/eu/engys/core/controller/actions/CommandException.java new file mode 100644 index 0000000..707ea9b --- /dev/null +++ b/src/eu/engys/core/controller/actions/CommandException.java @@ -0,0 +1,34 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +public class CommandException extends Exception { + + public CommandException(String message) { + super(message); + } + +} diff --git a/src/eu/engys/core/controller/actions/DeleteMesh.java b/src/eu/engys/core/controller/actions/DeleteMesh.java new file mode 100644 index 0000000..e2b0c31 --- /dev/null +++ b/src/eu/engys/core/controller/actions/DeleteMesh.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; + +public class DeleteMesh extends AbstractRunCommand { + + public DeleteMesh(Model model, Controller controller) { + super(model, controller); + } + + @Override + public void executeClient() { + model.getProject().getZeroFolder().deleteMesh(); + } + +} diff --git a/src/eu/engys/core/controller/actions/InitialiseFields.java b/src/eu/engys/core/controller/actions/InitialiseFields.java new file mode 100644 index 0000000..94f32cf --- /dev/null +++ b/src/eu/engys/core/controller/actions/InitialiseFields.java @@ -0,0 +1,69 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import static eu.engys.core.project.openFOAMProject.LOG; + +import java.io.File; +import java.nio.file.Paths; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.ScriptFactory; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.zero.ZeroFileManager; +import eu.engys.util.IOUtils; + +public class InitialiseFields extends AbstractRunCommand { + + public static final String ACTION_NAME = "Initialise Fields"; + public static final String LOG_NAME = "initialise.log"; + + protected ScriptFactory scriptFactory; + + public InitialiseFields(Model model, Controller controller, ScriptFactory scriptFactory) { + super(model, controller); + this.scriptFactory = scriptFactory; + } + + @Override + public void beforeExecute() { + IOUtils.clearFile(Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, LOG_NAME).toFile()); + clearLogFolder(); + clearPolyMesh(); + } + + private void clearLogFolder() { + File log = new File(model.getProject().getBaseDir(), openFOAMProject.LOG); + if (!log.exists()) + log.mkdir(); + } + + private void clearPolyMesh() { + ((ZeroFileManager) model.getProject().getZeroFolder().getFileManager()).removeNonZeroDirs("0"); + } + +} diff --git a/src/eu/engys/core/controller/actions/NamingConvention.java b/src/eu/engys/core/controller/actions/NamingConvention.java new file mode 100644 index 0000000..baf8d0d --- /dev/null +++ b/src/eu/engys/core/controller/actions/NamingConvention.java @@ -0,0 +1,35 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import eu.engys.core.project.geometry.Surface; + +public interface NamingConvention { + + String getPatchName(Surface surface); + + String getCellZoneName(Surface surface); +} diff --git a/src/eu/engys/core/controller/actions/RunCase.java b/src/eu/engys/core/controller/actions/RunCase.java new file mode 100644 index 0000000..05bbd68 --- /dev/null +++ b/src/eu/engys/core/controller/actions/RunCase.java @@ -0,0 +1,134 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import static eu.engys.core.project.system.ControlDict.CONTROL_DICT; +import static eu.engys.core.project.system.ControlDict.END_TIME_KEY; +import static eu.engys.core.project.system.ControlDict.STOP_AT_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_NOW_KEY; + +import java.io.File; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.Command; +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.ScriptFactory; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.executor.ExecutorHook; +import eu.engys.core.executor.ExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.core.project.SolverState; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.state.ServerState; +import eu.engys.core.project.system.ControlDict; +import eu.engys.util.PrefUtil; + +public class RunCase extends AbstractRunCommand { + + private static final Logger logger = LoggerFactory.getLogger(RunCase.class); + + public static final String ACTION_NAME = "Run Case"; + public static final String RUNNING_LABEL = "Running: "; + + protected final ScriptFactory scriptFactory; + + public RunCase(Model model, Controller controller, ScriptFactory scriptFactory) { + super(model, controller); + this.scriptFactory = scriptFactory; + } + + @Override + public void beforeExecute() { + setupLogFolder(); + setupPostProcFolder(); + clearPolyMesh(); + setStopAtVariableToEndTime(); + } + + private void setupLogFolder() { + File log = new File(model.getProject().getBaseDir(), openFOAMProject.LOG); + if (!log.exists()) + log.mkdir(); + } + + private void setupPostProcFolder() { + File log = new File(model.getProject().getBaseDir(), openFOAMProject.POST_PROC); + if (!log.exists()) + log.mkdir(); + } + + private void clearPolyMesh() { + model.getProject().getZeroFolder().removeNonZeroTimeFolders_GreaterThanActualTimeStep(); + } + + @Override + public void stop() throws TimeoutException { + int stop_refresh_time = PrefUtil.getInt(PrefUtil.SERVER_CONNECTION_REFRESH_TIME, 1000); + int stop_max_tries = PrefUtil.getInt(PrefUtil.SERVER_CONNECTION_MAX_TRIES, 60); + + int tryIndex = 0; + while (this.executor.getState().isDoingSomething() && (tryIndex < stop_max_tries)) { + try { + Thread.sleep(stop_refresh_time); + } catch (Exception e) { + } + setStopAtVariableToWriteNow(); + tryIndex++; + } + if (tryIndex >= stop_max_tries) { + throw new TimeoutException("Timeout stopping solver"); + } + setStopAtVariableToEndTime(); + } + + private void setStopAtVariableToWriteNow() { + File systemFolder = model.getProject().getSystemFolder().getFileManager().getFile(); + ControlDict controlDict = new ControlDict(new File(systemFolder, CONTROL_DICT)); + controlDict.add(STOP_AT_KEY, WRITE_NOW_KEY); + controlDict.functionObjectsToList(); + DictionaryUtils.writeDictionary(systemFolder, controlDict, null); + } + + private void setStopAtVariableToEndTime() { + File systemFolder = model.getProject().getSystemFolder().getFileManager().getFile(); + ControlDict controlDict = new ControlDict(new File(systemFolder, CONTROL_DICT)); + if (controlDict.found(STOP_AT_KEY) && controlDict.lookup(STOP_AT_KEY).equals(WRITE_NOW_KEY)) { + controlDict.add(STOP_AT_KEY, END_TIME_KEY); + controlDict.functionObjectsToList(); + DictionaryUtils.writeDictionary(systemFolder, controlDict, null); + } + } + + protected class StartHook implements ExecutorHook { + @Override + public void run(ExecutorMonitor m) { + model.getSolverModel().writeState(new ServerState(Command.RUN_CASE, SolverState.RUNNING), model); + } + } + +} diff --git a/src/eu/engys/core/controller/actions/RunCommand.java b/src/eu/engys/core/controller/actions/RunCommand.java new file mode 100644 index 0000000..7e45ed2 --- /dev/null +++ b/src/eu/engys/core/controller/actions/RunCommand.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import java.util.concurrent.ExecutorService; + +import eu.engys.core.controller.Server; +import eu.engys.core.executor.ExecutorTerminal; + +public interface RunCommand { + + public void beforeExecute(); + + public void executeClient(); + + public void executeBatch(); + + public void executeServer(Server server) throws CommandException; + + public String executeQueue(Server server) throws CommandException; + + public void stop() throws TimeoutException; + + public void kill(); + + public void inService(ExecutorService service); + + public void inTerminal(ExecutorTerminal terminal); + + public boolean isRunning(); + +} diff --git a/src/eu/engys/core/controller/actions/RunMesh.java b/src/eu/engys/core/controller/actions/RunMesh.java new file mode 100644 index 0000000..cbfebd9 --- /dev/null +++ b/src/eu/engys/core/controller/actions/RunMesh.java @@ -0,0 +1,74 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import static eu.engys.core.project.openFOAMProject.LOG; + +import java.io.File; +import java.nio.file.Paths; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.ScriptFactory; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.util.IOUtils; + +public class RunMesh extends AbstractRunCommand { + + public static final String ACTION_NAME = "Create Mesh"; + public static final String LOG_NAME = "snappyHexMesh.log"; + + protected final ScriptFactory scriptFactory; + + public RunMesh(Model model, Controller controller, ScriptFactory scriptFactory) { + super(model, controller); + this.scriptFactory = scriptFactory; + } + + @Override + public void beforeExecute() { + IOUtils.clearFile(Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, LOG_NAME).toFile()); + clearPolyMesh(); + setupLogFolder(); + fixDecomposeParDict(model); + } + + private void fixDecomposeParDict(Model model) { + model.getProject().getSystemFolder().getDecomposeParDict().toHierarchical(model); + } + + private void clearPolyMesh() { + model.getProject().getZeroFolder().deleteMesh(); + } + + private void setupLogFolder() { + File log = new File(model.getProject().getBaseDir(), openFOAMProject.LOG); + if (!log.exists()) { + log.mkdir(); + } + } + +} diff --git a/src/eu/engys/core/controller/actions/StandardInitialiseFields.java b/src/eu/engys/core/controller/actions/StandardInitialiseFields.java new file mode 100644 index 0000000..0cb18c8 --- /dev/null +++ b/src/eu/engys/core/controller/actions/StandardInitialiseFields.java @@ -0,0 +1,80 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; + +import java.io.File; +import java.nio.file.Paths; +import java.util.concurrent.ExecutorService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.Controller.OpenOptions; +import eu.engys.core.controller.ScriptFactory; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorHook; +import eu.engys.core.executor.ExecutorListener.ExecutorState; +import eu.engys.core.executor.ExecutorMonitor; +import eu.engys.core.executor.ExecutorTerminal; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; + +public class StandardInitialiseFields extends InitialiseFields { + + private static final Logger logger = LoggerFactory.getLogger(StandardInitialiseFields.class); + + public StandardInitialiseFields(Model model, Controller controller, ScriptFactory scriptFactory) { + super(model, controller, scriptFactory); + } + + @Override + public void executeClient() { + logger.debug("EXECUTE IN CLIENT"); + File script = scriptFactory.getInitialiseScript(model); + File baseDir = model.getProject().getBaseDir(); + File logFile = Paths.get(baseDir.getAbsolutePath(), openFOAMProject.LOG, LOG_NAME).toFile(); + + ExecutorTerminal terminal = new TerminalExecutorMonitor(logFile); + ExecutorMonitor monitor = new ExecutorMonitor(); + ExecutorService service = Executor.newExecutor(ACTION_NAME); + monitor.addHook(ExecutorState.FINISH, new FinishHook()); + + this.executor = Executor.script(script).description(ACTION_NAME).inFolder(baseDir).inTerminal(terminal).withMonitors(monitor).inService(service).env(getEnvironment(model, LOG_NAME)).keepFileOnEnd(); + executor.exec(); + } + + private class FinishHook implements ExecutorHook { + @Override + public void run(ExecutorMonitor m) { + controller.reopenCase(OpenOptions.CURRENT_SETTINGS); + } + } + +} diff --git a/src/eu/engys/core/controller/actions/StandardRunCase.java b/src/eu/engys/core/controller/actions/StandardRunCase.java new file mode 100644 index 0000000..fb18cca --- /dev/null +++ b/src/eu/engys/core/controller/actions/StandardRunCase.java @@ -0,0 +1,108 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; + +import java.io.File; +import java.nio.file.Paths; +import java.util.concurrent.ExecutorService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.Command; +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.ScriptFactory; +import eu.engys.core.controller.StopOrKillCommandOS; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorHook; +import eu.engys.core.executor.ExecutorListener.ExecutorState; +import eu.engys.core.executor.ExecutorMonitor; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.core.project.SolverState; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.state.ServerState; + +public class StandardRunCase extends RunCase { + + private static final Logger logger = LoggerFactory.getLogger(StandardRunCase.class); + + public StandardRunCase(Model model, Controller controller, ScriptFactory scriptFactory) { + super(model, controller, scriptFactory); + } + + @Override + public void executeClient() { + logger.debug("EXECUTE IN CLIENT"); + File logFile = Paths.get(model.getProject().getBaseDir().getAbsolutePath(), openFOAMProject.LOG, model.getSolverModel().getLogFile()).toFile(); + TerminalExecutorMonitor terminal = new TerminalExecutorMonitor(logFile); + terminal.setStopCommand(new StopOrKillCommandOS(controller)); + + ExecutorMonitor monitor = new ExecutorMonitor(); + monitor.addHook(ExecutorState.START, new StartHook()); + monitor.addHook(ExecutorState.RUNNING, new RunningHook()); + monitor.addHook(ExecutorState.FINISH, new FinishHook()); + monitor.addHook(ExecutorState.ERROR, new ErrorHook()); + + ExecutorService service = Executor.newExecutor(ACTION_NAME); + + File baseDir = model.getProject().getBaseDir(); + + this.executor = Executor.script(scriptFactory.getSolverScript(model)).description(ACTION_NAME).inFolder(baseDir).inTerminal(terminal).withMonitors(monitor).inService(service).env(getEnvironment(model, model.getSolverModel().getLogFile())).keepFileOnEnd(); + executor.exec(); + } + + private class StartHook implements ExecutorHook { + @Override + public void run(ExecutorMonitor m) { + model.getSolverModel().setServerState(new ServerState(Command.RUN_CASE, SolverState.STARTED)); + } + } + + private class RunningHook implements ExecutorHook { + @Override + public void run(ExecutorMonitor m) { + model.getSolverModel().setServerState(new ServerState(Command.RUN_CASE, SolverState.RUNNING)); + } + } + + protected class FinishHook implements ExecutorHook { + @Override + public void run(ExecutorMonitor m) { + model.getSolverModel().setServerState(new ServerState(Command.RUN_CASE, SolverState.FINISHED)); + } + } + + protected class ErrorHook implements ExecutorHook { + @Override + public void run(ExecutorMonitor m) { + model.getSolverModel().setServerState(new ServerState(Command.RUN_CASE, SolverState.ERROR)); + } + } + +} diff --git a/src/eu/engys/core/controller/actions/StandardRunMesh.java b/src/eu/engys/core/controller/actions/StandardRunMesh.java new file mode 100644 index 0000000..498ce38 --- /dev/null +++ b/src/eu/engys/core/controller/actions/StandardRunMesh.java @@ -0,0 +1,77 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; + +import java.io.File; +import java.nio.file.Paths; +import java.util.concurrent.ExecutorService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.ScriptFactory; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorHook; +import eu.engys.core.executor.ExecutorListener.ExecutorState; +import eu.engys.core.executor.ExecutorMonitor; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; + +public class StandardRunMesh extends RunMesh { + + private static final Logger logger = LoggerFactory.getLogger(StandardRunMesh.class); + + public StandardRunMesh(Model model, Controller controller, ScriptFactory scriptFactory) { + super(model, controller, scriptFactory); + } + + @Override + public void executeClient() { + logger.debug("EXECUTE IN CLIENT"); + File baseDir = model.getProject().getBaseDir(); + File logFile = Paths.get(baseDir.getAbsolutePath(), openFOAMProject.LOG, LOG_NAME).toFile(); + + ExecutorMonitor monitor = new ExecutorMonitor(); + monitor.addHook(ExecutorState.FINISH, new FinishHook()); + + ExecutorService service = Executor.newExecutor(ACTION_NAME); + + this.executor = Executor.script(scriptFactory.getMeshScript(model)).description(ACTION_NAME).inFolder(baseDir).inService(service).inTerminal(new TerminalExecutorMonitor(logFile)).withMonitors(monitor).env(getEnvironment(model, LOG_NAME)).keepFileOnEnd(); + executor.exec(); + } + + private class FinishHook implements ExecutorHook { + @Override + public void run(ExecutorMonitor m) { + controller.setupCase(); + } + } + +} diff --git a/src/eu/engys/core/controller/actions/StopCommandInfo.java b/src/eu/engys/core/controller/actions/StopCommandInfo.java new file mode 100644 index 0000000..76a1664 --- /dev/null +++ b/src/eu/engys/core/controller/actions/StopCommandInfo.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.CommandInfo; + +public class StopCommandInfo extends CommandInfo { + + private static final Logger logger = LoggerFactory.getLogger(StopCommandInfo.class); + + public boolean timeout; + + public static StopCommandInfo wrap(CommandInfo info) { + StopCommandInfo ci = new StopCommandInfo(); + ci.message = info.message; + ci.exception = info.exception; + ci.success = info.success; + ci.timeout = false; + return ci; + } + + public static StopCommandInfo timeoutException(Exception e) { + logger.error(">>> SERVER STOP ERROR", e); + StopCommandInfo ci = new StopCommandInfo(); + ci.message = "Timeout"; + ci.exception = e; + ci.success = false; + ci.timeout = true; + return ci; + } + + @Override + public String toString() { + return "Stop Command [success: " + success + "] - [timeout: " + timeout + "] - [message: " + message + "] - [exception: " + exception.getMessage() + "]"; + } + +} diff --git a/src/eu/engys/core/controller/actions/TimeoutException.java b/src/eu/engys/core/controller/actions/TimeoutException.java new file mode 100644 index 0000000..66a8ae3 --- /dev/null +++ b/src/eu/engys/core/controller/actions/TimeoutException.java @@ -0,0 +1,34 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.controller.actions; + +public class TimeoutException extends Exception { + + public TimeoutException(String message) { + super(message); + } + +} diff --git a/src/eu/engys/core/dictionary/BeanToDict.java b/src/eu/engys/core/dictionary/BeanToDict.java new file mode 100644 index 0000000..c27988a --- /dev/null +++ b/src/eu/engys/core/dictionary/BeanToDict.java @@ -0,0 +1,274 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary; + +import java.io.File; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BeanToDict { + + private static final Logger logger = LoggerFactory.getLogger(BeanToDict.class); + + public static B dictToBean(Dictionary dictionary, Class klass) { + try { + B bean = klass.newInstance(); + + dictToBean(dictionary, bean); + + return bean; + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + @SuppressWarnings("unchecked") + public static void dictToBean(Dictionary dictionary, B bean) { + Method[] methods = bean.getClass().getMethods(); + for (Method m : methods) { + if (m.getName().startsWith("set")) { + String fieldName = getFieldNameFromSetter(m); + if (dictionary.found(fieldName)) { + if (dictionary.isField(fieldName)) { + String value = dictionary.lookup(fieldName); + Class param = m.getParameterTypes()[0]; + if (param.equals(double.class)) { + setValue(bean, m, Double.valueOf(value)); + } else if (param.equals(long.class)) { + setValue(bean, m, Long.valueOf(value)); + } else if (param.equals(int.class)) { + setValue(bean, m, Integer.valueOf(value)); + } else if (param.equals(boolean.class)) { + setValue(bean, m, Boolean.valueOf(value)); + } else if (param.equals(String.class)) { + setValue(bean, m, value); + } else if (param.isEnum()) { + try { + setValue(bean, m, Enum.valueOf((Class) param, value)); + } catch (Exception e) { + setValue(bean, m, ((Class) param).getEnumConstants()[0]); + } + } else { + System.err.println("ERROR: " + param); + logger.error(""); + } + } else if (dictionary.isDictionary(fieldName)) { + Class class1 = m.getParameterTypes()[0]; + Object bean1 = dictToBean(dictionary.subDict(fieldName), class1); + setValue(bean, m, bean1); + } + + } + } + } + } + + private static void setValue(B bean, Method m, Object value) { + try { + m.invoke(bean, value); + } catch (Exception e) { + logger.error("ERROR: double parameter", e); + } + } + + // public static void dictToBean(Dictionary dictionary, Object bean) { + // Method[] methods = bean.getClass().getMethods(); + // try { + // for (Method m : methods) { + // if (m.getName().startsWith("set")) { + // String fieldName = getFieldNameFromSetter(m); + // if (dictionary.isField(fieldName)) { + // String value = dictionary.lookup(fieldName); + // m.invoke(bean, Double.valueOf(value)); + // } + // } + // } + // } catch(Exception ex) { + // ex.printStackTrace(); + // } + // } + + public static Dictionary beanToDict(Object obj) { + return beanToDict(null, obj); + } + + public static Dictionary beanToDict(String name, Object obj) { + Class klass = obj.getClass(); + Method[] methods = klass.getMethods(); + Dictionary dictionary = new Dictionary(name != null ? name : getFieldNameFromClass(klass)); + // dictionary.add("class", obj.getClass().getName()); + + for (Method m : methods) { + String fieldName = ""; + if (m.getName().startsWith("get") && !m.getName().startsWith("getClass")) { + fieldName = getFieldNameFromGetter(m); + } else if (m.getName().startsWith("is")) { + fieldName = getFieldNameFromBooleanGetter(m); + } else { + continue; + } + try { + Object value = m.invoke(obj); + if (value != null) { + addToDictionary(dictionary, fieldName, value); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + return dictionary; + } + + private static void addToDictionary(Dictionary dictionary, String fieldName, Object value) throws Exception { + if (isSimple(value.getClass())) { + dictionary.add(fieldName, value.toString()); + } else if (isList(value)) { + dictionary.add(toList(fieldName, value)); + } else if (isArray(value)) { + dictionary.add(fieldName, toArray(value)); + } else if (isMap(value)) { + dictionary.add(mapToDict(fieldName, value)); + } else if (isFile(value)) { + dictionary.add(fieldName, ((File) value).getAbsolutePath()); + } else if (isDictionary(value)) { + Dictionary d = new Dictionary((Dictionary) value); + d.setName(fieldName); + dictionary.add(d); + } else { + dictionary.add(beanToDict(fieldName, value)); + } + } + + private static boolean isSimple(Class klass) { + boolean isString = String.class.isAssignableFrom(klass); + boolean isNumber = Number.class.isAssignableFrom(klass); + boolean isBoolean = Boolean.class.isAssignableFrom(klass); + boolean isEnum = Enum.class.isAssignableFrom(klass); + boolean isPrimitive = klass.isPrimitive(); + return isString || isNumber || isBoolean || isEnum || isPrimitive; + } + + private static boolean isList(Object value) { + return List.class.isAssignableFrom(value.getClass()) || (value.getClass().isArray() && !isSimple(value.getClass().getComponentType())); + } + + private static boolean isMap(Object value) { + return Map.class.isAssignableFrom(value.getClass()); + } + + private static boolean isFile(Object value) { + return File.class.isAssignableFrom(value.getClass()); + } + + private static boolean isDictionary(Object value) { + return Dictionary.class.isAssignableFrom(value.getClass()); + } + + private static boolean isArray(Object value) { + return value.getClass().isArray(); + } + + private static ListField toList(String name, Object value) throws Exception { + ListField listField = new ListField(name); + List list = null; + if (value.getClass().isArray()) { + list = Arrays.asList((Object[]) value); + } else { + list = (List) value; + } + for (Object obj : list) { + listField.add(beanToDict(obj)); + } + return listField; + } + + public static Dictionary mapToDict(String name, Object value) { + Map map = (Map) value; + Dictionary dict = new Dictionary(name); + try { + for (Object key : map.keySet()) { + addToDictionary(dict, key.toString(), map.get(key)); + } + } catch (Exception ex) { + + } + return dict; + } + + private static String toArray(Object array) throws Exception { + return toBracketedArrayOfStrings(array); + } + + private static String toBracketedArrayOfStrings(Object array) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (int i = 0; i < Array.getLength(array); i++) { + sb.append(" "); + sb.append(Array.get(array, i).toString()); + } + sb.append(")"); + + return sb.toString(); + } + + private static String getFieldNameFromGetter(Method m) { + String name = m.getName().substring(3); + return name.substring(0, 1).toLowerCase() + name.substring(1); + } + + private static String getFieldNameFromBooleanGetter(Method m) { + String name = m.getName().substring(2); + return name.substring(0, 1).toLowerCase() + name.substring(1); + } + + private static String getFieldNameFromSetter(Method m) { + String name = m.getName().substring(3); + return name.substring(0, 1).toLowerCase() + name.substring(1); + } + + static private String getFieldNameFromClass(Class klass) { + String name = klass.getSimpleName(); + return name.substring(0, 1).toLowerCase() + name.substring(1); + } + + // private Method getSetterFromFieldName(String name, Class klass) throws Exception { + // String methodName = name.substring(0,1).toUpperCase()+name.substring(1); + // methodName = "set"+methodName; + // return klass.getMethod(methodName); + // } + // + // private static Class getClassFromFieldName(String name) throws ClassNotFoundException{ + // String className = name.substring(0,1).toUpperCase()+name.substring(1); + // return Class.forName(className); + // } +} diff --git a/src/eu/engys/core/dictionary/BlockMeshWriter.java b/src/eu/engys/core/dictionary/BlockMeshWriter.java new file mode 100644 index 0000000..6670671 --- /dev/null +++ b/src/eu/engys/core/dictionary/BlockMeshWriter.java @@ -0,0 +1,120 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import static eu.engys.core.dictionary.Dictionary.SPACER; +import static eu.engys.core.dictionary.Dictionary.TAB; +import static eu.engys.core.dictionary.Dictionary.VERBOSE; +import eu.engys.core.dictionary.parser.ListField2; + +public class BlockMeshWriter extends DictionaryWriter { + + + public BlockMeshWriter(Dictionary dictionary) { + super(dictionary); + } + + public String write() { + StringBuffer sb = new StringBuffer(); + writeDictionary(sb, ""); + return sb.toString(); + } + + public void writeDictionary(StringBuffer sb, String rowHeader) { + if (dictionary.getFoamFile() != null) { + sb.append(FoamFile.HEADER); + BlockMeshWriter writer = new BlockMeshWriter(dictionary.getFoamFile()); + writer.writeDictionary(sb, ""); + +// if (dictionary.isList("")) { +// ListField.class.cast(dictionary.getList()).writeListDict(sb, rowHeader); +// return; +// } + } else { + sb.append("\n"); + sb.append(rowHeader); + sb.append(dictionary.getName()); + sb.append("\n"); + sb.append(rowHeader); + sb.append(START); + } + for (String key : dictionary.getKeys()) { + DefaultElement ele = dictionary.getElement(key); + write(sb, rowHeader, ele); + } + + for (String includeFile : dictionary.getIncludeFiles()) { + writeInclude(sb, includeFile, rowHeader); + } + + if (dictionary.getFoamFile() == null) + sb.append("\n" + rowHeader + END); + } + + private void write(StringBuffer sb, String rowHeader, DefaultElement ele) { + if (ele instanceof Dictionary) { + BlockMeshWriter writer = new BlockMeshWriter((Dictionary) ele); + writer.writeDictionary(sb, rowHeader + TAB); + } else if (ele instanceof DimensionedScalar) { + writeDimensionedScalar(sb, (DimensionedScalar) ele, rowHeader); + } else if (ele instanceof ListField2) { + ListField2.class.cast(ele).writeListField(sb, rowHeader); + } else if (ele instanceof ListField) { + ListField.class.cast(ele).writeListField(sb, rowHeader); + } else { + super.writeField(sb, (FieldElement) ele, rowHeader); + } + } + + @Override + protected void writeInclude(StringBuffer sb, String includeFile, String rowHeader) { + if (VERBOSE) + System.out.println("Dictionary.writeInclude() " + includeFile); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append("#include"); + sb.append(SPACER); + sb.append(includeFile); + } + + private static void writeDimensionedScalar(StringBuffer sb, DimensionedScalar ds, String rowHeader) { + if (VERBOSE) + System.out.println("Dictionary.writeDimensionedScalar() " + (ds != null ? ds.getName() : "NULL!!!")); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(ds.getName()); + sb.append(SPACER); + sb.append(ds.getName()); + sb.append(SPACER); + sb.append(ds.getDimensions()); + sb.append(SPACER); + sb.append(ds.getValue()); + sb.append(";"); + } +} diff --git a/src/eu/engys/core/dictionary/DefaultElement.java b/src/eu/engys/core/dictionary/DefaultElement.java new file mode 100644 index 0000000..0fb3d97 --- /dev/null +++ b/src/eu/engys/core/dictionary/DefaultElement.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +public class DefaultElement { + + private String name; + + public DefaultElement(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DefaultElement) { + return ((DefaultElement) obj).name.equals(name); + } + return super.equals(obj); + } +} diff --git a/src/eu/engys/core/dictionary/Dictionary.java b/src/eu/engys/core/dictionary/Dictionary.java new file mode 100644 index 0000000..3511d55 --- /dev/null +++ b/src/eu/engys/core/dictionary/Dictionary.java @@ -0,0 +1,807 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.ArrayUtils; + +import eu.engys.core.dictionary.parser.ListField2; +import eu.engys.core.dictionary.parser.ThetaListField2; + +public class Dictionary extends DefaultElement { + + public static boolean VERBOSE = false; + + public static final String SPACER = " "; + public static final String TAB = " "; + + public static final String DICTIONARY_LINK = "DICTIONARY_LINK"; + public static final String VALUE_LINK = "VALUE_LINK"; + public static final String VALUE_UNIFORM_LINK = "VALUE_UNIFORM_LINK"; + + public static final String TYPE = "type"; + public static final String VALUE = "value"; + + private FoamFile foamFile; + + private Map elements = new LinkedHashMap(); + private List keys = new ArrayList(); + private List genericKeys = new ArrayList(); + private List includeFiles = new ArrayList(); + + public Dictionary(String name, File file) { + super(name); + readDictionary(file); + } + + public Dictionary(File file) { + this(file.getName(), file); + } + + + public Dictionary(String name, InputStream input, DictionaryLinkResolver resolver) { + super(name); + readDictionary(input, resolver); + } + + public Dictionary(String name, InputStream input) { + super(name); + readDictionary(input); + } + + public Dictionary(String name) { + super(name); + } + + public Dictionary(Dictionary d) { + this(d.getName(), d); + } + + public Dictionary(String name, Dictionary d) { + super(name); + setFoamFile(d.getFoamFile()); + for (String key : d.keys) { + DefaultElement el = d.elements.get(key); + if (el instanceof Dictionary) { + add(new Dictionary((Dictionary) el)); + } else if (el instanceof DimensionedScalar) { + DimensionedScalar ds = (DimensionedScalar) el; + add(new DimensionedScalar(ds)); + } else if (el instanceof FieldElement) { + FieldElement f = (FieldElement) el; + add(f.getName(), f.getValue()); + } else if (el instanceof ListField) { + ListField lf = (ListField) el; + add(lf.getName(), new ListField(lf)); + } else if (el instanceof ThetaListField2) { + ThetaListField2 tf = (ThetaListField2) el; + add(tf.getName(), new ThetaListField2(tf)); + } else if (el instanceof ListField2) { + ListField2 lf = (ListField2) el; + add(lf.getName(), new ListField2(lf)); + } + } + genericKeys.addAll(d.genericKeys); + } + + public void setFoamFile(FoamFile file) { + if (found("FoamFile")) + remove("FoamFile"); + this.foamFile = file; + } + + public FoamFile getFoamFile() { + return foamFile; + } + + public void check() throws DictionaryException { + } + + public void include(String includeFile) { + includeFiles.add(includeFile); + } + + private void put(String key, DefaultElement value) { + elements.put(key, value); + if (!keys.contains(key)) + keys.add(key); + } + + public void add(DefaultElement el) { + put(el.getName(), el); + } + + public void addGeneric(DefaultElement el) { + String name = el.getName(); + if (!genericKeys.contains(name)) { + genericKeys.add(name); + } + put(name, el); + } + + public void add(Dictionary dictionary) { + put(dictionary.getName(), dictionary); + } + + public void addToList(Dictionary dictionary) { + addToList("", dictionary); + } + + public void addToList(String listName, Dictionary dictionary) { + ListField list = getList(listName); + if (list == null) { + list = new ListField(listName); + add(list); + } + list.add(dictionary); + } + + public void addToList(String listName, FieldElement fe) { + ListField list = getList(listName); + if (list == null) { + list = new ListField(listName); + add(list); + } + list.add(fe); + } + + public void add(String name, String value) { + put(name, new FieldElement(name, value)); + } + +// public void add(Finder finder, String value) { +// String key = findKey(finder); +// put(key, new FieldElement(key, value)); +// } + + public void addGeneric(String name, String value) { + if (!genericKeys.contains(name)) { + genericKeys.add(name); + } + put(name, new FieldElement(name, value)); + } + + public void add(String name, double[] values) { + StringBuffer sb = new StringBuffer("("); + for (double d : values) { + sb.append(String.valueOf(d) + " "); + } + sb.append(")"); + this.add(name, sb.toString()); + } + + public void add(String name, int[] values) { + StringBuffer sb = new StringBuffer("("); + for (int d : values) { + sb.append(String.valueOf(d) + " "); + } + sb.append(")"); + this.add(name, sb.toString()); + } + + public void add(String name, String[] values) { + StringBuffer sb = new StringBuffer("("); + for (String p : values) { + sb.append(p + " "); + } + sb.append(")"); + this.add(name, sb.toString()); + } + + public void add(String name, List values) { + this.add(name, values.toArray(new String[0])); + } + + public void add(DimensionedScalar ds) { + put(ds.getName(), ds); + } + + public void add(String name, ListField list) { + put(name, list); + } + + public void add(String name, ListField2 list) { + put(name, list); + } + + public void add(ListField list) { + put(list.getName(), list); + } + + private String findKey(Finder finder) { + for (String key : keys) { + if (finder.accept(key)) { + return key; + } + } + return null; + } + + public boolean found(Finder finder) { + String key = findKey(finder); + return key != null; + } + + public boolean found(String name) { + if (foundGeneric(name)) + return true; + else + return keys.contains(name); + } + + private boolean foundGeneric(String name) { + if (!genericKeys.isEmpty()) { + for (String genericKey : genericKeys) { + if (("\"" + name + "\"").matches(genericKey)) { + return true; + } + } + } + return false; + } + + DefaultElement getElement(String name) { + if (elements.containsKey(name)) + return elements.get(name); + + if (!genericKeys.isEmpty()) { + for (String genericKey : genericKeys) { + if (("\"" + name + "\"").matches(genericKey)) { + return elements.get(genericKey); + } + } + } + return null; + } + + public boolean isDictionary(String name) { + DefaultElement el = getElement(name); + return (el != null && el instanceof Dictionary); + } + + public boolean isField(String name) { + DefaultElement el = getElement(name); + return (el != null && el instanceof FieldElement); + } + + public boolean isList(String name) { + DefaultElement el = getElement(name); + return (el != null && el instanceof ListField); + } + + public boolean isList2(String name) { + DefaultElement el = getElement(name); + return (el != null && el instanceof ListField2); + } + + public boolean isThetaList2(String name) { + DefaultElement el = getElement(name); + return (el != null && el instanceof ThetaListField2); + } + + public Dictionary subDict(String name) { + DefaultElement el = getElement(name); + if (isDictionary(name)) { + return (Dictionary) el; + } else if (el != null) + throw new DictionaryException(name + " not a dictionary"); + else + return null; + } + +// public ListField getList() { +// return getList(""); +// } +// +// public ListField2 getList2() { +// return getList2(""); +// } + + public ListField getList(String name) { + DefaultElement el = getElement(name); + if (isList(name)) { + return (ListField) el; + } else if (el != null) + throw new DictionaryException(name + " not a list"); + else + return null; + } + + public ListField2 getList2(String name) { + DefaultElement el = getElement(name); + if (isList2(name)) { + return (ListField2) el; + } else if (el != null) + throw new DictionaryException(name + " not a list"); + else + return null; + } + + public ThetaListField2 getThetaList2(String name) { + DefaultElement el = getElement(name); + if (isThetaList2(name)) { + return (ThetaListField2) el; + } else if (el != null) + throw new DictionaryException(name + " not a theta list"); + else + return null; + } + + public DefaultElement lookup(Finder finder) { + String key = findKey(finder); + if (key == null) { + throw new DictionaryException("Key " + key + " is NULL"); + } + + return getElement(key); + } + + public String lookup(String key) { + return lookupString(key); + } + + public String lookupString(String key) { + if (key == null) { + throw new DictionaryException("Key " + key + " is NULL"); + } + DefaultElement el = getElement(key); + if (isField(key)) { + return ((FieldElement) el).getValue(); + } else if (el != null) + throw new DictionaryException(key + " not a field"); + else + return null; + } + + public int lookupInt(String name) { + String value = lookupString(name); + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return -1; + } + } + + public double lookupDouble(String name) { + String value = lookupString(name); + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + return Double.NaN; + } + } + + public DimensionedScalar lookupScalar(String name) { + DefaultElement el = getElement(name); + if (el != null && el instanceof DimensionedScalar) { + return (DimensionedScalar) el; + } else if (el != null) + throw new DictionaryException(name + " not a dimensioned scalar"); + else + return null; + } + + public String[] lookupArray(String name) { + DefaultElement el = getElement(name); + if (el != null && el instanceof FieldElement) { + String value = ((FieldElement) el).getValue(); + if (value.startsWith("uniform")) { + value = value.replace("uniform", "").trim(); + } + if (value.startsWith("nonuniform")) { + return new String[] { "Infinity", "Infinity", "Infinity" }; + } + if (value.startsWith("(") && value.endsWith(")")) { + value = value.replace("(", "").replace(")", "").trim(); + // value = value.substring(1, value.length()-1); + if (value.isEmpty()) { + return new String[0]; + } + String[] values = value.split(SPACER); + // System.out.println("Dictionary.lookupArray() "+Arrays.toString(values)); + return values; + } else + throw new DictionaryException(name + " not an array"); + } else if (el != null) + throw new DictionaryException(name + " not a field"); + else + return null; + } + + public String[][] lookupMatrix(String name) { + DefaultElement el = getElement(name); + if (el != null && el instanceof FieldElement) { + String value = ((FieldElement) el).getValue(); + if (value.startsWith("uniform")) { + value = value.replace("uniform", "").trim(); + } + if (value.startsWith("(") && value.endsWith(")")) { + value = value.replaceAll("\\(\\s*\\(", ""); + value = value.replaceAll("\\)\\s*\\)", ""); + + String[] values = value.split("\\)\\s*\\("); + String[][] matrix = new String[values.length][]; + for (int r = 0; r < values.length; r++) { + String[] row = values[r].trim().split("\\s+"); + matrix[r] = row; + } + return matrix; + } else + throw new DictionaryException(name + " not an array"); + } else if (el != null) + throw new DictionaryException(name + " not a field"); + else + return null; + } + + public String[] lookupArray2(String name) { + DefaultElement el = getElement(name); + if (el != null && el instanceof ListField2) { + ListField2 list = (ListField2) el; + return listToArray(list); + } else if (el != null) + throw new DictionaryException(name + " not a field"); + else + return null; + } + + private String[] listToArray(ListField2 list) { + List elements = list.getListElements(); + + String[] values = new String[elements.size()]; + + for (int i = 0; i < elements.size(); i++) { + DefaultElement element = elements.get(i); + if (element instanceof FieldElement) { + String value = ((FieldElement) element).getValue(); + values[i] = value; + } else if (element instanceof ListField2) { + String[] listField = listToArray((ListField2) element); + values[i] = "("; + for (int j = 0; j < listField.length; j++) { + values[i] += listField[j] + " "; + } + values[i] += ")"; + } + } + return values; + } + + public String[][] lookupMatrix2(String name) { + DefaultElement el = getElement(name); + if (el != null && el instanceof ListField2) { + ListField2 list = (ListField2) el; + return listToMatrix(list); + } else if (el != null) { + throw new DictionaryException(name + " not a field"); + } else { + return null; + } + } + + private String[][] listToMatrix(ListField2 list) { + List rows = list.getListElements(); + if (rows.size() > 0 && rows.get(0) instanceof ListField2) { + ListField2 firstRow = (ListField2) rows.get(0); + String[][] values = new String[rows.size()][firstRow.getListElements().size()]; + + for (int i = 0; i < rows.size(); i++) { + if (rows.get(i) instanceof ListField2) { + ListField2 row = (ListField2) rows.get(i); + values[i] = listToArray(row); + } + } + return values; + } else { + return new String[0][0]; + } + } + + public double[] lookupDoubleArray(String name) { + String[] array = lookupArray(name); + double[] doubleArray = new double[array.length]; + for (int i = 0; i < doubleArray.length; i++) { + try { + doubleArray[i] = Double.valueOf(array[i]); + } catch (NumberFormatException e) { + } + } + return doubleArray; + } + + public double[] lookupDoubleArray2(String name) { + String[] array = lookupArray2(name); + double[] doubleArray = new double[array.length]; + for (int i = 0; i < doubleArray.length; i++) { + try { + doubleArray[i] = Double.valueOf(array[i]); + } catch (NumberFormatException e) { + } + } + return doubleArray; + } + + public double[][] lookupDoubleMatrix(String name) { + String[][] matrix = lookupMatrix(name); + double[][] doubleMatrix = new double[matrix.length][matrix[0].length]; + for (int i = 0; i < doubleMatrix.length; i++) { + for (int j = 0; j < doubleMatrix[i].length; j++) { + try { + doubleMatrix[i][j] = Double.valueOf(matrix[i][j]); + } catch (NumberFormatException e) { + } + } + } + return doubleMatrix; + } + + public double[][] lookupDoubleMatrix2(String name) { + String[][] matrix = lookupMatrix2(name); + double[][] doubleMatrix = new double[matrix.length][matrix[0].length]; + for (int i = 0; i < doubleMatrix.length; i++) { + for (int j = 0; j < doubleMatrix[i].length; j++) { + try { + doubleMatrix[i][j] = Double.valueOf(matrix[i][j]); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + } + return doubleMatrix; + } + + public int[] lookupIntArray(String name) { + String[] array = lookupArray(name); + int[] intArray = new int[array.length]; + for (int i = 0; i < intArray.length; i++) { + try { + intArray[i] = Integer.valueOf(array[i]); + } catch (NumberFormatException e) { + } + } + return intArray; + } + + public Dictionary removeDict(String name) { + keys.remove(name); + return (Dictionary) elements.remove(name); + } + + public DefaultElement remove(String name) { + keys.remove(name); + return elements.remove(name); + } + + public DefaultElement remove(Finder finder) { + String key = findKey(finder); + return remove(key); + } + + List getGenericKeys() { + return genericKeys; + } + + List getKeys() { + return keys; + } + + List getIncludeFiles() { + return includeFiles; + } + + public boolean isEmpty() { + return keys.isEmpty(); + } + + @Override + public String toString() { + return new DictionaryWriter(this).write(); + } + + public List getDictionaries() { + List list = new ArrayList(); + for (String key : keys) { + DefaultElement el = elements.get(key); + if (el instanceof Dictionary) { + list.add((Dictionary) el); + } + } + return list; + } + + public Map getDictionariesMap() { + Map map = new LinkedHashMap(); + for (String key : keys) { + DefaultElement el = elements.get(key); + if (el instanceof Dictionary) { + map.put(el.getName(), (Dictionary) el); + } + } + return map; + } + + public List getFields() { + List list = new ArrayList(); + for (DefaultElement el : elements.values()) { + if (el instanceof FieldElement) { + list.add((FieldElement) el); + } + } + return list; + } + + public List getListFields() { + List list = new ArrayList<>(); + for (DefaultElement el : elements.values()) { + if (el instanceof ListField) { + list.add((ListField) el); + } + } + return list; + } + + public boolean hasOnlyList(){ + return !getListFields().isEmpty() && getDictionaries().isEmpty() && getFieldsMap().isEmpty(); + } + + public boolean hasOnlyList2(){ + return !getListFields2().isEmpty() && getDictionaries().isEmpty() && getFieldsMap().isEmpty(); + } + + public List getListFields2() { + List list = new ArrayList<>(); + for (DefaultElement el : elements.values()) { + if (el instanceof ListField2) { + list.add((ListField2) el); + } + } + return list; + } + + public Map getFieldsMap() { + Map map = new LinkedHashMap(); + for (DefaultElement el : elements.values()) { + if (el instanceof FieldElement) { + FieldElement field = (FieldElement) el; + map.put(field.getName(), field.getValue()); + } + } + return map; + } + + public void merge(Dictionary dict) { + merge(dict, new String[0]); + } + + public void merge(Dictionary dict, String[] keysToExclude) { + if (dict == null) + return; + // System.out.println("Dictionary.merge(): "+dict); + for (String key : dict.getKeys()) { + if(ArrayUtils.contains(keysToExclude, key)){ + continue; + } + + DefaultElement ele = dict.getElement(key); + if (ele instanceof Dictionary) { + Dictionary d = (Dictionary) ele; + if (found(d.getName()) && isDictionary(d.getName())) { + subDict(d.getName()).merge(d); + } else { + add(new Dictionary(d.getName())); + subDict(d.getName()).merge(d); + } + } else if (ele instanceof ListField) { + ListField l = (ListField) ele; + if (found(l.getName()) && isList(l.getName())) { + getList(l.getName()).merge(l); + } else { + add(new ListField(l.getName())); + getList(l.getName()).merge(l); + } + } else if (ele instanceof ThetaListField2) { + ThetaListField2 t = (ThetaListField2) ele; + if (found(t.getName()) && isThetaList2(t.getName())) { + getThetaList2(t.getName()).merge(t); + } else { + add(new ThetaListField2(t)); + } + } else if (ele instanceof ListField2) { + ListField2 l = (ListField2) ele; + if (found(l.getName()) && isList2(l.getName())) { + getList2(l.getName()).merge(l); + } else { + add(new ListField2(l)); + } + } else if (ele instanceof FieldElement) { + FieldElement f = (FieldElement) ele; + if (f instanceof DimensionedScalar) { + add(new DimensionedScalar((DimensionedScalar) f)); + } else { + add(f.getName(), f.getValue()); + } + } + } + genericKeys.addAll(dict.genericKeys); + } + + public void clear() { + elements.clear(); + keys.clear(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Dictionary) { + Dictionary d = (Dictionary) obj; + if (elements.size() != d.elements.size()) + return false; + for (String key : elements.keySet()) { + if (!elements.get(key).equals(d.elements.get(key))) + return false; + } + return true; + } + return false; + } + + /* * * * * * * * * * * * * + * READ/WRITE STUFF * * * * * * * * * * * * + */ + + public void readDictionary(File file) { + DictionaryReader reader = new DictionaryReader(this); + reader.read(file); + } + + protected void readDictionary(InputStream input, DictionaryLinkResolver resolver) { + DictionaryReader reader = new DictionaryReader(this, resolver); + reader.read(input); + } + + protected void readDictionary(InputStream input) { + DictionaryReader reader = new DictionaryReader(this); + reader.read(input); + } + + protected void readDictionaryFromString(String text) { + DictionaryReader reader = new DictionaryReader(this); + reader.read(text); + } + + protected String write() { + DictionaryWriter writer = new DictionaryWriter(this); + return writer.write(); + } + +} diff --git a/src/eu/engys/core/dictionary/DictionaryBuilder.java b/src/eu/engys/core/dictionary/DictionaryBuilder.java new file mode 100644 index 0000000..1bce27d --- /dev/null +++ b/src/eu/engys/core/dictionary/DictionaryBuilder.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import eu.engys.core.dictionary.parser.ListField2; + +public class DictionaryBuilder { + + + private Dictionary dictionary; + + private DictionaryBuilder(String name) { + this.dictionary = new Dictionary(name); + } + + public static DictionaryBuilder newDictionary(String name) { + return new DictionaryBuilder(name); + } + + public DictionaryBuilder field(String k, String v) { + dictionary.add(k, v); + return this; + } + + public DictionaryBuilder dimensionedScalar(String k, String v, String d) { + dictionary.add(new DimensionedScalar(k, v, d)); + return this; + } + + public DictionaryBuilder array(String k, String... v) { + dictionary.add(k, v); + return this; + } + + public DictionaryBuilder dict(Dictionary d) { + dictionary.add(d); + return this; + } + + public Dictionary done() { + return dictionary; + } + + public DictionaryBuilder list(String string, Dictionary... dicts) { + ListField list = new ListField(string); + for (Dictionary dictionary : dicts) { + list.add(dictionary); + } + dictionary.add(list); + return this; + } + + public DictionaryBuilder list2(String string, DefaultElement... elements) { + ListField2 list = new ListField2(string); + for (DefaultElement fieldElement : elements) { + list.add(fieldElement); + } + dictionary.add(list); + return this; + } + + public DictionaryBuilder scalar(String k, String dimensions, String v) { + dictionary.add(new DimensionedScalar(k, v, dimensions)); + return this; + } + + public DictionaryBuilder foamFile(String parent, String name) { + dictionary.setFoamFile(FoamFile.getDictionaryFoamFile(parent,name)); + return this; + } + +} diff --git a/src/eu/engys/core/dictionary/DictionaryEditor.java b/src/eu/engys/core/dictionary/DictionaryEditor.java new file mode 100644 index 0000000..756fe39 --- /dev/null +++ b/src/eu/engys/core/dictionary/DictionaryEditor.java @@ -0,0 +1,253 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.SwingConstants; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.fife.ui.rtextarea.RTextScrollPane; + +import eu.engys.core.dictionary.parser.DictionaryReader2; +import eu.engys.core.project.system.BlockMeshDict; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public class DictionaryEditor { + + public static final String CODE_EDITOR = "codeEditor"; + public static final String DICTIONARY_EDITOR_DIALOG_NAME = "dictionary.editor.dialog"; + + private static DictionaryEditor instance; + + private JDialog dialog; + private RSyntaxTextArea editor; + private DocumentListener documentListener; + + private Dictionary dictionary; + private boolean modified; + + private Runnable onDisposeRunnable; + + private Runnable onOKRunnable; + + private JButton okButton; + + public static DictionaryEditor getInstance() { + if (instance == null) + instance = new DictionaryEditor(); + return instance; + } + + private DictionaryEditor() { + initEditor(); + initListeners(); + } + + private void initEditor() { + this.editor = new RSyntaxTextArea(); + editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JSON); + editor.setCodeFoldingEnabled(true); + editor.setAntiAliasingEnabled(true); + editor.setBackground(new Color(240, 240, 240)); + editor.setName(CODE_EDITOR); + } + + private void initListeners() { + documentListener = new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + documentModified(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + documentModified(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + documentModified(); + } + }; + } + + private void documentModified() { + if (!modified) { + dialog.setTitle("*" + dialog.getTitle()); + this.modified = true; + } + } + + public void show(Window parent, Dictionary dictionary) { + show(parent, dictionary, null, null, null); + } + + public void show(final Window parent, Dictionary dictionary, final Runnable onShowRunnable, Runnable onDisposeRunnable, Runnable onOKRunnable) { + this.dictionary = dictionary; + this.onDisposeRunnable = onDisposeRunnable; + this.onOKRunnable = onOKRunnable; + ExecUtil.invokeAndWait(new Runnable() { + + @Override + public void run() { + initDialog(parent); + load(); + if (onShowRunnable != null) { + onShowRunnable.run(); + } + dialog.setVisible(true); + } + }); + } + + private void initDialog(Window parent) { + dialog = new JDialog(parent != null ? parent : UiUtil.getActiveWindow(), ModalityType.MODELESS); + dialog.setName(DICTIONARY_EDITOR_DIALOG_NAME); + dialog.getContentPane().setLayout(new BorderLayout()); + dialog.getContentPane().add(createMainPanel(), BorderLayout.CENTER); + dialog.getContentPane().add(createButtonsPanel(), BorderLayout.SOUTH); + dialog.getContentPane().doLayout(); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + closeDialog(); + } + }); + + dialog.setSize(800, 600); + dialog.setLocationRelativeTo(null); + dialog.getRootPane().setDefaultButton(okButton); + } + + private JPanel createMainPanel() { + RTextScrollPane scrollPane = new RTextScrollPane(editor); + scrollPane.setFoldIndicatorEnabled(true); + scrollPane.setBorder(BorderFactory.createEmptyBorder()); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(scrollPane); + return mainPanel; + } + + private JPanel createButtonsPanel() { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + okButton = new JButton(new OKAction()); + okButton.setName("OK"); + + JButton cancelButton = new JButton(new CancelAction()); + cancelButton.setName("Cancel"); + + panel.add(okButton); + panel.add(cancelButton); + + JPanel buttonsPanel = new JPanel(new BorderLayout()); + buttonsPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.NORTH); + buttonsPanel.add(panel, BorderLayout.CENTER); + + return buttonsPanel; + } + + private void closeDialog() { + dialog.setVisible(false); + dialog.dispose(); + dialog = null; + if (onDisposeRunnable != null) { + onDisposeRunnable.run(); + } + } + + private void load() { + editor.getDocument().removeDocumentListener(documentListener); + try { + editor.setText(dictionary.toString()); + editor.setCaretPosition(0); + } catch (Exception e) { + e.printStackTrace(); + } + dialog.setTitle(dictionary.getName()); + editor.getDocument().addDocumentListener(documentListener); + this.modified = false; + } + + private void save() { + dictionary.clear(); + // use name not instanceof! + if (dictionary.getName().equals(BlockMeshDict.BLOCK_DICT)) { + new DictionaryReader2(dictionary).read(editor.getText(), true); + } else { + new DictionaryReader(dictionary).read(editor.getText(), true); + } + dialog.setTitle(dictionary.getName()); + } + + private class OKAction extends AbstractAction { + public OKAction() { + super("OK"); + } + + @Override + public void actionPerformed(ActionEvent e) { + save(); + if(onOKRunnable != null){ + onOKRunnable.run(); + } + closeDialog(); + } + } + + private class CancelAction extends AbstractAction { + public CancelAction() { + super("Cancel"); + } + + @Override + public void actionPerformed(ActionEvent e) { + closeDialog(); + } + } + +} diff --git a/src/eu/engys/core/dictionary/DictionaryException.java b/src/eu/engys/core/dictionary/DictionaryException.java new file mode 100644 index 0000000..51119be --- /dev/null +++ b/src/eu/engys/core/dictionary/DictionaryException.java @@ -0,0 +1,34 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +public class DictionaryException extends RuntimeException { + + public DictionaryException(String message) { + super(message); + } +} diff --git a/src/eu/engys/core/dictionary/DictionaryLinkResolver.java b/src/eu/engys/core/dictionary/DictionaryLinkResolver.java new file mode 100644 index 0000000..98f3411 --- /dev/null +++ b/src/eu/engys/core/dictionary/DictionaryLinkResolver.java @@ -0,0 +1,116 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +public class DictionaryLinkResolver { + +// private Dictionary dictionary; + private Dictionary linksDestination; + + public DictionaryLinkResolver(Dictionary linksDestination) { + this.linksDestination = linksDestination; + } + + public void resolve(Dictionary dictionary) { + resolveLinks(dictionary, linksDestination); + } + + private void resolveLinks(Dictionary dict, Dictionary linksDestination) { + for (Dictionary d : dict.getDictionaries()) { + resolveLinks(d, linksDestination); + } + if (dict.found(Dictionary.DICTIONARY_LINK)) { + String link = dict.lookupString(Dictionary.DICTIONARY_LINK); + //System.out.println("------------> link: "+link); + String name = link.replace("$", ""); + //System.out.println("------------> name: "+name); + dict.remove(Dictionary.DICTIONARY_LINK); + + Dictionary dest = findDestination(name, linksDestination); + if (dest != null) { + dict.merge(dest); + //System.out.println("------------> dest: "+dest); + } + } + + for(ListField lf : dict.getListFields()) { + for(DefaultElement el : lf.getListElements()) { + if (el instanceof Dictionary) { + resolveLinks((Dictionary) el, linksDestination); + } + } + } + + for(FieldElement f : dict.getFields()) { + if (f.getName().startsWith(Dictionary.VALUE_LINK)) { + String key = f.getName().replace(Dictionary.VALUE_LINK, ""); + //System.out.println("------------> key: "+key); + String link = dict.lookupString(f.getName()); + //System.out.println("------------> link: "+link); + String name = link.replace("$", ""); + //System.out.println("------------> name: "+name); + dict.remove(f.getName()); + if (linksDestination.found(name)) { + String dest = linksDestination.lookupString(name); + //System.out.println("------------> dest: "+dest); + dict.add(key, dest); + } else { + //System.err.println("Warning: "+name+" not found in dictionary "+linksDestination.getName()); + } + } else if (f.getName().startsWith(Dictionary.VALUE_UNIFORM_LINK)) { + String key = f.getName().replace(Dictionary.VALUE_UNIFORM_LINK, ""); + //System.out.println("------------> key: "+key); + String link = dict.lookupString(f.getName()); + //System.out.println("------------> link: "+link); + String name = link.replace("$", ""); + //System.out.println("------------> name: "+name); + dict.remove(f.getName()); + if (linksDestination.found(name)) { + String dest = linksDestination.lookupString(name); + //System.out.println("------------> dest: "+dest); + dict.add(key, "uniform "+dest); + } else { + //System.err.println("Warning: "+name+" not found in dictionary "+linksDestination.getName()); + } + } + } + } + + private Dictionary findDestination(String name, Dictionary linksDestination) { + if (linksDestination.isDictionary(name)) { + return linksDestination.subDict(name); + } else { + for (Dictionary d : linksDestination.getDictionaries()) { + Dictionary dest = findDestination(name, d); + if (dest != null) { + return dest; + } + } + } + return null; + } +} diff --git a/src/eu/engys/core/dictionary/DictionaryReader.java b/src/eu/engys/core/dictionary/DictionaryReader.java new file mode 100644 index 0000000..34fdc18 --- /dev/null +++ b/src/eu/engys/core/dictionary/DictionaryReader.java @@ -0,0 +1,363 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import static eu.engys.core.dictionary.Dictionary.DICTIONARY_LINK; +import static eu.engys.core.dictionary.Dictionary.SPACER; +import static eu.engys.core.dictionary.Dictionary.VALUE_LINK; +import static eu.engys.core.dictionary.Dictionary.VALUE_UNIFORM_LINK; +import static eu.engys.core.dictionary.Dictionary.VERBOSE; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.IOUtils; +import eu.engys.util.RegexpUtils; + +public class DictionaryReader { + + private static final Logger logger = LoggerFactory.getLogger(DictionaryReader.class); + + private static final String LIST_START = "!"; + private static final String MATRIX_START = "&"; + private static final String MATRIX_DELIMITER = "|"; + private static final String FIELD_END = ";"; + private static final String DICTIONARY_END = "}"; + private static final String DICTIONARY_START = "{"; + private static final String COMMENT_REGEX = "/\\*(?:.|[\\n\\r])*?\\*/"; + private Dictionary dictionary; + private DictionaryLinkResolver linkResolver; + + public DictionaryReader(Dictionary dictionary) { + this(dictionary, new DictionaryLinkResolver(dictionary)); + } + + public DictionaryReader(Dictionary dictionary, DictionaryLinkResolver linkResolver) { + this.dictionary = dictionary; + this.linkResolver = linkResolver; + } + + public void read(File file) { + String text = readFile(file); + text = prepareText(text, file); + textToDictionary(text); + if (dictionary.found("FoamFile")) + dictionary.remove("FoamFile"); + } + + public void read(InputStream is) { + String text = readStream(is); + text = prepareText(text, null); + textToDictionary(text); + if (dictionary.found("FoamFile")) + dictionary.remove("FoamFile"); + } + + public void read(String text) { + read(text, false); + } + + public void read(String text, boolean removeHeader) { + text = prepareText(text, null); + textToDictionary(text); + if (dictionary.found("FoamFile") && removeHeader) { + dictionary.remove("FoamFile"); + } + } + + private String readFile(File file) { + return IOUtils.readStringFromFile(file); + } + + private String readStream(InputStream is) { + String text = ""; + try { + text = IOUtils.readStringFromStream(is); + } catch (IOException e) { + logger.warn("Error reading stream: {} ", e.getMessage()); + } + return text; + } + + private String prepareText(String text, File file) { +// text = text.replaceAll(COMMENT_REGEX, ""); + text = new jregex.Pattern(COMMENT_REGEX).replacer("").replace(text); + text = text.replaceAll("\t", SPACER); + + StringTokenizer rowTokenizer = new StringTokenizer(text, "\n"); + StringBuffer sb = new StringBuffer(); + while (rowTokenizer.hasMoreTokens()) { + String token = rowTokenizer.nextToken(); + token = token.trim(); + if (token.startsWith("//")) + continue; + if (token.contains("//")) { + token = token.substring(0, token.indexOf("//")).trim(); + } + if (token.startsWith("#include")) { + sb.append(importFile(token, file)); + continue; + } + sb.append(token); + sb.append("\n"); + } + text = sb.toString(); + return text; + } + + private String importFile(String token, File file) { + String text = ""; + if (file != null) { + try { + Pattern regex = Pattern.compile("#include\\s+\"(.+)\""); + Matcher regexMatcher = regex.matcher(token); + if (regexMatcher.find() && regexMatcher.groupCount() == 1) { + String fileName = regexMatcher.group(1).trim(); + String parentDir = file.getParent(); + + File fileToImport = new File(parentDir, fileName); + text = readFile(fileToImport); + text = prepareText(text, fileToImport); + } + } catch (PatternSyntaxException ex) { + ex.printStackTrace(); + } + } + + return text; + } + + protected void textToDictionary(String text) { + text = text.replace("\n", SPACER); + + // exploit table data structure + text = text.replaceAll("\\(\\s*(" + RegexpUtils.DOUBLE + ")\\s*\\(([^\\)]*)\\)\\s*\\)", "< $1 <$2> >"); + + // exploit matrix structure + text = text.replaceAll("([\\d | \\s])\\(\\s*\\(", "$1" + SPACER + MATRIX_START); + text = text.replaceAll("\\)\\s*\\(", MATRIX_DELIMITER); + + // exploit list structure + /* a parenthesis preceded by whatever AND at least a space */ + text = text.replaceAll("(?<=[^\\]])\\s+\\(", SPACER + LIST_START); + /* a parenthesis preceded by a space+digit OR digit+digit */ + text = text.replaceAll("(?<=\\W\\d)\\(", SPACER + LIST_START); + + if (VERBOSE) + System.out.println(text); + + parseDictionary(text); + } + + protected void parseDictionary(String text) { + StringTokenizer tokenizer = new StringTokenizer(text, "};{!&", true); + Stack stack = new Stack(); + readDictionary(tokenizer, stack); + if (VERBOSE) + System.out.println("##################################\n" + toString()); + linkResolver.resolve(dictionary); + } + + void readDictionary(StringTokenizer st, Stack stack) { + while (st.hasMoreTokens()) { + String token = st.nextToken(); + token = token.trim(); // tolgo gli spazi + stack.push(token);// metto nella pila + + if (stack.peek().equals(DICTIONARY_START)) { + stack.pop(); + String name = stack.peek(); + Dictionary d = new Dictionary(name); + if (VERBOSE) + System.out.println("START DICTIONARY: " + name); + + new DictionaryReader(d).readDictionary(st, stack); + + if (isMultiple(name)) { + String[] names = extractMultipleKeys(name); + for (String n : names) { + if (isGeneric(withDoubleQuotes(n))) { + Dictionary copy = new Dictionary(d); + copy.setName(withDoubleQuotes(n)); + dictionary.addGeneric(copy); + } else { + Dictionary copy = new Dictionary(d); + copy.setName(n); + dictionary.add(copy); + } + } + } else if (isGeneric(name)) { + dictionary.addGeneric(d); + } else { + dictionary.add(d); + } + } else if (stack.peek().equals(DICTIONARY_END)) { + stack.pop(); + String name = stack.pop(); + if (VERBOSE) + System.out.println("FINE DICTIONARY: " + name); + return; + } else if (stack.peek().equals(FIELD_END)) { + stack.pop(); + String field = stack.pop(); + if (VERBOSE) + System.out.println(field); + + if (field.startsWith("$")) { + dictionary.add(DICTIONARY_LINK, field); + } else if (field.equals(")")) { + if (VERBOSE) + System.out.println("END LIST"); + return; + } else { + readField(field); + } + } else if (stack.peek().equals(LIST_START)) { + stack.pop(); + String name = stack.pop(); + if (VERBOSE) + System.out.println("START LIST: " + name); + ListField list = new ListField(name); + ListReader reader = new ListReader(list, dictionary); + reader.readList(st, stack); + if (!reader.isSimpleList()) { + dictionary.add(list); + } + } else if (stack.peek().equals(MATRIX_START)) { + stack.pop(); + String name = stack.pop(); + if (VERBOSE) + System.out.println("START MATRIX: " + name); + FieldElement matrix = new FieldElement(name, ""); + MatrixReader reader = new MatrixReader(matrix, dictionary); + reader.readMatrix(st, stack); + } + } + } + + protected void readField(String field) { + try { + dictionary.add(new DimensionedScalar(field)); + } catch (DictionaryException e) { + int splitIndex = field.indexOf(SPACER); + if (splitIndex < 0) { + String key = field.trim(); + String value = ""; + dictionary.add(key, value); + } else { + String key = field.substring(0, splitIndex).trim(); + String value = field.substring(splitIndex).trim(); + + // System.out.println("DictionaryReader.readField() FIELD: "+field+" -> K: "+key+", V: "+value); + + if (isMultiple(key)) { + String[] keys = extractMultipleKeys(key); + for (String k : keys) { + if (isGeneric(withDoubleQuotes(k))) { + dictionary.addGeneric(withDoubleQuotes(k), value); + } else { + dictionary.add(k, value); + } + } + } else if (isGeneric(key)) { + dictionary.addGeneric(key, value); + } else if (isLink(value)) { + extractLink(key, value); + } else { + dictionary.add(key, value); + } + } + } + } + + private String withDoubleQuotes(String k) { + return "\"" + k + "\""; + } + + public static String[] extractMultipleKeys(String key) { + key = key.replace("\"", ""); + + if (key.contains("(") && key.contains(")")) { + int start = key.indexOf("("); + int end = key.indexOf(")"); + String header = key.substring(0, start); + String footer = key.substring(end + 1, key.length()); + String core = key.substring(start + 1, end); + + String[] tokens = core.split("\\|"); + + String[] keys = new String[tokens.length]; + for (int i = 0; i < keys.length; i++) { + keys[i] = header + tokens[i] + footer; + } + return keys; + } else { + String[] tokens = key.split("\\|"); + return tokens; + } + + } + + public String cleanGenericKey(String key) { + key = key.substring(1, key.length() - 1); + key = key.substring(0, key.indexOf(".*")); + return key; + } + + public boolean isGeneric(String key) { + return key.startsWith("\"") && key.endsWith("\"") && key.contains(".*"); + } + + public boolean isMultiple(String key) { + return key.startsWith("\"") && key.endsWith("\"") && key.contains(MATRIX_DELIMITER); + } + + public boolean isLink(String value) { + return !value.startsWith("\"") && value.contains("$"); + } + + private void extractLink(String key, String value) { + if (value.startsWith("uniform")) { + String link = value.replace("uniform", "").trim(); + if (link.startsWith("$")) { + dictionary.add(VALUE_UNIFORM_LINK + key, link); + } + } else if (value.startsWith("$")) { + dictionary.add(VALUE_LINK + key, value); + } + } + +} diff --git a/src/eu/engys/core/dictionary/DictionaryUtils.java b/src/eu/engys/core/dictionary/DictionaryUtils.java new file mode 100644 index 0000000..1493183 --- /dev/null +++ b/src/eu/engys/core/dictionary/DictionaryUtils.java @@ -0,0 +1,160 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.parser.DictionaryReader2; +import eu.engys.util.progress.ProgressMonitor; + +public final class DictionaryUtils { + + private static final Logger logger = LoggerFactory.getLogger(DictionaryUtils.class); + + public static Dictionary readDictionary(String text) { + Dictionary dictionary = new Dictionary(""); + dictionary.readDictionaryFromString(text); + return dictionary; + } + + public static Dictionary readDictionary(File file, ProgressMonitor monitor) { + String name = file.getName(); + if (file.exists()) { + if (monitor != null) { + monitor.info(file.getName(), 1); + } + return new Dictionary(file); + } + if (monitor != null) + monitor.warning(file.getName() + " NOT FOUND", 1); + + return new Dictionary(name); + } + + public static Dictionary readDictionary2(File file) { + String name = file.getName(); + String parent = file.getParent(); + if (file.exists()) { + Dictionary d = new Dictionary(name); + d.setFoamFile(FoamFile.getDictionaryFoamFile(parent, name)); + DictionaryReader2 reader = new DictionaryReader2(d); + reader.read(file); + + return d; + } + + return new Dictionary(name); + } + + public static Dictionary readDictionary(File file, Dictionary linkDestination) { + String name = file.getName(); + if (file.exists()) { + Dictionary d = new Dictionary(name); + DictionaryReader reader = new DictionaryReader(d, new DictionaryLinkResolver(linkDestination)); + reader.read(file); + + return d; + } + return new Dictionary(name); + } + + public static void removeDictionary(File parent, Dictionary dict, ProgressMonitor monitor) { + if (dict != null) { + File dictFile = new File(parent, dict.getName()); + if (dictFile.exists()) { + logger.info("REMOVE: " + dict.getName() + " -> " + dictFile.getAbsolutePath()); + if (!dictFile.delete()) + logger.warn("REMOVE: Cannot remove {}", dictFile); + } else { + logger.warn("REMOVE: File {} does not exist", dictFile); + } + } + } + + public static void writeDictionary(File parent, Dictionary dict, ProgressMonitor monitor) { + if (dict != null) { + File dictFile = new File(parent, dict.getName()); + writeDictionaryFile(dictFile, dict); + String msg = "WRITE: " + dict.getName() + " -> " + dictFile.getAbsolutePath(); + if (monitor != null) { + monitor.info(dict.getName(), 1); + } + logger.info(msg); + } else { + logger.warn("Dictionary NOT FOUND in parent " + parent, 1); + } + } + + public static void writeDictionaryFile(File file, Dictionary dictionary) { + String text = dictionary.write(); + try { + FileUtils.writeStringToFile(file, text); + } catch (IOException e) { + logger.error(e.getMessage()); + } + } + + public static Dictionary header(String parent, Dictionary dict) { + if (dict == null) + return null; + dict.setFoamFile(FoamFile.getDictionaryFoamFile(parent, dict.getName())); + return dict; + } + + public static String[] string2StringArray(String list) { + String trimmedString = list.trim(); + String stringWithoutParentheses = trimmedString.substring(1, trimmedString.length() - 1).trim(); + if(stringWithoutParentheses.isEmpty()){ + return new String[0]; + } else { + return stringWithoutParentheses.split("\\s+"); + } + } + + public static String stringArray2String(String[] values) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (String value : values) { + sb.append(value); + sb.append(" "); + } + sb.append(")"); + return sb.toString(); + } + + public static void copyIfFound(Dictionary dest, Dictionary source, String key) { + if (source.found(key)) { + dest.add(key, source.lookup(key)); + } + } + +} diff --git a/src/eu/engys/core/dictionary/DictionaryWriter.java b/src/eu/engys/core/dictionary/DictionaryWriter.java new file mode 100644 index 0000000..6eefff9 --- /dev/null +++ b/src/eu/engys/core/dictionary/DictionaryWriter.java @@ -0,0 +1,182 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary; + +import static eu.engys.core.dictionary.Dictionary.SPACER; +import static eu.engys.core.dictionary.Dictionary.TAB; +import static eu.engys.core.dictionary.Dictionary.VERBOSE; +import eu.engys.core.dictionary.parser.ListField2; + +public class DictionaryWriter { + + protected Dictionary dictionary; + + protected final String START = "{"; + protected final String END = "}\n"; + + public DictionaryWriter(Dictionary dictionary) { + this.dictionary = dictionary; + } + + public String write() { + StringBuffer sb = new StringBuffer(); + writeDictionary(sb, ""); + return sb.toString(); + } + + public void writeDictionary(StringBuffer sb, String rowHeader) { + if (dictionary.getFoamFile() != null) { + sb.append(FoamFile.HEADER); + DictionaryWriter writer = new DictionaryWriter(dictionary.getFoamFile()); + writer.writeDictionary(sb, ""); + + if (dictionary.hasOnlyList()) { + for (ListField list : dictionary.getListFields()) { + if (list.getName().isEmpty()) { + list.writeListDict(sb, rowHeader); + } else { + list.writeListField(sb, rowHeader); + } + } + return; + } + + if (dictionary.hasOnlyList2()) { + for (ListField2 list : dictionary.getListFields2()) { + if (list.nameIsANumber()) { + list.writeListDict(sb, rowHeader); + } else { + list.writeListField(sb, rowHeader); + } + } + return; + } + } else { + sb.append("\n"); + sb.append(rowHeader); + sb.append(dictionary.getName()); + sb.append("\n"); + sb.append(rowHeader); + sb.append(START); + } + for (String key : dictionary.getKeys()) { + DefaultElement ele = dictionary.getElement(key); + if (ele != null) { + writeElement(sb, rowHeader, ele); + } else { + System.out.println("DictionaryWriter.writeDictionary() ------------------------------>> " + key + " is NUUULLLLL in " + dictionary.getKeys() + " and " + dictionary.getDictionaries()); + } + } + for (String includeFile : dictionary.getIncludeFiles()) { + writeInclude(sb, includeFile, rowHeader); + } + + if (dictionary.getFoamFile() == null) + sb.append("\n" + rowHeader + END); + } + + public static void writeElement(StringBuffer sb, String rowHeader, DefaultElement ele) { + if (ele instanceof Dictionary) { + DictionaryWriter writer = new DictionaryWriter((Dictionary) ele); + writer.writeDictionary(sb, rowHeader + TAB); + } else if (ele instanceof DimensionedScalar) { + writeDimensionedScalar(sb, (DimensionedScalar) ele, rowHeader); + } else if (ele instanceof ListField) { + ListField.class.cast(ele).writeListField(sb, rowHeader); + } else if (ele instanceof ListField2) { + ListField2.class.cast(ele).writeListField(sb, rowHeader); + } else if (ele instanceof TableRowElement) { + TableRowElement.class.cast(ele).writeTableRow(sb, rowHeader); + } else if (hasParenthesis(ele)) { + writeMatrix(sb, (FieldElement) ele, rowHeader); + } else { + writeField(sb, (FieldElement) ele, rowHeader); + } + } + + private static boolean hasParenthesis(DefaultElement ele) { + FieldElement fieldElement = (FieldElement) ele; + String value = fieldElement.getValue(); + return value != null && value.contains("(") && value.contains("List"); + } + + protected static void writeField(StringBuffer sb, FieldElement field, String rowHeader) { + if (field.getName().isEmpty()) { + sb.append(SPACER); + sb.append(field.getValue()); + } else { + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(field.getName()); + sb.append(SPACER); + sb.append(field.getValue()); + sb.append(";"); + } + } + + protected static void writeMatrix(StringBuffer sb, FieldElement field, String rowHeader) { + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(field.getName()); + sb.append(SPACER); + String value = field.getValue(); + if (value.contains("vector")) { + sb.append(value.replace("(", "\n(").replace("))", ")\n)").replace("", "\n")); + } else { + sb.append(value.replace("(", "\n(").replace("", "\n").replaceAll("\\s+", "\n")); + } + sb.append(";"); + } + + protected void writeInclude(StringBuffer sb, String includeFile, String rowHeader) { + if (VERBOSE) + System.out.println("Dictionary.writeInclude() " + includeFile); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append("#include"); + sb.append(SPACER); + sb.append(includeFile); + } + + private static void writeDimensionedScalar(StringBuffer sb, DimensionedScalar ds, String rowHeader) { + if (VERBOSE) + System.out.println("Dictionary.writeDimensionedScalar() " + (ds != null ? ds.getName() : "NULL!!!")); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(ds.getName()); + sb.append(SPACER); + sb.append(ds.getName()); + sb.append(SPACER); + sb.append(ds.getDimensions()); + sb.append(SPACER); + sb.append(ds.getValue()); + sb.append(";"); + } +} diff --git a/src/eu/engys/core/dictionary/DimensionedScalar.java b/src/eu/engys/core/dictionary/DimensionedScalar.java new file mode 100644 index 0000000..9d43777 --- /dev/null +++ b/src/eu/engys/core/dictionary/DimensionedScalar.java @@ -0,0 +1,145 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import java.util.ArrayList; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DimensionedScalar extends FieldElement { + private static final Pattern PATTERN = Pattern.compile("(\\w+)\\s+(\\[.+\\])\\s+(.*\\z)"); + // private static final Pattern PATTERN = + // Pattern.compile("(\\w+)\\s+(\\[.+\\])\\s+(\\d+\\.?\\d?)"); + + private Dimensions dimensions; + + public DimensionedScalar(String name, String value, String dimensions) { + super(name, value); + this.dimensions = new Dimensions(dimensions); + } + + public DimensionedScalar(String name, String value, Dimensions dimensions) { + super(name, value); + this.dimensions = dimensions; + } + + public DimensionedScalar(DimensionedScalar ds) { + super(ds.getName(), ds.getValue()); + this.dimensions = new Dimensions(ds.getDimensions().toString()); + } + + /** + * La stringa contiene il value del field di cui bisogna fare il parsing per + * estrarre valore e unita' di misura + * + * @param field + * value + */ + public DimensionedScalar(String fieldValue) throws IllegalArgumentException { + super("", ""); + + Matcher matcher = PATTERN.matcher(fieldValue); + if (matcher.find()) { + String name = matcher.group(1); + String dimensions = matcher.group(2); + String value = matcher.group(3); + setName(name); + setValue(value); + this.dimensions = new Dimensions(dimensions); + } else { + throw new DictionaryException("CANNOT PARSE: >" + fieldValue + "<"); + } + } + + public double doubleValue() { + return Double.parseDouble(getValue()); + } + + public Dimensions getDimensions() { + return dimensions; + } + + public class Dimensions extends ArrayList { + public Dimensions(String dimString) { + dimString = dimString.trim(); + dimString = dimString.substring(1, dimString.length() - 1); // tolgo + // le + // parentesi + // quadre + StringTokenizer st = new StringTokenizer(dimString); + if (st.countTokens() == 7 || st.countTokens() == 5) { + while (st.hasMoreTokens()) { + add(Integer.decode(st.nextToken())); + } + if (size() == 5) { + add(Integer.valueOf(0)); + add(Integer.valueOf(0)); + } + } else { + throw new IllegalStateException("Bad number of dimensions: " + dimString); + } + } + + public Dimensions() { + } + + /** + * Perform a division among dimensions: we need to subtract each + * component + * + * @param d + * @return + */ + public Dimensions divide(Dimensions d) { + Dimensions result = new Dimensions(); + for (int i = 0; i < d.size(); i++) { + result.add(new Integer(get(i).intValue() - d.get(i).intValue())); + } + return result; + } + + public String toString() { + if (size() == 0) + return "[]"; + StringBuilder sb = new StringBuilder(); + sb.append('['); + + for (Integer i : this) { + sb.append(i); + sb.append(" "); + } + return sb.append(']').toString(); + } + } + + @Override + public String toString() { + return getName() + " " + getDimensions() + " " + getValue(); + } + +} diff --git a/src/eu/engys/core/dictionary/FieldChangeListener.java b/src/eu/engys/core/dictionary/FieldChangeListener.java new file mode 100644 index 0000000..f95afad --- /dev/null +++ b/src/eu/engys/core/dictionary/FieldChangeListener.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import java.awt.event.ActionListener; + +public interface FieldChangeListener extends ActionListener { + + public void fieldChanged(); + public boolean isAdjusting(); + public void setAdjusting(boolean b); +} diff --git a/src/eu/engys/core/dictionary/FieldElement.java b/src/eu/engys/core/dictionary/FieldElement.java new file mode 100644 index 0000000..dcc3763 --- /dev/null +++ b/src/eu/engys/core/dictionary/FieldElement.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +public class FieldElement extends DefaultElement { + + private String value; + + public FieldElement(String name, String value) { + super(name); + this.value = value; + } + + public FieldElement(FieldElement el) { + this(el.getName(), el.getValue()); + } + + public void setValue(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return getName() + "[" + value + "]"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof FieldElement) { + return ((FieldElement) obj).getName().equals(getName()) && ((FieldElement) obj).value.equals(value) ; + } + return false; + } +} diff --git a/src/eu/engys/core/dictionary/FieldListener.java b/src/eu/engys/core/dictionary/FieldListener.java new file mode 100644 index 0000000..072aa20 --- /dev/null +++ b/src/eu/engys/core/dictionary/FieldListener.java @@ -0,0 +1,31 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +public interface FieldListener { + +} diff --git a/src/eu/engys/core/dictionary/FileEditor.java b/src/eu/engys/core/dictionary/FileEditor.java new file mode 100644 index 0000000..4cc76a1 --- /dev/null +++ b/src/eu/engys/core/dictionary/FileEditor.java @@ -0,0 +1,254 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.SwingConstants; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.fife.ui.rtextarea.RTextScrollPane; + +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public class FileEditor { + + public static final String FILE_EDITOR_DIALOG = "file.editor.dialog"; + public static final String FILE_EDITOR = "fileEditor"; + + private static FileEditor instance; + + private JDialog dialog; + private RSyntaxTextArea editor; + private DocumentListener documentListener; + + private String fileName; + private List fileContent; + private boolean modified; + + private Runnable onDisposeRunnable; + + private Runnable onOKRunnable; + + private JButton okButton; + + public static FileEditor getInstance() { + if (instance == null) + instance = new FileEditor(); + return instance; + } + + private FileEditor() { + initEditor(); + initListeners(); + } + + private void initEditor() { + this.editor = new RSyntaxTextArea(); + editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE); + editor.setCodeFoldingEnabled(true); + editor.setAntiAliasingEnabled(true); + editor.setBackground(new Color(240, 240, 240)); + editor.setName(FILE_EDITOR); + } + + private void initListeners() { + documentListener = new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + documentModified(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + documentModified(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + documentModified(); + } + }; + } + + private void documentModified() { + if (!modified) { + dialog.setTitle("*" + dialog.getTitle()); + this.modified = true; + } + } + + public void show(final Window parent, List fileContent, String fileName) { + show(parent, fileContent, fileName, null, null, null); + } + + public void show(final Window parent, List fileContent, String fileName, final Runnable onShowRunnable, Runnable onDisposeRunnable, Runnable onOKRunnable) { + this.fileContent = fileContent; + this.fileName = fileName; + this.onDisposeRunnable = onDisposeRunnable; + this.onOKRunnable = onOKRunnable; + ExecUtil.invokeAndWait(new Runnable() { + + @Override + public void run() { + initDialog(parent); + load(); + if (onShowRunnable != null) { + onShowRunnable.run(); + } + dialog.setVisible(true); + } + }); + } + + private void initDialog(Window parent) { + dialog = new JDialog(parent != null ? parent : UiUtil.getActiveWindow(), ModalityType.MODELESS); + dialog.setName(FILE_EDITOR_DIALOG); + dialog.getContentPane().setLayout(new BorderLayout()); + dialog.getContentPane().add(createMainPanel(), BorderLayout.CENTER); + dialog.getContentPane().add(createButtonsPanel(), BorderLayout.SOUTH); + dialog.getContentPane().doLayout(); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + closeDialog(); + } + }); + + dialog.setSize(800, 600); + dialog.setLocationRelativeTo(null); + dialog.getRootPane().setDefaultButton(okButton); + } + + private JPanel createMainPanel() { + RTextScrollPane scrollPane = new RTextScrollPane(editor); + scrollPane.setFoldIndicatorEnabled(true); + scrollPane.setBorder(BorderFactory.createEmptyBorder()); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(scrollPane); + return mainPanel; + } + + private JPanel createButtonsPanel() { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + okButton = new JButton(new OKAction()); + okButton.setName("OK"); + + JButton cancelButton = new JButton(new CancelAction()); + cancelButton.setName("Cancel"); + + panel.add(okButton); + panel.add(cancelButton); + + JPanel buttonsPanel = new JPanel(new BorderLayout()); + buttonsPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.NORTH); + buttonsPanel.add(panel, BorderLayout.CENTER); + + return buttonsPanel; + } + + private void closeDialog() { + dialog.setVisible(false); + dialog.dispose(); + dialog = null; + if (onDisposeRunnable != null) { + onDisposeRunnable.run(); + } + } + + private void load() { + editor.getDocument().removeDocumentListener(documentListener); + editor.setText(""); + try { + for (String line : fileContent) { + editor.append(line + "\n"); + } + editor.setCaretPosition(0); + } catch (Exception e) { + e.printStackTrace(); + } + dialog.setTitle(fileName); + editor.getDocument().addDocumentListener(documentListener); + this.modified = false; + } + + private void save() { + fileContent.clear(); + for (String line : editor.getText().split("\\n")){ + fileContent.add(line); + } + dialog.setTitle(fileName); + } + + private class OKAction extends AbstractAction { + public OKAction() { + super("OK"); + } + + @Override + public void actionPerformed(ActionEvent e) { + save(); + if(onOKRunnable != null){ + onOKRunnable.run(); + } + closeDialog(); + } + } + + private class CancelAction extends AbstractAction { + public CancelAction() { + super("Cancel"); + } + + @Override + public void actionPerformed(ActionEvent e) { + closeDialog(); + } + } + +} diff --git a/src/eu/engys/core/dictionary/Finder.java b/src/eu/engys/core/dictionary/Finder.java new file mode 100644 index 0000000..6f5547b --- /dev/null +++ b/src/eu/engys/core/dictionary/Finder.java @@ -0,0 +1,32 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary; + +public interface Finder { + + boolean accept(String key); + +} diff --git a/src/eu/engys/core/dictionary/FoamFile.java b/src/eu/engys/core/dictionary/FoamFile.java new file mode 100644 index 0000000..fcf8f70 --- /dev/null +++ b/src/eu/engys/core/dictionary/FoamFile.java @@ -0,0 +1,65 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import eu.engys.util.ApplicationInfo; + +public class FoamFile extends Dictionary { + + private static final String HELYX = ApplicationInfo.getName(); + private static final String VERSION = ApplicationInfo.getVersion(); + public static final String HEADER = + "/*--------------------------------*- C++ -*----------------------------------*\\"+"\n"+ + "| o | |" +"\n"+ + "| o o | "+HELYX+" |" +"\n"+ + "| o O o | Version: "+VERSION+" |" +"\n"+ + "| o o | Web: http://www.engys.com |" +"\n"+ + "| o | |" +"\n"+ + "\\*---------------------------------------------------------------------------*/"; + + private FoamFile(String version, String format, String classe, String location, String object) { + super("FoamFile"); + add("version", version); + add("format", format); + add("class", classe); + add("location", location); + add("object", object); + } + + public static FoamFile getFieldFoamFile(String name) { + return new FoamFile("2.0", "ascii", name.startsWith("U") ? "volVectorField" : (name.startsWith("point") ? "pointVectorField" : "volScalarField"), "\"0\"", name); + } + + public static FoamFile getDictionaryFoamFile(String parent, String name) { + return new FoamFile("2.0", "ascii", "dictionary", parent, name); + } + + public static FoamFile getDictionaryFoamFile(String classe, String parent, String name) { + return new FoamFile("2.0", "ascii", classe, parent, name); + } + +} diff --git a/src/eu/engys/core/dictionary/ListField.java b/src/eu/engys/core/dictionary/ListField.java new file mode 100644 index 0000000..7ce63b9 --- /dev/null +++ b/src/eu/engys/core/dictionary/ListField.java @@ -0,0 +1,188 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import static eu.engys.core.dictionary.Dictionary.TAB; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.StringTokenizer; + +public class ListField extends DefaultElement { + + private static final String SPACER = " "; + private List list = new ArrayList(); + + public ListField(String name) { + super(decodeName(name)); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public ListField(ListField lf) { + super(lf.getName()); + for (DefaultElement el : lf.getListElements()) { + if (el instanceof Dictionary) { + add(new Dictionary((Dictionary) el)); + } else { + System.err.println("ListField only dictionaries are allowed as elements: " + el.getName()); + } + } + } + + private static String decodeName(String name) { + if (name.contains(SPACER)) { + StringTokenizer tokenizer = new StringTokenizer(name, SPACER); + if (tokenizer.countTokens() == 1) { + // System.out.println("ListField.decodeName() 1 TOKEN"); + String token = tokenizer.nextToken(); + try { + int size = Integer.parseInt(token); + return ""; + } catch (NumberFormatException ex) { + return token; + } + } else if (tokenizer.countTokens() == 2) { + // System.out.println("ListField.decodeName() 2 TOKEN"); + String token1 = tokenizer.nextToken(); + String token2 = tokenizer.nextToken(); + try { + int size = Integer.parseInt(token2); + } catch (NumberFormatException ex) { + return name; + } + return token1; + } else if (tokenizer.countTokens() == 3) { + // System.out.println("ListField.decodeName() 3 TOKEN"); + String token1 = tokenizer.nextToken(); + String token2 = tokenizer.nextToken(); + String token3 = tokenizer.nextToken(); + try { + int size = Integer.parseInt(token3); + } catch (NumberFormatException ex) { + } + return name; + } + } else { + // System.out.println("ListField.decodeName() 4+ TOKEN"); + try { + int size = Integer.parseInt(name); + return ""; + } catch (NumberFormatException ex) { + return name; + } + } + return name; + } + + public void add(DefaultElement element) { + list.add(element); + } + + public List getListElements() { + return Collections.unmodifiableList(list); + } + + public void merge(ListField l) { + for (DefaultElement el : l.getListElements()) { + if (containsElement(el)) { + if (el instanceof Dictionary) { + Dictionary dictionary = getDictionary(el.getName()); + if (dictionary != null) { + dictionary.merge((Dictionary) el); + } else { + System.err.println("Error merging list '" + getName() + "' with " + l.getName() + ""); + } + } else { + // do nothing + } + } else { + add(el); + } + } + } + + private boolean containsElement(DefaultElement element) { + for (DefaultElement e : list) { + if (e instanceof Dictionary && e.getName().equals(element.getName()) && !e.getName().isEmpty()) { + return true; + } else if (e.getName().equals(element.getName()) && e.equals(element)) { + return true; + } + } + return false; + } + + public void writeListField(StringBuffer sb, String rowHeader) { + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(getName()); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append("("); + for (DefaultElement el : getListElements()) { + DictionaryWriter.writeElement(sb, rowHeader, el); + } + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(");"); + } + + public void writeListDict(StringBuffer sb, String rowHeader) { + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(list.size()); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append("("); + for (DefaultElement el : getListElements()) { + DictionaryWriter.writeElement(sb, rowHeader, el); + } + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(")"); + } + + public Dictionary getDictionary(String name) { + for (DefaultElement e : list) { + if (e instanceof Dictionary && !e.getName().isEmpty() && e.getName().equals(name)) { + return (Dictionary) e; + } + } + return null; + } + +} diff --git a/src/eu/engys/core/dictionary/ListReader.java b/src/eu/engys/core/dictionary/ListReader.java new file mode 100644 index 0000000..f83cdfd --- /dev/null +++ b/src/eu/engys/core/dictionary/ListReader.java @@ -0,0 +1,118 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import static eu.engys.core.dictionary.Dictionary.VERBOSE; + +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ListReader { + + private ListField list; + private Dictionary parent; + private boolean simpleList; + + public ListReader(ListField list, Dictionary parent) { + this.list = list; + this.parent = parent; + } + + public void readList(StringTokenizer st, Stack stack) { + while (st.hasMoreTokens()) { + String token = st.nextToken(); + token = token.trim(); /* tolgo gli spazi */ + stack.push(token);/* metto nella pila */ + + if (stack.peek().equals("{")) { + stack.pop(); + String name = stack.peek(); + Dictionary d = new Dictionary(name); + if (VERBOSE) + System.out.println("START LIST DICTIONARY: " + name); + + new DictionaryReader(d).readDictionary(st, stack); + list.add(d); + } else if (stack.peek().equals("}")) { + stack.pop(); + String name = stack.pop(); + if (VERBOSE) + System.out.println("END LIST DICTIONARY: " + name); + return; + } else if (stack.peek().equals(";")) { + stack.pop(); + String field = stack.pop(); + if (VERBOSE) + System.out.println(list.getName()+", "+field); + + if (field.endsWith(")")) { + if (list.getListElements().isEmpty()) { + Pattern pattern = Pattern.compile("(\\w+)\\s+nonuniform\\s*(List)?\\s*(\\d+)?\\s*"); + Matcher listFieldMatcher = pattern.matcher(list.getName()); + if (field.equals(")")) { + if (listFieldMatcher.matches()) {/* is an empty array nonuniform 'nonuniform 0()' */ + parent.add(listFieldMatcher.group(1), "nonuniform 0()"); + simpleList = true; + } + } else { + if (listFieldMatcher.matches()) { + field = processField(field); + + parent.add(listFieldMatcher.group(1), "nonuniform List "+(listFieldMatcher.groupCount() == 3 ? listFieldMatcher.group(3)+" " : "" )+"( "+field); + } else if (list.getName().contains(" uniform")) {/* is a simple array (val1 val2 val3) not empty '( )' */ + parent.add(list.getName().replace("uniform", "").trim(), "uniform ( " + field); + } else if (field.startsWith("<")) {/* is a dataTable ( +++ (+++ +++ +++) ) */ + parent.add(list.getName(), "( " + field.replace("<", "(").replace(">", ")")); + } else { + field = processField(field); + parent.add(list.getName(), "( " + field); + } + simpleList = true; + } + } + if (VERBOSE) + System.out.println("END LIST"); + return; + } + } + } + } + + private String processField(String field) { + if (field.contains("|")) { + field = field.replace("|", ") ("); + } + return field; + } + + public boolean isSimpleList() { + return simpleList; + } + +} diff --git a/src/eu/engys/core/dictionary/MatrixReader.java b/src/eu/engys/core/dictionary/MatrixReader.java new file mode 100644 index 0000000..1282a35 --- /dev/null +++ b/src/eu/engys/core/dictionary/MatrixReader.java @@ -0,0 +1,98 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import static eu.engys.core.dictionary.Dictionary.VERBOSE; + +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MatrixReader { + + private FieldElement matrix; + private Dictionary parent; + + public MatrixReader(FieldElement matrix, Dictionary parent) { + this.matrix = matrix; + this.parent = parent; + } + + public void readMatrix(StringTokenizer st, Stack stack) { + while(st.hasMoreTokens()) { + String token = st.nextToken(); + token = token.trim(); //tolgo gli spazi + stack.push(token);//metto nella pila + + if (stack.peek().equals(";")) { + stack.pop(); + String field = stack.pop(); + if (VERBOSE) System.out.println(field); + + if (field.endsWith(")")) { + Pattern pattern = Pattern.compile("(\\w+)\\s+nonuniform\\s+(List)?\\s+(\\d+)?"); + Matcher matcher = pattern.matcher(matrix.getName()); + + if (matcher.matches()) { + field = processField(field); + parent.add(matcher.group(1), "nonuniform List "+(matcher.groupCount() == 3 ? matcher.group(3)+" " : "" )+"(( "+field); + } else { + field = processField(field); + parent.add(matrix.getName(), "(( "+field); + } + return; + } + } + } + } + + private String processField(String field) { + if (field.contains("|")) { + field = field.replace("|", ") ("); + } + return field; + } + + public static void matrixToVector(Dictionary dictionary, String key) { + if ( dictionary.found(key) ) { + String value = dictionary.lookupString(key); + value = value.replace("(", "").replace(")", ""); + value = "( "+value+" )"; + dictionary.add(key, value); + } + } + + public static void vectorToMatrix(Dictionary dictionary, String key) { + if ( dictionary.found(key) ) { + String value = dictionary.lookupString(key); + value = value.replace("(", "").replace(")", ""); + value = "(( "+value+" ))"; + dictionary.add(key, value); + } + } +} diff --git a/src/eu/engys/core/dictionary/StartWithFinder.java b/src/eu/engys/core/dictionary/StartWithFinder.java new file mode 100644 index 0000000..861483a --- /dev/null +++ b/src/eu/engys/core/dictionary/StartWithFinder.java @@ -0,0 +1,40 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary; + +public class StartWithFinder implements Finder { + + private String keyToFind; + + public StartWithFinder(String keyToFind) { + this.keyToFind = keyToFind; + } + + @Override + public boolean accept(String key) { + return key.startsWith(keyToFind); + } +} diff --git a/src/eu/engys/core/dictionary/TableRowElement.java b/src/eu/engys/core/dictionary/TableRowElement.java new file mode 100644 index 0000000..6eee171 --- /dev/null +++ b/src/eu/engys/core/dictionary/TableRowElement.java @@ -0,0 +1,100 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary; + +import static eu.engys.core.dictionary.Dictionary.SPACER; +import eu.engys.core.dictionary.parser.ListField2; + +public class TableRowElement extends DefaultElement { + + private ListField2 key; + private FieldElement[] values; + + public TableRowElement(ListField2 key, FieldElement... values) { + super(""); + this.key = key; + this.values = values; + } + + public TableRowElement(TableRowElement el) { + super(""); + this.key = new ListField2(el.getKey()); + this.values = copy(el.getValues()); + } + + private FieldElement[] copy(FieldElement[] values) { + FieldElement[] copy = new FieldElement[values.length]; + for (int i = 0; i < values.length; i++) { + copy[i] = new FieldElement(values[i]); + } + return copy; + } + + public void writeTableRow(StringBuffer sb, String rowHeader) { +// System.out.println("ListField2.writeListField() name: "+getName()+", size: "+size+", uniformity: "+uniformity+", identifier: "+identifier); + sb.append("\n"); + key.writeListField(sb, rowHeader); + sb.append(SPACER); + for (FieldElement f : values) { + sb.append(SPACER); + sb.append(f.getValue()); + } + } + + public ListField2 getKey() { + return key; + } + + public FieldElement[] getValues() { + return values; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TableRowElement) { + TableRowElement t = ((TableRowElement) obj); + return key.equals(t.key) /*&& valuesAreEquals(t.values)*/; + } + return super.equals(obj); + } + + private boolean valuesAreEquals(FieldElement[] values) { + if (this.values.length != values.length) { + return false; + } + for (int i = 0; i < values.length; i++) { + if (!this.values[i].equals(values[i])) { + return false; + } + } + return true; + } + + public void merge(TableRowElement el) { + this.values = el.values; + } +} diff --git a/src/eu/engys/core/dictionary/model/AbstractTableAdapter.java b/src/eu/engys/core/dictionary/model/AbstractTableAdapter.java new file mode 100644 index 0000000..d8ea2e8 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/AbstractTableAdapter.java @@ -0,0 +1,233 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.model; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSeparator; + +import eu.engys.util.ui.builder.PanelBuilder; + +public abstract class AbstractTableAdapter extends JPanel { + + public static final Integer LEAVE_ONE_LINE = 1; + + private Map rowsMap = new LinkedHashMap<>(); + + private final String[] columnLabels; + private final String rowLabel; + private PanelBuilder builder; + private final Integer linesToLeave; + protected JPanel buttonsPanel; + private boolean showColumnNames; + + public AbstractTableAdapter(String[] columnNames) { + this(columnNames, "", 0, true); + } + + public AbstractTableAdapter(String[] columnNames, String rowsLabel, Integer linesToLeave, boolean showColumnNames) { + super(new BorderLayout()); + this.rowLabel = rowsLabel; + this.columnLabels = columnNames; + this.linesToLeave = linesToLeave; + this.showColumnNames = showColumnNames; + layoutComponents(); + } + + private void layoutComponents() { + setOpaque(false); + setName("abstract.table.adapter"); + + this.builder = new PanelBuilder(); + buttonsPanel = getButtonsPanel(); + add(buttonsPanel, BorderLayout.NORTH); + add(builder.getPanel(), BorderLayout.CENTER); + clear(); + } + + private JPanel getButtonsPanel() { + JPanel buttonsPanel = new JPanel(new FlowLayout()); + buttonsPanel.setOpaque(false); + + JButton addButton = new JButton(new AddRowAction()); + addButton.setName("add.row.button"); + buttonsPanel.add(addButton); + + JButton remButton = new JButton(new RemRowAction()); + remButton.setName("rem.row.button"); + buttonsPanel.add(remButton); + return buttonsPanel; + } + + public void clear() { + rowsMap.clear(); + builder.clear(); + if(showColumnNames){ + builder.addComponent("", labelArrayField()); + builder.addFill(new JSeparator()); + } + } + + private JLabel[] labelArrayField() { + JLabel[] labels = new JLabel[columnLabels.length]; + for (int i = 0; i < labels.length; i++) { + labels[i] = new JLabel(columnLabels[i]); + } + return labels; + } + + public void hideButtonsPanel() { + buttonsPanel.setVisible(false); + } + + protected abstract void addRow(); + + protected JComponent[] addRow(JComponent[] field) { + return addRow(field, true); + } + + protected JComponent[] addRow(JComponent[] field, boolean save) { + addPropertyChangeListeners(field); + String label = rowLabel.isEmpty() ? "" : rowLabel + (rowsMap.size() + 1); + JComponent[] componentToAdd = createComponent(field); + builder.addComponent(label, componentToAdd); + setNames(rowsMap.size(), field); + updateGUI(); + rowsMap.put(rowsMap.size(), field); + if(save){ + save(); + } + return componentToAdd; + } + + private void setNames(int row, JComponent... c) { + for (int i = 0; i < c.length; i++) { + c[i].setName((rowLabel.isEmpty() ? getName() : rowLabel) + "." + columnLabels[i] + "." + row); + } + } + + protected JComponent[] createComponent(JComponent[] field) { + return field; + } + + protected void removeRow() { + if (rowsMap.size() > linesToLeave) { + removeLastRowFromMap(); + clear(); + load(); + updateGUI(); + } + } + + private void removeLastRowFromMap() { + Integer[] keys = rowsMap.keySet().toArray(new Integer[0]); + JComponent[] removedComp = rowsMap.remove(keys[keys.length - 1]); + save(); + triggerEventFor3D(removedComp); + } + + private void updateGUI() { + JPanel panel = builder.getPanel(); + panel.revalidate(); + panel.repaint(); + } + + public Map getRowsMap() { + return rowsMap; + } + + protected int elementsCount() { + return rowsMap.size(); + } + + protected abstract void load(); + + protected abstract void save(); + + protected void addPropertyChangeListeners(JComponent[] field) { + for (int i = 0; i < field.length; i++) { + JComponent f = field[i]; + if (f instanceof JCheckBox) { + ((JCheckBox) f).addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + save(); + } + }); + } else { + f.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + save(); + } + } + }); + } + } + } + + protected void triggerEventFor3D(JComponent[] comp) { + } + + private final class AddRowAction extends AbstractAction { + + private AddRowAction() { + super("+"); + } + + @Override + public void actionPerformed(ActionEvent e) { + addRow(); + } + } + + private final class RemRowAction extends AbstractAction { + private RemRowAction() { + super("-"); + } + + @Override + public void actionPerformed(ActionEvent e) { + removeRow(); + } + } + +} diff --git a/src/eu/engys/core/dictionary/model/AxisInfo.java b/src/eu/engys/core/dictionary/model/AxisInfo.java new file mode 100644 index 0000000..70da1e8 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/AxisInfo.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.model; + +import eu.engys.util.ui.textfields.DoubleField; + +public class AxisInfo { + + public static final String PROPERTY_NAME = "point.location"; + public static final String LABEL = "Point "; + private DoubleField[] center; + private EventActionType action; + private DoubleField[] axis; + + public AxisInfo(DoubleField[] axis, DoubleField[] center, EventActionType action) { + this.axis = axis; + this.center = center; + this.action = action; + } + + public DoubleField[] getAxis() { + return axis; + } + + public DoubleField[] getCenter() { + return center; + } + + public EventActionType getAction() { + return action; + } + +} diff --git a/src/eu/engys/core/dictionary/model/DictionaryModel.java b/src/eu/engys/core/dictionary/model/DictionaryModel.java new file mode 100644 index 0000000..dc35441 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/DictionaryModel.java @@ -0,0 +1,1428 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.model; + +import static eu.engys.util.ui.ComponentsFactory.checkBoxControllerField; +import static eu.engys.util.ui.ComponentsFactory.checkField; +import static eu.engys.util.ui.ComponentsFactory.comboBoxControllerField; +import static eu.engys.util.ui.ComponentsFactory.doubleArrayField; +import static eu.engys.util.ui.ComponentsFactory.doubleField; +import static eu.engys.util.ui.ComponentsFactory.doublePointField; +import static eu.engys.util.ui.ComponentsFactory.intArrayField; +import static eu.engys.util.ui.ComponentsFactory.intField; +import static eu.engys.util.ui.ComponentsFactory.listField; +import static eu.engys.util.ui.ComponentsFactory.radioField; +import static eu.engys.util.ui.ComponentsFactory.selectField; +import static eu.engys.util.ui.ComponentsFactory.spinnerField; +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JPanel; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.DimensionedScalar; +import eu.engys.core.dictionary.FieldChangeListener; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.FileFieldPanel; +import eu.engys.util.ui.ListBuilder; +import eu.engys.util.ui.ListFieldPanel; +import eu.engys.util.ui.RadioFieldPanel; +import eu.engys.util.ui.SelectionValueConfigurator; +import eu.engys.util.ui.builder.JCheckBoxController; +import eu.engys.util.ui.builder.JComboBoxController; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; +import eu.engys.util.ui.textfields.SpinnerField; +import eu.engys.util.ui.textfields.StringField; + +public class DictionaryModel { + + private static final Logger logger = LoggerFactory.getLogger(DictionaryModel.class); + + private final String key; + + private Dictionary dictionary; + private List companions = new LinkedList<>(); + + public interface DictionaryListener { + public void dictionaryChanged() throws DictionaryError; + } + + private List listeners = new CopyOnWriteArrayList(); + private Map subModels = new HashMap(); + + public static class DictionaryError extends Exception { + private String[] messages; + + public DictionaryError(String... msg) { + super(msg[0]); + this.messages = msg; + } + + public String[] getMessages() { + return messages; + } + } + + public DictionaryModel() { + this(null, new Dictionary("")); + } + + public DictionaryModel(String key) { + this(key, new Dictionary("")); + } + + public DictionaryModel(Dictionary dictionary) { + this(null, dictionary); + } + + public DictionaryModel(String key, Dictionary dictionary) { + this.key = key; + this.dictionary = dictionary; + } + + public void addCompanion(DictionaryModel companion) { + this.companions.add(companion); + } + + public void setCompanion(DictionaryModel companion) { + this.companions.clear(); + this.companions.add(companion); + } + + public List getCompanions() { + return companions; + } + + public Dictionary getDictionary() { + return dictionary; + } + + public DictionaryModel subModel(String key) { + if (subModels.containsKey(key)) { + return subModels.get(key); + } else { + Dictionary subDict = dictionary.subDict(key); + DictionaryModel model = new DictionaryModel(subDict != null ? subDict : new Dictionary(key)); + subModels.put(key, model); + return model; + } + } + + public void refresh() { + try { + fireDictionaryChange(); + } catch (DictionaryError e) { + } + } + + public void setDictionary(Dictionary dictionary) { + try { + if (dictionary != null) { + this.dictionary = dictionary; + for (String key : subModels.keySet()) { + DictionaryModel subModel = subModels.get(key); + subModel.setDictionary(dictionary.subDict(key)); + } + fireDictionaryChange(); + } + } catch (DictionaryError e) { + String[] messages = e.getMessages(); + + StringBuilder sb = new StringBuilder(); + for (String message : messages) { + sb.append(message); + sb.append("\n"); + } + // System.err.println(sb.toString()); + logger.warn(sb.toString()); + } + } + + private void fireDictionaryChange() throws DictionaryError { + List errors = new ArrayList(); + for (DictionaryListener listener : listeners) { + try { + // System.out.println("Listener: "+listener.getClass()); + // System.out.println("pre: "+dictionary); + listener.dictionaryChanged(); + // System.out.println("post: "+dictionary); + + } catch (DictionaryError e) { + errors.add(e.getMessage()); + // e.printStackTrace(); + } + } + if (!errors.isEmpty()) { + throw new DictionaryError(errors.toArray(new String[errors.size()])); + } + } + + public void addDictionaryListener(DictionaryListener listener) { + listeners.add(listener); + } + + /* + * BINDING + */ + public StringField bindLabel(String key) { + StringField field = stringField(); + field.addPropertyChangeListener(new LabelFieldHandler(key, field)); + return field; + } + + public StringField bindLabel(String key, boolean allowEmpty) { + StringField field = stringField(); + field.setToVerifier(allowEmpty, true); + field.addPropertyChangeListener(new LabelFieldHandler(key, field)); + return field; + } + + public JCheckBox bindBoolean(String key) { + JCheckBox field = checkField(); + field.addActionListener(new BooleanFieldHandler(key, field, false)); + return field; + } + + public JCheckBox bindBoolean(String key, boolean def) { + JCheckBox field = checkField(def); + field.addActionListener(new BooleanFieldHandler(key, field, def)); + return field; + } + + public JCheckBox bindBoolean(String key, String trueValue, String falseValue) { + JCheckBox field = checkField(); + field.addActionListener(new BooleanValuesFieldHandler(key, field, trueValue, falseValue)); + return field; + } + + public JCheckBox bindBoolean(String key, String trueValue, String falseValue, boolean def) { + JCheckBox field = checkField(def); + field.addActionListener(new BooleanValuesFieldHandler(key, field, trueValue, falseValue)); + return field; + } + + public SpinnerField bindSpinner(String key) { + SpinnerField field = spinnerField(); + field.addPropertyChangeListener(new SpinnerFieldHandler(key, field)); + return field; + } + + public IntegerField bindIntegerPositive(String key) { + IntegerField field = intField(0, Integer.MAX_VALUE); + field.addPropertyChangeListener(new IntFieldHandler(key, field)); + return field; + } + + public IntegerField bindIntegerNegative(String key) { + IntegerField field = intField(-Integer.MAX_VALUE, 0); + field.addPropertyChangeListener(new IntFieldHandler(key, field)); + return field; + } + + public IntegerField bindInteger(String key) { + IntegerField field = intField(-Integer.MAX_VALUE, Integer.MAX_VALUE); + field.addPropertyChangeListener(new IntFieldHandler(key, field)); + return field; + } + + public IntegerField bindInteger(String key, Integer lb, Integer ub) { + IntegerField field = intField(lb, ub); + field.addPropertyChangeListener(new IntFieldHandler(key, field)); + return field; + } + + public IntegerField bindIntegerAngle_360(String key) { + // Negative value = disabled + IntegerField field = intField(-Integer.MAX_VALUE, 359); + field.addPropertyChangeListener(new IntFieldHandler(key, field)); + return field; + } + + public IntegerField bindIntegerAngle_180(String key) { + // Negative value = disabled + IntegerField field = intField(-Integer.MAX_VALUE, 180); + field.addPropertyChangeListener(new IntFieldHandler(key, field)); + return field; + } + + // public IntegerField bindInteger(String key, String name) { + // IntegerField field = bindInteger(key); + // field.setName(name); + // return field; + // } + + public IntegerField bindIntegerLevels(String key, String mode) { + IntegerField field = intField(); + field.addPropertyChangeListener(new IntLevelsFieldHandler(key, mode, field)); + return field; + } + + public IntegerField[] bindIntegerArray(String key, Integer dimensions) { + return bindIntegerArray(key, dimensions, null); + } + + public IntegerField[] bindIntegerArray(String key, Integer dimensions, FieldChangeListener listener) { + IntegerField[] field = intArrayField(dimensions); + for (int i = 0; i < field.length; i++) { + IntegerField f = field[i]; + f.addPropertyChangeListener(new IntPointFieldHandler(key, field, listener)); + } + return field; + } + + public DoubleField bindDimensionedDouble(String key, String dimensions, Double lb, Double ub) { + DoubleField field = doubleField(lb, ub); + field.addPropertyChangeListener(new DoubleDimensionedFieldHandler(key, field, dimensions)); + return field; + } + + public DoubleField bindDimensionedDouble(String key, String dimensions) { + DoubleField field = doubleField(); + field.addPropertyChangeListener(new DoubleDimensionedFieldHandler(key, field, dimensions)); + return field; + } + + public DoubleField bindUniformDouble(String key) { + DoubleField field = doubleField(); + field.addPropertyChangeListener(new DoubleUniformFieldHandler(key, field)); + return field; + } + + // public DoubleField bindUniformDoubleWithName(String key, String name) { + // DoubleField field = doubleField(); + // field.setName(name); + // field.addPropertyChangeListener(new DoubleUniformFieldHandler(key, + // field)); + // return field; + // } + + public DoubleField bindUniformDouble(String key, double lb, double ub, double def) { + DoubleField field = doubleField(def, lb, ub); + field.addPropertyChangeListener(new DoubleUniformFieldHandler(key, field)); + return field; + } + + public DoubleField bindUniformDouble(String key, double lb, double ub) { + DoubleField field = doubleField(lb, ub); + field.addPropertyChangeListener(new DoubleUniformFieldHandler(key, field)); + return field; + } + + public DoubleField bindUniformNegativeDouble(String key) { + DoubleField field = doubleField(); + field.addPropertyChangeListener(new DoubleUniformNegativeFieldHandler(key, field)); + return field; + } + + public DoubleField bindUniformPositiveDouble(String key) { + DoubleField field = doubleField(); + field.addPropertyChangeListener(new DoubleUniformPositiveFieldHandler(key, field)); + return field; + } + + public DoubleField bindConstantDouble(String key) { + DoubleField field = doubleField(); + field.addPropertyChangeListener(new DoubleConstantFieldHandler(key, field)); + return field; + } + + public DoubleField bindUniformDouble(String key1, String key2) { + DoubleField field = doubleField(); + field.addPropertyChangeListener(new DoubleUniformFieldHandler(key1, field)); + field.addPropertyChangeListener(new DoubleUniformFieldHandler(key2, field)); + return field; + } + + public DoubleField bindDouble(String key) { + return bindDouble(key, (FieldChangeListener) null); + } + + public DoubleField bindDouble(String key, FieldChangeListener listener) { + DoubleField field = doubleField(); + field.addPropertyChangeListener(new DoubleFieldHandler(key, field, listener)); + return field; + } + + public DoubleField bindDouble(String key, Integer places, FieldChangeListener listener) { + DoubleField field = doubleField(places); + field.addPropertyChangeListener(new DoubleFieldHandler(key, field, listener)); + return field; + } + + public DoubleField bindDouble(String key, Double def) { + DoubleField field = doubleField(def); + field.addPropertyChangeListener(new DoubleFieldHandler(key, field, null)); + return field; + } + + public DoubleField bindDouble(String key, double lb, double ub) { + DoubleField field = doubleField(lb, ub); + field.addPropertyChangeListener(new DoubleFieldHandler(key, field, null)); + return field; + } + + public DoubleField bindDoublePositive(String key) { + DoubleField field = doubleField(0.0, Double.MAX_VALUE); + field.addPropertyChangeListener(new DoubleFieldHandler(key, field, null)); + return field; + } + + public DoubleField bindDoubleNegative(String key) { + DoubleField field = doubleField(-Double.MAX_VALUE, 0.0); + field.addPropertyChangeListener(new DoubleFieldHandler(key, field, null)); + return field; + } + + public DoubleField bindDoubleAngle_360(String key) { + // Negative value = disabled + DoubleField field = doubleField(-Double.MAX_VALUE, 360 - Double.MIN_VALUE); + field.addPropertyChangeListener(new DoubleFieldHandler(key, field, null)); + return field; + } + + public DoubleField bindDoubleAngle_180(String key) { + // Negative value = disabled + DoubleField field = doubleField(-Double.MAX_VALUE, 180.0); + field.addPropertyChangeListener(new DoubleFieldHandler(key, field, null)); + return field; + } + + public DoubleField[] bindPoint(String key, FieldChangeListener listener) { + DoubleField[] field = doublePointField(); + for (int i = 0; i < field.length; i++) { + DoubleField f = field[i]; + f.setName(key + "." + i); + f.addPropertyChangeListener(new PointFieldHandler(key, field, listener)); + } + return field; + } + + public DoubleField[] bindPoint(String key, Integer places, FieldChangeListener listener) { + DoubleField[] field = doublePointField(places); + for (int i = 0; i < field.length; i++) { + DoubleField f = field[i]; + f.setName(key + "." + i); + f.addPropertyChangeListener(new PointFieldHandler(key, field, listener)); + } + return field; + } + + public DoubleField[] bindPoint(String key) { + return bindPoint(key, null); + } + + public ShowLocationAdapter bindLocation(String key, int places) { + return bindLocation(key, places, Color.RED); + } + + public ShowAxisAdapter bindAxis(String key, Color colorKey) { + DoubleField[] axis = bindPoint(key, null); + DoubleField[] center = bindPoint(key, null); + return new ShowAxisAdapter(axis, center); + } + + public ShowLocationAdapter bindLocation(String key, int places, Color colorKey) { + DoubleField[] field = bindPoint(key, places, null); + return new ShowLocationAdapter(field, colorKey); + } + + public DoubleField[] bindUniformPoint(String key) { + DoubleField[] field = doublePointField(); + for (int i = 0; i < field.length; i++) { + DoubleField f = field[i]; + f.addPropertyChangeListener(new PointUniformFieldHandler(key, field)); + } + return field; + } + + // public DoubleField[] bindUniformPointWithName(String key, String name) { + // DoubleField[] field = doublePointField(); + // for (int i = 0; i < field.length; i++) { + // DoubleField f = field[i]; + // f.setName(name + "." + i); + // f.addPropertyChangeListener(new PointUniformFieldHandler(key, field)); + // } + // return field; + // } + + public DoubleField[] bindUniformPoint(String key1, String key2) { + DoubleField[] field = doublePointField(); + for (int i = 0; i < field.length; i++) { + DoubleField f = field[i]; + f.addPropertyChangeListener(new PointUniformFieldHandler(key1, field)); + f.addPropertyChangeListener(new PointUniformFieldHandler(key2, field)); + } + return field; + } + + public DoubleField[] bindDimensionedPoint(String key, String dimensions) { + DoubleField[] field = doublePointField(); + for (int i = 0; i < field.length; i++) { + DoubleField f = field[i]; + f.addPropertyChangeListener(new PointDimensionedFieldHandler(key, field, dimensions)); + } + return field; + } + + public DoubleField[] bindArray(String key, int dimensions) { + DoubleField[] field = doubleArrayField(dimensions); + for (int i = 0; i < field.length; i++) { + DoubleField f = field[i]; + f.setColumns(1); + f.setName(key + "." + i); + f.addPropertyChangeListener(new PointFieldHandler(key, field, null)); + } + return field; + } + + public FileFieldPanel bindFile(String key) { + FileFieldPanel field = ComponentsFactory.fileField(SelectionMode.FILES_ONLY, "Select file", true); + field.addPropertyChangeListener(new FileFieldHandler(key, field)); + return field; + } + + public FileFieldPanel bindFolder(String key) { + FileFieldPanel field = ComponentsFactory.fileField(SelectionMode.DIRS_ONLY, "Select folder", true); + field.addPropertyChangeListener(new FileFieldHandler(key, field)); + return field; + } + + public JComboBox bindSelection(String key) { + JComboBox combo = selectField(); + combo.addActionListener(new SelectFieldHandler(key, combo, null)); + return combo; + } + + public JComboBox bindSelection(String key, ListBuilder builder) { + JComboBox combo = selectField(builder); + combo.addActionListener(new SelectFieldHandler(key, combo, null)); + return combo; + } + + public JComboBox bindSelection(String key, String... keys) { + JComboBox combo = selectField(keys, keys); + combo.addActionListener(new SelectFieldHandler(key, combo, null)); + return combo; + } + + public JComboBox bindSelection(String key, String[] keys, String[] items) { + return bindSelection(key, keys, items, null); + } + + public JComboBox bindSelection(String key, String[] keys, String[] items, SelectionValueConfigurator configurator) { + JComboBox combo = selectField(keys, items); + combo.addActionListener(new SelectFieldHandler(key, combo, configurator)); + return combo; + } + + public JComboBoxController bindComboBoxController(String key) { + JComboBoxController combo = comboBoxControllerField(); + combo.addActionListener(new SelectFieldHandler(key, combo, null)); + return combo; + } + + public JCheckBoxController bindCheckBoxController(String key, String name) { + JCheckBoxController combo = checkBoxControllerField(name); + combo.addActionListener(new BooleanFieldHandler(key, combo, false)); + return combo; + } + + public RadioFieldPanel bindChoice(String key, String[] keys, String[] items) { + RadioFieldPanel panel = radioField(keys, items); + panel.addPropertyChangeListener(new ChoiceFieldHandler(key, panel)); + return panel; + } + + public ListFieldPanel bindList(String key, ListBuilder listBuilder) { + ListFieldPanel field = listField(listBuilder); + field.addPropertyChangeListener(new ListFieldHandler(key, field)); + return field; + } + + public PatchesMapTableAdapter bindPatchMapTable(DictionaryModel dictionaryModel, Patches targetPatches) { + return new PatchesMapTableAdapter(dictionaryModel, targetPatches); + } + + public JPanel bindTableLevels(String[] columnNames, final Class[] type) { + return new LevelsTableAdapter(this, columnNames, type); + } + + public PointTableAdapter bindPointMatrix(String[] columnNames, final String tableKey, int linesToLeave, boolean showPoint) { + return new PointTableAdapter(this, columnNames, tableKey, linesToLeave, showPoint); + } + + public JPanel bindOneDictionaryPerRowTable(String[] columnNames, final String[] columnKeys, final String tableKey, String[] rowNames, String[] rowKeys, final Class[] type) { + return new OneDictionaryPerRowTableAdapter(this, columnNames, columnKeys, rowNames, rowKeys, tableKey, type); + } + + class DoubleDimensionedFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private String dimensions; + private DoubleField field; + + public DoubleDimensionedFieldHandler(String key, DoubleField field, String dimensions) { + this.key = key; + this.field = field; + this.dimensions = dimensions; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + dictionary.add(new DimensionedScalar(key, Double.toString(field.getDoubleValue()), dimensions)); + logger.trace("DoubleFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + if (value != null) { + field.setDoubleValue(parseDouble(value)); + } else { + field.setDoubleValue(0); + } + logger.trace("DoubleFieldHandler -> read value: {}", value); + } + } + + class PointDimensionedFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private String dimensions; + private DoubleField[] field; + + public PointDimensionedFieldHandler(String key, DoubleField[] field, String dimensions) { + this.key = key; + this.field = field; + this.dimensions = dimensions; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (int i = 0; i < field.length; i++) { + sb.append(field[i].getDoubleValue()); + sb.append(" "); + } + sb.append(")"); + dictionary.add(new DimensionedScalar(key, sb.toString(), dimensions)); + logger.trace("PointDimensionedFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + if (value != null) { + String[] values = value.trim().substring(1, value.length() - 1).trim().split("\\s+"); + for (int i = 0; i < values.length; i++) { + field[i].setDoubleValue(parseDouble(values[i])); + } + } else { + for (int i = 0; i < field.length; i++) { + field[i].setDoubleValue(0); + } + } + logger.trace("PointDimensionedFieldHandler -> value: {}", value); + } + + } + + class LabelFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private StringField field; + + public LabelFieldHandler(String key, StringField field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + if (field.getValue() == null) { + if (dictionary.found(key)) + dictionary.remove(key); + } else { + dictionary.add(key, field.getStringValue()); + } + logger.trace("LabelFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + field.setValue(value); + logger.trace("LabelFieldHandler -> value: {}", value); + } + } + + class ListFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private ListFieldPanel field; + + public ListFieldHandler(String key, ListFieldPanel field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + String value = DictionaryUtils.stringArray2String(field.getValues()); + dictionary.add(key, value); + logger.trace("ListFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + if (dictionary.isField(key)) { + String value = dictionary.lookup(key); + String[] values = DictionaryUtils.string2StringArray(value); + field.setValues(values); + logger.trace("ListFieldHandler -> value: {}", value); + } else { + field.setValues(new String[0]); + } + } + } + + class ChoiceFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private RadioFieldPanel field; + + public ChoiceFieldHandler(String key, RadioFieldPanel field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + dictionary.add(key, field.getSelectedKey()); + logger.trace("ChoiceFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + field.select(value); + logger.trace("ChoiceFieldHandler -> value: {}", value); + } + } + + class SpinnerFieldHandler implements PropertyChangeListener, DictionaryListener { + public SpinnerFieldHandler(String key, SpinnerField field) { + // TODO Auto-generated constructor stub + } + + @Override + public void dictionaryChanged() throws DictionaryError { + // TODO Auto-generated method stub + + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + // TODO Auto-generated method stub + + } + } + + class IntFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private IntegerField field; + + public IntFieldHandler(String key, IntegerField field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + if (field.getValue() == null) { + if (dictionary.found(key)) + dictionary.remove(key); + } else { + dictionary.add(key, Integer.toString(field.getIntValue())); + } + logger.trace("IntegerFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + if (value != null) { + field.setIntValue(parseInt(value)); + } else { + field.setValue(null); + } + logger.trace("IntegerFieldHandler -> value: {}", value); + } + } + + class IntLevelsFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private IntegerField field; + private String mode; + + public IntLevelsFieldHandler(String key, String mode, IntegerField field) { + this.key = key; + this.mode = mode; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + String lookupMode = dictionary.lookup("mode"); + if (mode.equals(lookupMode)) { + if (field.getValue() == null) { + if (dictionary.found(key)) + dictionary.remove(key); + } else { + dictionary.add(key, String.format("(( 1E5 %s ))", Integer.toString(field.getIntValue()))); + } + logger.trace("IntegerFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String lookupMode = dictionary.lookup("mode"); + if (lookupMode != null) { + if (mode.equals(lookupMode)) { + String value = dictionary.lookup(key); + if (value != null && value.length() > 4) { + String[] values = value.trim().substring(2, value.length() - 2).trim().split("\\s+"); + field.setIntValue(parseInt(values[1])); + } else { + field.setValue(null); + } + logger.trace("IntegerFieldHandler -> value: {}", value); + } else { + field.setValue(null); + } + } else { + field.setValue(null); + } + } + } + + class IntPointFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private IntegerField[] field; + private FieldChangeListener listener; + + public IntPointFieldHandler(String key, IntegerField[] field, FieldChangeListener listener) { + this.key = key; + this.field = field; + this.listener = listener; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (int i = 0; i < field.length; i++) { + if (field[i].getValue() != null) { + sb.append(field[i].getIntValue()); + sb.append(" "); + } else { + if (dictionary.found(key)) + dictionary.remove(key); + return; + } + } + sb.append(")"); + dictionary.add(key, sb.toString()); + logger.trace("PointFieldHandler -> value: {}", dictionary.lookup(key)); + if (listener != null) { + listener.fieldChanged(); + } + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + if (listener != null) { + listener.setAdjusting(true); + } + if (value != null) { + String[] values = value.trim().substring(1, value.length() - 1).trim().split("\\s+"); + for (int i = 0; i < values.length; i++) { + field[i].setIntValue(parseInt(values[i])); + } + logger.trace("PointFieldHandler -> value: {}", value); + } else { + for (int i = 0; i < field.length; i++) { + field[i].setValue(null); + } + } + if (listener != null) { + listener.setAdjusting(false); + } + } + } + + class DoubleFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private DoubleField field; + private FieldChangeListener listener; + + public DoubleFieldHandler(String key, DoubleField field, FieldChangeListener listener) { + this.key = key; + this.field = field; + this.listener = listener; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + if (field.getValue() == null) { + if (dictionary.found(key)) + dictionary.remove(key); + } else { + dictionary.add(key, Double.toString(field.getDoubleValue())); + logger.trace("DoubleFieldHandler -> value: {}", dictionary.lookup(key)); + if (listener != null) { + listener.fieldChanged(); + } + } + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + if (listener != null) + listener.setAdjusting(true); + if (value != null) { + field.setDoubleValue(parseDouble(value)); + } else { + field.setValue(field.getDefaultValue()); + } + if (listener != null) + listener.setAdjusting(false); + + logger.trace("DoubleFieldHandler -> value: {}", value); + } + } + + class DoubleUniformFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private DoubleField field; + + public DoubleUniformFieldHandler(String key, DoubleField field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + if (!Double.isInfinite(field.getDoubleValue())) { + dictionary.add(key, "uniform " + Double.toString(field.getDoubleValue())); + logger.trace("DoubleUniformFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); // uniform value + logger.trace("DoubleUniformFieldHandler -> value: {}", value); + if (value != null) { + if (value.startsWith("nonuniform")) { + field.setDoubleValue(Double.POSITIVE_INFINITY); + } else { + value = value.replace("uniform ", ""); + field.setDoubleValue(parseDouble(value)); + } + } else { + field.setDoubleValue(field.getDefaultValue()); + } + } + } + + class DoubleUniformNegativeFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private DoubleField field; + + public DoubleUniformNegativeFieldHandler(String key, DoubleField field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + dictionary.add(key, "uniform " + Double.toString(-Math.abs(field.getDoubleValue()))); + logger.trace("DoubleUniformFieldHandler -> " + dictionary.toString()); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); // uniform value + logger.trace("DoubleUniformFieldHandler -> value: " + value); + if (value != null) { + value = value.replace("uniform ", ""); + field.setDoubleValue(Math.abs(parseDouble(value))); + } else { + field.setDoubleValue(field.getDefaultValue()); + } + } + } + + class DoubleUniformPositiveFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private DoubleField field; + + public DoubleUniformPositiveFieldHandler(String key, DoubleField field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + dictionary.add(key, "uniform " + Double.toString(Math.abs(field.getDoubleValue()))); + logger.trace("DoubleUniformFieldHandler -> " + dictionary.toString()); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); // uniform value + logger.trace("DoubleUniformFieldHandler -> value: " + value); + if (value != null) { + value = value.replace("uniform ", ""); + field.setDoubleValue(Math.abs(parseDouble(value))); + } else { + field.setDoubleValue(field.getDefaultValue()); + } + } + } + + class DoubleConstantFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private DoubleField field; + + public DoubleConstantFieldHandler(String key, DoubleField field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + dictionary.add(key, "constant " + Double.toString(field.getDoubleValue())); + logger.trace("DoubleUniformFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); // uniform value + logger.trace("DoubleUniformFieldHandler -> value: {}", value); + if (value != null) { + value = value.replace("constant ", ""); + field.setDoubleValue(parseDouble(value)); + } else { + field.setDoubleValue(field.getDefaultValue()); + } + } + } + + class BooleanFieldHandler implements ActionListener, DictionaryListener { + + private JCheckBox check; + private String key; + private final boolean def; + + public BooleanFieldHandler(String key, JCheckBox check, boolean def) { + this.check = check; + this.key = key; + this.def = def; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void actionPerformed(ActionEvent e) { + boolean selected = check.isSelected(); + dictionary.add(key, selected ? "true" : "false"); + logger.trace("BooleanFieldHandler -> value: {}", dictionary.lookup(key)); + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + String correctedForYesNo = value == null ? String.valueOf(def) : value.equals("yes") ? "true" : value.equals("no") ? "false" : value; + boolean b = Boolean.parseBoolean(correctedForYesNo); + if (b != check.isSelected()) { + check.doClick(); + check.setSelected(b); + } + logger.trace("BooleanFieldHandler -> value: {}", value); + } + } + + class BooleanValuesFieldHandler implements ActionListener, DictionaryListener { + + private JCheckBox check; + private String key; + private final String trueValue; + private final String falseValue; + + public BooleanValuesFieldHandler(String key, JCheckBox check, String trueValue, String falseValue) { + this.check = check; + this.key = key; + this.trueValue = trueValue; + this.falseValue = falseValue; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void actionPerformed(ActionEvent e) { + boolean selected = check.isSelected(); + dictionary.add(key, selected ? trueValue : falseValue); + logger.trace("BooleanValuesFieldHandler -> value: {}", dictionary.lookup(key)); + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + boolean selected = value != null && value.equals(trueValue); + if (shouldClick(selected, check.isSelected())) { + check.doClick(); + } + logger.trace("BooleanValuesFieldHandler -> value: {}", value); + } + + private boolean shouldClick(boolean select, boolean isSelected) { + return (isSelected && !select) || (!isSelected && select); + } + } + + class FileFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private FileFieldPanel field; + + public FileFieldHandler(String key, FileFieldPanel field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + if (field.getFilePath() != null && !field.getFilePath().isEmpty()) { + String value = "\"" + field.getFilePath() + "\""; + dictionary.add(key, value); + logger.trace("FileFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + loadFromDictionary(); + } + + private void loadFromDictionary() { + String value = dictionary.lookup(key); + if (value != null) { + value = value.replace("\"", ""); + File file = new File(value); + if (file.exists()) { + field.setFile(file); + } else { + field.setFile(new File("")); + // throw new DictionaryError("File doesn't exist: " + + // value); + } + } else { + field.setFile(new File("")); + } + } + } + + class PointFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private DoubleField[] field; + private FieldChangeListener listener; + + public PointFieldHandler(String key, DoubleField[] field, FieldChangeListener listener) { + this.key = key; + this.field = field; + this.listener = listener; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (int i = 0; i < field.length; i++) { + if (field[i].getValue() != null) { + sb.append(field[i].getDoubleValue()); + sb.append(" "); + } else { + sb.append("0 "); + } + } + sb.append(")"); + dictionary.add(key, sb.toString()); + logger.trace("PointFieldHandler -> value: {}", dictionary.lookup(key)); + if (listener != null) { + listener.fieldChanged(); + } + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + if (listener != null) + listener.setAdjusting(true); + if (value != null && !value.isEmpty()) { + try { + String[] values = value.trim().substring(1, value.length() - 1).trim().split("\\s+"); + for (int i = 0; i < values.length; i++) { + field[i].setDoubleValue(parseDouble(values[i])); + } + } catch (ArrayIndexOutOfBoundsException e) { + } + logger.trace("PointFieldHandler -> value: {}", value); + } else { + for (int i = 0; i < field.length; i++) { + field[i].setDoubleValue(0); + } + } + if (listener != null) + listener.setAdjusting(false); + } + } + + class PointUniformFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private DoubleField[] field; + + public PointUniformFieldHandler(String key, DoubleField[] field) { + this.key = key; + this.field = field; + DictionaryModel.this.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + for (int i = 0; i < field.length; i++) { + if (Double.isInfinite(field[i].getDoubleValue())) { + return; + } + } + StringBuilder sb = new StringBuilder(); + sb.append("uniform ("); + for (int i = 0; i < field.length; i++) { + sb.append(field[i].getDoubleValue()); + sb.append(" "); + } + sb.append(")"); + dictionary.add(key, sb.toString()); + logger.trace("PointFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + String value = dictionary.lookup(key); + if (value != null) { + if (value.startsWith("nonuniform")) { + for (int i = 0; i < field.length; i++) { + field[i].setDoubleValue(Double.POSITIVE_INFINITY); + } + } else { + value = value.replace("uniform ", ""); + String[] values = value.trim().substring(1, value.length() - 1).trim().split("\\s+"); + for (int i = 0; i < values.length; i++) { + field[i].setDoubleValue(parseDouble(values[i])); + } + } + logger.trace("PointFieldHandler -> value: {}", value); + } else { + for (int i = 0; i < field.length; i++) { + field[i].setDoubleValue(0); + } + } + } + } + + class SelectFieldHandler implements ActionListener, DictionaryListener { + + private JComboBox combo; + private String key; + private SelectionValueConfigurator configurator; + + public SelectFieldHandler(String key, JComboBox combo, SelectionValueConfigurator configurator) { + this.combo = combo; + this.key = key; + this.configurator = configurator; + DictionaryModel.this.addDictionaryListener(this); + try { + loadFromDictionary(); + } catch (DictionaryError e) { + // e.printStackTrace(); + } + } + + @Override + public void actionPerformed(ActionEvent e) { + Object item; + if (combo instanceof JComboBoxController) { + item = ((JComboBoxController) combo).getSelectedKey(); + } else { + item = combo.getSelectedItem(); + } + if (item != null && item instanceof String) { + String value = (String) item; + if (configurator != null) + value = configurator.write(value); + if (value != null) + dictionary.add(key, value); + logger.trace("SelectFieldHandler -> value: {}", dictionary.lookup(key)); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + loadFromDictionary(); + } + + public void loadFromDictionary() throws DictionaryError { + if (dictionary.found(key)) { + String value = dictionary.lookup(key); + if (configurator != null) + value = configurator.read(value); + + if (combo instanceof JComboBoxController) { + ((JComboBoxController) combo).setSelectedKey(value); + } else if (contains(value)) { + combo.setSelectedItem(value); + } else if (value == null || "".equals(value)) { + combo.setSelectedIndex(-1); + } else if (combo.getItemCount() > 0) { + combo.setSelectedIndex(0); + throw new DictionaryError(String.format("Missing %s value. Set to %s", value, combo.getItemAt(0))); + } + + logger.trace("SelectFieldHandler -> value: {}", value); + } else { + combo.setSelectedIndex(-1); + // throw new + // DictionaryError(String.format("Missing %s key in %s dictionary", + // key, dictionary.getName())); + } + } + + private boolean contains(String value) { + for (int i = 0; i < combo.getItemCount(); i++) { + if (value.equals(combo.getItemAt(i))) { + return true; + } + } + return false; + } + + } + + public String getKey() { + return key != null ? key : String.valueOf(hashCode()); + } + + private double parseDouble(String value) { + try { + return Double.parseDouble(value); + } catch (Exception e) { + return 0; + } + } + + private int parseInt(String value) { + try { + return Double.valueOf(value).intValue(); + } catch (Exception e) { + return 0; + } + } +} diff --git a/src/eu/engys/core/dictionary/model/DictionaryPanelBuilder.java b/src/eu/engys/core/dictionary/model/DictionaryPanelBuilder.java new file mode 100644 index 0000000..eb695b8 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/DictionaryPanelBuilder.java @@ -0,0 +1,206 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.model; + +import static eu.engys.core.dictionary.Dictionary.TYPE; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.ui.builder.GroupController; +import eu.engys.util.ui.builder.PanelBuilder; + +public class DictionaryPanelBuilder extends PanelBuilder { + + private static final Logger logger = LoggerFactory.getLogger(DictionaryPanelBuilder.class); + + private DictionaryModel selectedModel; + private Map modelsByKey = new HashMap(); + private Map dictionarySelectors = new HashMap(); + + private boolean selectModelAfterSelection = true; + + public DictionaryPanelBuilder() { + super(); + } + + public DictionaryPanelBuilder(String name) { + super(name); + } + + public void startDictionary(String groupName, DictionaryModel model) { + String groupKey = model.getKey(); + + startGroup(groupKey, groupName); + + modelsByKey.put(groupKey, model); + dictionarySelectors.put(groupKey, new DictionarySelector(controllers, groups)); + + checkForParent(); + } + + public void endDictionary() { + modelsByKey.get(groups.peek().groupKey).refresh(); + endGroup(); + } + + public DictionaryModel getSelectedModel() { + return selectedModel; + } + + private void setSelectedModel(DictionaryModel selectedModel) { + if (selectedModel != null) { + this.selectedModel = selectedModel; + } + } + + public void selectDictionaries(Dictionary newDictionary, Dictionary newCompanion) { + String newName = newDictionary.getName(); + String newType = newDictionary.lookup(TYPE); + String newCompanionType = newCompanion.lookup(TYPE); + // System.out.println("ChoicePanelBuilder.selectDictionary() NEW TYPE: "+newType+" NEW NAME: "+newName+" NEW COMPANION TYPE: "+newCompanionType); + // System.out.println("-------------------"); + for (String key : modelsByKey.keySet()) { + DictionaryModel model = modelsByKey.get(key); + Dictionary oldDictionary = model.getDictionary(); + if (model.getCompanions().size() > 0) { + Dictionary oldCompanion = model.getCompanions().get(0).getDictionary(); + String oldName = oldDictionary.getName(); + String oldType = oldDictionary.lookup(TYPE); + String oldCompanionType = oldCompanion.lookup(TYPE); + // System.out.println("DictionaryPanelBuilder.selectDictionaries() OLD TYPE: "+oldType+" OLD NAME: "+oldName+" OLD COMPANION TYPE: "+oldCompanionType); + + if (newName.equals(oldName) && newType.equals(oldType) && newCompanionType.equals(oldCompanionType)) { + // System.out.println("DictionaryPanelBuilder.selectDictionaries() FOUND"); + dictionarySelectors.get(key).select(); + selectedModel.setDictionary(newDictionary); + + DictionaryModel companion = selectedModel.getCompanions().get(0); + if (companion != null) { + companion.setDictionary(newCompanion); + } + return; + } + } + } + // System.out.println("DictionaryPanelBuilder.selectDictionaries() NOT FOUND"); + } + + public void selectDictionary(Dictionary newDictionary) { + if (newDictionary != null /* && newDictionary.found(TYPE) */) { + String newName = newDictionary.getName(); + String newType = newDictionary.lookup(TYPE); + + // System.out.println("DictionaryPanelBuilder.selectDictionary() NEW TYPE: "+newType+" NEW NAME: "+newName); + if (newName != null && newType != null) { + for (String key : modelsByKey.keySet()) { + DictionaryModel model = modelsByKey.get(key); + if (model.getCompanions().size() == 0) { + Dictionary oldDictionary = model.getDictionary(); + String oldName = oldDictionary.getName(); + String oldType = oldDictionary.lookup(TYPE); + + // System.out.println("DictionaryPanelBuilder.selectDictionary() OLD TYPE: "+oldType+" OLD NAME: "+oldName); + + if (newName.equals(oldName) && newType.equals(oldType)) { + // System.out.println("DictionaryPanelBuilder.selectDictionary() FOUND"); + dictionarySelectors.get(key).select(); + selectedModel.setDictionary(newDictionary); + return; + } + } + } + logger.warn("NOT FOUND: if the model you are trying to select has a companion, use the metod 'selectDictionaries(dictionary,companion) ' instead"); + } else { + logger.warn("DICTIONARY NAME OR TYPE ARE NULL. NAME: {}, TYPE: {}", newName, newType); + } + } else { + logger.warn("NULL DICTIONARY"); + } + } + + public void setShowing(String hideable, String group) { + selectModelAfterSelection = false; + super.setShowing(hideable, group); + selectModelAfterSelection = true; + } + + public void selectDictionaryByModel(DictionaryModel model, Dictionary newDictionary) { + String key = model.getKey(); + dictionarySelectors.get(key).select(); + selectedModel.setDictionary(newDictionary); + } + + public void selectDictionaryByKey(String key, Dictionary newDictionary) { + dictionarySelectors.get(key).select(); + selectedModel.setDictionary(newDictionary); + } + + @Override + protected void afterSelection(String selectedKey) { + super.afterSelection(selectedKey); + DictionaryModel model = modelsByKey.get(selectedKey); + // System.out.println("DictionaryPanelBuilder.afterSelection() "+selectedKey); + if (model != null && selectModelAfterSelection) { + setSelectedModel(model); + model.refresh(); + if (model.getCompanions().size() > 0) { + model.getCompanions().get(0).refresh(); + } + } else { + // System.err.println("setSelectedModel -> -> -> -> -> -> Model is NULLLL"); + } + } + + class DictionarySelector { + + private List controllersStack = new ArrayList(); + private List groupsStack = new ArrayList(); + + public DictionarySelector(Stack controllers, Stack groups) { + this.controllersStack.addAll(controllers); + this.groupsStack.addAll(groups); + } + + public void select() { + for (int i = 0; i < controllersStack.size(); i++) { + GroupController controller = controllersStack.get(i); + KeydRowGroup group = groupsStack.get(i); + // System.out.println("DictionaryPanelBuilder.DictionarySelector.select() ["+i+"] "+group.groupKey); + controller.setSelectedKey(group.groupKey); + } + } + + } + +} diff --git a/src/eu/engys/core/dictionary/model/DictionaryTableAdapter.java b/src/eu/engys/core/dictionary/model/DictionaryTableAdapter.java new file mode 100644 index 0000000..dfbea5a --- /dev/null +++ b/src/eu/engys/core/dictionary/model/DictionaryTableAdapter.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.model; + +import eu.engys.core.dictionary.model.DictionaryModel.DictionaryListener; + +public abstract class DictionaryTableAdapter extends AbstractTableAdapter { + + protected DictionaryModel dictionaryModel; + + public DictionaryTableAdapter(DictionaryModel dictionaryModel, String[] columnNames) { + super(columnNames); + this.dictionaryModel = dictionaryModel; + dictionaryModel.addDictionaryListener(new DictionaryListener() { + @Override + public void dictionaryChanged() { + clear(); + load(); + } + }); + } + + public DictionaryTableAdapter(DictionaryModel dictionaryModel, String[] columnNames, String rowsLabel, Integer linesToLeave, boolean showColumnNames) { + super(columnNames, rowsLabel, linesToLeave, showColumnNames); + this.dictionaryModel = dictionaryModel; + dictionaryModel.addDictionaryListener(new DictionaryListener() { + @Override + public void dictionaryChanged() { + clear(); + load(); + } + }); + } + + public void setDictionaryModel(DictionaryModel dictionaryModel) { + this.dictionaryModel = dictionaryModel; + } + +} diff --git a/src/eu/engys/core/dictionary/model/EventActionType.java b/src/eu/engys/core/dictionary/model/EventActionType.java new file mode 100644 index 0000000..086d797 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/EventActionType.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.model; + +public enum EventActionType { + SHOW, HIDE, REMOVE; + + public void isShow() { + this.equals(SHOW); + } + + public void isHide() { + this.equals(HIDE); + } + + public void isRemove() { + this.equals(REMOVE); + } +} diff --git a/src/eu/engys/core/dictionary/model/LevelsTableAdapter.java b/src/eu/engys/core/dictionary/model/LevelsTableAdapter.java new file mode 100644 index 0000000..4adb732 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/LevelsTableAdapter.java @@ -0,0 +1,129 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.swing.JComponent; +import javax.swing.JTextField; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; + +public class LevelsTableAdapter extends DictionaryTableAdapter { + + protected final String[] columnNames; + private static final String DICTKEY = "levels"; + private static final String MODE = "distance"; + private final Class[] type; + + public LevelsTableAdapter(DictionaryModel dictionaryModel, String[] names, final Class[] type) { + super(dictionaryModel, names); + this.columnNames = names; + this.type = type; + } + + @Override + protected void addRow() { + JTextField[] fields = new JTextField[2]; + fields[0] = new DoubleField(); + fields[1] = new IntegerField(); + addRow(fields); + } + + @Override + public void load() { + Dictionary dictionary = dictionaryModel.getDictionary(); + if (MODE.equals(dictionary.lookup("mode")) && dictionary.isField(DICTKEY)) { + String value = dictionary.lookup(DICTKEY); + if (value != null && value.startsWith("(") && value.endsWith(")")) { + value = value.substring(1, value.length() - 1); + try { + Pattern regex = Pattern.compile("\\((\\s*\\d+\\.?\\d+)\\s*(\\d+\\s*)\\)"); + Matcher regexMatcher = regex.matcher(value); + while (regexMatcher.find()) { + JTextField[] row = new JTextField[type.length]; + for (int j = 1; j <= regexMatcher.groupCount(); j++) { + String cellValue = regexMatcher.group(j).trim(); + int i = j - 1; + Class klass = type[i]; + if (klass == Integer.class) { + row[i] = new IntegerField(); + ((IntegerField) row[i]).setIntValue(Integer.valueOf(cellValue)); + } else if (klass == Double.class) { + row[i] = new DoubleField(); + ((DoubleField) row[i]).setDoubleValue(Double.valueOf(cellValue)); + } else { + row[i] = new JTextField(); + } + } + addRow(row); + } + } catch (PatternSyntaxException ex) { + // Syntax error in the regular expression + } + } + } + } + + @Override + protected void save() { + if (getRowsMap().isEmpty()) { + dictionaryModel.getDictionary().remove(DICTKEY); + return; + } + StringBuilder sb = new StringBuilder(); + sb.append("( "); + + TreeMap orderedMap = getOrderedMap(); + for (Integer key : orderedMap.descendingKeySet()) { + sb.append("( "); + sb.append(orderedMap.get(key)); + sb.append(" "); + sb.append(key); + sb.append(" )"); + sb.append(" "); + } + sb.append(")"); + dictionaryModel.getDictionary().add(DICTKEY, sb.toString()); + } + + private TreeMap getOrderedMap() { + Map map = new HashMap<>(); + for (JComponent[] row : getRowsMap().values()) { + map.put(((IntegerField) row[1]).getIntValue(), ((DoubleField) row[0]).getDoubleValue()); + } + return new TreeMap(map); + } + +} diff --git a/src/eu/engys/core/dictionary/model/LinesTableAdapter.java b/src/eu/engys/core/dictionary/model/LinesTableAdapter.java new file mode 100644 index 0000000..1dfa915 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/LinesTableAdapter.java @@ -0,0 +1,191 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.model; + +import java.awt.BorderLayout; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; + +public class LinesTableAdapter extends DictionaryTableAdapter { + + private static final String LEVELS = "levels"; + private static final String LEVEL = "level"; + private Dictionary lineDictionary; + private final Class[] type; + + public LinesTableAdapter(DictionaryModel dictionaryModel, Dictionary lineDictionary, String[] columnNames, final Class[] type) { + super(dictionaryModel, columnNames, "", LEAVE_ONE_LINE, true); + this.lineDictionary = lineDictionary; + this.type = type; + fixOldStyleLevels(); + } + + public JButton getButton() { + JButton b = new JButton(new AbstractAction("Edit") { + @Override + public void actionPerformed(ActionEvent e) { + getDialog().setVisible(true); + } + + }); + return b; + } + + private JDialog getDialog() { + final JDialog dialog = new JDialog(UiUtil.getActiveWindow(), "Refinement Level", ModalityType.MODELESS); + dialog.setName("line.adapter.dialog"); + + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + JButton okButton = new JButton(new AbstractAction("OK") { + @Override + public void actionPerformed(ActionEvent e) { + save(); + dialog.setVisible(false); + } + }); + okButton.setName("OK"); + buttonsPanel.add(okButton); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(new JScrollPane(this), BorderLayout.CENTER); + mainPanel.add(buttonsPanel, BorderLayout.SOUTH); + + dialog.add(mainPanel); + dialog.setSize(600, 400); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.getRootPane().setDefaultButton(okButton); + return dialog; + } + + private void fixOldStyleLevels() { + if (lineDictionary.found(LEVEL)) { + Dictionary clone = new Dictionary(lineDictionary); + String levelValue = clone.lookup(LEVEL); + clone.remove(LEVEL); + clone.add(LEVELS, "( ( 0.0 " + levelValue + " ) )"); + this.lineDictionary = clone; + } + } + + public Dictionary getLineDictionary() { + return lineDictionary; + } + + @Override + protected void addRow() { + JTextField[] fields = new JTextField[2]; + fields[0] = new DoubleField(); + fields[1] = new IntegerField(); + addRow(fields); + } + + @Override + public void load() { + String value = lineDictionary.lookup(LEVELS); + if (value != null && value.startsWith("(") && value.endsWith(")")) { + value = value.substring(1, value.length() - 1); + try { + Pattern regex = Pattern.compile("\\((\\s*\\d+\\.?\\d+)\\s*(\\d+\\s*)\\)"); + Matcher regexMatcher = regex.matcher(value); + while (regexMatcher.find()) { + JTextField[] row = new JTextField[type.length]; + for (int j = 1; j <= regexMatcher.groupCount(); j++) { + String cellValue = regexMatcher.group(j).trim(); + int i = j - 1; + Class klass = type[i]; + if (klass == Integer.class) { + row[i] = new IntegerField(); + ((IntegerField) row[i]).setIntValue(Integer.valueOf(cellValue)); + } else if (klass == Double.class) { + row[i] = new DoubleField(); + ((DoubleField) row[i]).setDoubleValue(Double.valueOf(cellValue)); + } else { + row[i] = new JTextField(); + } + } + addRow(row); + } + } catch (PatternSyntaxException ex) { + ex.printStackTrace(); + } + } + if (getRowsMap().isEmpty()) { + addRow(); + } + } + + @Override + protected void save() { + if (getRowsMap().isEmpty()) { + lineDictionary.remove(LEVELS); + return; + } + StringBuilder sb = new StringBuilder(); + TreeMap orderedMap = getOrderedMap(); + sb.append("( "); + for (Integer key : orderedMap.descendingKeySet()) { + sb.append("( "); + sb.append(orderedMap.get(key)); + sb.append(" "); + sb.append(key); + sb.append(" )"); + sb.append(" "); + } + sb.append(")"); + lineDictionary.add(LEVELS, sb.toString()); + } + + private TreeMap getOrderedMap() { + Map map = new HashMap<>(); + for (JComponent[] row : getRowsMap().values()) { + map.put(((IntegerField) row[1]).getIntValue(), ((DoubleField) row[0]).getDoubleValue()); + } + return new TreeMap(map); + } + +} diff --git a/src/eu/engys/core/dictionary/model/OneDictionaryPerRowTableAdapter.java b/src/eu/engys/core/dictionary/model/OneDictionaryPerRowTableAdapter.java new file mode 100644 index 0000000..c049afa --- /dev/null +++ b/src/eu/engys/core/dictionary/model/OneDictionaryPerRowTableAdapter.java @@ -0,0 +1,188 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.model; + +import static eu.engys.util.Symbols.DOT; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; +import eu.engys.util.ui.textfields.StringField; + +public class OneDictionaryPerRowTableAdapter extends DictionaryTableAdapter { + + private final int NAME_COL = 0; + protected final String[] columnNames; + protected final String[] columnKeys; + protected final String[] rowNames; + protected final String[] rowKeys; + protected final String dictKey; + + protected final Class[] type; + + public static void main(String[] args) { + String[] columnNames = { "Name", "Thickness [m]", "Conductivity [W/K" + DOT + "m]" }; + String[] columnKeys = { "thickness", "lambda" }; + Class[] type = { String.class, Double.class, Double.class }; + + JPanel table = new OneDictionaryPerRowTableAdapter(new DictionaryModel(), columnNames, columnKeys, null, null, "layers", type); + JFrame f = UiUtil.defaultTestFrame("test", table); + f.setSize(600, 600); + f.setVisible(true); + } + + public OneDictionaryPerRowTableAdapter(DictionaryModel dictionaryModel, String[] columnNames, String[] columnKeys, String[] rowNames, String[] rowKeys, String key, Class[] type) { + super(dictionaryModel, columnNames); + this.columnNames = columnNames; + this.columnKeys = columnKeys; + this.rowNames = rowNames; + this.rowKeys = rowKeys; + this.dictKey = key; + this.type = type; + + setName("one.dict.row"); + + if (isStaticTable()) { + setRowHeader(); + hideButtonsPanel(); + } + } + + @Override + protected void addRow() { + if (!isStaticTable()) { + JTextField[] row = new JTextField[type.length]; + for (int i = 0; i < type.length; i++) { + Class klass = type[i]; + if (klass == Integer.class) { + row[i] = new IntegerField(); + ((IntegerField) row[i]).setIntValue(Integer.valueOf(0)); + } else if (klass == Double.class) { + row[i] = new DoubleField(); + ((DoubleField) row[i]).setDoubleValue(Integer.valueOf(0)); + } else if (klass == String.class) { + row[i] = new StringField("name" + (getRowsMap().size() + 1)); + } else { + row[i] = new StringField(""); + } + } + addRow(row); + } + } + + private boolean isStaticTable() { + return rowNames != null; + } + + public void setRowHeader() { + for (int i = 0; i < rowNames.length; i++) { + JComponent[] row = new JComponent[columnKeys.length + 1]; + row[0] = new JLabel(rowNames[i]); + for (int j = 1; j < row.length; j++) { + Class klass = type[j]; + if (klass == Integer.class) { + row[j] = new IntegerField(); + ((IntegerField) row[j]).setIntValue(Integer.valueOf(0)); + } else if (klass == Double.class) { + row[j] = new DoubleField(); + ((DoubleField) row[j]).setDoubleValue(Double.valueOf(0)); + } else { + row[j] = new JLabel(""); + } + } + addRow(row, false); + } + } + + @Override + public void load() { + if (dictionaryModel.getDictionary().found(dictKey)) { + Dictionary dict = dictionaryModel.getDictionary().subDict(dictKey); + if (isStaticTable() && dict.getDictionaries().size() != rowKeys.length) { + setRowHeader(); + } else { + int rowIndex = 0; + for (Dictionary d : dict.getDictionaries()) { + JComponent[] row = new JComponent[columnKeys.length + 1]; + if (isStaticTable()) + row[0] = new JLabel(rowKeys[rowIndex]); + else + row[0] = new StringField(d.getName()); + + for (int k = 0; k < columnKeys.length; k++) { + String value = d.lookup(columnKeys[k]); + int j = k + 1; + if (value == null) + row[j] = new JTextField("0"); + else if (type[j] == Double.class) { + row[j] = new DoubleField(); + ((DoubleField) row[j]).setDoubleValue(Double.valueOf(value)); + } else if (type[j] == Integer.class) { + row[j] = new IntegerField(); + ((IntegerField) row[j]).setIntValue(Integer.valueOf(value)); + } else { + row[j] = new JLabel(value); + } + } + addRow(row); + rowIndex++; + } + } + } + } + + @Override + protected void save() { + Dictionary layers = new Dictionary(dictKey); + for (int r = 0; r < getRowsMap().values().size(); r++) { + String name; + if (isStaticTable()) { + name = rowKeys[r]; + } else { + JComponent[][] fields = getRowsMap().values().toArray(new JComponent[0][0]); + name = String.valueOf(((JTextField) fields[r][NAME_COL]).getText()); + } + + Dictionary layer = new Dictionary(name); + for (int k = 0; k < columnKeys.length; k++) { + JComponent[][] fields = getRowsMap().values().toArray(new JComponent[0][0]); + String value = String.valueOf(((JTextField) fields[r][k + 1]).getText()); + layer.add(columnKeys[k], value); + } + layers.add(layer); + } + dictionaryModel.getDictionary().add(layers); + } + +} diff --git a/src/eu/engys/core/dictionary/model/PatchesMapTableAdapter.java b/src/eu/engys/core/dictionary/model/PatchesMapTableAdapter.java new file mode 100644 index 0000000..0d1eb13 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/PatchesMapTableAdapter.java @@ -0,0 +1,162 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.model; + +import static eu.engys.core.project.system.MapFieldsDict.PATCH_MAP_KEY; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JComboBox; +import javax.swing.JOptionPane; + +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.util.ui.UiUtil; + +public class PatchesMapTableAdapter extends DictionaryTableAdapter { + + private Patches sourcePatches = new Patches(); + private Patches targetPatches; + private ActionListener sourceListener; + private ActionListener targetListener; + + public PatchesMapTableAdapter(DictionaryModel dictionaryModel, Patches targetPatches) { + super(dictionaryModel, new String[] { "Source", "Target" }); + this.targetPatches = targetPatches; + this.sourceListener = new SourceComboActionListener(); + this.targetListener = new TargetComboActionListener(); + } + + public void updateSourceList(Patches sourcePatches) { + this.sourcePatches = sourcePatches; + } + + @SuppressWarnings("unchecked") + @Override + protected void addRow() { + JComboBox[] fields = new JComboBox[2]; + fields[0] = new JComboBox(); + for (Patch sp : sourcePatches) { + fields[0].addItem(sp.getName()); + } + fields[0].setSelectedIndex(-1); + fields[0].addActionListener(sourceListener); + + fields[1] = new JComboBox(); + for (Patch sp : targetPatches) { + fields[1].addItem(sp.getName()); + } + fields[1].setSelectedIndex(-1); + fields[1].addActionListener(targetListener); + + addRow(fields, false); + } + + @SuppressWarnings("unchecked") + @Override + public void load() { + String patchMap = dictionaryModel.getDictionary().lookup(PATCH_MAP_KEY); + String[] patches = DictionaryUtils.string2StringArray(patchMap); + + for (int i = 0; i < patches.length; i += 2) { + JComboBox[] fields = new JComboBox[2]; + fields[0] = new JComboBox(); + fields[0].removeActionListener(sourceListener); + for (Patch sp : sourcePatches) { + fields[0].addItem(sp.getName()); + } + fields[0].setSelectedItem(patches[i]); + fields[0].addActionListener(sourceListener); + + fields[1] = new JComboBox(); + fields[1].removeActionListener(targetListener); + for (Patch sp : targetPatches) { + fields[1].addItem(sp.getName()); + } + fields[1].setSelectedItem(patches[i + 1]); + fields[1].addActionListener(targetListener); + + addRow(fields, false); + } + } + + @SuppressWarnings("unchecked") + @Override + public void save() { + dictionaryModel.getDictionary().remove(PATCH_MAP_KEY); + + StringBuilder sb = new StringBuilder("("); + for (Integer key : getRowsMap().keySet()) { + JComboBox[] comps = (JComboBox[]) getRowsMap().get(key); + if(comps[0].getSelectedIndex() > -1){ + sb.append((String) comps[0].getSelectedItem() + " "); + sb.append((String) comps[1].getSelectedItem() + " "); + } + } + sb.append(")"); + dictionaryModel.getDictionary().add(PATCH_MAP_KEY, sb.toString()); + } + + private class SourceComboActionListener implements ActionListener { + + @SuppressWarnings("unchecked") + @Override + public void actionPerformed(ActionEvent e) { + JComboBox combo = ((JComboBox) e.getSource()); + for (Integer key : getRowsMap().keySet()) { + JComboBox sourceCombo = (JComboBox) getRowsMap().get(key)[0]; + if (sourceCombo != combo && sourceCombo.getSelectedItem() !=null && sourceCombo.getSelectedItem().equals(combo.getSelectedItem())) { + combo.hidePopup(); + combo.setSelectedIndex(-1); + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Source patch already used", "Fields Map Error", JOptionPane.ERROR_MESSAGE); + return; + } + } + } + } + + private class TargetComboActionListener implements ActionListener { + + @SuppressWarnings("unchecked") + @Override + public void actionPerformed(ActionEvent e) { + JComboBox combo = ((JComboBox) e.getSource()); + for (Integer key : getRowsMap().keySet()) { + JComboBox targetCombo = (JComboBox) getRowsMap().get(key)[1]; + if (targetCombo != combo && targetCombo.getSelectedItem() != null && targetCombo.getSelectedItem().equals(combo.getSelectedItem())) { + combo.hidePopup(); + combo.setSelectedIndex(-1); + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Target patch already used", "Fields Map Error", JOptionPane.ERROR_MESSAGE); + return; + } + } + } + } + +} diff --git a/src/eu/engys/core/dictionary/model/PointInfo.java b/src/eu/engys/core/dictionary/model/PointInfo.java new file mode 100644 index 0000000..89c0dd8 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/PointInfo.java @@ -0,0 +1,64 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.model; + +import java.awt.Color; + +import eu.engys.util.ui.textfields.DoubleField; + +public class PointInfo { + + public static final String PROPERTY_NAME = "point.location"; + public static final String LABEL = "Point "; + private DoubleField[] field; + private Color color; + private String key; + private EventActionType action; + + public PointInfo(DoubleField[] field, String key, EventActionType action, Color color) { + this.field = field; + this.key = key; + this.action = action; + this.color = color; + } + + public DoubleField[] getPoint() { + return field; + } + + public String getKey() { + return key; + } + + public EventActionType getAction() { + return action; + } + + public Color getColor() { + return color; + } + +} diff --git a/src/eu/engys/core/dictionary/model/PointTableAdapter.java b/src/eu/engys/core/dictionary/model/PointTableAdapter.java new file mode 100644 index 0000000..aa8c7e2 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/PointTableAdapter.java @@ -0,0 +1,175 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.model; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.swing.JComponent; +import javax.swing.JToggleButton; + +import eu.engys.util.ColorUtil; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.textfields.DoubleField; + +public class PointTableAdapter extends DictionaryTableAdapter { + + private String dictKey; + private List buttons; + private List visibility; + private final boolean showPoint; + + public PointTableAdapter(DictionaryModel dictionaryModel, String[] columnNames, String dictKey, int linesToLeave, boolean showPoint) { + super(dictionaryModel, columnNames, PointInfo.LABEL, linesToLeave, false); + this.dictKey = dictKey; + this.showPoint = showPoint; + this.buttons = new LinkedList<>(); + this.visibility = new LinkedList(); + } + + @Override + protected void addRow() { + DoubleField[] fields = ComponentsFactory.doublePointField(4); + addRow(fields); + } + + @Override + protected void removeRow() { + updateVisibilityList(); + super.removeRow(); + visibility.clear(); + } + + private void updateVisibilityList() { + visibility.clear(); + for (int i = 0; i < buttons.size() - 1; i++) { + visibility.add(buttons.get(i).isSelected()); + } + turnOffPointsIn3D(); + buttons.clear(); + } + + @Override + protected JComponent[] createComponent(final JComponent[] field) { + if (showPoint) { + List comps = new ArrayList(Arrays.asList(field)); + JToggleButton showMaterialPoint = null; + if (visibility.size() > getRowsMap().size()) { + showMaterialPoint = ShowLocationAdapter.newShowPointButton((DoubleField[]) field, getRowsMap().size(), visibility.get(getRowsMap().size())); + } else { + showMaterialPoint = ShowLocationAdapter.newShowPointButton((DoubleField[]) field, getRowsMap().size(), false); + } + showMaterialPoint.getAction().addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if(evt.getPropertyName().equals(PointInfo.PROPERTY_NAME)){ + firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()); + } + } + }); + + buttons.add(showMaterialPoint); + comps.add(showMaterialPoint); + return comps.toArray(new JComponent[0]); + } else { + return field; + } + } + + @Override + protected void triggerEventFor3D(JComponent[] comp) { + String key = ColorUtil.getColor(getRowsMap().size()).toString(); + firePropertyChange(PointInfo.PROPERTY_NAME, null, new PointInfo((DoubleField[]) comp, key, EventActionType.REMOVE, null)); + } + + public void turnOffPointsIn3D() { + for (JToggleButton b : buttons) { + if (b.isSelected()) { + b.doClick(); + } + } + } + + @Override + public void load() { + turnOffPointsIn3D(); + buttons.clear(); + String value = dictionaryModel.getDictionary().lookup(dictKey); + if (value != null && value.startsWith("(") && value.endsWith(")")) { + value = value.substring(1, value.length() - 1).trim(); + try { + Pattern regex = Pattern.compile("(\\([^\\)]*\\))"); + Matcher regexMatcher = regex.matcher(value); + + while (regexMatcher.find()) { + DoubleField[] fields = new DoubleField[3]; + String row = regexMatcher.group().trim(); + Pattern rowRegex = Pattern.compile("(\\s*\\-?\\d*\\.?\\d+([eE][-+]?[0-9]+)*\\s*)"); + Matcher rowRegexMatcher = rowRegex.matcher(row); + + int columnCounter = 0; + while (rowRegexMatcher.find()) { + fields[columnCounter] = new DoubleField(); + fields[columnCounter].setDoubleValue(Double.valueOf(rowRegexMatcher.group().trim())); + if (columnCounter > fields.length) { + break; + } + columnCounter++; + } + addRow(fields); + } + } catch (PatternSyntaxException ex) { + // Syntax error in the regular expression + } + } + } + + @Override + protected void save() { + StringBuilder sb = new StringBuilder(); + sb.append("( "); + for (JComponent[] row : getRowsMap().values()) { + sb.append("( "); + for (DoubleField doubleField : (DoubleField[]) row) { + sb.append(doubleField.getDoubleValue()); + sb.append(" "); + } + sb.append(")"); + sb.append(" "); + } + sb.append(")"); + dictionaryModel.getDictionary().add(dictKey, sb.toString()); + } +} diff --git a/src/eu/engys/core/dictionary/model/ShowAxisAdapter.java b/src/eu/engys/core/dictionary/model/ShowAxisAdapter.java new file mode 100644 index 0000000..f556783 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/ShowAxisAdapter.java @@ -0,0 +1,112 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.model; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JToggleButton; + +import net.java.dev.designgridlayout.Componentizer; +import eu.engys.util.ui.textfields.DoubleField; + +public class ShowAxisAdapter extends JPanel { + + private static final ImageIcon ICON_ON = new ImageIcon(AbstractTableAdapter.class.getClassLoader().getResource("eu/engys/resources/images/lightbulb16.png")); + private static final ImageIcon ICON_OFF = new ImageIcon(AbstractTableAdapter.class.getClassLoader().getResource("eu/engys/resources/images/lightbulb_off16.png")); + + private JToggleButton button; + private DoubleField[] axis; + private DoubleField[] centre; + + public ShowAxisAdapter(DoubleField[] axis, DoubleField[] centre) { + super(new BorderLayout()); + this.axis = axis; + this.centre = centre; + this.button = newShowAxisButton(false); + JComponent component = Componentizer.create().minAndMore(centre).minToPref(button).component(); + add(component, BorderLayout.CENTER); + } + + @Override + public void setName(String name) { + super.setName(name); + button.setName(getName()+".button"); + axis[0].setName(getName()+".axis.0"); + axis[1].setName(getName()+".axis.1"); + axis[2].setName(getName()+".axis.2"); + centre[0].setName(getName()+".centre.0"); + centre[1].setName(getName()+".centre.1"); + centre[2].setName(getName()+".centre.2"); + } + + @Override + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + super.addPropertyChangeListener(propertyName, listener); + if (propertyName.equals("point.location")) { + button.getAction().addPropertyChangeListener(listener); + } + } + + public void turnOff() { + if (button.isSelected()) { + button.doClick(); + } + } + + public JToggleButton newShowAxisButton(boolean selected) { + final JToggleButton button = new JToggleButton(new AbstractAction() { + // private Border originalBorder; + + @Override + public void actionPerformed(ActionEvent e) { + AbstractButton b = ((AbstractButton) e.getSource()); + if (b.isSelected()) { + firePropertyChange(PointInfo.PROPERTY_NAME, null, new AxisInfo(axis, centre, EventActionType.SHOW)); + } else { + firePropertyChange(PointInfo.PROPERTY_NAME, null, new AxisInfo(axis, centre, EventActionType.HIDE)); + } + } + }); + if (selected && !button.isSelected() || (!selected && button.isSelected())) { + button.doClick(); + } + button.setPreferredSize(new Dimension(22, 22)); + button.setIcon(ICON_OFF); + button.setSelectedIcon(ICON_ON); + button.setToolTipText("Click to display this point in the 3D canvas"); + return button; + } + +} diff --git a/src/eu/engys/core/dictionary/model/ShowLocationAdapter.java b/src/eu/engys/core/dictionary/model/ShowLocationAdapter.java new file mode 100644 index 0000000..72f99f0 --- /dev/null +++ b/src/eu/engys/core/dictionary/model/ShowLocationAdapter.java @@ -0,0 +1,125 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.model; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.border.Border; + +import net.java.dev.designgridlayout.Componentizer; +import eu.engys.util.ColorUtil; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.textfields.DoubleField; + +public class ShowLocationAdapter extends JPanel { + + private static final Icon ICON_ON = ResourcesUtil.getResourceIcon("eu/engys/resources/images/lightbulb16.png"); + private static final Icon ICON_OFF = ResourcesUtil.getResourceIcon("eu/engys/resources/images/lightbulb_off16.png"); + + private JToggleButton button; + private DoubleField[] fields; + + public ShowLocationAdapter(DoubleField[] fields, Color key) { + super(new BorderLayout()); + this.fields = fields; + this.button = newShowPointButton(fields, key, false); + JComponent component = Componentizer.create().minAndMore(fields).minToPref(button).component(); + add(component, BorderLayout.CENTER); + } + + @Override + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + super.addPropertyChangeListener(propertyName, listener); + if (propertyName.equals(PointInfo.PROPERTY_NAME)) { + button.getAction().addPropertyChangeListener(listener); + } + } + + public void turnMaterialPointsOn() { + if (!button.isSelected()) { + button.doClick(); + } + } + + public void turnMaterialPointsOff() { + if (button.isSelected()) { + button.doClick(); + } + } + + public static JToggleButton newShowPointButton(final DoubleField[] locationInMesh, int index, boolean selected) { + return newShowPointButton(locationInMesh, ColorUtil.getColor(index), selected); + } + + public static JToggleButton newShowPointButton(final DoubleField[] locationInMesh, final Color color, boolean selected) { + final JToggleButton button = new JToggleButton(new AbstractAction() { + private Border originalBorder; + + @Override + public void actionPerformed(ActionEvent e) { + AbstractButton b = ((AbstractButton) e.getSource()); + if (b.isSelected()) { + firePropertyChange(PointInfo.PROPERTY_NAME, null, new PointInfo(locationInMesh, color.toString(), EventActionType.SHOW, color)); + originalBorder = b.getBorder(); + b.setBorder(BorderFactory.createLineBorder(color, 2)); + } else { + firePropertyChange(PointInfo.PROPERTY_NAME, null, new PointInfo(locationInMesh, color.toString(), EventActionType.HIDE, color)); + if (originalBorder != null) { + b.setBorder(originalBorder); + } + } + } + }); + if (selected && !button.isSelected() || (!selected && button.isSelected())) { + button.doClick(); + } + button.setPreferredSize(new Dimension(22, 22)); + button.setIcon(ICON_OFF); + button.setSelectedIcon(ICON_ON); + button.setToolTipText("Click to display this point in the 3D canvas"); + return button; + } + + @Override + public void setToolTipText(String text) { + super.setToolTipText(text); + for (DoubleField f : fields) { + f.setToolTipText(text); + } + } + +} diff --git a/src/eu/engys/core/dictionary/parser/DictionaryReader2.java b/src/eu/engys/core/dictionary/parser/DictionaryReader2.java new file mode 100644 index 0000000..b02e5b7 --- /dev/null +++ b/src/eu/engys/core/dictionary/parser/DictionaryReader2.java @@ -0,0 +1,443 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.parser; + +import static eu.engys.core.dictionary.Dictionary.SPACER; +import static eu.engys.core.dictionary.Dictionary.VALUE_LINK; +import static eu.engys.core.dictionary.Dictionary.VALUE_UNIFORM_LINK; +import static eu.engys.core.dictionary.Dictionary.VERBOSE; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.DictionaryLinkResolver; +import eu.engys.core.dictionary.DimensionedScalar; +import eu.engys.util.IOUtils; + +public class DictionaryReader2 { + + private static final String NAME_WITH_PARENTHESIS_REGEXP = ";\\s([^(\\s]*?\\([^\\s]*?\\)[^)\\s]*?)\\s"; + static final String LIST_START = "("; + static final String LIST_END = ")"; + // private static final String LIST_START = "!"; + // private static final String MATRIX_START = "&"; + // private static final String MATRIX_DELIMITER = "|"; + static final String FIELD_END = ";"; + static final String DICTIONARY_END = "}"; + static final String DICTIONARY_START = "{"; + + static final String TOKENS_LIST = DICTIONARY_END + FIELD_END + DICTIONARY_START + LIST_START + LIST_END;// " };{("; + + private static final String COMMENT_REGEX = "/\\*(?:.|[\\n\\r])*?\\*/"; + private Dictionary dictionary; + private DictionaryLinkResolver linkResolver; + + public DictionaryReader2(Dictionary dictionary) { + this(dictionary, new DictionaryLinkResolver(dictionary)); + } + + public DictionaryReader2(Dictionary dictionary, DictionaryLinkResolver linkResolver) { + this.dictionary = dictionary; + this.linkResolver = linkResolver; + } + + public void read(File file) { + String text = readFile(file); + text = prepareText(text, file); + textToDictionary(text); + if (dictionary.found("FoamFile")) + dictionary.remove("FoamFile"); + } + + public void read(InputStream is) { + String text = readStream(is); + text = prepareText(text, null); + textToDictionary(text); + if (dictionary.found("FoamFile")) + dictionary.remove("FoamFile"); + } + + public void read(String text) { + read(text, false); + } + + public void read(String text, boolean removeHeader) { + text = prepareText(text, null); + textToDictionary(text); + if (dictionary.found("FoamFile") && removeHeader) { + dictionary.remove("FoamFile"); + } + } + + private String readFile(File file) { + return IOUtils.readStringFromFile(file); + } + + private String readStream(InputStream is) { + String text = ""; + try { + text = IOUtils.readStringFromStream(is); + } catch (IOException e) { + System.err.println("Error reading stream : " + e.getMessage()); + } + return text; + } + + private String prepareText(String text, File file) { + text = text.replaceAll(COMMENT_REGEX, ""); + text = text.replaceAll("\t", SPACER); + + StringTokenizer rowTokenizer = new StringTokenizer(text, "\n"); + StringBuffer sb = new StringBuffer(); + while (rowTokenizer.hasMoreTokens()) { + String token = rowTokenizer.nextToken(); + token = token.trim(); + if (token.startsWith("//")) + continue; + if (token.contains("//")) { + token = token.substring(0, token.indexOf("//")).trim(); + } + if (token.startsWith("#include")) { + sb.append(importFile(token, file)); + continue; + } + sb.append(token); + sb.append("\n"); + } + text = sb.toString(); + return text; + } + + private String importFile(String token, File file) { + String text = ""; + if (file != null) { + try { + Pattern regex = Pattern.compile("#include\\s+\"(.+)\""); + Matcher regexMatcher = regex.matcher(token); + if (regexMatcher.find() && regexMatcher.groupCount() == 1) { + String fileName = regexMatcher.group(1).trim(); + String parentDir = file.getParent(); + + File fileToImport = new File(parentDir, fileName); + text = readFile(fileToImport); + text = prepareText(text, fileToImport); + } + } catch (PatternSyntaxException ex) { + ex.printStackTrace(); + } + } + + return text; + } + + protected void textToDictionary(String text) { + text = text.replace("\n", SPACER); + text = new Rewriter(NAME_WITH_PARENTHESIS_REGEXP) { + public String replacement() { + String nameWithParenthesis = group(1); + // System.out.println("nameWithParentesis = "+nameWithParenthesis); + return FIELD_END + SPACER + nameWithParenthesis.replace("(", "<<").replace(")", ">>") + SPACER; + } + }.rewrite(text); + + printOut(text); + + text = text.replaceAll("\\{", SPACER + "{" + SPACER); + text = text.replaceAll("\\}", SPACER + "}" + SPACER); + text = text.replaceAll(";", SPACER + ";" + SPACER); + text = text.replaceAll("\\(", SPACER + "(" + SPACER); + text = text.replaceAll("\\)", SPACER + ")" + SPACER); + text = text.replaceAll("\\s+", SPACER); + text = text.replaceAll("<<", "("); + text = text.replaceAll(">>", ")"); + + printOut(text); + + parseDictionary(text); + } + + protected void parseDictionary(String text) { + StringTokenizer tokenizer = new StringTokenizer(text, SPACER); + Stack stack = new Stack(); + readDictionary(tokenizer, stack); + printOut("##################################\n" + toString()); + linkResolver.resolve(dictionary); + } + + void readDictionary(StringTokenizer st, Stack stack) { + while (st.hasMoreTokens()) { + String token = st.nextToken(); + printOut("TOKEN: " + token); + stack.push(token);// metto nella pila + + if (stack.peek().equals(DICTIONARY_START)) { + stack.pop(); + String name = stack.pop(); + Dictionary d = new Dictionary(name); + printOut("START DICTIONARY: " + name); + + new DictionaryReader2(d).readDictionary(st, stack); + + if (isMultiple(name)) { + String[] names = extractMultipleKeys(name); + for (String n : names) { + if (isGeneric(withDoubleQuotes(n))) { + Dictionary copy = new Dictionary(d); + copy.setName(withDoubleQuotes(n)); + dictionary.addGeneric(copy); + } else { + Dictionary copy = new Dictionary(d); + copy.setName(n); + dictionary.add(copy); + } + } + } else if (isGeneric(name)) { + dictionary.addGeneric(d); + } else { + dictionary.add(d); + } + } else if (stack.peek().equals(DICTIONARY_END)) { + // stack.pop(); + String name = stack.pop(); + printOut("FINE DICTIONARY: " + name); + return; + } else if (stack.peek().equals(FIELD_END)) { + stack.pop(); // tolgo il ; + + /* in teoria nello stack c'e' tutto il field */ + if (stack.isEmpty()) + continue; + + readFields(stack); + } else if (stack.peek().equals(LIST_START)) { + ListField2 list = listFromStack(stack); + + printOut("START LIST: " + list.getName()); + + ListReader2 reader; + if (list instanceof ThetaListField2) { + reader = new ThetaListReader2((ThetaListField2) list, true); + } else { + if (dictionary.getFoamFile() != null) { + reader = new ListReader2(list, true); + } else { + reader = new ListReader2(list, false); + } + } + + if (reader.readList(st, stack)) { + dictionary.add(list); + } else { + List unspecifiedList = new ArrayList<>(stack); + String key = list.getName(); + String value = ""; + for (String item : unspecifiedList) { + value += SPACER + item; + } + dictionary.add(key, value); + } + } + } + } + + private ListField2 listFromStack(Stack stack) { + String separator = stack.pop(); + Stack listStack = new Stack<>(); + while (!stack.isEmpty() && !isSeparator(stack.peek())) { + String pop = stack.pop(); + listStack.push(pop); + } + if (listStack.isEmpty()) { + stack.push(separator); + return new ListField2(""); + } else { + String name = listStack.pop(); + while (!listStack.isEmpty()) { + name += " " + listStack.pop(); + } + stack.push(separator); + + if (name.equals("thetaProperties")) { + return new ThetaListField2(name); + } else { + return new ListField2(name); + } + } + } + + private void readFields(Stack stack) { + Stack fieldStack = new Stack<>(); + while (!stack.isEmpty() && !isSeparator(stack.peek())) { + String pop = stack.pop(); + fieldStack.push(pop); + } + if (fieldStack.size() == 0) { + // do nothing + } else if (fieldStack.size() == 1) { + dictionary.add(fieldStack.pop(), ""); + } else if (fieldStack.size() >= 2) { + String key = fieldStack.pop(); + String value = fieldStack.pop(); + while (!fieldStack.isEmpty()) { + value += " " + fieldStack.pop(); + } + + if (readDimensionedScalar(key + " " + value)) { + return; + } + + if (isMultiple(key)) { + String[] keys = extractMultipleKeys(key); + for (String k : keys) { + if (isGeneric(withDoubleQuotes(k))) { + dictionary.addGeneric(withDoubleQuotes(k), value); + } else { + dictionary.add(k, value); + } + } + } else if (isGeneric(key)) { + dictionary.addGeneric(key, value); + } else if (isLink(value)) { + extractLink(key, value); + } else { + dictionary.add(key, value); + } + } + } + + static boolean isSeparator(String token) { + return token.equals("{") || token.equals("}") || token.equals("(") || token.equals(")") || token.equals(";"); + } + + private boolean readDimensionedScalar(String field) { + try { + dictionary.add(new DimensionedScalar(field)); + return true; + } catch (DictionaryException e) { + return false; + } + } + + private String withDoubleQuotes(String k) { + return "\"" + k + "\""; + } + + public static String[] extractMultipleKeys(String key) { + key = key.replace("\"", ""); + + if (key.contains("(") && key.contains(")")) { + int start = key.indexOf("("); + int end = key.indexOf(")"); + String header = key.substring(0, start); + String footer = key.substring(end + 1, key.length()); + String core = key.substring(start + 1, end); + + String[] tokens = core.split("\\|"); + + String[] keys = new String[tokens.length]; + for (int i = 0; i < keys.length; i++) { + keys[i] = header + tokens[i] + footer; + } + return keys; + } else { + String[] tokens = key.split("\\|"); + return tokens; + } + + } + + public String cleanGenericKey(String key) { + key = key.substring(1, key.length() - 1); + key = key.substring(0, key.indexOf(".*")); + return key; + } + + public boolean isGeneric(String key) { + return key.startsWith("\"") && key.endsWith("\"") && key.contains(".*"); + } + + public boolean isMultiple(String key) { + return key.startsWith("\"") && key.endsWith("\"") && key.contains("|"); + } + + public boolean isLink(String value) { + return !value.startsWith("\"") && value.contains("$"); + } + + private void extractLink(String key, String value) { + if (value.startsWith("uniform")) { + String link = value.replace("uniform", "").trim(); + if (link.startsWith("$")) { + dictionary.add(VALUE_UNIFORM_LINK + key, link); + } + } else if (value.startsWith("$")) { + dictionary.add(VALUE_LINK + key, value); + } + } + + private static void printOut(String msg) { + if (VERBOSE) + System.out.println("[DICT] " + msg); + } + + public static abstract class Rewriter { + private Pattern pattern; + private Matcher matcher; + + public Rewriter(String regex) { + this.pattern = Pattern.compile(regex); + } + + public String group(int i) { + return matcher.group(i); + } + + public abstract String replacement(); + + public String rewrite(CharSequence original) { + this.matcher = pattern.matcher(original); + StringBuffer result = new StringBuffer(original.length()); + while (matcher.find()) { + matcher.appendReplacement(result, ""); + result.append(replacement()); + } + matcher.appendTail(result); + return result.toString(); + } + + } +} diff --git a/src/eu/engys/core/dictionary/parser/ListField2.java b/src/eu/engys/core/dictionary/parser/ListField2.java new file mode 100644 index 0000000..52a04c1 --- /dev/null +++ b/src/eu/engys/core/dictionary/parser/ListField2.java @@ -0,0 +1,361 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.parser; + +import static eu.engys.core.dictionary.Dictionary.SPACER; +import static eu.engys.core.dictionary.Dictionary.TAB; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.commons.lang.math.NumberUtils; + +import com.google.common.primitives.Doubles; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryWriter; +import eu.engys.core.dictionary.FieldElement; + +public class ListField2 extends DefaultElement { + + private List listElements = new ArrayList(); + private int size; + private String uniformity = ""; + private String identifier = ""; + + public ListField2(String name) { + super(name); + decodeName(name); + } + + public boolean isEmpty() { + return listElements.isEmpty(); + } + + public ListField2(ListField2 lf) { + super(lf.getName()); + for (DefaultElement el : lf.getListElements()) { + if (el instanceof Dictionary) { + add(new Dictionary((Dictionary) el)); + } else if (el instanceof ListField2) { + add(new ListField2((ListField2) el)); + } else if (el instanceof FieldElement) { + add(new FieldElement((FieldElement) el)); + } else { + System.err.println("ListField2: only dictionaries are allowed as elements " + el.getName()); + } + } + this.size = lf.size; + this.uniformity = lf.uniformity; + this.identifier = lf.identifier; + } + + private void decodeName(String name) { + if (name.contains(SPACER)) { + StringTokenizer tokenizer = new StringTokenizer(name, SPACER); + if (tokenizer.countTokens() == 1) { // internalField (...); oppure + // 10 (...); +// System.out.println("ListField2.decodeName() 1"); + String token = tokenizer.nextToken(); + try { + this.size = Integer.parseInt(token); + setName(""); + } catch (NumberFormatException ex) { + this.size = -1; + setName(token); + } + this.uniformity = ""; + this.identifier = ""; + } else if (tokenizer.countTokens() == 2) {// internalField 10 (...); + String token1 = tokenizer.nextToken(); + String token2 = tokenizer.nextToken(); +// System.out.println("ListField2.decodeName() token1: [" + token1 + "], token2: [" + token2 + "]"); + + try { + this.size = Integer.parseInt(token2); + } catch (NumberFormatException ex) { + this.size = -1; + } + if(size < 0){ + setName(token1 + " " + token2); + } else { + setName(token1); + } + this.uniformity = ""; + this.identifier = ""; + } else if (tokenizer.countTokens() == 3) {// internalField + // nonuniform 0() +// System.out.println("ListField2.decodeName() 3"); + String token1 = tokenizer.nextToken(); + String token2 = tokenizer.nextToken(); + String token3 = tokenizer.nextToken(); +// System.out.println("ListField2.decodeName() token1 = '" + token1 + "'"); +// System.out.println("ListField2.decodeName() token2 = '" + token2 + "'"); +// System.out.println("ListField2.decodeName() token3 = '" + token3 + "'"); + try { + this.size = Integer.parseInt(token3); + } catch (NumberFormatException ex) { + this.size = -1; + } + setName(token1); + this.uniformity = token2; + this.identifier = ""; + } else if (tokenizer.countTokens() == 4) { // internalField + // nonuniform + // List 10 +// System.out.println("ListField2.decodeName() 4"); + String token1 = tokenizer.nextToken(); + String token2 = tokenizer.nextToken(); + String token3 = tokenizer.nextToken(); + String token4 = tokenizer.nextToken(); + try { + this.size = Integer.parseInt(token4); + } catch (NumberFormatException ex) { + this.size = -1; + } + setName(token1); + this.uniformity = token2; + this.identifier = token3; + } + } else { + try { + this.size = Integer.parseInt(name); + setName(Integer.toString(hashCode())); + } catch (NumberFormatException ex) { + this.size = -1; + setName(name); + } + } + } + + public void add(DefaultElement element) { + listElements.add(element); + } + + public void add(Collection elements) { + listElements.addAll(elements); + } + + public void add(String... values) { + for (String value : values) { + listElements.add(new FieldElement("", value)); + } + } + + public List getListElements() { + return Collections.unmodifiableList(listElements); + } + + public void removeTopElements(int n) { + for (int i = 0; i < n; i++) { + listElements.remove(0); + } + } + + public void merge(ListField2 l) { + for (DefaultElement el : l.getListElements()) { + if (!containsElement(el)) { + add(el); + } else { + } + } + } + + private boolean containsElement(DefaultElement element) { + if (element instanceof FieldElement) { + return false; + } + for (DefaultElement e : listElements) { + if (haveSameName(element, e) && e.equals(element)) { + return true; + } + } + return false; + } + + protected boolean haveSameName(DefaultElement element, DefaultElement e) { + return e.getName().equals(element.getName()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ListField2) { + ListField2 list = (ListField2) obj; + boolean haveSameName = haveSameName(this, list); +// boolean equalCollection = CollectionUtils.isEqualCollection(list.getListElements(), listElements); + boolean equalCollection = list.getListElements().containsAll(listElements) && listElements.containsAll(list.getListElements()); + return haveSameName && equalCollection; + } + return false; + } + + public void writeListField(StringBuffer sb, String rowHeader) { +// System.out.println("ListField2.writeListField() name: "+getName()+", size: "+size+", uniformity: "+uniformity+", identifier: "+identifier); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + writeName(sb); + sb.append(SPACER); + sb.append(uniformity); + sb.append(SPACER); + sb.append(identifier); + if (size >= 0 && !identifier.isEmpty()) { + sb.append(SPACER); + sb.append(size); + } else if (size == 0 && isNonuniform()) { + sb.append(SPACER); + sb.append("0();"); + return; + } + if (!getName().isEmpty()) { + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + } + sb.append("("); + for (DefaultElement el : getListElements()) { + DictionaryWriter.writeElement(sb, rowHeader, el); + } + if (!getName().isEmpty()) { + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(");"); + } else { + sb.append(")"); + } + } + + public boolean nameIsANumber() { + String name = getName(); + return NumberUtils.isNumber(name); + } + + private void writeName(StringBuffer sb) { + String name = getName(); + if (NumberUtils.isNumber(name)) { + sb.append(""); + } else { + sb.append(name); + } + } + + public void writeListDict(StringBuffer sb, String rowHeader) { + sb.append(uniformity); + sb.append(identifier); + sb.append("\n"); + sb.append(rowHeader); + writeName(sb); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(listElements.size()); + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append("("); + for (DefaultElement el : getListElements()) { + DictionaryWriter.writeElement(sb, rowHeader, el); + } + sb.append("\n"); + sb.append(rowHeader); + sb.append(TAB); + sb.append(")"); + } + + public Dictionary getDictionary(String name) { + for (DefaultElement e : listElements) { + if (e instanceof Dictionary && !e.getName().isEmpty() && e.getName().equals(name)) { + return (Dictionary) e; + } + } + return null; + } + + public void setListSize(int size2) { + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + writeListField(sb, ""); + return sb.toString(); + } + + public boolean isNonuniform() { + return uniformity.equals("nonuniform"); + } + + public static String convertToString(ListField2 listField) { + StringBuilder sb = new StringBuilder(); + convertToString(listField, sb); + return sb.toString(); + } + + private static void convertToString(ListField2 listField, StringBuilder sb) { + sb.append("("); + for (DefaultElement el : listField.getListElements()) { + if(el instanceof FieldElement){ + sb.append(((FieldElement) el).getValue()); + sb.append(" "); + } else if(el instanceof ListField2){ + convertToString((ListField2)el, sb); + } + } + sb.append(")"); + } + + public List getElementsAsScalarList() { + List list = new ArrayList<>(); + for (DefaultElement e : listElements) { + if (e instanceof FieldElement && e.getName().isEmpty()) { + String value = ((FieldElement) e).getValue(); + try { + list.add(Double.parseDouble(value)); + } catch (NumberFormatException ex) { + } + } + } + return list; + } + + public List getElementsAsVectorList() { + List list = new ArrayList<>(); + for (DefaultElement e : listElements) { + if (e instanceof ListField2 && e.getName().isEmpty()) { + List value = ((ListField2) e).getElementsAsScalarList(); + list.add(Doubles.toArray(value)); + } + } + return list; + } + +} diff --git a/src/eu/engys/core/dictionary/parser/ListReader2.java b/src/eu/engys/core/dictionary/parser/ListReader2.java new file mode 100644 index 0000000..132f7c7 --- /dev/null +++ b/src/eu/engys/core/dictionary/parser/ListReader2.java @@ -0,0 +1,420 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.dictionary.parser; + +import static eu.engys.core.dictionary.Dictionary.VERBOSE; +import static eu.engys.core.dictionary.parser.DictionaryReader2.DICTIONARY_END; +import static eu.engys.core.dictionary.parser.DictionaryReader2.DICTIONARY_START; +import static eu.engys.core.dictionary.parser.DictionaryReader2.FIELD_END; +import static eu.engys.core.dictionary.parser.DictionaryReader2.LIST_END; +import static eu.engys.core.dictionary.parser.DictionaryReader2.LIST_START; + +import java.util.List; +import java.util.Stack; +import java.util.StringTokenizer; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldElement; + +class ListReader2 { + + private final ListField2 list; + private final boolean subList; + + public ListReader2(ListField2 list, boolean subList) { + this.list = list; + this.subList = subList; + } + + public boolean readList(StringTokenizer st, Stack stack) { + while (st.hasMoreTokens()) { + String token = st.nextToken(); + stack.push(token); + + printOut("TOKEN: " + token); + + if (stack.peek().equals(DICTIONARY_START)) { + stack.pop(); + String name = (stack.isEmpty() || stack.peek().equals(LIST_START) || stack.peek().equals(LIST_END)) ? "" : stack.pop(); + Dictionary d = new Dictionary(name); + printOut("START LIST DICTIONARY: " + name); + + new DictionaryReader2(d).readDictionary(st, stack); + list.add(d); + } else if (stack.peek().equals(DICTIONARY_END)) { + /* should not happen ! */ + } else if (stack.peek().equals(LIST_START)) { + printOut("START SUB LIST"); + processStack(stack); + + ListField2 child = new ListField2(""); + ListReader2 reader = new ListReader2(child, true); + reader.readList(st, stack); + list.add(child); + printOut("ADDING CHILD: " + child); + } else if (stack.peek().equals(LIST_END)) { + if (subList) { + printOut("END SUB LIST"); + return processStack(stack); + } + } else if (stack.peek().equals(FIELD_END)) { + printOut("FIELD_END"); + stack.pop(); // ; + + if (stack.peek().equals(LIST_END)) { + return processStack(stack); + } else { + // throw new + // RuntimeException("finisce il field ma non la lista"); + /* forse qui non si arriva mai ? */ + return false; + } + } + } + return true; + } + + private boolean processStack(Stack stack) { + printOut("-BEGIN PROCESS STACK: " + stackToString(stack)); + boolean success = false; + if (containsBox(stack)) { + printOut("-PROCESS STACK BOX"); + // readBox(stack); + success = false; + } else if (containsMatrix(stack)) { + printOut("-PROCESS STACK MATRIX"); + readMatrix(stack); + success = true; + } else if (containsVector(stack)) { + printOut("-PROCESS STACK VECTOR"); + readVector(stack); + success = true; + } else if (containsScalar(stack)) { + printOut("-PROCESS STACK SCALAR"); + readScalar(stack); + success = true; + } else if (containsWord(stack)) { + printOut("-PROCESS STACK WORD"); + readWord(stack); + success = true; + } else if (contains2Words(stack)) { + printOut("-PROCESS STACK 2 WORDS"); + read2Words(stack); + success = true; + } else if (containsScalarList(stack)) { + printOut("-PROCESS STACK SCALAR LIST"); + readScalarList(stack); + success = true; + } else { + printOut("-PROCESS STACK NOT RECOGNIZED"); + success = false; + } + printOut("-END PROCESS STACK"); + return success; + } + + private static boolean isNumeric(String str) { + try { + Double.parseDouble(str); + } catch (NumberFormatException nfe) { + return false; + } + return true; + } + + private static boolean isWord(String str) { + for (char c : str.toCharArray()) { + if(!isValid(c)){ + return false; + } + } + return true; + } + + private static boolean isValid(char c) { + return Character.isLetterOrDigit(c) || c == '_' || c == '-'; + } + + private String stackToString(Stack stack) { + StringBuilder sb = new StringBuilder(); + for (String s : stack) { + sb.append(s + ","); + } + return sb.toString(); + } + + private boolean containsBox(Stack stack) { + int counter = 0, start = 0, end = 0, max = 0; + for (int i = stack.size() - 1; i >= 0; i--) { + String s = stack.get(i); + + if (s.equals(LIST_START)) { + counter--; + start++; + } + if (s.equals(LIST_END)) { + counter++; + end++; + } + + max = Math.max(max, counter); + + if (counter == 0 && max == 1 && start == 2 && end == 2) { + printOut("Contains BOX"); + return true; + } + } + return false; + } + + // private void readBox(Stack stack) { + // int start = getListStart(stack, 2); + // int end = getListEnd(stack, ); + // List subList = stack.subList(start, end); + // for (String item : subList) { + // if (item.equals(LIST_START) || item.equals(LIST_END) ) continue; + // list.add(new FieldElement("", item)); + // } + // subList.clear(); + // } + + private boolean containsWord(Stack stack) { + String list_start = stack.pop(); // could be a LIST_START + String word = stack.pop(); // token to analyze + if (!stack.isEmpty() && stack.peek().equals(LIST_START)) { + stack.push(word); + stack.push(list_start); + if (isWord(word)) { + printOut("Contains WORD"); + return true; + } else { + return false; + } + } else { + stack.push(word); + stack.push(list_start); + return false; + } + } + + private boolean contains2Words(Stack stack) { + String list_start = stack.pop(); // could be a LIST_START + String word1 = stack.pop(); // token to analyze + if(!stack.isEmpty()){ + String word2 = stack.pop(); // token to analyze + if (!stack.isEmpty() && stack.peek().equals(LIST_START)) { + stack.push(word2); + stack.push(word1); + stack.push(list_start); + if (isWord(word1) && isWord(word2)) { + printOut("Contains TWO WORDS"); + return true; + } else { + return false; + } + } else { + stack.push(word2); + stack.push(word1); + stack.push(list_start); + return false; + } + } + stack.push(word1); + stack.push(list_start); + return false; + } + + private boolean containsScalar(Stack stack) { + String list_start = stack.pop(); // could be a LIST_START + String scalar = stack.pop(); // token to analyze + if (!stack.isEmpty() && stack.peek().equals(LIST_START)) { + stack.push(scalar); + stack.push(list_start); + if (isNumeric(scalar)) { + printOut("Contains SCALAR"); + return true; + } else { + return false; + } + } else { + stack.push(scalar); + stack.push(list_start); + return false; + } + } + + private void readScalarList(Stack stack) { + int start = 1; + int end = stack.size() - 1; + List subList = stack.subList(start, end); + for (String item : subList) { + if (item.equals(LIST_START) || item.equals(LIST_END)) + continue; + list.add(new FieldElement("", item)); + } + subList.clear(); + } + + private void readScalar(Stack stack) { + String pop = stack.pop(); + String s = stack.pop(); + stack.push(pop); + list.add(new FieldElement("", s)); + } + + private void readWord(Stack stack) { + String pop = stack.pop();//should be list start + String s = stack.pop(); + stack.push(pop); + list.add(new FieldElement("", s)); + } + + private void read2Words(Stack stack) { + String pop = stack.pop();//should be list start + String w1 = stack.pop(); + String w2 = stack.pop(); + stack.push(pop); + list.add(new FieldElement("", w2)); + list.add(new FieldElement("", w1)); + } + + private boolean containsScalarList(List stack) { + if (stack.get(0).equals(LIST_START)) { + if (stack.get(stack.size() - 1).equals(LIST_START)) { + if (stack.size() > 2) { + for (int i = stack.size() - 2; i > 0; i--) { + if (!isNumeric(stack.get(i))) { + return false; + } + } + return true; + } + return false; + } else { + return false; + } + } else { + return false; + } + } + + private boolean containsVector(List stack) { + int counter = 0, max = 0; + for (int i = stack.size() - 1; i >= 0; i--) { + String s = stack.get(i); + + if (s.equals(LIST_START)) + counter--; + if (s.equals(LIST_END)) + counter++; + + max = Math.max(max, counter); + + if (counter == 0 && max == 1) { + printOut("-Contains VECTOR"); + return true; + } + } + return false; + } + + private void readVector(Stack stack) { + int start = getListStart(stack); + int end = getListEnd(stack); + List subList = stack.subList(start, end); + for (String item : subList) { + if (item.equals(LIST_START) || item.equals(LIST_END)) + continue; + list.add(new FieldElement("", item)); + } + subList.clear(); + } + + private int getListStart(List stack) { + for (int i = stack.size() - 1; i >= 0; i--) { + String s = stack.get(i); + if (s.equals(LIST_START)) + return i; + } + return -1; + } + + private int getListEnd(List stack) { + for (int i = stack.size() - 1; i >= 0; i--) { + String s = stack.get(i); + if (s.equals(LIST_END)) + return i + 1; + } + return -1; + } + + private boolean containsMatrix(List stack) { + int start = 0, end = 0, level = 0, max = 0; + for (String s : stack) { + if (s.equals(LIST_START)) { + start++; + level++; + } + if (s.equals(LIST_END)) { + end++; + level--; + } + max = Math.max(max, level); + } + return start == end && max == 2; + } + + private void readMatrix(List stackList) { + ListField2 child = null; + for (String item : stackList) { + if (item.equals(LIST_START) && child == null) { + child = new ListField2(""); + list.add(child); + continue; + } + if (item.equals(LIST_END) && child != null) { + child = null; + continue; + } + if (item.equals(LIST_START) || item.equals(LIST_END)) + continue; + child.add(new FieldElement("", item)); + } + } + + private String processField(String field) { + if (field.contains("|")) { + field = field.replace("|", ") ("); + } + return field; + } + + private static void printOut(String msg) { + if (VERBOSE) + System.out.println("[LIST] " + msg); + } +} diff --git a/src/eu/engys/core/dictionary/parser/ThetaListField2.java b/src/eu/engys/core/dictionary/parser/ThetaListField2.java new file mode 100644 index 0000000..3bd9e08 --- /dev/null +++ b/src/eu/engys/core/dictionary/parser/ThetaListField2.java @@ -0,0 +1,93 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.parser; + +import java.util.ArrayList; +import java.util.List; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.dictionary.TableRowElement; + +public class ThetaListField2 extends ListField2 { + + public ThetaListField2(String name) { + super(name); + } + + public ThetaListField2(ThetaListField2 tf) { + super(tf.getName()); + for (DefaultElement el : tf.getListElements()) { + if (el instanceof TableRowElement) { + add(new TableRowElement((TableRowElement) el)); + } else { + System.err.println("ThetaListField2: only TableRowElement are allowed as elements"); + } + } + } + + public void merge(ListField2 l) { + if (l instanceof ThetaListField2) { + for (DefaultElement el : l.getListElements()) { + DefaultElement this_el = containsElement(el); + + if (this_el == null) { + add(el); + } else { + if (this_el instanceof TableRowElement) { + if (el instanceof TableRowElement) { + ((TableRowElement) this_el).merge((TableRowElement) el); + } + } + } + } + } else { + super.merge(l); + } + } + + private DefaultElement containsElement(DefaultElement element) { + if (element instanceof FieldElement) { + return null; + } + for (DefaultElement e : getListElements()) { + if (haveSameName(element, e) && e.equals(element)) { + return e; + } + } + return null; + } + + public List getRows() { + List list = new ArrayList<>(); + for (DefaultElement e : getListElements()) { + if (e instanceof TableRowElement) { + list.add((TableRowElement) e); + } + } + return list; + } +} diff --git a/src/eu/engys/core/dictionary/parser/ThetaListReader2.java b/src/eu/engys/core/dictionary/parser/ThetaListReader2.java new file mode 100644 index 0000000..27479a6 --- /dev/null +++ b/src/eu/engys/core/dictionary/parser/ThetaListReader2.java @@ -0,0 +1,72 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.dictionary.parser; + +import static eu.engys.core.dictionary.Dictionary.VERBOSE; + +import java.util.List; +import java.util.Stack; +import java.util.StringTokenizer; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.dictionary.TableRowElement; + +public class ThetaListReader2 extends ListReader2 { + private ThetaListField2 thetaList; + + public ThetaListReader2(ThetaListField2 list, boolean subList) { + super(list, subList); + this.thetaList = list; + } + + @Override + public boolean readList(StringTokenizer st, Stack stack) { + boolean b = super.readList(st, stack); + if (b) { + processElements(); + } + return b; + } + + private void processElements() { + printOut("--- PROCESS ELEMENTS ---"); + List elements = thetaList.getListElements(); + int size = elements.size(); + if (size > 0 && (size%5 == 0) ) { + int rowCount = size/5; + for (int i = 0; i < rowCount; i++) { + thetaList.add(new TableRowElement((ListField2) elements.get(5*i), (FieldElement)elements.get(5*i+1), (FieldElement)elements.get(5*i+2), (FieldElement)elements.get(5*i+3), (FieldElement)elements.get(5*i+4))); + } + } + thetaList.removeTopElements(size); + } + + private static void printOut(String msg) { + if (VERBOSE) + System.out.println("[THETA LIST] " + msg); + } +} diff --git a/src/eu/engys/core/executor/AbstractExecutor.java b/src/eu/engys/core/executor/AbstractExecutor.java new file mode 100644 index 0000000..2b8972f --- /dev/null +++ b/src/eu/engys/core/executor/AbstractExecutor.java @@ -0,0 +1,230 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import java.io.File; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +import eu.engys.core.executor.ExecutorListener.ExecutorState; + + +public abstract class AbstractExecutor extends Executor { + + + protected File currentDir; + protected String description; + protected ExecutorTerminal terminal; + protected Map environment; + protected ExecutorService service; + protected Properties properties; + protected ExecutorMonitor[] monitors; + protected boolean keepFileOnEnd = false; + protected boolean loadOpenFoamEnv; + + private ExecutorState state; + private ExecutorError error; + + @Override + public Executor env(Map environment) { + this.environment = environment; + return this; + } + + @Override + public Executor description(String description) { + this.description = description; + return this; + } + + @Override + public Executor properties(Properties p) { + this.properties = p; + return this; + } + + @Override + public Executor inService(ExecutorService service) { + this.service = service; + return this; + } + + @Override + public ExecutorService getService() { + return service; + } + + @Override + public Executor inTerminal(ExecutorTerminal terminal) { + this.terminal = terminal; + return this; + } + + @Override + public Executor withMonitors(ExecutorMonitor... monitors) { + this.monitors = monitors; + return this; + } + + @Override + public Executor inFolder(File currentDir) { + this.currentDir = currentDir; + return this; + } + + @Override + public Executor withOpenFoamEnv() { + this.loadOpenFoamEnv = true; + return this; + } + + @Override + public Executor keepFileOnEnd() { + this.keepFileOnEnd = true; + return this; + } + + @Override + public int execAndWait() { + int returnValue = 0; + if (service == null) { + this.service = Executor.newExecutor("BuiltInExecutor"); + } + + if (terminal != null) { + terminal.setExecutor(service); + terminal.setTitle(description); + } + + Future task = service.submit(new Callable() { + @Override + public Integer call() throws Exception { + return _exec(); + } + }); + try { + returnValue = task.get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + return returnValue; + } + + @Override + public void exec() { + if (service == null) { + this.service = Executor.newExecutor("BuiltInExecutor"); + } + if (terminal != null) { + terminal.setExecutor(service); + terminal.setTitle(description); + } + service.submit(new Runnable() { + @Override + public void run() { + _exec(); + } + }); + } + + protected abstract int _exec(); + + @Override + public ExecutorState getState() { + return state; + } + + @Override + public ExecutorError getError() { + return error; + } + + protected void notifyStart() { + this.state = ExecutorState.START; + if (terminal != null) { + terminal.start(); + } + if (monitors != null) { + for (ExecutorMonitor monitor : monitors) { + monitor.start(); + } + } + } + protected void notifyRefresh() { + this.state = ExecutorState.RUNNING; + if (terminal != null) { + terminal.refresh(); + } + if (monitors != null) { + for (ExecutorMonitor monitor : monitors) { + monitor.refresh(); + } + } + } + protected void notifyError(int exitValue, String msg) { + this.state = ExecutorState.ERROR; + this.error = new ExecutorError(exitValue, msg); + + if (terminal != null) { + terminal.error(exitValue, msg); + } + if (monitors != null) { + for (ExecutorMonitor monitor : monitors) { + monitor.error(exitValue, msg); + } + } + } + + protected void notifyFinish(int exitValue) { + this.state = ExecutorState.FINISH; + if (terminal != null) { + terminal.finish(exitValue); + } + if (monitors != null) { + for (ExecutorMonitor monitor : monitors) { + monitor.finish(exitValue); + } + } + } + + @Override + public void notify(ExecutorState state) { + switch (state) { + case START: notifyStart(); break; + case RUNNING: notifyRefresh(); break; + case ERROR: notifyError(1, ""); break; + + default: break; + } + } +} diff --git a/src/eu/engys/core/executor/AbstractScriptExecutor.java b/src/eu/engys/core/executor/AbstractScriptExecutor.java new file mode 100644 index 0000000..0fd6f47 --- /dev/null +++ b/src/eu/engys/core/executor/AbstractScriptExecutor.java @@ -0,0 +1,231 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.DefaultExecuteResultHandler; +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.ExecuteException; +import org.apache.commons.exec.ExecuteStreamHandler; +import org.apache.commons.exec.ExecuteWatchdog; +import org.apache.commons.exec.PumpStreamHandler; +import org.apache.commons.exec.environment.EnvironmentUtils; +import org.apache.commons.io.FileUtils; + +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; + +public abstract class AbstractScriptExecutor extends AbstractExecutor { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + protected int _exec() { + int returnValue = 0; + CommandLine cmdLine = getCommandLine(); + + DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); + ExecuteWatchdog watchdog = new ScriptExecuteWatchdog(); + + DefaultExecutor executor = new DefaultExecutor(); + executor.setExitValue(0); + executor.setWorkingDirectory(currentDir); + executor.setWatchdog(watchdog); + if (terminal != null) { + ExecuteStreamHandler monitorStreamHandler = new PumpStreamHandler(terminal.getOutputStream(), terminal.getErrorStream()); + executor.setStreamHandler(monitorStreamHandler); + } else { + ExecuteStreamHandler silentStreamHandler = new PumpStreamHandler(); + executor.setStreamHandler(silentStreamHandler); + } + + Map procEnvironment = null; + if (environment != null) { + try { + procEnvironment = EnvironmentUtils.getProcEnvironment(); + procEnvironment.putAll(environment); + } catch (IOException e) { + logger.error(e.getMessage()); + procEnvironment = null; + } + } + + try { + executor.execute(cmdLine, procEnvironment, resultHandler); + notifyStart(); + } catch (Exception e) { + logger.warn("[EXECUTOR] ERROR: {}", e.getMessage()); + + notifyError(-1, e.getMessage()); + + return 1; + } + + try { + if (resultHandler.hasResult()) { + notifyRefresh(); + } else { + logger.info("[EXECUTOR] RUNNING"); + while (!resultHandler.hasResult()) { + resultHandler.waitFor(PrefUtil.getInt(PrefUtil.SCRIPT_RUN_REFRESH_TIME, 1000)); + notifyRefresh(); + } + } + } catch (InterruptedException e) { + logger.warn("[EXECUTOR] INTERRUPTED"); + watchdog.destroyProcess(); + } finally { + if (watchdog.killedProcess()) { + logger.warn("[EXECUTOR] WAITING FOR KILL"); + try { + resultHandler.waitFor(PrefUtil.getInt(PrefUtil.SCRIPT_WAIT_FOR_KILL_REFRESH_TIME, 5000)); + } catch (InterruptedException e) { + logger.warn("[EXECUTOR] INTERRUPTED: {}", e.getMessage()); + notifyError(-1, e.getMessage()); + } + } + try { + ExecuteException exception = resultHandler.getException(); + if (exception != null) { + returnValue = resultHandler.getExitValue(); + logger.warn("[EXECUTOR] ERROR: {}", exception.getMessage()); + + if (terminal != null) { + // String error = terminal.getErrorStream().peekLines(); + // notifyError(returnValue, error); + // error is empty + notifyError(returnValue, exception.getMessage()); + } else { + notifyError(returnValue, exception.getMessage()); + } + service.shutdownNow(); + } else { + returnValue = resultHandler.getExitValue(); + logger.info("[EXECUTOR] FINISH: {}", returnValue); + notifyFinish(resultHandler.getExitValue()); + } + } catch (IllegalStateException e) { + returnValue = -1; + logger.warn("[EXECUTOR] INTERRUPTED: {}", e.getMessage()); + notifyError(returnValue, e.getMessage()); + } + } + if (!keepFileOnEnd) { + internalDeleteOnEnd(); + } + + return returnValue; + } + + protected abstract void internalDeleteOnEnd(); + + private class ScriptExecuteWatchdog extends ExecuteWatchdog { + + public ScriptExecuteWatchdog() { + super(ExecuteWatchdog.INFINITE_TIMEOUT); + } + + private Process process; + + @Override + public synchronized void start(Process process) { + this.process = process; + super.start(process); + } + + @Override + public synchronized void destroyProcess() { + if (Util.isWindows()) { + killWindowsProcess(); + } else { + killLinuxProcess(); + } + super.destroyProcess(); + } + + private void killWindowsProcess() { + int pid = -1; + try { + pid = Util.getWindowsProcessId(process); + if (pid != -1) { + CommandLine command = getWindowsKillCommand(pid); + DefaultExecutor executor = new DefaultExecutor(); + executor.setStreamHandler(new PumpStreamHandler(System.out)); + executor.execute(command); + } + } catch (Exception e) { + logger.error("No process for pid {}", pid); + } + } + + private CommandLine getWindowsKillCommand(int pid) { + CommandLine command = new CommandLine("taskkill"); + command.addArgument("/F"); + command.addArgument("/PID"); + command.addArgument("" + pid); + command.addArgument("/T"); + return command; + } + + private void killLinuxProcess() { + try { + int pid = Util.getLinuxProcessId(process); + File file = new File(currentDir, "killer.run"); + FileUtils.write(file, getLinuxKillScript(pid)); + try { + file.createNewFile(); + } catch (IOException e) { + // e.printStackTrace(); + logger.error(e.getMessage()); + } + file.setExecutable(true); + Executor.script(file).inService(Executor.newExecutor("Killer")).execAndWait(); + } catch (Exception e) { + // e.printStackTrace(); + logger.error(e.getMessage()); + } + } + + private String getLinuxKillScript(int pid) { + StringBuilder sb = new StringBuilder(); + sb.append("#!/bin/bash"); + sb.append("\n\n"); + sb.append("for i in `ps h --ppid " + pid + " -o pid`;"); + sb.append("\n"); + sb.append("do"); + sb.append("\n"); + sb.append("kill -9 $i"); + sb.append("\n"); + sb.append("done"); + sb.append("\n"); + return sb.toString(); + } + }; + +} diff --git a/src/eu/engys/core/executor/CollapseManager.java b/src/eu/engys/core/executor/CollapseManager.java new file mode 100644 index 0000000..1ab312b --- /dev/null +++ b/src/eu/engys/core/executor/CollapseManager.java @@ -0,0 +1,83 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +public class CollapseManager { + + private JTabbedPane tabbedPane; + + public CollapseManager(JTabbedPane tabbedPane) { + this.tabbedPane = tabbedPane; + tabbedPane.getModel().addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + collapsePanelIfEmpty(); + } + }); + } + + private void collapsePanelIfEmpty() { + boolean isEmpty = tabbedPane.getTabCount() == 0; + if (isEmpty) { + collapse(); + } else if (canExpand()) { + expand(); + } + } + + public boolean canExpand() { + boolean hasOne = tabbedPane.getTabCount() >= 1; + boolean isCollapsed = getSplitPane().getResizeWeight() == 1; + return hasOne && isCollapsed; + } + + public void collapse() { + getSplitPane().setDividerLocation(getSplitPane().getHeight()); + getSplitPane().setResizeWeight(1); + } + + public void expand() { + getSplitPane().setDividerLocation(getSplitPane().getHeight() - 300); + getSplitPane().setResizeWeight(0.7); + } + + public void toggle() { + if (canExpand()) { + expand(); + } else { + collapse(); + } + } + + private JSplitPane getSplitPane() { + return (JSplitPane) tabbedPane.getParent(); + } +} diff --git a/src/eu/engys/core/executor/CommandExecutor.java b/src/eu/engys/core/executor/CommandExecutor.java new file mode 100644 index 0000000..9cf7e3d --- /dev/null +++ b/src/eu/engys/core/executor/CommandExecutor.java @@ -0,0 +1,91 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import static eu.engys.core.OpenFOAMEnvironment.cleanEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.loadEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.printHeader; + +import java.io.File; +import java.util.List; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.io.FileUtils; + +import eu.engys.core.controller.ScriptBuilder; +import eu.engys.util.IOUtils; +import eu.engys.util.Util; + +public class CommandExecutor extends AbstractScriptExecutor { + + private CommandLine commandLine; + private File supportFile; + + public CommandExecutor(String command, String... arguments) { + this.commandLine = new CommandLine(command); + commandLine.addArguments(arguments); + } + + @Override + protected CommandLine getCommandLine() { + this.supportFile = IOUtils.getSupportFile(currentDir); + writeCommandInSupportFile(supportFile); + return new CommandLine(supportFile); + } + + @Override + protected void internalDeleteOnEnd() { + FileUtils.deleteQuietly(supportFile); + } + + private void writeCommandInSupportFile(File supportFile) { + IOUtils.writeLinesToFile(supportFile, getCommand()); + supportFile.setExecutable(true); + } + + private List getCommand() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, description); + if (Util.isWindows()) { + if (loadOpenFoamEnv) { + loadEnvironment(sb); + sb.append("cd /D \"" + currentDir + "\""); + } else { + cleanEnvironment(sb); + } + sb.append(commandLine.toString()); + } else { + if (loadOpenFoamEnv) { + loadEnvironment(sb); + } else { + cleanEnvironment(sb); + } + sb.append(commandLine.toString()); + } + return sb.getLines(); + } + +} diff --git a/src/eu/engys/core/executor/ConsoleExecutorMonitor.java b/src/eu/engys/core/executor/ConsoleExecutorMonitor.java new file mode 100644 index 0000000..b92fade --- /dev/null +++ b/src/eu/engys/core/executor/ConsoleExecutorMonitor.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +public class ConsoleExecutorMonitor extends ExecutorTerminal { + + @Override + public void start() { + } + + @Override + public void finish(int returnValue) { + super.finish(returnValue); + System.err.print(getErrorStream().flushLinesBuffer()); + } + + @Override + public void error(int returnValue, String msg) { + System.err.println(msg); + System.err.print(getErrorStream().flushLinesBuffer()); + } + + @Override + public void refresh() { + System.out.print(getOutputStream().flushLinesBuffer()); + } + +} diff --git a/src/eu/engys/core/executor/Executor.java b/src/eu/engys/core/executor/Executor.java new file mode 100644 index 0000000..c9c4d8d --- /dev/null +++ b/src/eu/engys/core/executor/Executor.java @@ -0,0 +1,131 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import java.io.File; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.exec.CommandLine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import eu.engys.core.executor.ExecutorListener.ExecutorState; + +public abstract class Executor { + + protected static final Logger logger = LoggerFactory.getLogger(Executor.class); + + + public static Executor script(File file, String... args) { + return new ScriptExecutor(file, args); + } + + public static Executor command(String command, String... args) { + return new CommandExecutor(command, args); + } + + public static Executor command(File file, String... args) { + return new CommandExecutor("\"" + file.getAbsolutePath() + "\"", args); + } + + public static JavaExecutor jvm(String className, String... args) { + return new JavaExecutor(className, args); + } + + public abstract Executor description(String description); + + public abstract Executor keepFileOnEnd(); + + public abstract Executor inFolder(File currentDir); + + public abstract Executor env(Map environment); + + public abstract Executor inService(ExecutorService service); + + public abstract Executor inTerminal(ExecutorTerminal terminal); + + public abstract Executor withMonitors(ExecutorMonitor... monitor); + + public abstract Executor withOpenFoamEnv(); + + public abstract void exec(); + + public abstract int execAndWait(); + + public abstract Executor properties(Properties p); + + protected abstract CommandLine getCommandLine(); + + public abstract ExecutorService getService(); + public abstract ExecutorState getState(); + public abstract ExecutorError getError(); + + public void notify(ExecutorState state) { + } + + public static ThreadPoolExecutor newExecutor(final String name) { + ThreadFactory threadFactory = new ThreadFactoryBuilder() + .setNameFormat(name + "-%d") + .setDaemon(false) + .build(); + + return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), threadFactory) { + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + if (t == null && r instanceof Future) { + try { + Future future = (Future) r; + if (future.isDone()) + future.get(); + } catch (CancellationException ce) { + t = ce; + } catch (ExecutionException ee) { + t = ee.getCause(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); // ignore/reset + } + } + if (t != null) { + logger.error("ERROR FOR EXECUTOR: " + name, t); + } + } + }; + } + +} diff --git a/src/eu/engys/core/executor/ExecutorError.java b/src/eu/engys/core/executor/ExecutorError.java new file mode 100644 index 0000000..085bf0f --- /dev/null +++ b/src/eu/engys/core/executor/ExecutorError.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import java.io.Serializable; + +public class ExecutorError implements Serializable { + + private int returnValue; + private String message; + + public ExecutorError() { + } + + public ExecutorError(int returnValue, String message) { + this.returnValue = returnValue; + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public int getReturnValue() { + return returnValue; + } + + public void setReturnValue(int returnValue) { + this.returnValue = returnValue; + } + + @Override + public String toString() { + return "(" +returnValue+ ") " + (message != null ? message : ""); + } +} diff --git a/src/eu/engys/core/executor/ExecutorHook.java b/src/eu/engys/core/executor/ExecutorHook.java new file mode 100644 index 0000000..3bbe5a4 --- /dev/null +++ b/src/eu/engys/core/executor/ExecutorHook.java @@ -0,0 +1,32 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +public interface ExecutorHook { + + public void run(ExecutorMonitor monitor); + +} diff --git a/src/eu/engys/core/executor/ExecutorListener.java b/src/eu/engys/core/executor/ExecutorListener.java new file mode 100644 index 0000000..f138d14 --- /dev/null +++ b/src/eu/engys/core/executor/ExecutorListener.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +public interface ExecutorListener { + + public enum ExecutorState { + START, RUNNING, FINISH, ERROR; + + public boolean isDoingSomething() { + return this == START || this == RUNNING; + } + + public boolean isError() { + return this == ERROR; + } + + public boolean isRunning() { + return this == RUNNING; + } + } + + public void refresh(); + public void start(); + public void finish(int exitValue); + public void error(int exitValue, String msg); + +} diff --git a/src/eu/engys/core/executor/ExecutorMonitor.java b/src/eu/engys/core/executor/ExecutorMonitor.java new file mode 100644 index 0000000..7ffc3f1 --- /dev/null +++ b/src/eu/engys/core/executor/ExecutorMonitor.java @@ -0,0 +1,124 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExecutorMonitor implements ExecutorListener { + + protected static final Logger logger = LoggerFactory.getLogger(ExecutorMonitor.class); + private Map> stateHooks = new HashMap<>(); + + protected ExecutorService executor; + private ExecutorState state; + + private int returnValue; + private String errorMessage; + + @Override + public void start() { + logger.info("[EXECUTOR MONITOR] START"); + state = ExecutorState.START; + runHook(); + } + + @Override + public void refresh() { + state = ExecutorState.RUNNING; + runHook(); + } + + @Override + public void finish(int returnValue) { + logger.info("[EXECUTOR MONITOR] FINISH: value = {}", returnValue); + this.state = ExecutorState.FINISH; + this.returnValue = returnValue; + runHook(); + } + + @Override + public void error(int returnValue, String msg) { + logger.info("[EXECUTOR MONITOR] ERROR: {}", msg); + this.returnValue = -1; + this.errorMessage = decodeError(returnValue, msg); + this.state = ExecutorState.ERROR; + runHook(); + } + + public static String decodeError(int returnValue, String msg) { + switch (returnValue) { + case 127: + return "Command not found"; + case 130: + return "Script Terminated"; + case 137: + return "Process Killed"; + case 255: + return "Script Error"; + + default: + return msg; + } + } + + public void setExecutor(ExecutorService executor) { + this.executor = executor; + } + + public void addHook(ExecutorState state, ExecutorHook hook) { + if (!stateHooks.containsKey(state)) { + stateHooks.put(state, new ArrayList()); + } + stateHooks.get(state).add(hook); + } + + public String getErrorMessage() { + return errorMessage; + } + + public int getReturnValue() { + return returnValue; + } + + public ExecutorState getState() { + return state; + } + + private void runHook() { + if (stateHooks.containsKey(state)) { + for (ExecutorHook hook : stateHooks.get(state)) { + hook.run(this); + } + } + } +} diff --git a/src/eu/engys/core/executor/ExecutorTerminal.java b/src/eu/engys/core/executor/ExecutorTerminal.java new file mode 100644 index 0000000..f22ab4d --- /dev/null +++ b/src/eu/engys/core/executor/ExecutorTerminal.java @@ -0,0 +1,85 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import java.util.concurrent.ExecutorService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class ExecutorTerminal implements ExecutorListener { + + protected static final Logger logger = LoggerFactory.getLogger(ExecutorTerminal.class); + + private TerminalOutputStream outputStream = new TerminalOutputStream(); + private TerminalOutputStream errorStream = new TerminalOutputStream(); + + private String title; + + protected ExecutorService executor; + + @Override + public void start() { + } + + @Override + public void refresh() { + } + + @Override + public void finish(int returnValue) { + logger.info("[TERMINAL] FINISH: value = {}", returnValue); + outputStream.close(); + errorStream.close(); + } + + @Override + public void error(int exitValue, String msg) { + logger.info("[TERMINAL] ERROR: value = {}", exitValue); + outputStream.close(); + errorStream.close(); + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + public TerminalOutputStream getOutputStream() { + return outputStream; + } + + public TerminalOutputStream getErrorStream() { + return errorStream; + } + + public void setExecutor(ExecutorService executor) { + this.executor = executor; + } +} diff --git a/src/eu/engys/core/executor/FileManagerSupport.java b/src/eu/engys/core/executor/FileManagerSupport.java new file mode 100644 index 0000000..4216049 --- /dev/null +++ b/src/eu/engys/core/executor/FileManagerSupport.java @@ -0,0 +1,170 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import java.awt.Desktop; +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JOptionPane; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.PDFFileFilter; +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.ui.UiUtil; + +public class FileManagerSupport { + + private static final Logger logger = LoggerFactory.getLogger(FileManagerSupport.class); + + private static final String ACTION_NAME = "Open File Manager"; + + public static void openPDF(File parent, String key) { + logger.debug("Looking for PDF file with key {} inside {}", key, parent.getAbsolutePath()); + Collection files = FileUtils.listFiles(parent, new PDFFileFilter(key), null); + if (files.size() == 1) { + open(files.iterator().next()); + } else { + boolean emptyDocumentation = (files.size() == 0); + UiUtil.showDocumentationNotLoadedWarning(emptyDocumentation); + } + } + + public static void open(File file) { + if (Util.isWindows()) { + // Desktop.getDesktop().open(file) on windows may hang + _open(file, "Open action not supported"); + } else { + openOnLinux(file); + } + } + + private static void openOnLinux(File file) { + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + if (desktop.isSupported(Desktop.Action.OPEN)) { + try { + Desktop.getDesktop().open(file); + } catch (IOException e) { + _open(file, e.getMessage()); + } + } else { + _open(file, "Open action not supported"); + } + } else { + _open(file, "Desktop class not supported by this platform"); + } + } + + private static void _open(File file, String logInfo) { + Executor.command(getOpenCommand(file), getOpenCommandArguments(file)).description(ACTION_NAME).exec(); + } + + private static String getOpenCommand(File file) { + String command; + if (Util.isWindows()) { + if (file.isDirectory()) { + command = "explorer"; + } else { + command = "rundll32.exe"; + } + } else { + if (file.isDirectory()) { + command = getLinuxFileManager(); + } else { + command = getLinuxFileOpener(); + } + } + return command; + } + + private static String[] getOpenCommandArguments(File file) { + List command = new LinkedList<>(); + if (Util.isWindows() && !file.isDirectory()) { + command.add("url.dll,FileProtocolHandler"); + } + command.add(file.getAbsolutePath()); + return command.toArray(new String[0]); + } + + private static String getLinuxFileManager() { + String preferredFileManager = PrefUtil.getString(PrefUtil.HELYX_DEFAULT_FILE_MANAGER); + if (preferredFileManager.isEmpty()) { + if (checkTerminal("nautilus")) { + return "nautilus"; + } else if (checkTerminal("dolphin")) { + return "dolphin"; + } else if (checkTerminal("konqueror")) { + return "konqueror"; + } else if (checkTerminal("thunar")) { + return "thunar"; + } else { + logger.error("No file manager found"); + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No File Manager Found", "File System error", JOptionPane.ERROR_MESSAGE); + return ""; + } + } else { + return preferredFileManager; + } + } + + private static String getLinuxFileOpener() { + String preferredFileOpener = PrefUtil.getString(PrefUtil.HELYX_DEFAULT_FILE_OPENER); + if (preferredFileOpener.isEmpty()) { + if (checkTerminal("gnome-open")) { + return "gnome-open"; + } else if (checkTerminal("xdg-open")) { + return "xdg-open"; + } else if (checkTerminal("kde-open")) { + return "kde-open"; + } else { + logger.error("No command available to open the default application, containing folder will be opened instead"); + return getLinuxFileManager(); + } + } else { + return preferredFileOpener; + } + } + + private static boolean checkTerminal(String terminal) { + try { + new ProcessBuilder(terminal, "--help").start().waitFor(); + // System.out.println("RunScript.checkTerminal() "+terminal+" OK"); + return true; + } catch (InterruptedException | IOException e) { + // System.out.println("RunScript.checkTerminal() "+terminal+" NO"); + return false; + } + } + +} diff --git a/src/eu/engys/core/executor/JavaExecutor.java b/src/eu/engys/core/executor/JavaExecutor.java new file mode 100644 index 0000000..753d5cc --- /dev/null +++ b/src/eu/engys/core/executor/JavaExecutor.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.apache.commons.exec.CommandLine; + +public class JavaExecutor extends AbstractScriptExecutor { + + private String className; + private String[] args; + + public JavaExecutor(String className, String... args) { + super(); + this.className = className; + this.args = args; + } + + @Override + public CommandLine getCommandLine() { + return buildCommandLineScript(); + } + + private CommandLine buildCommandLineScript() { + String separator = System.getProperty("file.separator"); + String classpath = System.getProperty("java.class.path"); + String java = System.getProperty("java.home") + separator + "bin" + separator + "java"; + + final CommandLine cmdLine = new CommandLine(java); + cmdLine.addArgument("-classpath"); + cmdLine.addArgument(reletivize(classpath)); + addSystemProperties(cmdLine); + cmdLine.addArgument(className); + cmdLine.addArguments(args); + + return cmdLine; + } + + private String reletivize(String classpath) { + if (currentDir != null) { + String relative = ""; + String[] paths = classpath.split(System.getProperty("path.separator")); + for (String path : paths) { + Path p = Paths.get(path); + if(!p.isAbsolute()){ + p = p.toAbsolutePath(); + } + Path relativize = currentDir.getAbsoluteFile().toPath().relativize(p); + relative += (relativize + System.getProperty("path.separator")); + } + return relative; + } else { + return classpath; + } + } + + private void addSystemProperties(CommandLine cmdLine) { + if (properties != null) { + for (String key : properties.stringPropertyNames()) { + cmdLine.addArgument("-D"+key+"="+properties.getProperty(key)); + } + } + } + + @Override + protected void internalDeleteOnEnd() { + + } +} diff --git a/src/eu/engys/core/executor/MailManagerSupport.java b/src/eu/engys/core/executor/MailManagerSupport.java new file mode 100644 index 0000000..d414568 --- /dev/null +++ b/src/eu/engys/core/executor/MailManagerSupport.java @@ -0,0 +1,136 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import java.awt.Desktop; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.swing.JOptionPane; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.Util; +import eu.engys.util.ui.UiUtil; + +public class MailManagerSupport { + + private static final Logger logger = LoggerFactory.getLogger(MailManagerSupport.class); + // private static final String PREFERRED_MAIL_MANAGER = + // PrefUtil.getString(PrefUtil.HELYX_DEFAULT_MAIL_MANAGER); + private static final String SUPPORT_MAIL = "support@engys.com"; + private static final String SUPPORT_SUBJECT = "Support request"; + + public static void mailSupport() { + mail(SUPPORT_MAIL, SUPPORT_SUBJECT); + } + + public static void mail(String to, String subject) { + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + if (desktop.isSupported(Desktop.Action.MAIL)) { + try { + Desktop.getDesktop().mail(new URI("mailto:" + to + "?subject=" + subject + "&body=")); + } catch (IOException | URISyntaxException e) { + _mail(to, subject, e.getMessage()); + } + } else { + _mail(to, subject, "Mail action not supported"); + } + } else { + _mail(to, subject, "Desktop class not supported by this platform"); + } + } + + private static void _mail(String to, String subject, String logInfo) { + try { + ProcessBuilder pb = getProcessBuilder(to, subject); + pb.start(); + } catch (IOException e) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No mail client found.", "Mail error", JOptionPane.ERROR_MESSAGE); + } + } + + private static ProcessBuilder getProcessBuilder(String to, String subject) { + ProcessBuilder pb = null; + if (Util.isWindows()) { + pb = new ProcessBuilder("rundll32.exe", "url.dll,FileProtocolHandler", "mailto:" + to + "?subject=" + subject + "&body="); + } else { + MailToken token = getLinuxMailManager(to, subject); + pb = new ProcessBuilder(token.getProvider(), token.getCommand()); + } + return pb; + } + + private static MailToken getLinuxMailManager(String to, String subject) { + // if (PREFERRED_MAIL_MANAGER.isEmpty()) { + if (checkMailClient("thunderbird")) { + return new MailToken("thunderbird", "-compose \"to='" + to + "',subject='" + subject.replace("%20", " ") + "'\""); + } else if (checkMailClient("evolution")) { + return new MailToken("evolution", ""); + } else { + logger.error("No mail client found"); + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No mail client found", "Mail Error", JOptionPane.ERROR_MESSAGE); + return new MailToken("", ""); + } + // } else { + // return new MailToken(PREFERRED_MAIL_MANAGER, ""); + // } + } + + private static boolean checkMailClient(String client) { + try { + new ProcessBuilder(client, "--help").start().waitFor(); + return true; + } catch (InterruptedException | IOException e) { + return false; + } + } + + private static class MailToken { + + private final String provider; + private final String command; + + public MailToken(String provider, String command) { + this.provider = provider; + this.command = command; + } + + public String getProvider() { + return provider; + } + + public String getCommand() { + return command; + } + + } + +} diff --git a/src/eu/engys/core/executor/ProgressExecutorMonitor.java b/src/eu/engys/core/executor/ProgressExecutorMonitor.java new file mode 100644 index 0000000..cf1585f --- /dev/null +++ b/src/eu/engys/core/executor/ProgressExecutorMonitor.java @@ -0,0 +1,116 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import javax.swing.JOptionPane; +import javax.swing.ProgressMonitor; + +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public class ProgressExecutorMonitor extends ExecutorTerminal { + + private ProgressMonitor progressMonitor; + private double counter = 0; +// private int counter = 0; + private int max; + private boolean stopped; + + public ProgressExecutorMonitor(int max) { + this.max = max; + } + + @Override + public void start() { + counter = 0; + progressMonitor = new ProgressMonitor(UiUtil.getActiveWindow(), getTitle(),"", 0, 100); + progressMonitor.setProgress((int) counter); +// progressMonitor.setProgress(counter); + } + + @Override + public void finish(int returnValue) { + super.finish(returnValue); + progressMonitor.setProgress(progressMonitor.getMaximum()); + progressMonitor.setNote("Finished"); + } + + @Override + public void error(final int returnValue, final String msg) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), ExecutorMonitor.decodeError(returnValue, msg), "Execution Error", JOptionPane.ERROR_MESSAGE); + } + }); + } + + @Override + public void refresh() { + if (stopped) return; + + counter += getIncrement(); + progressMonitor.setProgress((int)counter); +// progressMonitor.setProgress(++counter); + + String message = String.format("%d%% Completed", (int) counter); + + progressMonitor.setNote(message); +// if (progressMonitor.isCanceled() || getState() == ExecutorState.FINISH || getState() == ExecutorState.ERROR ) { + if (progressMonitor.isCanceled()) { + this.stopped = stopExecutor(); + } +// } + } + + private double getIncrement() { + if (counter < 50) { + return 1; + } else if (counter < 75) { + return 1/2D; + } else { + return 1/4D; + } + } + + public boolean stopExecutor() { +// if (getState() == ExecutorState.START || getState() == ExecutorState.RUNNING) { + if (executor != null) { + int retVal = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "Stop execution?", "Close Monitor", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (retVal == JOptionPane.YES_OPTION) { + executor.shutdownNow(); + return true; + } + return false; + } else { + return true; + } +// } else { +// return true; +// } + } +} diff --git a/src/eu/engys/core/executor/QueueExecutorMonitor.java b/src/eu/engys/core/executor/QueueExecutorMonitor.java new file mode 100644 index 0000000..9600bce --- /dev/null +++ b/src/eu/engys/core/executor/QueueExecutorMonitor.java @@ -0,0 +1,91 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.input.Tailer; +import org.apache.commons.io.input.TailerListenerAdapter; + +public class QueueExecutorMonitor extends ExecutorTerminal { + + private File[] outputFiles; + private List tailers; + + public QueueExecutorMonitor(File... outputFile) { + this.outputFiles = outputFile; + this.tailers = new ArrayList<>(); + } + + @Override + public void start() { + super.start(); + for (File outputFile : outputFiles) { + tailers.add(Tailer.create(outputFile, new MyListener(), 500L)); + } + } + + @Override + public void finish(int returnValue) { + super.finish(returnValue); + for (Tailer tailer : tailers) { + tailer.stop(); + } + } + + @Override + public void error(int returnValue, String msg) { + super.error(returnValue, msg); + for (Tailer tailer : tailers) { + tailer.stop(); + } + System.err.println(msg); + } + + @Override + public void refresh() { + super.refresh(); + System.out.print(getOutputStream().flushLinesBuffer()); + System.err.print(getErrorStream().flushLinesBuffer()); + } + + class MyListener extends TailerListenerAdapter { + + @Override + public void handle(String line) { + System.out.println("[out] "+line); + } + + @Override + public void handle(Exception exception) { + System.err.println("[err] "+exception.getMessage()); + } + + } +} diff --git a/src/eu/engys/core/executor/QueueTerminalExecutorMonitor.java b/src/eu/engys/core/executor/QueueTerminalExecutorMonitor.java new file mode 100644 index 0000000..9e55c84 --- /dev/null +++ b/src/eu/engys/core/executor/QueueTerminalExecutorMonitor.java @@ -0,0 +1,89 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.input.Tailer; +import org.apache.commons.io.input.TailerListenerAdapter; + +public class QueueTerminalExecutorMonitor extends TerminalExecutorMonitor { + + private File[] outputFiles; + private List tailers; + + public QueueTerminalExecutorMonitor(File... outputFile) { + this.outputFiles = outputFile; + this.tailers = new ArrayList<>(); + } + + @Override + public void start() { + for (File outputFile : outputFiles) { + tailers.add(Tailer.create(outputFile, new MyListener(), 500L)); + } + super.start(); + } + + @Override + public void finish(int returnValue) { + super.finish(returnValue); + for (Tailer tailer : tailers) { + tailer.stop(); + } + } + + @Override + public void error(int returnValue, String msg) { + super.error(returnValue, msg); + for (Tailer tailer : tailers) { + tailer.stop(); + } + // System.err.println(msg); + } + + @Override + public void refresh() { + super.refresh(); + // System.out.print(flushLinesBuffer()); + } + + class MyListener extends TailerListenerAdapter { + + @Override + public void handle(String line) { + area.append("[out] " + line + "\n"); + } + + @Override + public void handle(Exception exception) { + area.append("[err] " + exception.getMessage() + "\n"); + } + + } +} diff --git a/src/eu/engys/core/executor/ScriptExecutor.java b/src/eu/engys/core/executor/ScriptExecutor.java new file mode 100644 index 0000000..db08d71 --- /dev/null +++ b/src/eu/engys/core/executor/ScriptExecutor.java @@ -0,0 +1,58 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import java.io.File; + +import org.apache.commons.exec.CommandLine; + +public class ScriptExecutor extends AbstractScriptExecutor { + + private File file; + private String[] args; + + public ScriptExecutor(File file, String... args) { + super(); + this.file = file; + this.args = args; + } + + @Override + protected CommandLine getCommandLine() { + CommandLine commandLine = new CommandLine(file.getAbsolutePath()); + if (args != null && args.length > 0) { + commandLine.addArguments(args); + } + return commandLine; + } + + @Override + protected void internalDeleteOnEnd() { + file.delete(); + } + +} diff --git a/src/eu/engys/core/executor/StateMapperHook.java b/src/eu/engys/core/executor/StateMapperHook.java new file mode 100644 index 0000000..8ad94da --- /dev/null +++ b/src/eu/engys/core/executor/StateMapperHook.java @@ -0,0 +1,49 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import eu.engys.core.controller.Command; +import eu.engys.core.controller.StateConnector; +import eu.engys.core.project.SolverState; +import eu.engys.core.project.state.ServerState; + +public class StateMapperHook implements ExecutorHook { + + private StateConnector connector; + private Command command; + private SolverState solverState; + + public StateMapperHook(StateConnector connector, Command command, SolverState solverState) { + this.command = command; + this.connector = connector; + this.solverState = solverState; + } + + @Override + public void run(ExecutorMonitor m) { + connector.offer(new ServerState(command, solverState, new ExecutorError(m.getReturnValue(), m.getErrorMessage()))); + } +} diff --git a/src/eu/engys/core/executor/TerminalExecutorMonitor.java b/src/eu/engys/core/executor/TerminalExecutorMonitor.java new file mode 100644 index 0000000..d948431 --- /dev/null +++ b/src/eu/engys/core/executor/TerminalExecutorMonitor.java @@ -0,0 +1,318 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import static eu.engys.util.ui.UiUtil.createToolBarButton; +import static eu.engys.util.ui.UiUtil.createToolBarToggleButton; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.swing.Box; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.executor.actions.CloseMonitorAction; +import eu.engys.core.executor.actions.CopyMonitorToClipboardAction; +import eu.engys.core.executor.actions.MaximiseMonitorAction; +import eu.engys.core.executor.actions.SaveLogFileAction; +import eu.engys.core.executor.actions.ScrollLockAction; +import eu.engys.core.executor.actions.ShowLogAction; +import eu.engys.core.executor.actions.StopCommandAction; +import eu.engys.util.PrefUtil; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class TerminalExecutorMonitor extends ExecutorTerminal { + + private static final Logger logger = LoggerFactory.getLogger(TerminalExecutorMonitor.class); + + private static final String RUNNING_LABEL = "Running..."; + public static final String TERMINAL_PANEL_AREA = "terminal.panel.area"; + + protected JTextArea area; + private JScrollPane scroll; + private JToolBar toolbar; + private JPanel panel; + + private Date startTime; + + private JLabel stateLabel; + private JLabel debugLabel; + + private ViewAction copyAction; + private ViewAction saveAsAction; + protected ViewAction closeAction; + protected ViewAction maxAction; + + private ShowLogAction logAction; + private ScrollLockAction scrollAction; + private StopCommandAction stopAction; + + private Runnable stopCommand = new Runnable() { + public void run() { + stopExecutor(); + } + }; + + public TerminalExecutorMonitor() { + super(); + layoutComponents(); + } + + public TerminalExecutorMonitor(File logFile) { + this(); + setLogFile(logFile); + } + + private void layoutComponents() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + area = new JTextArea(); + scroll = new JScrollPane(area); + toolbar = new JToolBar(); + panel = new JPanel(new BorderLayout()); + + scroll.setName("terminal.panel.scroll"); + area.setName(TERMINAL_PANEL_AREA); + + stateLabel = new JLabel(); + stateLabel.setFont(new Font(stateLabel.getFont().getName(), Font.ITALIC, stateLabel.getFont().getSize())); + + debugLabel = new JLabel(); + + stopAction = new StopCommandAction(); + stopAction.setStopCommand(stopCommand); + stopAction.setEnabled(false); + + copyAction = new CopyMonitorToClipboardAction(area); + logAction = new ShowLogAction(); + logAction.setEnabled(false); + saveAsAction = new SaveLogFileAction(area); + + scrollAction = new ScrollLockAction(area); + + toolbar.setFloatable(false); + toolbar.setRollover(false); + toolbar.add(createToolBarButton(stopAction)); + toolbar.addSeparator(); + toolbar.add(createToolBarButton(logAction)); + toolbar.add(createToolBarButton(saveAsAction)); + toolbar.add(createToolBarButton(copyAction)); + toolbar.addSeparator(); + toolbar.add(createToolBarToggleButton(scrollAction)); + toolbar.addSeparator(); + toolbar.add(stateLabel); + toolbar.add(debugLabel); + toolbar.add(Box.createHorizontalGlue()); + + configureFrameActions(toolbar); + + panel.add(toolbar, BorderLayout.NORTH); + panel.add(scroll, BorderLayout.CENTER); + setupFont(); + } + }); + } + + protected void configureFrameActions(JToolBar toolbar) { + maxAction = new MaximiseMonitorAction(panel); + closeAction = new CloseMonitorAction(panel); + closeAction.setEnabled(false); + toolbar.add(createToolBarToggleButton(maxAction)); + toolbar.add(createToolBarButton(closeAction)); + + } + + public void setLogFile(File logFile) { + this.logAction.setLogFile(logFile); + this.logAction.setEnabled(logFile != null); + } + + public void setStopCommand(Runnable stopCommand) { + this.stopAction.setStopCommand(stopCommand); + } + + @Override + public void start() { + startTime = new Date(); + ExecUtil.invokeLater(new Runnable() { + + @Override + public void run() { + show(); + _refresh(); + + stateLabel.setText(RUNNING_LABEL); + stopAction.setEnabled(true); + if (closeAction != null) + closeAction.setEnabled(false); + } + }); + } + + public void show() { + TerminalManager.getInstance().addTerminal(panel, TerminalExecutorMonitor.this); + } + + @Override + public String getTitle() { + return super.getTitle() + " " + getTime(); + } + + private String getTime() { + return new SimpleDateFormat("'['HH:mm:ss']'").format(startTime); + } + + private void setupFont() { + Font font = new Font(Font.MONOSPACED, Font.PLAIN, 10); + area.setFont(font); + area.setBackground(Color.BLACK); + area.setForeground(Color.LIGHT_GRAY); + } + + @Override + public void error(final int returnValue, final String msg) { + super.error(returnValue, msg); + refresh(); + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + stateLabel.setText(""); + stopAction.setEnabled(false); + if (closeAction != null) { + closeAction.setEnabled(true); + } + JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(area), ExecutorMonitor.decodeError(returnValue, msg), "Execution Error", JOptionPane.ERROR_MESSAGE); + } + }); + } + + @Override + public void finish(int returnValue) { + super.finish(returnValue); + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + _refresh(); + stateLabel.setText(""); + stopAction.setEnabled(false); + if (closeAction != null) + closeAction.setEnabled(true); + } + }); + } + + @Override + public void refresh() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + _refresh(); + } + }); + } + + protected void _refresh() { + int maxLines = PrefUtil.getInt(PrefUtil.BATCH_MONITOR_DIALOG_MAX_ROW, 10000); + + String lines = getOutputStream().flushLinesBuffer(); + if (!lines.isEmpty()) { + area.append(lines); + } + + String errors = getErrorStream().flushLinesBuffer(); + if (!errors.isEmpty()) { + area.append(errors); + } + + int lineCount = area.getLineCount(); + if (lineCount > maxLines) { + try { + area.replaceRange("", 0, area.getLineEndOffset(lineCount - maxLines)); + } catch (BadLocationException e) { + logger.warn("Error cleaning text area, {}", e.getMessage()); + } + } + + if (!scrollAction.isSelected()) { + area.setCaretPosition(area.getText().length()); + } + } + + private boolean stopExecutor() { + // if (getState() == ExecutorState.START || getState() == ExecutorState.RUNNING) { + if (executor != null) { + int retVal = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "Stop execution?", "Close Monitor", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (retVal == JOptionPane.YES_OPTION) { + executor.shutdownNow(); + return true; + } + return false; + } else { + return true; + } + // } else { + // return true; + // } + } + + public JPopupMenu createMenu(Component component) { + JPopupMenu pMenu = new JPopupMenu(); + pMenu.add(UiUtil.createMenuItem(new StopCommandAction(true))); + pMenu.add(UiUtil.createMenuItem(new CloseMonitorAction(panel, true))); + return pMenu; + } + + public boolean canClose() { + return closeAction != null && closeAction.isEnabled(); + } + + public void disconnect() { + } + + public JPanel getPanel() { + return panel; + } + +} diff --git a/src/eu/engys/core/executor/TerminalManager.java b/src/eu/engys/core/executor/TerminalManager.java new file mode 100644 index 0000000..9209a39 --- /dev/null +++ b/src/eu/engys/core/executor/TerminalManager.java @@ -0,0 +1,256 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.AbstractButton; +import javax.swing.ImageIcon; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; + +import eu.engys.util.ApplicationInfo; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class TerminalManager { + + private static TerminalManager instance = null; + private Map frames = new HashMap<>(); + private Map monitors = new HashMap<>(); + + public static final String TERMINAL_MANAGER = "terminal.manager"; + + private CollapseManager collapseManager; + private JTabbedPane tabbedPane; + + public static TerminalManager getInstance() { + if (instance == null) { + instance = new TerminalManager(); + } + return instance; + } + + private TerminalManager() { + this.tabbedPane = new JTabbedPane(); + this.tabbedPane.setName(TERMINAL_MANAGER); + this.collapseManager = new CollapseManager(tabbedPane); + } + + public void toggleVisibility() { + collapseManager.toggle(); + } + + public void addTerminal(Component component, TerminalExecutorMonitor monitor) { + if (!contains(component)) { + tabbedPane.addTab(monitor.getTitle(), component); + tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new TerminalTabComponent(this)); + tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1); + + if (!monitors.containsKey(component)) { + monitors.put(component, monitor); + } + } + } + + public boolean contains(Component component) { + return tabbedPane.indexOfComponent(component) >= 0 || frames.containsKey(component); + } + + public String getTitleFor(TerminalTabComponent tabComponent) { + int i = tabbedPane.indexOfTabComponent(tabComponent); + if (i != -1) { + return tabbedPane.getTitleAt(i); + } + return ""; + } + + public void clear() { + closeAll(true); + clearFrames(); + } + + private void clearFrames() { + for (JFrame frame : frames.values()) { + frame.dispose(); + } + frames.clear(); + } + + public void closeAll(boolean forced) { + for (int i = tabbedPane.getTabCount() - 1; i >= 0; i--) { + close(tabbedPane.getComponentAt(i), forced); + } + } + + public void close(Component component, boolean forced) { + final TerminalExecutorMonitor monitor = monitors.get(component); + if (monitor != null && (forced || monitor.canClose())) { + monitor.disconnect(); + _close(component); + } + } + + private void _close(final Component component) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + int i = tabbedPane.indexOfComponent(component); + if (i >= 0) { + tabbedPane.remove(i); + } else if (frames.containsKey(component)) { + frames.remove(component).dispose(); + } + } + }); + } + + public void toTab(final Component component) { + int index = tabbedPane.indexOfComponent(component); + if (index < 0) { + final TerminalExecutorMonitor monitor = monitors.get(component); + _close(component); + addTerminal(component, monitor); + } + } + + public void toDialog(final Component component) { + int index = tabbedPane.indexOfComponent(component); + if (index >= 0) { + final String title = tabbedPane.getTitleAt(index); + _close(component); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + final JFrame frame = createTerminalFrame(component, title, true); + frame.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + frame.dispose(); + } + }); + frame.setVisible(true); + frames.put(component, frame); + } + }); + } + } + + private static void removeMinMaxClose(Component comp) { + if (comp instanceof AbstractButton) { + comp.getParent().remove(comp); + } + if (comp instanceof Container) { + Component[] comps = ((Container) comp).getComponents(); + for (int x = 0, y = comps.length; x < y; x++) { + removeMinMaxClose(comps[x]); + } + } + } + + public static JFrame createTerminalFrame(final Component component, final String title, boolean removeMinMax) { + final JFrame frame = new JFrame(title) { + /** + * This method fixes the Synthetica laf bug that causes incorrect fullscreen window size on secondary monitor. + */ + @Override + public void setMaximizedBounds(Rectangle bounds) { + GraphicsDevice currentFrame = getGraphicsConfiguration().getDevice(); + if (UiUtil.isSecondaryScreen(currentFrame) && getExtendedState() == JFrame.NORMAL) { + super.setMaximizedBounds(UiUtil.getCurrentScreenSize(this)); + } else { + super.setMaximizedBounds(bounds); + } + } + + }; + + if (removeMinMax) { + removeMinMaxClose(frame); + } + + frame.setIconImage(((ImageIcon) ResourcesUtil.getIcon(ApplicationInfo.getVendor().toLowerCase() + ".logo")).getImage()); + frame.setAlwaysOnTop(false); + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(component, BorderLayout.CENTER); + frame.setSize(600, 800); + return frame; + } + + public void showPopup(MouseEvent e) { + Component c = e.getComponent(); + if (c instanceof TerminalTabComponent) { + int index = tabbedPane.indexOfTabComponent(c); + tabbedPane.setSelectedIndex(index); + Component component = tabbedPane.getComponentAt(index); + if (SwingUtilities.isRightMouseButton(e)) { + TerminalExecutorMonitor monitor = monitors.get(component); + JPopupMenu pMenu = monitor.createMenu(component); + pMenu.addSeparator(); + pMenu.add(new JMenuItem(new CloseAllAction(true))); + pMenu.show(c, e.getX(), e.getY()); + } + } + } + + class CloseAllAction extends ViewAction { + + public CloseAllAction() { + this(false); + } + + public CloseAllAction(boolean label) { + super(label ? "Close All Monitors" : "", ResourcesUtil.getIcon("console.tab.closeall.icon"), "Close All Monitors"); + } + + @Override + public void actionPerformed(ActionEvent e) { + closeAll(false); + } + } + + public Component getComponent() { + return tabbedPane; + } +} diff --git a/src/eu/engys/core/executor/TerminalOutputStream.java b/src/eu/engys/core/executor/TerminalOutputStream.java new file mode 100644 index 0000000..5c8433e --- /dev/null +++ b/src/eu/engys/core/executor/TerminalOutputStream.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor; + +import java.io.IOException; +import java.io.OutputStream; + +public class TerminalOutputStream extends OutputStream { + + public static final char NEW_LINE = '\n'; + + private final StringBuffer charactersBuffer = new StringBuffer(128); + private final StringBuffer linesBuffer = new StringBuffer(); + + @Override + public void write(int c) throws IOException { + // append character to buffer + charactersBuffer.append((char) c); + // and newline appends to textarea + if (c == NEW_LINE) { + flush(); + } + } + + @Override + public void close() { + } + + @Override + public final void flush() { + String str = charactersBuffer.toString(); + linesBuffer.append(str); + charactersBuffer.setLength(0); + } + + public String flushLinesBuffer() { + String s = linesBuffer.toString(); + linesBuffer.setLength(0); + return s; + } + + public String peekLines() { + return linesBuffer.toString(); + } +} diff --git a/src/eu/engys/core/executor/TerminalSupport.java b/src/eu/engys/core/executor/TerminalSupport.java new file mode 100644 index 0000000..445a956 --- /dev/null +++ b/src/eu/engys/core/executor/TerminalSupport.java @@ -0,0 +1,86 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.getTestEnvironment; + +import java.io.File; +import java.io.IOException; + +import eu.engys.core.project.Model; +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; + +public class TerminalSupport { + + private static final String ACTION_NAME = "Open Terminal"; + + public static void openTerminal(Model model) { + if (Util.isWindows()) { + Executor.command("start", "cmd", "/K").inFolder(model.getProject().getBaseDir()).withOpenFoamEnv().env(getEnvironment(model)).description(ACTION_NAME).exec(); + } else { + Executor.command(getTerminal() + "$SHELL").inFolder(model.getProject().getBaseDir()).withOpenFoamEnv().env(getEnvironment(model)).description(ACTION_NAME).exec(); + } + } + + public static void openTerminal(File baseDir) { + if (Util.isWindows()) { + Executor.command("start", "cmd", "/K").inFolder(baseDir).withOpenFoamEnv().env(getTestEnvironment()).description(ACTION_NAME).exec(); + } else { + Executor.command(getTerminal() + "$SHELL").inFolder(baseDir).withOpenFoamEnv().env(getTestEnvironment()).description(ACTION_NAME).exec(); + } + } + + private static String getTerminal() { + String preferredTerminal = PrefUtil.getString(PrefUtil.HELYX_DEFAULT_TERMINAL); + if (preferredTerminal.isEmpty()) { + if (checkTerminal("gnome-terminal")) { + return "gnome-terminal --disable-factory --geometry 80x40 -e "; + } else if (checkTerminal("konsole")) { + return "konsole --geometry 80x40 -e "; + } else if (checkTerminal("xterm")) { + return "xterm -sb -font -*-fixed-medium-r-*-*-18-*-*-*-*-*-iso8859-* -geometry 80x40 -hold -e "; + } else { + System.err.println("No terminal found"); + } + } else { + return preferredTerminal + " -e "; + } + + return ""; + } + + private static boolean checkTerminal(String terminal) { + try { + new ProcessBuilder(terminal, "--help").start().waitFor(); + return true; + } catch (InterruptedException | IOException e) { + return false; + } + } +} diff --git a/src/eu/engys/core/executor/TerminalTabComponent.java b/src/eu/engys/core/executor/TerminalTabComponent.java new file mode 100644 index 0000000..af3ea61 --- /dev/null +++ b/src/eu/engys/core/executor/TerminalTabComponent.java @@ -0,0 +1,82 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.executor; + +import java.awt.FlowLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import eu.engys.util.ui.ResourcesUtil; + +public class TerminalTabComponent extends JPanel { + + private static final Icon CONSOLE_ICON = ResourcesUtil.getIcon("console.tab.icon"); + private final TerminalManager manager; + + public TerminalTabComponent(final TerminalManager terminalManager) { + super(new FlowLayout(FlowLayout.LEFT, 0, 0)); + if (terminalManager == null) { + throw new NullPointerException("TabbedPane is null"); + } + this.manager = terminalManager; + setOpaque(false); + + JLabel label = createTabComponent(); + add(label); + label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0)); + addMouseListener(showPopupMenuListener); + } + + private JLabel createTabComponent() { + JLabel label = new JLabel() { + @Override + public String getText() { + return manager.getTitleFor(TerminalTabComponent.this); + } + + @Override + public Icon getIcon() { + return CONSOLE_ICON; + } + }; + return label; + } + + private final MouseListener showPopupMenuListener = new MouseAdapter() { + @Override + public void mouseReleased(MouseEvent e) { + manager.showPopup(e); + }; + }; +} diff --git a/src/eu/engys/core/executor/actions/CloseMonitorAction.java b/src/eu/engys/core/executor/actions/CloseMonitorAction.java new file mode 100644 index 0000000..1f50e97 --- /dev/null +++ b/src/eu/engys/core/executor/actions/CloseMonitorAction.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.JPanel; + +import eu.engys.core.executor.TerminalManager; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.ViewAction; + +public class CloseMonitorAction extends ViewAction { + + private JPanel panel; + + public CloseMonitorAction(JPanel panel) { + this(panel, false); + } + + public CloseMonitorAction(JPanel panel, boolean label) { + super(label ? "Close Current Monitor" : null, ResourcesUtil.getIcon("console.tab.close.icon"), "Close Current Monitor"); + this.panel = panel; + } + + @Override + public void actionPerformed(ActionEvent e) { + TerminalManager.getInstance().close(panel, false); + } +} diff --git a/src/eu/engys/core/executor/actions/CopyMonitorToClipboardAction.java b/src/eu/engys/core/executor/actions/CopyMonitorToClipboardAction.java new file mode 100644 index 0000000..b6ca06f --- /dev/null +++ b/src/eu/engys/core/executor/actions/CopyMonitorToClipboardAction.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor.actions; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; + +import javax.swing.JTextArea; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.ViewAction; + +public class CopyMonitorToClipboardAction extends ViewAction { + + private JTextArea area; + + public CopyMonitorToClipboardAction(JTextArea area) { + this(area, false); + } + + public CopyMonitorToClipboardAction(JTextArea area, boolean label) { + super(label ? "Copy Log to Clipboard" : "", ResourcesUtil.getIcon("console.copy.icon"), "Copy Log to Clipboard"); + this.area = area; + } + + @Override + public void actionPerformed(ActionEvent e) { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(new StringSelection(area.getText()), null); + } +} diff --git a/src/eu/engys/core/executor/actions/MaximiseMonitorAction.java b/src/eu/engys/core/executor/actions/MaximiseMonitorAction.java new file mode 100644 index 0000000..ed50ec0 --- /dev/null +++ b/src/eu/engys/core/executor/actions/MaximiseMonitorAction.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.JPanel; + +import eu.engys.core.executor.TerminalManager; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.ViewAction; + +public class MaximiseMonitorAction extends ViewAction { + + private JPanel panel; + + public MaximiseMonitorAction(JPanel panel) { + this(panel, false); + } + + public MaximiseMonitorAction(JPanel panel, boolean label) { + super(label ? "Maximise Current Monitor" : null, ResourcesUtil.getIcon("console.tab.max.icon"), "Maximise Current Monitor"); + this.panel = panel; + putValue(SMALL_ICON + SELECTED_KEY, ResourcesUtil.getIcon("console.tab.restore.icon")); + putValue(SHORT_DESCRIPTION + SELECTED_KEY, "Restore"); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (isSelected()) { + TerminalManager.getInstance().toDialog(panel); + } else { + TerminalManager.getInstance().toTab(panel); + } + } +} diff --git a/src/eu/engys/core/executor/actions/SaveLogFileAction.java b/src/eu/engys/core/executor/actions/SaveLogFileAction.java new file mode 100644 index 0000000..e8ee606 --- /dev/null +++ b/src/eu/engys/core/executor/actions/SaveLogFileAction.java @@ -0,0 +1,97 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor.actions; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.IOException; + +import javax.swing.JOptionPane; +import javax.swing.JTextArea; + +import org.apache.commons.io.FileUtils; + +import eu.engys.util.PrefUtil; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class SaveLogFileAction extends ViewAction { + + private JTextArea area; + + public SaveLogFileAction(JTextArea area) { + this(area, false); + } + + public SaveLogFileAction(JTextArea area, boolean label) { + super(label ? "Save Log to File" : "", ResourcesUtil.getIcon("save.log.file"), "Save Log to File"); + this.area = area; + } + + @Override + public void actionPerformed(ActionEvent e) { + File workDir = PrefUtil.getWorkDir(PrefUtil.LAST_OPEN_EXPORT_DIR); + HelyxFileChooser fc = new HelyxFileChooser(workDir.getAbsolutePath()); + fc.setTitle("Save Log File"); + fc.setSelectionMode(SelectionMode.FILES_ONLY); + ReturnValue retVal = fc.showSaveAsDialog(); + if (retVal.isApprove()) { + File file = fc.getSelectedFile(); + if (file != null) { + if (file.exists()) { + int answer = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "File already exists. Overwrite?", "File Overwrite", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (answer == JOptionPane.YES_OPTION) { + writeToFile(file); + } + } else { + createFile(file); + writeToFile(file); + } + PrefUtil.putFile(PrefUtil.LAST_OPEN_EXPORT_DIR, file.getParentFile()); + } + } + } + + private void createFile(File file) { + try { + file.createNewFile(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + + private void writeToFile(File file) { + try { + FileUtils.writeStringToFile(file, area.getText()); + } catch (IOException e1) { + e1.printStackTrace(); + } + } +} diff --git a/src/eu/engys/core/executor/actions/ScrollLockAction.java b/src/eu/engys/core/executor/actions/ScrollLockAction.java new file mode 100644 index 0000000..ab68c32 --- /dev/null +++ b/src/eu/engys/core/executor/actions/ScrollLockAction.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.JTextArea; +import javax.swing.text.DefaultCaret; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.ViewAction; + +public class ScrollLockAction extends ViewAction { + + private JTextArea area; + + public ScrollLockAction(JTextArea area) { + this(area, false); + } + + public ScrollLockAction(JTextArea area, boolean label) { + super(label ? "Scroll Lock" : null, ResourcesUtil.getIcon("console.scroll.icon"), "Scroll Lock"); + this.area = area; + putValue(SMALL_ICON + SELECTED_KEY, ResourcesUtil.getIcon("console.scroll.lock.icon")); + putValue(SHORT_DESCRIPTION + SELECTED_KEY, "Scroll Lock"); + + } + + @Override + public void actionPerformed(ActionEvent e) { + if (isSelected()) { + DefaultCaret caret = (DefaultCaret) area.getCaret(); + caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); + } else { + DefaultCaret caret = (DefaultCaret) area.getCaret(); + caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); + } + } + +} diff --git a/src/eu/engys/core/executor/actions/ShowLogAction.java b/src/eu/engys/core/executor/actions/ShowLogAction.java new file mode 100644 index 0000000..a291460 --- /dev/null +++ b/src/eu/engys/core/executor/actions/ShowLogAction.java @@ -0,0 +1,65 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor.actions; + +import java.awt.event.ActionEvent; +import java.io.File; + +import javax.swing.JOptionPane; + +import eu.engys.core.executor.FileManagerSupport; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class ShowLogAction extends ViewAction { + + public static final String OPEN_LOG_FILE = "Open Log File"; + + private File logFile; + + public ShowLogAction() { + this(false); + } + + public ShowLogAction(boolean label) { + super(label ? OPEN_LOG_FILE : null, ResourcesUtil.getIcon("console.browse.icon"), OPEN_LOG_FILE); + } + + public void setLogFile(File logFile) { + this.logFile = logFile; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (logFile != null && logFile.exists()) { + FileManagerSupport.open(logFile); + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No log file has been created.", "File System error", JOptionPane.ERROR_MESSAGE); + } + } + +} diff --git a/src/eu/engys/core/executor/actions/StopCommandAction.java b/src/eu/engys/core/executor/actions/StopCommandAction.java new file mode 100644 index 0000000..4272fe5 --- /dev/null +++ b/src/eu/engys/core/executor/actions/StopCommandAction.java @@ -0,0 +1,57 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.executor.actions; + +import java.awt.event.ActionEvent; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.ViewAction; + +public class StopCommandAction extends ViewAction { + + public static final String STOP_EXECUTION = "Stop Execution"; + + private Runnable stopCommand; + + public StopCommandAction() { + this(false); + } + + public StopCommandAction(boolean label) { + super(label ? STOP_EXECUTION : null, ResourcesUtil.getIcon("console.stop.icon"), STOP_EXECUTION); + } + + public void setStopCommand(Runnable stopCommand) { + this.stopCommand = stopCommand; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (stopCommand != null) { + stopCommand.run(); + } + } +} diff --git a/src/eu/engys/core/modules/ApplicationModule.java b/src/eu/engys/core/modules/ApplicationModule.java new file mode 100644 index 0000000..16d5ac6 --- /dev/null +++ b/src/eu/engys/core/modules/ApplicationModule.java @@ -0,0 +1,91 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules; + +import java.util.Set; + +import eu.engys.core.modules.boundaryconditions.BoundaryConditionsView; +import eu.engys.core.modules.cellzones.CellZonesView; +import eu.engys.core.modules.materials.MaterialsView; +import eu.engys.core.modules.solutionmodelling.SolutionView; +import eu.engys.core.modules.tree.TreeView; +import eu.engys.core.project.InvalidProjectException; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; + +public interface ApplicationModule { + + TreeView getTreeView(); + + Set getCaseSetupPanels(); + + SolutionView getSolutionView(); + + MaterialsView getMaterialsView(); + + BoundaryConditionsView getBoundaryConditionsView(); + + CellZonesView getCellZonesView(); + + FieldsInitialisationView getFieldsInitialisationView(); + + String getName(); + + void loadState() throws InvalidProjectException; + + void loadMaterials(); + + void save(); + + void write(); + + void saveDefaultsToProject(); + + void saveDefaultsTurbulenceModelsToProject(); + + void saveMaterialsToProject(); + + Fields loadDefaultsFields(String region); + +// void initialiseFields(Controller controller, ExecutorService service, Server server); + + CaseSetupWriter getCaseSetupWriter(); + + CaseSetupReader getCaseSetupReader(); + + boolean isFieldInitialisationVetoed(Field field); + + boolean isNonNewtonianViscosityModelVetoed(); + + void updateSolver(State state); + + void updateSolverFamilies(State state, Set families); + + boolean checkLicense(); + +} diff --git a/src/eu/engys/core/modules/ApplicationModuleAdapter.java b/src/eu/engys/core/modules/ApplicationModuleAdapter.java new file mode 100644 index 0000000..95d49f4 --- /dev/null +++ b/src/eu/engys/core/modules/ApplicationModuleAdapter.java @@ -0,0 +1,124 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules; + +import java.util.Collections; +import java.util.Set; + +import eu.engys.core.modules.boundaryconditions.BoundaryConditionsView; +import eu.engys.core.modules.cellzones.CellZonesView; +import eu.engys.core.modules.materials.MaterialsView; +import eu.engys.core.modules.tree.TreeView; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.fields.Field; + +public abstract class ApplicationModuleAdapter implements ApplicationModule { + + @Override + public boolean checkLicense() { + return true; + } + + @Override + public void loadMaterials() { + } + + @Override + public void saveDefaultsToProject() { + } + + @Override + public void saveDefaultsTurbulenceModelsToProject() { + } + + @Override + public void saveMaterialsToProject() { + } + +// @Override +// public void initialiseFields(Controller controller, ExecutorService service, Server server) { +// } + + @Override + public void updateSolver(State state) { + } + + @Override + public void updateSolverFamilies(State state, Set families) { + } + + @Override + public TreeView getTreeView() { + return null; + } + + @Override + public MaterialsView getMaterialsView() { + return null; + } + + @Override + public BoundaryConditionsView getBoundaryConditionsView() { + return null; + } + + @Override + public CellZonesView getCellZonesView() { + return null; + } + + @Override + public FieldsInitialisationView getFieldsInitialisationView() { + return null; + } + + @Override + public CaseSetupReader getCaseSetupReader() { + return null; + } + + @Override + public CaseSetupWriter getCaseSetupWriter() { + return null; + } + + @Override + public Set getCaseSetupPanels() { + return Collections. emptySet(); + } + + @Override + public boolean isFieldInitialisationVetoed(Field field) { + return false; + } + + @Override + public boolean isNonNewtonianViscosityModelVetoed() { + return false; + } + +} diff --git a/src/eu/engys/core/modules/CaseSetupReader.java b/src/eu/engys/core/modules/CaseSetupReader.java new file mode 100644 index 0000000..0299813 --- /dev/null +++ b/src/eu/engys/core/modules/CaseSetupReader.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; + +public interface CaseSetupReader { + + void readFromState(State state, String stateString); + + void readFromConstant(Model loadedModel, Dictionary constant); + + void readFromSystem(Dictionary system); + + void readMaterials(Model model, Dictionary globals); +} diff --git a/src/eu/engys/core/modules/CaseSetupWriter.java b/src/eu/engys/core/modules/CaseSetupWriter.java new file mode 100644 index 0000000..5adf001 --- /dev/null +++ b/src/eu/engys/core/modules/CaseSetupWriter.java @@ -0,0 +1,39 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; + +public interface CaseSetupWriter { + + void addState(StringBuffer sb); + + void addToMaterials(Model model, Dictionary materialProperties); + void addToConstant(Dictionary constantFolder); + void addToSystem(Dictionary constantFolder); + +} diff --git a/src/eu/engys/core/modules/FieldsInitialisationView.java b/src/eu/engys/core/modules/FieldsInitialisationView.java new file mode 100644 index 0000000..5211ba9 --- /dev/null +++ b/src/eu/engys/core/modules/FieldsInitialisationView.java @@ -0,0 +1,38 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.modules; + +import java.util.List; + +import javax.swing.Action; + + +public interface FieldsInitialisationView { + + void configure(List actions); + +} diff --git a/src/eu/engys/core/modules/ModuleDefaults.java b/src/eu/engys/core/modules/ModuleDefaults.java new file mode 100644 index 0000000..40dbfae --- /dev/null +++ b/src/eu/engys/core/modules/ModuleDefaults.java @@ -0,0 +1,72 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.defaults.AbstractDefaultsProvider; +import eu.engys.core.project.defaults.DefaultsProvider; + +public class ModuleDefaults extends AbstractDefaultsProvider { + + private ApplicationModule module; + private DefaultsProvider parent; + private Dictionary fieldsData; + private Dictionary stateData; + private Dictionary turbulenceProperties; + + public ModuleDefaults(ApplicationModule module, DefaultsProvider parent, Dictionary linkResolver) { + this.module = module; + this.parent = parent; + this.fieldsData = ModulesUtil.readDictionary(module, linkResolver, module.getName() + ".fields"); + this.stateData = ModulesUtil.readDictionary(module, linkResolver, module.getName() + ".stateData"); + this.turbulenceProperties = ModulesUtil.readDictionary(module, linkResolver, module.getName() + ".turbulenceProperties"); + } + + @Override + public String getName() { + return module.getName() + " module"; + } + + @Override + public Dictionary getDefaultFieldsData() { + return fieldsData; + } + + @Override + public Dictionary getDefaultStateData() { + return stateData; + } + + @Override + public Dictionary getDefaultTurbulenceProperties() { + return turbulenceProperties; + } + + @Override + public Dictionary getStates() { + return stateData.found("states") ? stateData.subDict("states") : parent.getStates(); + } +} diff --git a/src/eu/engys/core/modules/ModulePanel.java b/src/eu/engys/core/modules/ModulePanel.java new file mode 100644 index 0000000..2e0e850 --- /dev/null +++ b/src/eu/engys/core/modules/ModulePanel.java @@ -0,0 +1,40 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules; + +import javax.swing.JComponent; + + +public interface ModulePanel { + + String getTitle(); + String getKey(); + + JComponent getPanel(); + + int getIndex(); + +} diff --git a/src/eu/engys/core/modules/ModulesUtil.java b/src/eu/engys/core/modules/ModulesUtil.java new file mode 100644 index 0000000..c24148e --- /dev/null +++ b/src/eu/engys/core/modules/ModulesUtil.java @@ -0,0 +1,275 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.Action; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryLinkResolver; +import eu.engys.core.dictionary.parser.DictionaryReader2; +import eu.engys.core.modules.boundaryconditions.BoundaryConditionsView; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.modules.boundaryconditions.IBoundaryConditionsPanel; +import eu.engys.core.modules.cellzones.CellZonesView; +import eu.engys.core.modules.materials.MaterialsView; +import eu.engys.core.modules.tree.ModuleElementPanel; +import eu.engys.core.modules.tree.TreeView; +import eu.engys.core.project.InvalidProjectException; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.core.project.zero.cellzones.CellZones; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.util.ui.builder.PanelBuilder; + +public class ModulesUtil { + + private static final Logger logger = LoggerFactory.getLogger(ModulesUtil.class); + public static final String EXCEPTION_MESSAGE = "You need a valid license for %s add-on module to open this case!"; + + public static Dictionary readDictionary(ApplicationModule module, Dictionary linkResolver, String resource) { + String resourcePath = module.getClass().getPackage().getName().replace(".", "/") + "/resources" + "/" + resource; + InputStream is = ModulesUtil.class.getClassLoader().getResourceAsStream(resourcePath); + if (is != null) { + if (linkResolver != null) { + return new Dictionary(resource, is, new DictionaryLinkResolver(linkResolver)); + } else { + return new Dictionary(resource, is); + } + } else { + logger.warn("FILE NOT FOUND: {}", resourcePath); + return null; + } + } + + public static Dictionary readDictionary2(ApplicationModule module, String resource) { + String resourcePath = module.getClass().getPackage().getName().replace(".", "/") + "/resources" + "/" + resource; + InputStream is = ModulesUtil.class.getClassLoader().getResourceAsStream(resourcePath); + if (is != null) { + + Dictionary dictionary = new Dictionary(resource); + DictionaryReader2 reader = new DictionaryReader2(dictionary); + reader.read(is); + + return dictionary; + } else { + logger.warn("FILE NOT FOUND: {}", resourcePath); + return null; + } + } + + public static Dictionary extractRelativeToStateSettings(String encodedPrimalState, Dictionary mDict) { + if (mDict.found("requirements")) { + Dictionary requirements = (Dictionary) mDict.remove("requirements"); + if (requirements.found("conditional")) { + if (requirements.subDict("conditional").found(encodedPrimalState)) { + Dictionary conditional = requirements.subDict("conditional").subDict(encodedPrimalState); + return conditional; + } + } + } + return null; + } + + public static void updateStateFromGUI(Set modules) { + for (ApplicationModule module : modules) { + module.getSolutionView().updateStateFromGUI(); + } + } + + public static void loadState(Set modules) throws InvalidProjectException { + for (ApplicationModule module : modules) { + module.loadState(); + } + } + + public static void updateSolver(Set modules, State state) { + for (ApplicationModule module : modules) { + module.updateSolver(state); + } + } + + public static void updateSolverFamilies(Set modules, State state, Set families) { + for (ApplicationModule module : modules) { + module.updateSolverFamilies(state, families); + } + } + + public static void loadMaterials(Set modules) { + for (ApplicationModule module : modules) { + module.loadMaterials(); + } + } + + public static void saveDefaultsToProject(Set modules) { + for (ApplicationModule module : modules) { + module.saveDefaultsToProject(); + } + } + + public static void saveDefaultsTurbulenceModelsToProject(Set modules) { + for (ApplicationModule module : modules) { + module.saveDefaultsTurbulenceModelsToProject(); + } + } + + public static void saveDefaultMaterialsToProject(Set modules) { + for (ApplicationModule module : modules) { + module.saveMaterialsToProject(); + } + } + + public static void save(Set modules) { + for (ApplicationModule module : modules) { + module.save(); + } + } + +// public static void initaliseFields(Set modules, Controller controller, ExecutorService service, Server server) { +// for (ApplicationModule module : modules) { +// module.initialiseFields(controller, service, server); +// } +// } + + public static Fields loadFieldsFromDefaults(Set modules, String region) { + Fields fields = new Fields(); + for (ApplicationModule module : modules) { + fields.merge(module.loadDefaultsFields(region)); + } + return fields; + } + + public static void configureMaterialsView(Set modules, PanelBuilder parametersBuilder) { + for (ApplicationModule module : modules) { + MaterialsView materialsView = module.getMaterialsView(); + if (materialsView == null) { + continue; + } + materialsView.configure(parametersBuilder); + } + } + + public static void configureFieldsInitialization(Set modules, List actions) { + for (ApplicationModule module : modules) { + FieldsInitialisationView fieldsView = module.getFieldsInitialisationView(); + if (fieldsView == null) { + continue; + } + fieldsView.configure(actions); + } + } + + public static void configureBoundaryConditionsView(Set modules, IBoundaryConditionsPanel panel) { + for (ApplicationModule module : modules) { + BoundaryConditionsView boundaryConditionsView = module.getBoundaryConditionsView(); + if (boundaryConditionsView == null) + continue; + boundaryConditionsView.configure(panel); + } + } + + public static void configureBoundaryConditionsView(Set modules, BoundaryTypePanel typePanel) { + for (ApplicationModule module : modules) { + BoundaryConditionsView boundaryConditionsView = module.getBoundaryConditionsView(); + if (boundaryConditionsView == null) + continue; + boundaryConditionsView.configure(typePanel); + } + } + + public static List getCellZoneTypes(Set modules) { + List moduleCellZoneTypes = new ArrayList(); + for (ApplicationModule module : modules) { + CellZonesView cellZonesView = module.getCellZonesView(); + if (cellZonesView != null){ + moduleCellZoneTypes.addAll(cellZonesView.getCellZoneTypes()); + } + } + return moduleCellZoneTypes; + } + + public static void updateCellZonesFromModel(Set modules, CellZones cellZones) { + for (ApplicationModule module : modules) { + CellZonesView cellZonesView = module.getCellZonesView(); + if (cellZonesView == null) + continue; + cellZonesView.updateCellZonesFromModel(cellZones); + } + } + + public static void updateModelFromCellZones(Set modules) { + for (ApplicationModule module : modules) { + CellZonesView cellZonesView = module.getCellZonesView(); + if (cellZonesView == null) + continue; + cellZonesView.updateModelFromCellZones(); + } + } + + public static boolean isFieldInitialisationVetoed(Field field, Set modules) { + for (ApplicationModule module : modules) { + if (module.isFieldInitialisationVetoed(field)) + return true; + } + return false; + } + + public static boolean isNonNewtonianViscosityModelVetoed(Set modules) { + for (ApplicationModule module : modules) { + if (module.isNonNewtonianViscosityModelVetoed()) + return true; + } + return false; + } + + public static Set getCaseSetupPanels(Set modules) { + Set panels = new HashSet<>(); + for (ApplicationModule module : modules) { + panels.addAll(module.getCaseSetupPanels()); + } + return panels; + } + + public static void updateTree(Set modules, ModuleElementPanel viewElementPanel) { + for (ApplicationModule module : modules) { + TreeView treeView = module.getTreeView(); + if (treeView == null) + continue; + treeView.updateTree(viewElementPanel); + } + } + +} diff --git a/src/eu/engys/core/modules/boundaryconditions/BoundaryConditionsView.java b/src/eu/engys/core/modules/boundaryconditions/BoundaryConditionsView.java new file mode 100644 index 0000000..4233824 --- /dev/null +++ b/src/eu/engys/core/modules/boundaryconditions/BoundaryConditionsView.java @@ -0,0 +1,38 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.boundaryconditions; + +public interface BoundaryConditionsView { + + // to be removed once the names are fixed + public static final String SINGLE_SPACE = " "; + public static final String DOUBLE_SPACE = " "; + + void configure(BoundaryTypePanel typePanel); + + void configure(IBoundaryConditionsPanel panel); + +} diff --git a/src/eu/engys/core/modules/boundaryconditions/BoundaryTypePanel.java b/src/eu/engys/core/modules/boundaryconditions/BoundaryTypePanel.java new file mode 100644 index 0000000..cb6ea78 --- /dev/null +++ b/src/eu/engys/core/modules/boundaryconditions/BoundaryTypePanel.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.modules.boundaryconditions; + +import java.awt.Component; + +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.core.project.zero.patches.Patch; + +public interface BoundaryTypePanel { + + public static final String MOMENTUM = "Momentum"; + + public static final String TURBULENCE = "Turbulence"; + public static final String THERMAL = "Thermal"; + public static final String PASSIVE_SCALARS = "Passive Scalars"; + public static final String PHASE_FRACTION = "Phase Fraction"; + + void layoutPanel(); + + void loadFromPatches(Patch... patches); + + void saveToPatch(Patch patch); + + BoundaryType getType(); + Component getPanel(); + + ParametersPanel getMomentumPanel(); + ParametersPanel getTurbulencePanel(); + ParametersPanel getThermalPanel(); + ParametersPanel getPanel(String name); + + void stateChanged(); + void materialsChanged(); + + void addMomentumPanel(ParametersPanel momentumPanel); + void addTurbulencePanel(ParametersPanel momentumPanel); + void addThermalPanel(ParametersPanel momentumPanel); + + void addPanel(String name, ParametersPanel pPanel); + void addPanel(String name, ParametersPanel pPanel, int index); + + void resetToDefault(); +} diff --git a/src/eu/engys/core/modules/boundaryconditions/IBoundaryConditionsPanel.java b/src/eu/engys/core/modules/boundaryconditions/IBoundaryConditionsPanel.java new file mode 100644 index 0000000..81978c3 --- /dev/null +++ b/src/eu/engys/core/modules/boundaryconditions/IBoundaryConditionsPanel.java @@ -0,0 +1,34 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.boundaryconditions; + + +public interface IBoundaryConditionsPanel { + + void addTypePanel(BoundaryTypePanel panel); + void removeTypePanel(BoundaryTypePanel panel); + +} diff --git a/src/eu/engys/core/modules/boundaryconditions/ParametersPanel.java b/src/eu/engys/core/modules/boundaryconditions/ParametersPanel.java new file mode 100644 index 0000000..bebd08b --- /dev/null +++ b/src/eu/engys/core/modules/boundaryconditions/ParametersPanel.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.modules.boundaryconditions; + +import javax.swing.JPanel; + +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryConditions; + +public interface ParametersPanel { + + public String getTitle(); + public JPanel getComponent(); + public void tabChanged(Model model); + public void stateChanged(Model model); + public void materialsChanged(Model model); + public DictionaryModel getDictionaryModel(); + + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc); + public void saveToBoundaryConditions(String patchName, BoundaryConditions bc); + + public void setMultipleEditing(boolean multipleSelection); + public boolean canEdit(); + public boolean isEnabled(Model model); + public void resetToDefault(Model model); +} diff --git a/src/eu/engys/core/modules/cellzones/CellZonePanel.java b/src/eu/engys/core/modules/cellzones/CellZonePanel.java new file mode 100644 index 0000000..138231b --- /dev/null +++ b/src/eu/engys/core/modules/cellzones/CellZonePanel.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.modules.cellzones; + +import static eu.engys.util.Symbols.KELVIN; +import static eu.engys.util.Symbols.SQUARE; + +import javax.swing.JComponent; + +import eu.engys.core.dictionary.Dictionary; + +public interface CellZonePanel { + + public static final String MODEL_LABEL = "Model"; + + /* + * MRF + */ + public static final String ORIGIN_LABEL = "Origin"; + public static final String AXIS_LABEL = "Axis"; + public static final String OMEGA_RAD_S_LABEL = "Omega [rad/s]"; + + /* + * Porous + */ + public static final String C1_LABEL = "C1"; + public static final String C0_LABEL = "C0"; + public static final String POWER_LAW = "Power-law"; + public static final String DARCY_FORCHHEIMER = "Darcy-Forchheimer"; + public static final String INERTIAL_LOSS_LABEL = "Inertial Loss Coefficient [1/m]"; + public static final String VISCOUS_LOSS_LABEL = "Viscous Loss Coefficient [1/m" + SQUARE + "]"; + public static final String E2_LABEL = "e2 [m]"; + public static final String E1_LABEL = "e1 [m]"; + + /* + * Thermal + */ + public static final String FIXED_TEMPERATURE_LABEL = "Fixed Temperature"; + public static final String FIXED_TEMPERATURE_K_LABEL = "Fixed Temperature " + KELVIN; + + // CellZoneType getType(); + + JComponent getPanel(); + + void stateChanged(); + + void loadFromDictionary(Dictionary cellZoneDictionary); + + Dictionary saveToDictionary(); + + // Dictionary getDefault(); + + void layoutPanel(); + + // boolean isEnabled(); + +} diff --git a/src/eu/engys/core/modules/cellzones/CellZonesView.java b/src/eu/engys/core/modules/cellzones/CellZonesView.java new file mode 100644 index 0000000..2669ecb --- /dev/null +++ b/src/eu/engys/core/modules/cellzones/CellZonesView.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.cellzones; + +import java.util.List; + +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.core.project.zero.cellzones.CellZones; + +public interface CellZonesView { + + public List getCellZoneTypes(); + + public void updateCellZonesFromModel(CellZones cellZones); + + public void updateModelFromCellZones(); + +} diff --git a/src/eu/engys/core/modules/materials/MaterialsBuilder.java b/src/eu/engys/core/modules/materials/MaterialsBuilder.java new file mode 100644 index 0000000..cd710c0 --- /dev/null +++ b/src/eu/engys/core/modules/materials/MaterialsBuilder.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.modules.materials; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; + +public interface MaterialsBuilder { + + Dictionary saveCompressible(Model model, Dictionary materialGUIDict); + + Dictionary saveIncompressible(Model model, Dictionary materialDict); + + Dictionary toGUIFormat(Dictionary defaultMaterialDict); + + Dictionary loadCompressible(Model model); + +} diff --git a/src/eu/engys/core/modules/materials/MaterialsDatabase.java b/src/eu/engys/core/modules/materials/MaterialsDatabase.java new file mode 100644 index 0000000..1e9dac8 --- /dev/null +++ b/src/eu/engys/core/modules/materials/MaterialsDatabase.java @@ -0,0 +1,93 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.materials; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.defaults.Defaults; + +public class MaterialsDatabase { + + private Map compressibleMaterialsMap = new HashMap<>(); + private Map incompressibleMaterialsMap = new HashMap<>(); + public static final String AIR = "air"; + public static final String MERCURY = "mercury"; + public static final String WATER = "water"; + public static final String OIL = "oil"; + + @Inject + public MaterialsDatabase(Defaults defaults) { + load(defaults); + } + + private void load(Defaults defaults) { + compressibleMaterialsMap.clear(); + incompressibleMaterialsMap.clear(); + + Dictionary compressibleMaterials = defaults.getCompressibleMaterials(); + Dictionary incompressibleMaterials = defaults.getIncompressibleMaterials(); + + for (Dictionary matDict : compressibleMaterials.getDictionaries()) { + matDict.add("materialName", matDict.getName()); + compressibleMaterialsMap.put(matDict.getName(), matDict); + } + for (Dictionary matDict : incompressibleMaterials.getDictionaries()) { + matDict.add("materialName", matDict.getName()); + incompressibleMaterialsMap.put(matDict.getName(), matDict); + } + } + + public Map getCompressibleMaterialsMap() { + return compressibleMaterialsMap; + } + + public Map getIncompressibleMaterialsMap() { + return incompressibleMaterialsMap; + } + + public Collection getCompressibleMaterials() { + return Collections.unmodifiableCollection(compressibleMaterialsMap.values()); + } + + public Collection getIncompressibleMaterials() { + return Collections.unmodifiableCollection(incompressibleMaterialsMap.values()); + } + + public Dictionary getCompressibleMaterial(String materialName) { + return new Dictionary(compressibleMaterialsMap.get(materialName)); + } + + public Dictionary getIncompressibleMaterial(String materialName) { + return new Dictionary(incompressibleMaterialsMap.get(materialName)); + } + +} diff --git a/src/eu/engys/core/modules/materials/MaterialsView.java b/src/eu/engys/core/modules/materials/MaterialsView.java new file mode 100644 index 0000000..ac7a191 --- /dev/null +++ b/src/eu/engys/core/modules/materials/MaterialsView.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.modules.materials; + +import eu.engys.core.project.materials.Material; +import eu.engys.util.ui.builder.PanelBuilder; + +public interface MaterialsView { + + void updateGUIFromModel(Material material); + + void updateModelFromGUI(Material material); + + void configure(PanelBuilder builder); + + void updateDefaultMaterial(Material material); + +} diff --git a/src/eu/engys/core/modules/solutionmodelling/AbstractSolutionView.java b/src/eu/engys/core/modules/solutionmodelling/AbstractSolutionView.java new file mode 100644 index 0000000..d84f361 --- /dev/null +++ b/src/eu/engys/core/modules/solutionmodelling/AbstractSolutionView.java @@ -0,0 +1,86 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.solutionmodelling; + +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.ThermalState; +import eu.engys.util.ui.ChooserPanel; +import eu.engys.util.ui.builder.PanelBuilder; + +public class AbstractSolutionView implements SolutionView { + + @Override + public void buildSolution(ChooserPanel solutionPanel) { + } + + @Override + public void buildMultiphase(MultiphaseBuilder builder) { + } + + @Override + public void buildScalar(SolutionModellingPanel solutionPanel) { + } + + @Override + public void buildDynamic(PanelBuilder builder) { + } + + @Override + public void buildThermal(PanelBuilder builder) { + } + + @Override + public void updateGUIFromState(State state) { + SolutionState ss = new SolutionState(state); + fixSolutionState(ss); + fixMultiphase(state.getMultiphaseModel()); + fixThermal(ss, new ThermalState(state)); + } + + @Override + public void updateStateFromGUI() { + } + + @Override + public boolean hasChanged() { + return false; + } + + @Override + public void fixSolutionState(SolutionState ss) { + } + + @Override + public void fixMultiphase(MultiphaseModel mm) { + } + + @Override + public void fixThermal(SolutionState ss, ThermalState ts) { + } + +} diff --git a/src/eu/engys/core/modules/solutionmodelling/MultiphaseBuilder.java b/src/eu/engys/core/modules/solutionmodelling/MultiphaseBuilder.java new file mode 100644 index 0000000..de060de --- /dev/null +++ b/src/eu/engys/core/modules/solutionmodelling/MultiphaseBuilder.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.solutionmodelling; + +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.util.ui.textfields.SpinnerField; + +public interface MultiphaseBuilder { + + void addMultiphaseChoice(MultiphaseModel vofModel); + + SpinnerField getPhasesField(); + + void enableChoice(MultiphaseModel eulerEulerModel); + + void disableChoice(MultiphaseModel eulerEulerModel); + +} diff --git a/src/eu/engys/core/modules/solutionmodelling/SolutionModellingPanel.java b/src/eu/engys/core/modules/solutionmodelling/SolutionModellingPanel.java new file mode 100644 index 0000000..d598907 --- /dev/null +++ b/src/eu/engys/core/modules/solutionmodelling/SolutionModellingPanel.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.modules.solutionmodelling; + +import eu.engys.util.ui.ChooserPanel; +import eu.engys.util.ui.builder.PanelBuilder; + +public interface SolutionModellingPanel { + + PanelBuilder getDynamicBuilder(); + + MultiphaseBuilder getMultiphasePanel(); + + ChooserPanel getSolverTypePanel(); + + PanelBuilder getScalarsBuilderLeft(); + + PanelBuilder getScalarsBuilderRight(); + +} diff --git a/src/eu/engys/core/modules/solutionmodelling/SolutionView.java b/src/eu/engys/core/modules/solutionmodelling/SolutionView.java new file mode 100644 index 0000000..2aac1d4 --- /dev/null +++ b/src/eu/engys/core/modules/solutionmodelling/SolutionView.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.solutionmodelling; + +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.ThermalState; +import eu.engys.util.ui.ChooserPanel; +import eu.engys.util.ui.builder.PanelBuilder; + +public interface SolutionView { + + void buildSolution(ChooserPanel solutionPanel); + + void buildThermal(PanelBuilder builder); + + void buildMultiphase(MultiphaseBuilder builder); + + void buildDynamic(PanelBuilder builder); + + void buildScalar(SolutionModellingPanel solutionPanel); + + void updateGUIFromState(State state); + + void updateStateFromGUI(); + + boolean hasChanged(); + + void fixSolutionState(SolutionState ss); + + void fixMultiphase(MultiphaseModel mm); + + void fixThermal(SolutionState ss, ThermalState ts); + +} diff --git a/src/eu/engys/core/modules/tree/ModuleElementPanel.java b/src/eu/engys/core/modules/tree/ModuleElementPanel.java new file mode 100644 index 0000000..de1c024 --- /dev/null +++ b/src/eu/engys/core/modules/tree/ModuleElementPanel.java @@ -0,0 +1,35 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.tree; + +import eu.engys.core.modules.ModulePanel; + +public interface ModuleElementPanel { + + void addPanel(ModulePanel phasesPanel); + void removePanel(ModulePanel phasesPanel); + +} diff --git a/src/eu/engys/core/modules/tree/TreeView.java b/src/eu/engys/core/modules/tree/TreeView.java new file mode 100644 index 0000000..fdb848a --- /dev/null +++ b/src/eu/engys/core/modules/tree/TreeView.java @@ -0,0 +1,32 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.modules.tree; + +public interface TreeView { + + void updateTree(ModuleElementPanel viewElementPanel); + +} diff --git a/src/eu/engys/core/parameters/Parameter.java b/src/eu/engys/core/parameters/Parameter.java new file mode 100644 index 0000000..8c34f6d --- /dev/null +++ b/src/eu/engys/core/parameters/Parameter.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.parameters; + +import java.io.Serializable; + +import eu.engys.util.ui.builder.PanelBuilder; + +public interface Parameter extends Serializable { + + public interface ParameterKey extends Serializable { + void generateKey(); + } + + public interface ParameterKeyArgument extends Serializable { + String getArgument(); + } + + ParameterKey getKey(); + + void setName(String name); + String getName(); + + void populate(PanelBuilder builder); + + Number getValue(int component); + + void setValue(Number value, int component); + + Parameter cloneParameter(); + +} diff --git a/src/eu/engys/core/parameters/Parameters.java b/src/eu/engys/core/parameters/Parameters.java new file mode 100644 index 0000000..55a0228 --- /dev/null +++ b/src/eu/engys/core/parameters/Parameters.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.parameters; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import eu.engys.core.parameters.Parameter.ParameterKey; +import eu.engys.util.ui.builder.PanelBuilder; + +public class Parameters implements Serializable { + + private Map delegate = new HashMap<>(); + + public Parameters(Parameters parameters) { + for (ParameterKey key : parameters.delegate.keySet()) { + Parameter parameter = parameters.get(key).cloneParameter(); + add(parameter); + } + } + + public Parameters() { + } + + public void add(Parameter p) { + delegate.put(p.getKey(), p); + } + + public Parameter get(ParameterKey key) { + return delegate.get(key); + } + + public int getSize() { + return delegate.size(); + } + + public void clear() { + delegate.clear(); + } + + public void populate(PanelBuilder builder) { + for (ParameterKey key : delegate.keySet()) { + Parameter p = delegate.get(key); + p.populate(builder); + } + } + + public Collection values() { + return delegate.values(); + } + + public Parameter get(String keyString) { + for (ParameterKey key : delegate.keySet()) { + if (key.toString().equals(keyString)) { + return delegate.get(key); + } + } + return null; + } + + public void print() { + for (ParameterKey key : delegate.keySet()) { + System.out.println("[print] " + key.getClass().getSimpleName()); + } + } + + public Map toMap() { + return delegate; + } + +} diff --git a/src/eu/engys/core/presentation/Action.java b/src/eu/engys/core/presentation/Action.java new file mode 100644 index 0000000..90a937f --- /dev/null +++ b/src/eu/engys/core/presentation/Action.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.presentation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +public @interface Action { + String key(); + boolean checkLicense() default false; + boolean checkEnv() default false; +} diff --git a/src/eu/engys/core/presentation/ActionContainer.java b/src/eu/engys/core/presentation/ActionContainer.java new file mode 100644 index 0000000..7bb2052 --- /dev/null +++ b/src/eu/engys/core/presentation/ActionContainer.java @@ -0,0 +1,31 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.presentation; + +public interface ActionContainer { + + boolean isDemo(); +} diff --git a/src/eu/engys/core/presentation/ActionManager.java b/src/eu/engys/core/presentation/ActionManager.java new file mode 100644 index 0000000..d95fb93 --- /dev/null +++ b/src/eu/engys/core/presentation/ActionManager.java @@ -0,0 +1,140 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.presentation; + +import java.awt.event.ActionEvent; +import java.lang.reflect.Method; + +import javax.swing.ActionMap; +import javax.swing.Icon; + +import eu.engys.core.OpenFOAMEnvironment; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class ActionManager { + + private static ActionManager instance; + private ActionMap map = new ActionMap(); + + public static ActionManager getInstance() { + if (instance == null) + instance = new ActionManager(); + return instance; + } + + public void parseActions(final ActionContainer o) { + Class klass = o.getClass(); + + for (final Method m : klass.getMethods()) { + Action action = m.getAnnotation(Action.class); + if (action != null) { + String key = action.key(); + final boolean checkEnv = action.checkEnv(); + final boolean checkLic = action.checkLicense(); + +// System.out.println("ActionManager.parseActions() FOUND: "+key); + + String label = ResourcesUtil.getString(key+".label"); + String tooltip = ResourcesUtil.getString(key+".tooltip"); + Icon icon = ResourcesUtil.getIcon(key+".icon"); + + map.put(key, new ViewAction(label, icon, tooltip) { + @Override + public void actionPerformed(ActionEvent e) { + try { + if (checkLic) { + if (o.isDemo()) { + UiUtil.showDemoMessage(); + return; + } + } + if (checkEnv) { + if (!OpenFOAMEnvironment.isEnvironementLoaded()) { + UiUtil.showCoreEnvironmentNotLoadedWarning(); + return; + } + } + + m.invoke(o); + + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); + } + ActionToggle actionToggle = m.getAnnotation(ActionToggle.class); + if (actionToggle != null) { + Class[] parameterTypes = m.getParameterTypes(); + if (parameterTypes.length != 1 || (parameterTypes.length == 1 && !parameterTypes[0].equals(boolean.class)) ) { + throw new RuntimeException("'ActionToggle' annotation: the method must have 1 boolean parameter"); + } + String key = actionToggle.key(); + String normal = actionToggle.normal(); + String selected = actionToggle.selected(); +// System.out.println("ActionManager.pa1rseActions() FOUND: "+key); + + String labelNormal = ResourcesUtil.getString(key+"."+normal+".label"); + String tooltipNormal = ResourcesUtil.getString(key+"."+normal+".tooltip"); + Icon iconNormal = ResourcesUtil.getIcon(key+"."+normal+".icon"); + + String labelSelected = ResourcesUtil.getString(key+"."+selected+".label"); + final String tooltipSelected = ResourcesUtil.getString(key+"."+selected+".tooltip"); + final Icon iconSelected = ResourcesUtil.getIcon(key+"."+selected+".icon"); + + map.put(key, new ViewAction(labelNormal, iconNormal, tooltipNormal) { + { + putValue(SMALL_ICON + SELECTED_KEY, iconSelected); + putValue(SHORT_DESCRIPTION + SELECTED_KEY, tooltipSelected); + } + @Override + public void actionPerformed(ActionEvent e) { + try { + m.invoke(o, isSelected()); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); + } + } + } + public void invoke(String string) { + get(string).actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, string)); + } + + public ViewAction get(String string) { + return (ViewAction) map.get(string); + } + + public boolean contains(String string) { + return map.get(string) != null; + } + +} diff --git a/src/eu/engys/core/presentation/ActionToggle.java b/src/eu/engys/core/presentation/ActionToggle.java new file mode 100644 index 0000000..786b8ab --- /dev/null +++ b/src/eu/engys/core/presentation/ActionToggle.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.presentation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +public @interface ActionToggle { + String key(); + String normal(); + String selected(); +} diff --git a/src/eu/engys/core/project/AbstractProjectReader.java b/src/eu/engys/core/project/AbstractProjectReader.java new file mode 100644 index 0000000..b77e9ec --- /dev/null +++ b/src/eu/engys/core/project/AbstractProjectReader.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import java.util.ArrayList; +import java.util.List; + +import eu.engys.util.progress.ProgressMonitor; + +public abstract class AbstractProjectReader implements ProjectReader { + + protected final ProgressMonitor monitor; + protected final Model model; + + protected List readers = new ArrayList<>(); + + public AbstractProjectReader(Model model, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + } + + public Model getModel() { + return model; + } + + public ProgressMonitor getMonitor() { + return monitor; + } + + @Override + public void registerReader(ProjectReader reader) { + if (reader != null) + readers.add(reader); + } +} diff --git a/src/eu/engys/core/project/AbstractProjectWriter.java b/src/eu/engys/core/project/AbstractProjectWriter.java new file mode 100644 index 0000000..e4fcbdc --- /dev/null +++ b/src/eu/engys/core/project/AbstractProjectWriter.java @@ -0,0 +1,64 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.util.progress.ProgressMonitor; + +public abstract class AbstractProjectWriter implements ProjectWriter { + + protected static final Logger logger = LoggerFactory.getLogger(ProjectWriter.class); + + protected final Model model; + protected final ProgressMonitor monitor; + protected final Set modules; + + protected List writers = new ArrayList<>(); + + @Inject + public AbstractProjectWriter(Model model, Set modules, ProgressMonitor monitor) { + this.model = model; + this.modules = modules; + this.monitor = monitor; + } + + @Override + public void registerWriter(ProjectWriter writer) { + if (writer != null) + writers.add(writer); + } + +} diff --git a/src/eu/engys/core/project/CaseParameters.java b/src/eu/engys/core/project/CaseParameters.java new file mode 100644 index 0000000..5016c85 --- /dev/null +++ b/src/eu/engys/core/project/CaseParameters.java @@ -0,0 +1,73 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import java.io.File; + +public class CaseParameters { + private File baseDir; + private boolean isParallel; + private int nProcessors; + private int[] nHierarchy; + + @Override + public String toString() { + return String.format("New %s case (%s processors [%s, %s, %s] ) - ", isParallel() ? "parallel" : "serial", getnProcessors(), getnHierarchy()[0], getnHierarchy()[1], getnHierarchy()[2], getBaseDir().getAbsolutePath()); + } + + public File getBaseDir() { + return baseDir; + } + + public void setBaseDir(File baseDir) { + this.baseDir = baseDir; + } + + public boolean isParallel() { + return isParallel; + } + + public void setParallel(boolean isParallel) { + this.isParallel = isParallel; + } + + public int getnProcessors() { + return nProcessors; + } + + public void setnProcessors(int nProcessors) { + this.nProcessors = nProcessors; + } + + public int[] getnHierarchy() { + return nHierarchy; + } + + public void setnHierarchy(int[] nHierarchy) { + this.nHierarchy = nHierarchy; + } +} diff --git a/src/eu/engys/core/project/CreateCase.java b/src/eu/engys/core/project/CreateCase.java new file mode 100644 index 0000000..98544cc --- /dev/null +++ b/src/eu/engys/core/project/CreateCase.java @@ -0,0 +1,160 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +import static eu.engys.core.project.system.DecomposeParDict.HIERARCHICAL_COEFFS_KEY; +import static eu.engys.core.project.system.DecomposeParDict.NUMBER_OF_SUBDOMAINS_KEY; +import static eu.engys.core.project.system.DecomposeParDict.N_KEY; + +import java.io.File; +import java.io.FileFilter; + +import org.apache.commons.io.FileUtils; + +import eu.engys.core.controller.AbstractScriptFactory; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.project.constant.ConstantFolder; +import eu.engys.core.project.defaults.Defaults; +import eu.engys.core.project.system.SystemFolder; +import eu.engys.util.Util; +import eu.engys.util.progress.ProgressMonitor; + +public class CreateCase { + + public static final int OK = 0; + public static final int CANCEL = 1; + + private ProgressMonitor monitor; + private Defaults defaults; + + public CreateCase(Defaults defaults, ProgressMonitor monitor) { + this.defaults = defaults; + this.monitor = monitor; + } + + public openFOAMProject create(CaseParameters params) { + File baseDir = params.getBaseDir(); + boolean isParallel = params.isParallel(); + int nProcessors = params.getnProcessors(); + int[] nHierarchy = params.getnHierarchy(); + + if (baseDir.exists()) { + deleteAll(baseDir, isParallel, nProcessors); + } else { + baseDir.mkdirs(); + } + + openFOAMProject prj = isParallel ? openFOAMProject.newParallelProject(baseDir, nProcessors) : openFOAMProject.newSerialProject(baseDir); + + SystemFolder systemFolder = prj.getSystemFolder(); + try { + systemFolder.setBlockMeshDict(defaults.getDefaultBlockMeshDict()); + systemFolder.setSnappyHexMeshDict(defaults.getDefaultSnappyHexMeshDict()); + systemFolder.setControlDict(defaults.getDefaultControlDict()); + systemFolder.setFvSchemes(defaults.getDefaultFvSchemes()); + systemFolder.setFvSolution(defaults.getDefaultFvSolution()); + systemFolder.setFvOptions(defaults.getDefaultFvOptions()); + // systemFolder.setRunDict(defaults.getDefaultRunDict()); + systemFolder.setMapFieldsDict(defaults.getDefaultMapFieldsDict()); + systemFolder.setDecomposeParDict(defaults.getDefaultDecomposeParDict()); + systemFolder.setCustomNodeDict(defaults.getDefaultCustomNodeDict()); + systemFolder.getDecomposeParDict().add(NUMBER_OF_SUBDOMAINS_KEY, Integer.toString(nProcessors)); + if (systemFolder.getDecomposeParDict().found(HIERARCHICAL_COEFFS_KEY)) { + String x = Integer.toString(nHierarchy[0]); + String y = Integer.toString(nHierarchy[1]); + String z = Integer.toString(nHierarchy[2]); + // Y X Z + systemFolder.getDecomposeParDict().subDict(HIERARCHICAL_COEFFS_KEY).add(N_KEY, "(" + y + " " + x + " " + z + ")"); + } + } catch (DictionaryException e) { + e.printStackTrace(); + monitor.error(e.getMessage()); + } + + return prj; + } + + public static void deleteAll(File baseDir, boolean isParallel, int nProcessors) { + deleteFile(baseDir, ConstantFolder.CONSTANT); + deleteFile(baseDir, SystemFolder.SYSTEM); + deleteFile(baseDir, "0"); + deleteFile(baseDir, openFOAMProject.LOG); + deleteFile(baseDir, openFOAMProject.POST_PROC); + deleteFile(baseDir, openFOAMProject.HOSTFILE); + deleteFile(baseDir, openFOAMProject.MACHINEFILE); + + if (isParallel) { + for (File processorDir : baseDir.listFiles(new ProcessorDirectoryFileFilter())) { + FileUtils.deleteQuietly(processorDir); + } + } + + if (Util.isWindows()) { + deleteFile(baseDir, AbstractScriptFactory.MESH_SERIAL_BAT); + deleteFile(baseDir, AbstractScriptFactory.MESH_PARALLEL_BAT); + + deleteFile(baseDir, AbstractScriptFactory.CHECK_MESH_SERIAL_BAT); + deleteFile(baseDir, AbstractScriptFactory.CHECK_MESH_PARALLEL_BAT); + + deleteFile(baseDir, AbstractScriptFactory.SOLVER_SERIAL_BAT); + deleteFile(baseDir, AbstractScriptFactory.SOLVER_PARALLEL_BAT); + + deleteFile(baseDir, AbstractScriptFactory.INITIALISE_FIELDS_SERIAL_BAT); + deleteFile(baseDir, AbstractScriptFactory.INITIALISE_FIELDS_PARALLEL_BAT); + + } else { + deleteFile(baseDir, AbstractScriptFactory.MESH_SERIAL_RUN); + deleteFile(baseDir, AbstractScriptFactory.MESH_PARALLEL_RUN); + + deleteFile(baseDir, AbstractScriptFactory.CHECK_MESH_SERIAL_RUN); + deleteFile(baseDir, AbstractScriptFactory.CHECK_MESH_PARALLEL_RUN); + + deleteFile(baseDir, AbstractScriptFactory.SOLVER_SERIAL_RUN); + deleteFile(baseDir, AbstractScriptFactory.SOLVER_PARALLEL_RUN); + + deleteFile(baseDir, AbstractScriptFactory.INITIALISE_FIELDS_SERIAL_RUN); + deleteFile(baseDir, AbstractScriptFactory.INITIALISE_FIELDS_PARALLEL_RUN); + + } + + } + + private static void deleteFile(File baseDir, String name) { + File file = new File(baseDir, name); + if (file.exists()) + FileUtils.deleteQuietly(file); + } + + private static class ProcessorDirectoryFileFilter implements FileFilter { + + @Override + public boolean accept(File pathname) { + boolean isDir = pathname.isDirectory(); + boolean isProcessor = pathname.getName().startsWith("processor"); + return isDir && isProcessor; + } + } +} diff --git a/src/eu/engys/core/project/DefaultProjectReader.java b/src/eu/engys/core/project/DefaultProjectReader.java new file mode 100644 index 0000000..e7b5d24 --- /dev/null +++ b/src/eu/engys/core/project/DefaultProjectReader.java @@ -0,0 +1,159 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +import java.io.File; +import java.util.Set; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.geometry.factory.DefaultGeometryFactory; +import eu.engys.core.project.materials.MaterialsReader; +import eu.engys.core.project.state.StateBuilder; +import eu.engys.core.project.state.Table15; +import eu.engys.core.project.system.ControlDict; +import eu.engys.core.project.system.fieldmanipulationfunctionobjects.FieldManipulationFunctionObjectType; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObjectType; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; +import eu.engys.core.project.zero.fields.Initialisations; +import eu.engys.util.progress.ProgressMonitor; + +public class DefaultProjectReader extends AbstractProjectReader { + + private static final Logger logger = LoggerFactory.getLogger(ProjectReader.class); + private Set modules; + private Set ffoTypes; + private Set mfoTypes; + private final Initialisations initialisation; + private MaterialsReader materialsReader; + private Table15 solversTable; + private CellZonesBuilder cellZoneBuilder; + + @Inject + public DefaultProjectReader(Model model, Table15 solversTable, MaterialsReader materialsReader, CellZonesBuilder cellZoneBuilder, Set modules, Set ffoTypes, Set mfoTypes, Initialisations initialisation, ProgressMonitor monitor) { + super(model, monitor); + this.solversTable = solversTable; + this.materialsReader = materialsReader; + this.cellZoneBuilder = cellZoneBuilder; + this.modules = modules; + this.initialisation = initialisation; + this.ffoTypes = ffoTypes; + this.mfoTypes = mfoTypes; + } + + @Override + public void read() throws InvalidProjectException { + File baseDir = model.getProject().getBaseDir(); + logger.info("################## Read '{}' ################## ", baseDir.getName()); + if (baseDir.exists() && baseDir.isDirectory()) { + defaultRead(); + for (ProjectReader reader : readers) { + reader.read(); + } + DefaultGeometryFactory.clearSTLCache(); + } else { + monitor.error(baseDir + " not found"); + } + logger.info("################## End Read ################## "); + } + + @Override + public void readMesh() { + File baseDir = model.getProject().getBaseDir(); + if (baseDir.exists() && baseDir.isDirectory()) { + openFOAMProject prj = model.getProject(); + ControlDict controlDict = prj.getSystemFolder().getControlDict(); + if (controlDict != null) { + if (controlDict.isBinary()) { + monitor.error("Binary fields format not supported"); + } else { + logger.info("### Read mesh: '{}' ### ", prj.getZeroFolder().getFileManager().getFile()); + prj.getZeroFolder().read(model, cellZoneBuilder, modules, initialisation, monitor); + } + } + + if (!model.getPatches().isEmpty()) { + model.getGeometry().hideSurfaces(); + } + } else { + monitor.error(baseDir + " not found"); + } + } + + protected void defaultRead() throws InvalidProjectException { + monitor.info(""); + monitor.info("Reading Project"); + openFOAMProject project = model.getProject(); + + monitor.info("-> Reading Constant Folder"); + project.getConstantFolder().load(model, monitor); + + monitor.info("-> Reading System Folder"); + project.getSystemFolder().read(model, ffoTypes, mfoTypes, monitor); + + new SolverModelReader(model).load(); + + monitor.info("-> Reading Geometry"); + model.getGeometry().loadGeometry(model, monitor); + + monitor.info("-> Reading State"); + StateBuilder.loadState(model, solversTable, monitor); + solversTable.updateSolver(model.getState()); + + /* + * Call updateSolver after loadState because some module may need some other module state in order to select the correct solver (e.g. Dynamic and VOF) + */ + monitor.info("-> Reading Modules State"); + ModulesUtil.loadState(modules); + ModulesUtil.updateSolver(modules, model.getState()); + + monitor.info("-> Reading Materials"); + model.getMaterials().loadMaterials(model, materialsReader, monitor); + ModulesUtil.loadMaterials(modules); + + monitor.info("-> Reading Zero Folder"); + ControlDict controlDict = project.getSystemFolder().getControlDict(); + if (controlDict != null) { + if (controlDict.isBinary()) { + monitor.error("Binary fields format not supported", 1); + } else { + project.getZeroFolder().read(model, cellZoneBuilder, modules, initialisation, monitor); + } + } else { + monitor.error("No control dict found", 1); + } + + if (!model.getPatches().isEmpty()) { + model.getGeometry().hideSurfaces(); + } + } + +} diff --git a/src/eu/engys/core/project/DefaultProjectWriter.java b/src/eu/engys/core/project/DefaultProjectWriter.java new file mode 100644 index 0000000..ba1202d --- /dev/null +++ b/src/eu/engys/core/project/DefaultProjectWriter.java @@ -0,0 +1,182 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.materials.MaterialsWriter; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; +import eu.engys.core.project.zero.fields.Initialisations; +import eu.engys.util.progress.ProgressMonitor; + +public class DefaultProjectWriter extends AbstractProjectWriter { + + protected static final Logger logger = LoggerFactory.getLogger(ProjectWriter.class); + private MaterialsWriter materialsWriter; + private Initialisations initialisations; + private CellZonesBuilder cellZoneBuilder; + + @Inject + public DefaultProjectWriter(Model model, MaterialsWriter materialsWriter, CellZonesBuilder cellZoneBuilder, Set modules, Initialisations initialisations, ProgressMonitor monitor) { + super(model, modules, monitor); + this.materialsWriter = materialsWriter; + this.cellZoneBuilder = cellZoneBuilder; + this.initialisations = initialisations; + } + + @Override + public void create(CaseParameters params) { + openFOAMProject project = new CreateCase(model.getDefaults(), monitor).create(params); + model.setProject(project); + if (params.isParallel()) { + model.getFields().newParallelFields(project.getProcessors()); + model.getPatches().newParallelPatches(project.getProcessors()); + } + + write(project.getBaseDir()); + for (ProjectWriter writer : writers) { + writer.create(params); + } + } + + @Override + public void write(File baseDir) { + logger.info("################## Write '{}' ################## ", baseDir.getName()); + monitor.info(""); + monitor.info("Saving Project"); + if (!baseDir.exists()) { + baseDir.mkdirs(); + } + + openFOAMProject oldProject = model.getProject(); + boolean isSaveAs = !baseDir.getAbsoluteFile().equals(oldProject.getBaseDir().getAbsoluteFile()); + if (isSaveAs) { + CreateCase.deleteAll(baseDir, oldProject.isParallel(), oldProject.getProcessors()); + makeACopy(baseDir); + setNewProject(baseDir); + } + + writeFoamFile(baseDir); + + model.getGeometry().writeGeometry(model, monitor); + + model.getCustom().saveCustomDict(model); + + new SolverModelWriter(model).save(); + + openFOAMProject project = model.getProject(); + + monitor.info("-> Saving Zero Folder"); + project.getZeroFolder().write(model, cellZoneBuilder, modules, initialisations, monitor); + + monitor.info("-> Saving Constant Folder"); + project.getConstantFolder().write(model, materialsWriter, monitor); + + monitor.info("-> Saving System Folder"); + project.getSystemFolder().write(model, monitor); + + monitor.info("-> Saving Modules"); + for (ApplicationModule m : modules) { + monitor.info(m.getName(), 1); + m.write(); + } + + for (ProjectWriter writer : writers) { + writer.write(baseDir); + } + + File logFolder = new File(baseDir, "log"); + if (!logFolder.exists()) { + logFolder.mkdir(); + } + + monitor.info("-> Saving Custom"); + model.getCustom().write(model, monitor); + + logger.info("################## End Write ############################## "); + } + + private void makeACopy(File baseDir) { + File srcDir = model.getProject().getBaseDir(); + + boolean indeterminate = monitor.isIndeterminate(); + monitor.setIndeterminate(true); + + monitor.info(String.format("Copy: %s -> %s", srcDir.getName(), baseDir.getName())); + logger.info("Copy: {} -> {}", srcDir.getName(), baseDir.getName()); + + try { + FileUtils.copyDirectory(srcDir, baseDir); + } catch (IOException e) { + monitor.error("Error copying folder"); + monitor.error(e.getMessage()); + } + + if (!indeterminate) { + monitor.setIndeterminate(false); + } + + } + + private void setNewProject(File baseDir) { + openFOAMProject prj = openFOAMProject.newCopy(baseDir, model.getProject()); + model.setProject(prj); + } + + private void writeFoamFile(File baseDir) { + FilenameFilter filter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".foam"); + } + }; + File[] foamFiles = baseDir.listFiles(filter); + + if (foamFiles.length > 0) { + for (int i = 0; i < foamFiles.length; i++) { + FileUtils.deleteQuietly(foamFiles[i]); + } + } + + File foamFile = new File(baseDir, baseDir.getName() + ".foam"); + try { + foamFile.createNewFile(); + } catch (IOException e) { + } + } + +} diff --git a/src/eu/engys/core/project/InvalidProjectException.java b/src/eu/engys/core/project/InvalidProjectException.java new file mode 100644 index 0000000..1c47ca1 --- /dev/null +++ b/src/eu/engys/core/project/InvalidProjectException.java @@ -0,0 +1,34 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +public class InvalidProjectException extends RuntimeException { + + public InvalidProjectException(String message) { + super(message); + } + +} diff --git a/src/eu/engys/core/project/Model.java b/src/eu/engys/core/project/Model.java new file mode 100644 index 0000000..f777c29 --- /dev/null +++ b/src/eu/engys/core/project/Model.java @@ -0,0 +1,342 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +import java.util.Observable; + +import javax.inject.Inject; + +import eu.engys.core.modules.materials.MaterialsDatabase; +import eu.engys.core.project.custom.Custom; +import eu.engys.core.project.custom.CustomFile; +import eu.engys.core.project.defaults.Defaults; +import eu.engys.core.project.geometry.Geometry; +import eu.engys.core.project.geometry.factory.GeometryFactory; +import eu.engys.core.project.materials.Materials; +import eu.engys.core.project.mesh.Mesh; +import eu.engys.core.project.runtimefields.RuntimeFields; +import eu.engys.core.project.state.State; +import eu.engys.core.project.system.fieldmanipulationfunctionobjects.FieldManipulationFunctionObjects; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObjects; +import eu.engys.core.project.zero.cellzones.CellZones; +import eu.engys.core.project.zero.facezones.FaceZones; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.patches.Patches; + +public class Model extends Observable { + + private State state; + private openFOAMProject project; + private Geometry geometry; + private Defaults defaults; + private MaterialsDatabase materialsDatabase; + + private Fields fields; + private RuntimeFields runtimeFields; + private Patches patches; + private CellZones cellZones; + private FaceZones faceZones; + private FieldManipulationFunctionObjects fieldManipulationFunctionObjects; + private MonitoringFunctionObjects monitoringFunctionObjects; + private Mesh mesh; + + private Materials materials; + private TurbulenceModels turbulenceModels; + private SolverModel solverModel; + private Custom custom; + + private GeometryFactory geometryFactory; + + public State getState() { + return state; + } + + public void setState(State state) { + this.state = state; + } + + public openFOAMProject getProject() { + return project; + } + + public void setProject(openFOAMProject project) { + this.project = project; + } + + public Fields getFields() { + return fields; + } + + public void setFields(Fields fields) { + this.fields = fields; + } + + public RuntimeFields getRuntimeFields() { + return runtimeFields; + } + + public void setRuntimeFields(RuntimeFields runtimeFields) { + this.runtimeFields = runtimeFields; + } + + public Patches getPatches() { + return patches; + } + + public void setPatches(Patches patches) { + this.patches = patches; + } + + public CellZones getCellZones() { + return cellZones; + } + + public void setCellZones(CellZones cellZones) { + this.cellZones = cellZones; + } + + public FaceZones getFaceZones() { + return faceZones; + } + + public void setFaceZones(FaceZones faceZones) { + this.faceZones = faceZones; + } + + public Materials getMaterials() { + return materials; + } + + public void setMaterials(Materials materials) { + this.materials = materials; + } + + public Geometry getGeometry() { + return geometry; + } + + public void setGeometry(Geometry geometry) { + this.geometry = geometry; + } + + @Inject + public void setGeometryFactory(GeometryFactory geometryFactory) { + this.geometryFactory = geometryFactory; + } + + public Defaults getDefaults() { + return defaults; + } + + @Inject + public void setDefaults(Defaults defaults) { + this.defaults = defaults; + } + + public MaterialsDatabase getMaterialsDatabase() { + return materialsDatabase; + } + + @Inject + public void setMaterialsDatabase(MaterialsDatabase materialsDatabase) { + this.materialsDatabase = materialsDatabase; + } + + public FieldManipulationFunctionObjects getFieldManipulationFunctionObjects() { + return fieldManipulationFunctionObjects; + } + + public void setFieldManipulationFunctionObjects(FieldManipulationFunctionObjects fieldManipulationFunctionObjects) { + this.fieldManipulationFunctionObjects = fieldManipulationFunctionObjects; + } + + public MonitoringFunctionObjects getMonitoringFunctionObjects() { + return monitoringFunctionObjects; + } + + public void setMonitoringFunctionObjects(MonitoringFunctionObjects monitoringFunctionObjects) { + this.monitoringFunctionObjects = monitoringFunctionObjects; + } + + public TurbulenceModels getTurbulenceModels() { + return turbulenceModels; + } + + @Inject + public void setTurbulenceModels(TurbulenceModels turbulenceModels) { + this.turbulenceModels = turbulenceModels; + } + + public SolverModel getSolverModel() { + return solverModel; + } + + public void setSolverModel(SolverModel solverModel) { + this.solverModel = solverModel; + } + + public Mesh getMesh() { + return mesh; + } + + public void setMesh(Mesh mesh) { + this.mesh = mesh; + } + + public Custom getCustom() { + return custom; + } + + public void setCustom(Custom custom) { + this.custom = custom; + } + + public void init() { + setState(new State()); + setGeometry(new Geometry(geometryFactory)); + setMesh(new Mesh()); + setCellZones(new CellZones()); + setFaceZones(new FaceZones()); + setFields(new Fields()); + setRuntimeFields(new RuntimeFields()); + setPatches(new Patches()); + setFieldManipulationFunctionObjects(new FieldManipulationFunctionObjects()); + setMonitoringFunctionObjects(new MonitoringFunctionObjects()); + setMaterials(new Materials()); + setSolverModel(new SolverModel()); + setCustom(new Custom()); + + geometryChanged(); + materialsChanged(); + patchesChanged(); + cellZonesChanged(); + fieldManipulationFunctionObjectsChanged(); + monitoringFunctionObjectsChanged(); + customChanged(); + } + + public boolean hasProject() { + return project != null; + } + + public void stateChanged() { + setChanged(); + notifyObservers(state); + } + + public void patchesChanged() { + setChanged(); + notifyObservers(patches); + } + + public void fieldsChanged() { + setChanged(); + notifyObservers(fields); + } + + public void runtimeFieldsChanged() { + setChanged(); + notifyObservers(runtimeFields); + } + + public void materialsChanged() { + setChanged(); + notifyObservers(materials); + } + + public void cellZonesChanged() { + setChanged(); + notifyObservers(cellZones); + } + + public void faceZonesChanged() { + setChanged(); + notifyObservers(faceZones); + } + + public void monitoringFunctionObjectsChanged() { + setChanged(); + notifyObservers(monitoringFunctionObjects); + } + + public void fieldManipulationFunctionObjectsChanged() { + setChanged(); + notifyObservers(fieldManipulationFunctionObjects); + } + + public void projectChanged() { + setChanged(); + notifyObservers(project); + } + + public void solverChanged() { + setChanged(); + notifyObservers(state.getSolver()); + } + + public void geometryChanged() { + setChanged(); + notifyObservers(geometry); + } + + public void geometryChanged(Object obj) { + setChanged(); + notifyObservers(obj); + } + + public void blockChanged() { + setChanged(); + notifyObservers(geometry.getBlock()); + } + + // public void solverChanged() { + // setChanged(); + // notifyObservers(this); + // } + + public void customFileChanged(CustomFile file) { + setChanged(); + notifyObservers(file); + } + + public void customChanged() { + setChanged(); + notifyObservers(custom); + } + + @Deprecated + @Override + public void notifyObservers() { + super.notifyObservers(); + } + + @Deprecated + @Override + public void notifyObservers(Object arg) { + super.notifyObservers(arg); + } + +} diff --git a/src/eu/engys/core/project/NullProjectReader.java b/src/eu/engys/core/project/NullProjectReader.java new file mode 100644 index 0000000..e5653b7 --- /dev/null +++ b/src/eu/engys/core/project/NullProjectReader.java @@ -0,0 +1,47 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import javax.inject.Inject; + +import eu.engys.util.progress.ProgressMonitor; + +public class NullProjectReader extends AbstractProjectReader { + + @Inject + public NullProjectReader(Model model, ProgressMonitor monitor) { + super(model, monitor); + } + + @Override + public void read() { + } + + @Override + public void readMesh() { + } +} diff --git a/src/eu/engys/core/project/NullProjectWriter.java b/src/eu/engys/core/project/NullProjectWriter.java new file mode 100644 index 0000000..6f20943 --- /dev/null +++ b/src/eu/engys/core/project/NullProjectWriter.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import java.io.File; +import java.util.Set; + +import javax.inject.Inject; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.util.progress.ProgressMonitor; + +public class NullProjectWriter extends AbstractProjectWriter { + + @Inject + public NullProjectWriter(Model model, Set modules, ProgressMonitor monitor) { + super(model, modules, monitor); + } + + @Override + public void write(File baseDir) { + } + + @Override + public void create(CaseParameters params) { + } + +} diff --git a/src/eu/engys/core/project/Project200To210Converter.java b/src/eu/engys/core/project/Project200To210Converter.java new file mode 100644 index 0000000..9531715 --- /dev/null +++ b/src/eu/engys/core/project/Project200To210Converter.java @@ -0,0 +1,438 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +import static eu.engys.core.controller.AbstractScriptFactory.MESH_PARALLEL_BAT; +import static eu.engys.core.controller.AbstractScriptFactory.MESH_PARALLEL_RUN; +import static eu.engys.core.controller.AbstractScriptFactory.MESH_SERIAL_BAT; +import static eu.engys.core.controller.AbstractScriptFactory.MESH_SERIAL_RUN; +import static eu.engys.core.controller.AbstractScriptFactory.SOLVER_PARALLEL_BAT; +import static eu.engys.core.controller.AbstractScriptFactory.SOLVER_PARALLEL_RUN; +import static eu.engys.core.controller.AbstractScriptFactory.SOLVER_SERIAL_BAT; +import static eu.engys.core.controller.AbstractScriptFactory.SOLVER_SERIAL_RUN; +import static eu.engys.core.project.openFOAMProject.HOSTFILE; +import static eu.engys.core.project.openFOAMProject.MACHINEFILE; +import static eu.engys.core.project.system.ControlDict.CONTROL_DICT; +import static eu.engys.core.project.system.ControlDict.FUNCTIONS_KEY; +import static eu.engys.core.project.system.RunDict.HOSTFILE_PATH; +import static eu.engys.core.project.system.RunDict.LOG_FILE; +import static eu.engys.core.project.system.RunDict.RMI_PORT; +import static eu.engys.core.project.system.RunDict.RUN_DICT; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.dictionary.ListField; +import eu.engys.core.project.constant.ConstantFolder; +import eu.engys.core.project.constant.ThermophysicalProperties; +import eu.engys.core.project.materials.Materials200To210Converter; +import eu.engys.core.project.system.CustomNodeDict; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.core.project.system.SystemFolder; +import eu.engys.core.project.zero.cellzones.CellZones; +import eu.engys.core.project.zero.cellzones.CellZones200To210Converter; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; +import eu.engys.util.Util; +import eu.engys.util.progress.SilentMonitor; + +public class Project200To210Converter { + + private static final Logger logger = LoggerFactory.getLogger(Project200To210Converter.class); + + private final SilentMonitor monitor = new SilentMonitor(); + + public static final String POROUS_ZONES = "porousZones"; + public static final String MRF_ZONES = "MRFZones"; + + private openFOAMProject project; + private CellZonesBuilder cellZonesBuilder; + + public Project200To210Converter(openFOAMProject project, CellZonesBuilder cellZonesBuilder) { + this.project = project; + this.cellZonesBuilder = cellZonesBuilder; + } + + public void convert() { + ConstantFolder constantFolder = project.getConstantFolder(); + SystemFolder systemFolder = project.getSystemFolder(); + + convertCellZones(cellZonesBuilder, constantFolder, systemFolder); + convertThermophysicalProperties(constantFolder); + convertSnappyHexMeshDict(systemFolder); + convertRunDict(project); + convertHELYXDict(project); + convertForcesPostProcMapEntry(project); + convertMeshAndSolverScriptName(project); + moveFunctionObjectLogs(project); + } + + private void convertHELYXDict(openFOAMProject project) { + SystemFolder systemFolder = project.getSystemFolder(); + File helyxDictFile = systemFolder.getFileManager().getFile("HELYXDict"); + if (helyxDictFile.exists()) { + CustomNodeDict customDict = new CustomNodeDict(helyxDictFile); + DictionaryUtils.writeDictionary(systemFolder.getFileManager().getFile(), DictionaryUtils.header("system", customDict), monitor); + FileUtils.deleteQuietly(helyxDictFile); + } + } + + private void convertRunDict(openFOAMProject project) { + SystemFolder systemFolder = project.getSystemFolder(); + File runDictFile = systemFolder.getFileManager().getFile(RUN_DICT); + if (runDictFile.exists()) { + Dictionary runDict = DictionaryUtils.readDictionary(runDictFile, monitor); + + boolean writeNeed = false; + // BAD STRUCTURE + if (runDict.isDictionary(RUN_DICT)) { + runDict = new Dictionary(runDict.subDict(RUN_DICT)); + writeNeed = true; + } + // DELETE OLD FUNCTION OBJECTS MAP + if (runDict.found("logFileMap")) { + runDict.remove("logFileMap"); + writeNeed = true; + } + if (runDict.found("postProcFileMap")) { + runDict.remove("postProcFileMap"); + writeNeed = true; + } + // RMI PORT FIX + if (runDict.found(RMI_PORT)) { + int rmiPort = runDict.lookupInt(RMI_PORT); + if (rmiPort < 20000) { + runDict.add(RMI_PORT, String.valueOf(20001)); + writeNeed = true; + } + } + // LOG FILE NAME FIX + if (runDict.found(RMI_PORT)) { + String logName = runDict.lookup(LOG_FILE); + if (logName != null) { + File logFile = new File(logName); + if (!logName.isEmpty() && logFile.isAbsolute()) { + runDict.add(LOG_FILE, logFile.getName()); + writeNeed = true; + } + } + } + String hostfilePath = runDict.lookup(HOSTFILE_PATH); + if (hostfilePath == null || hostfilePath.isEmpty()) { + fixHostFilePath(project, runDict); + writeNeed = true; + } + if (writeNeed) { + DictionaryUtils.writeDictionary(systemFolder.getFileManager().getFile(), DictionaryUtils.header("system", runDict), monitor); + } + } + } + + private void fixHostFilePath(openFOAMProject project, Dictionary runDict) { + File baseDir = project.getBaseDir(); + if (new File(baseDir, HOSTFILE).exists()) { + runDict.add(HOSTFILE_PATH, HOSTFILE); + } else if (new File(baseDir, MACHINEFILE).exists()) { + runDict.add(HOSTFILE_PATH, MACHINEFILE); + } else if (new File(project.getSystemFolder().getFileManager().getFile(), HOSTFILE).exists()) { + runDict.add(HOSTFILE_PATH, SystemFolder.SYSTEM + "/" + HOSTFILE); + } else if (new File(project.getSystemFolder().getFileManager().getFile(), MACHINEFILE).exists()) { + runDict.add(HOSTFILE_PATH, SystemFolder.SYSTEM + "/" + MACHINEFILE); + } else { + runDict.add(HOSTFILE_PATH, HOSTFILE); + } + } + + private void convertForcesPostProcMapEntry(openFOAMProject project) { + File runDictFile = project.getSystemFolder().getFileManager().getFile(RUN_DICT); + if (runDictFile.exists()) { + Dictionary runDict = DictionaryUtils.readDictionary(runDictFile, monitor); + boolean writeNeed = false; + + if (writeNeed) { + DictionaryUtils.writeDictionary(project.getSystemFolder().getFileManager().getFile(), DictionaryUtils.header("system", runDict), monitor); + } + } + } + + private void convertMeshAndSolverScriptName(openFOAMProject project) { + File baseDir = project.getBaseDir(); + + String parallelIdentifier = Util.isWindows() ? "mpiexec -n" : "mpirun -np"; + + try { + File solverScript = new File(baseDir, Util.isWindows() ? "solver.bat" : "solver.run"); + if (solverScript.exists()) { + if (FileUtils.readFileToString(solverScript).contains(parallelIdentifier)) { + solverScript.renameTo(new File(baseDir, Util.isWindows() ? SOLVER_PARALLEL_BAT : SOLVER_PARALLEL_RUN)); + } else { + solverScript.renameTo(new File(baseDir, Util.isWindows() ? SOLVER_SERIAL_BAT : SOLVER_SERIAL_RUN)); + } + } + + File meshScript = new File(baseDir, Util.isWindows() ? "mesh.bat" : "mesh.run"); + if (meshScript.exists()) { + if (FileUtils.readFileToString(meshScript).contains(parallelIdentifier)) { + meshScript.renameTo(new File(baseDir, Util.isWindows() ? MESH_PARALLEL_BAT : MESH_PARALLEL_RUN)); + } else { + meshScript.renameTo(new File(baseDir, Util.isWindows() ? MESH_SERIAL_BAT : MESH_SERIAL_RUN)); + } + } + } catch (IOException e) { + logger.error("Could not rename script files"); + } + } + + private void moveFunctionObjectLogs(openFOAMProject project) { + setupPostProcFolder(project); + File controlDictFile = project.getSystemFolder().getFileManager().getFile(CONTROL_DICT); + if (controlDictFile.exists()) { + Dictionary controlDict = DictionaryUtils.readDictionary(controlDictFile, monitor); + boolean hasFunctionObjects = controlDict.isList(FUNCTIONS_KEY); + if (hasFunctionObjects) { + ListField fos = controlDict.getList(FUNCTIONS_KEY); + String baseDirPath = project.getBaseDir().getAbsolutePath(); + for (DefaultElement element : fos.getListElements()) { + if (element instanceof Dictionary) { + Dictionary foDict = (Dictionary) element; + if (foDict.found(Dictionary.TYPE)) { + String type = foDict.lookup(Dictionary.TYPE); + switch (type) { + case "liftDrag": + moveLiftDragFunctionObject(baseDirPath, foDict); + break; + case "volumeReport": + moveVolumeReportFunctionObject(baseDirPath, foDict); + break; + case "forces": + moveForcesFunctionObject(baseDirPath, foDict); + break; + default: + break; + } + } + + } + } + } + } + } + + private void moveLiftDragFunctionObject(String baseDirPath, Dictionary foDict) { + String foName = foDict.getName(); + File logFolder = Paths.get(baseDirPath, openFOAMProject.LOG).toFile(); + if (logFolder.exists()) { + for (File child : logFolder.listFiles()) { + String fileName = child.getName(); + if (fileName.startsWith(foName) && fileName.endsWith(".dat")) { + File postProcFolder = Paths.get(baseDirPath, openFOAMProject.POST_PROC).toFile(); + File functionObjectFolder = new File(postProcFolder, foName); + try { + FileUtils.moveFileToDirectory(child, functionObjectFolder, true); + } catch (IOException e) { + logger.error("Could not move " + child + " to " + functionObjectFolder); + } + } + } + } + } + + private void moveVolumeReportFunctionObject(String baseDirPath, Dictionary foDict) { + String foName = foDict.getName(); + File logFolder = Paths.get(baseDirPath, openFOAMProject.LOG).toFile(); + if (logFolder.exists()) { + for (File child : logFolder.listFiles()) { + String fileName = child.getName(); + if (fileName.startsWith(foName + "_volumeStatistics.")) { + File postProcFolder = Paths.get(baseDirPath, openFOAMProject.POST_PROC).toFile(); + File functionObjectFolder = new File(postProcFolder, foName); + try { + FileUtils.moveFileToDirectory(child, functionObjectFolder, true); + } catch (IOException e) { + logger.error("Could not move " + child + " to " + functionObjectFolder); + } + } + } + } + } + + private void moveForcesFunctionObject(String baseDirPath, Dictionary foDict) { + String foName = foDict.getName(); + File foFolder = Paths.get(baseDirPath, foName).toFile(); + if (foFolder.exists() && foFolder.isDirectory()) { + File postProcFolder = Paths.get(baseDirPath, openFOAMProject.POST_PROC).toFile(); + try { + FileUtils.moveDirectoryToDirectory(foFolder, postProcFolder, true); + } catch (IOException e) { + logger.error("Could not move " + foFolder + " to " + postProcFolder); + } + } + } + + private void setupPostProcFolder(openFOAMProject project) { + File postProcFolder = Paths.get(project.getBaseDir().getAbsolutePath(), openFOAMProject.POST_PROC).toFile(); + if (!postProcFolder.exists()) { + postProcFolder.mkdir(); + } + } + + private void convertSnappyHexMeshDict(SystemFolder systemFolder) { + File snappyFile = systemFolder.getFileManager().getFile(SnappyHexMeshDict.SNAPPY_DICT); + if (snappyFile.exists()) { + Dictionary snappy = DictionaryUtils.readDictionary(snappyFile, monitor); + if (snappy.isDictionary("castellatedMeshControls")) { + Dictionary castellated = snappy.subDict("castellatedMeshControls"); + Dictionary layers = snappy.subDict("addLayersControls"); + + boolean needWrite = false; + /* LOCATIONS IN MESH */ + if (castellated.isField("locationsInMesh")) { + try { + String[][] matrix = castellated.lookupMatrix("locationsInMesh"); + castellated.remove("locationsInMesh"); + castellated.add("locationInMesh", "(" + matrix[0][0] + " " + matrix[0][1] + " " + matrix[0][2] + ")"); + } catch (DictionaryException e) { + castellated.remove("locationsInMesh"); + if (!castellated.isField("locationInMesh")) { + castellated.add("locationInMesh", "(0 0 0)"); + } + } + needWrite = true; + } + + /* FEATURE LINES */ + if (castellated.isList("features")) { + for (DefaultElement el : castellated.getList("features").getListElements()) { + if (el instanceof Dictionary) { + Dictionary d = (Dictionary) el; + // System.out.println("Project200To210Converter.Project200To210Converter() "+d); + if (d.isField("level")) { + d.add("levels", "( 0.0 " + d.lookup("level") + ")"); + d.remove("level"); + needWrite = true; + } + } + } + } + + /* LAYERS OPTIONS */ + if (layers != null) { + if (!layers.found("writeVTK")) { + layers.add("writeVTK", "false"); + needWrite = true; + } + if (!layers.found("noErrors")) { + layers.add("noErrors", "false"); + needWrite = true; + } + if (!layers.found("layerRecovery")) { + layers.add("layerRecovery", "1"); + needWrite = true; + } + if (!layers.found("growZoneLayers")) { + layers.add("growZoneLayers", "false"); + needWrite = true; + } + if (!layers.found("projectGrownUp")) { + layers.add("projectGrownUp", "0.0"); + needWrite = true; + } + } + + if (needWrite) { + DictionaryUtils.writeDictionary(systemFolder.getFileManager().getFile(), DictionaryUtils.header("system", snappy), monitor); + } + } + } + } + + private void convertThermophysicalProperties(ConstantFolder constantFolder) { + File thermoPhysicalPropertiesFile = constantFolder.getFileManager().getFile(ThermophysicalProperties.THERMOPHYSICAL_PROPERTIES); + if (thermoPhysicalPropertiesFile.exists()) { + Dictionary thermophysicalPropertiesOLD = DictionaryUtils.readDictionary(thermoPhysicalPropertiesFile, monitor); + if (thermophysicalPropertiesOLD.isField("thermoType")) { + Materials200To210Converter converter = new Materials200To210Converter(); + Dictionary thermophysicalPropertiesNEW = converter.convert(thermophysicalPropertiesOLD); + DictionaryUtils.writeDictionary(constantFolder.getFileManager().getFile(), DictionaryUtils.header("constant", thermophysicalPropertiesNEW), monitor); + } + } + } + + private void convertCellZones(CellZonesBuilder cellZonesBuilder, ConstantFolder constantFolder, SystemFolder systemFolder) { + CellZones zones = new CellZones(); + + File MRFZonesFile = constantFolder.getFileManager().getFile(MRF_ZONES); + if (MRFZonesFile.exists()) { + MRFZones mrfZones = getMRFZones(DictionaryUtils.readDictionary(MRFZonesFile, monitor)); + zones.addAll(CellZones200To210Converter.loadMRFDictionary(mrfZones)); + } + File porousZonesFile = constantFolder.getFileManager().getFile(POROUS_ZONES); + if (porousZonesFile.exists()) { + PorousZones porousZones = getPorousZones(DictionaryUtils.readDictionary(porousZonesFile, monitor)); + zones.addAll(CellZones200To210Converter.loadPorousDictionary(porousZones)); + } + + cellZonesBuilder.saveMRFDictionary(zones, systemFolder.getFvOptions()); + cellZonesBuilder.savePorousDictionary(zones, systemFolder.getFvOptions()); + + DictionaryUtils.writeDictionary(systemFolder.getFileManager().getFile(), systemFolder.getFvOptions(), monitor); + } + + private PorousZones getPorousZones(Dictionary dict) { + PorousZones porousZones = new PorousZones(); + porousZones.merge(dict); + return porousZones; + } + + private MRFZones getMRFZones(Dictionary dict) { + MRFZones MRFZones = new MRFZones(); + MRFZones.merge(dict); + return MRFZones; + } + + public class PorousZones extends Dictionary { + public PorousZones() { + super(POROUS_ZONES); + setFoamFile(FoamFile.getDictionaryFoamFile(ConstantFolder.CONSTANT, POROUS_ZONES)); + } + } + + public class MRFZones extends Dictionary { + public MRFZones() { + super(MRF_ZONES); + setFoamFile(FoamFile.getDictionaryFoamFile(ConstantFolder.CONSTANT, MRF_ZONES)); + } + } +} diff --git a/src/eu/engys/core/project/ProjectFolderAnalyzer.java b/src/eu/engys/core/project/ProjectFolderAnalyzer.java new file mode 100644 index 0000000..6d03ec7 --- /dev/null +++ b/src/eu/engys/core/project/ProjectFolderAnalyzer.java @@ -0,0 +1,276 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import static eu.engys.core.project.constant.ConstantFolder.CONSTANT; +import static eu.engys.core.project.system.ControlDict.CONTROL_DICT; +import static eu.engys.core.project.system.FvSchemes.FV_SCHEMES; +import static eu.engys.core.project.system.FvSolution.FV_SOLUTION; +import static eu.engys.core.project.system.SystemFolder.SYSTEM; + +import java.awt.Window; +import java.io.File; +import java.io.FileFilter; + +import javax.swing.JOptionPane; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.Arguments; +import eu.engys.core.Arguments.CaseType; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.project.system.DecomposeParDict; +import eu.engys.core.project.system.SystemFolder; +import eu.engys.core.project.zero.ParallelZeroFileManager; +import eu.engys.core.project.zero.SerialZeroFileManager; +import eu.engys.core.project.zero.ZeroFolderStructure; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.progress.SilentMonitor; +import eu.engys.util.ui.UiUtil; + +public class ProjectFolderAnalyzer { + + private static final Logger logger = LoggerFactory.getLogger(ProjectFolderAnalyzer.class); + +// parallel parallel serial serial +// zero constant zero constant +// +// T T T T -> A +// T T T F -> A +// T T F T -> P +// T T F F -> P +// +// T F T T -> A +// T F T F -> A +// T F F T -> P +// T F F F -> P +// +// F T T T -> S +// F T T F -> S +// F T F T -> A +// F T F F -> P +// +// F F T T -> S +// F F T F -> S +// F F F T -> S +// F F F F -> N + + + private static final String PROCESSOR = "processor"; + + private final File baseDir; + + private int processors; + + private boolean parallel_constant;/* whether boudary is in 0 or in constant */ + private boolean parallel_zero;/* whether boudary is in 0 or in constant */ + + private boolean serial_constant;/* whether boudary is in 0 or in constant */ + private boolean serial_zero;/* whether boudary is in 0 or in constant */ + + private final ProgressMonitor monitor; + + public ProjectFolderAnalyzer(File baseDir, ProgressMonitor monitor) { + this.baseDir = baseDir; + this.monitor = monitor; + } + + public ProjectFolderStructure checkAll() { + checkSerialOrParallel(); + return populateStructure(); + } + + private ProjectFolderStructure populateStructure() { + ProjectFolderStructure structure = new ProjectFolderStructure(); + if (parallel_zero) { + if (serial_zero) { + logger.debug("Case is PARALLEL {} proc, mesh is BOTH on parallel_and_serial_zero folder", processors); + askToUser(structure); + } else { + logger.debug("Case is PARALLEL {} proc, mesh is ONLY on parallel_zero folder", processors); + structure.setParallel(true); + structure.setProcessors(processors); + } + } else { + if (parallel_constant) { + if (serial_zero) { + logger.debug("Case is SERIAL, mesh is BOTH on parallel_constant folder and serial_zero folder"); + structure.setParallel(false); + structure.setProcessors(-1); + } else { + if (serial_constant) { + logger.debug("Case is PARALLEL {} proc, mesh is BOTH on parallel_and_serial_constant folder", processors); + askToUser(structure); + } else { + logger.debug("Case is PARALLEL {} proc, mesh is on parallel_constant folder", processors); + structure.setParallel(true); + structure.setProcessors(processors); + } + } + } else { + if (serial_zero) { + logger.debug("Case is SERIAL, mesh is on serial_zero folder"); + structure.setParallel(false); + structure.setProcessors(-1); + } else { + if (serial_constant) { + logger.debug("Case is SERIAL, mesh is both on serial zero and constant folder"); + structure.setParallel(false); + structure.setProcessors(-1); + } else { + logger.debug("Looking into decomposeParDict"); + checkIntoDecomposePar(structure); + } + } + } + } + logger.debug(structure.toString()); + return structure; + } + + public ProjectFolderAnalyzer checkSerialOrParallel() { + if (baseDir.exists() && baseDir.isDirectory()) { + processors = findProcessorsFolders(); + if (processors > 0) { + checkParallelBoundary(); + } + + checkSerialBoundary(); + } + return this; + } + + public int findProcessorsFolders() { + File[] processorFiles = baseDir.listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + return file.isDirectory() && file.getName().startsWith(PROCESSOR); + } + }); + int numberOfProcessors = -1; + for (File file : processorFiles) { + String processorIndexString = file.getName().replace(PROCESSOR, ""); + int processorIndex = Integer.parseInt(processorIndexString); + numberOfProcessors = Math.max(numberOfProcessors, processorIndex); + } + return numberOfProcessors + 1; + } + + void checkParallelBoundary() { + ParallelZeroFileManager fileManager = new ParallelZeroFileManager(baseDir, processors); + ZeroFolderStructure structure = fileManager.checkFileSystem(); + + parallel_zero = structure.isBoundaryFieldInZero(); + parallel_constant = structure.isBoundaryFieldInConstant(); + } + + void checkSerialBoundary() { + SerialZeroFileManager fileManager = new SerialZeroFileManager(baseDir); + ZeroFolderStructure structure = fileManager.checkFileSystem(); + + serial_zero = structure.isBoundaryFieldInZero(); + serial_constant = structure.isBoundaryFieldInConstant(); + } + + private void askToUser(ProjectFolderStructure checkList) { + if (Arguments.isBatch()) { + if (Arguments.caseType == CaseType.SERIAL) { + logger.debug("Is Batch, case type is SERIAL"); + checkList.setParallel(false); + checkList.setProcessors(-1); + } else if (Arguments.caseType == CaseType.PARALLEL) { + logger.debug("Is Batch, case type is PARALLEL"); + checkList.setParallel(true); + checkList.setProcessors(processors); + } else { + System.err.println("Case folder contains a serial AND a parallel case.\nPlease select which case to load: use '-serial' or '-parallel' option"); + System.exit(-1); + } + } else { + Object[] options = { "Serial", "Parallel" }; + Window parentComponent = monitor != null ? monitor.getDialog() : UiUtil.getActiveWindow(); + int answer = JOptionPane.showOptionDialog(parentComponent, "Project contains serial AND parallel case.\nPlease select which case to load", "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options, options[0]); + logger.debug("Asking user"); + if (answer == 0) { + checkList.setParallel(false); + checkList.setProcessors(-1); + } else { + checkList.setParallel(true); + checkList.setProcessors(processors); + } + } + } + + void checkIntoDecomposePar(ProjectFolderStructure checkList) { + File decomposePar = new File(new File(baseDir, SystemFolder.SYSTEM), DecomposeParDict.DECOMPOSE_PAR_DICT); + if (decomposePar.exists()) { + Dictionary dPar = DictionaryUtils.readDictionary(decomposePar, new SilentMonitor()); + String nPar = dPar.lookup(DecomposeParDict.NUMBER_OF_SUBDOMAINS_KEY); + + try { + int n = Integer.parseInt(nPar); + checkList.setParallel(n > 1); + checkList.setProcessors(n); + } catch (Exception e) { + } + } + } + + public boolean isParallel_constant() { + return parallel_constant; + } + + public boolean isParallel_zero() { + return parallel_zero; + } + + public boolean isSerial_constant() { + return serial_constant; + } + + public boolean isSerial_zero() { + return serial_zero; + } + + public static boolean isSuitable(File file) { + if (file != null && file.exists() && file.isDirectory()) { + File constant = new File(file, CONSTANT); + File system = new File(file, SYSTEM); + + if (constant.exists() && constant.isDirectory() && system.exists() && system.isDirectory()) { + File controlDict = new File(system, CONTROL_DICT); + File fvSchemes = new File(system, FV_SCHEMES); + File fvSolution = new File(system, FV_SOLUTION); + return fvSchemes.exists() && controlDict.exists() && fvSolution.exists(); + } + return false; + } + return false; + } +} diff --git a/src/eu/engys/core/project/ProjectFolderStructure.java b/src/eu/engys/core/project/ProjectFolderStructure.java new file mode 100644 index 0000000..ab87db4 --- /dev/null +++ b/src/eu/engys/core/project/ProjectFolderStructure.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +public class ProjectFolderStructure { + + private boolean parallel; + private int processors; + + public boolean isParallel() { + return parallel; + } + + public void setParallel(boolean parallel) { + this.parallel = parallel; + } + + public int getProcessors() { + return processors; + } + + public void setProcessors(int processors) { + this.processors = processors; + } + + @Override + public String toString() { + return "Project Structure: " + (isParallel() ? ("parallel with " + processors + " processors") : "serial"); + } + +} diff --git a/src/eu/engys/core/project/ProjectReader.java b/src/eu/engys/core/project/ProjectReader.java new file mode 100644 index 0000000..36f4d7a --- /dev/null +++ b/src/eu/engys/core/project/ProjectReader.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +public interface ProjectReader { + + public void read() throws InvalidProjectException; + + public void readMesh(); + + public void registerReader(ProjectReader reader); +} diff --git a/src/eu/engys/core/project/ProjectWriter.java b/src/eu/engys/core/project/ProjectWriter.java new file mode 100644 index 0000000..6e8113a --- /dev/null +++ b/src/eu/engys/core/project/ProjectWriter.java @@ -0,0 +1,38 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import java.io.File; + + +public interface ProjectWriter { + + public void write(File baseDir); + public void create(CaseParameters params); + public void registerWriter(ProjectWriter writer); + +} diff --git a/src/eu/engys/core/project/SolverModel.java b/src/eu/engys/core/project/SolverModel.java new file mode 100644 index 0000000..4ae6e9c --- /dev/null +++ b/src/eu/engys/core/project/SolverModel.java @@ -0,0 +1,156 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +import static eu.engys.core.project.system.RunDict.RUN_DICT; + +import java.io.File; +import java.io.Serializable; +import java.util.Observable; + +import eu.engys.core.controller.Command; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.project.state.ServerState; +import eu.engys.util.connection.QueueParameters; +import eu.engys.util.connection.SshParameters; +import eu.engys.util.progress.SilentMonitor; + +public class SolverModel extends Observable implements Serializable { + + private String logFile = ""; + private String hostfilePath = ""; +// private int rmiPort = 20001; +// private int logPort = 21001; + private boolean multiMachine = false; + + private ServerState serverState = new ServerState(Command.NONE, SolverState.FINISHED); + + private SshParameters sshParameters = new SshParameters(); + private QueueParameters queueParameters = new QueueParameters(); + private boolean remote = false; + private boolean queue = false; + + private String serverID; + + public String getHostfilePath() { + return hostfilePath; + } + public void setHostfilePath(String hostfilePath) { + this.hostfilePath = hostfilePath; + } + + public boolean getMultiMachine() { + return multiMachine; + } + public void setMultiMachine(boolean multiMachine) { + this.multiMachine = multiMachine; + } + + public String getServerID() { + return serverID; + } + public void setServerID(String serverID) { + this.serverID = serverID; + } + + public String getLogFile() { + return logFile; + } + public void setLogFile(String logFile) { + this.logFile = logFile; + } + + public ServerState getServerState() { + return serverState; + } + + public void setServerState(ServerState serverState) { + this.serverState = serverState; + setChanged(); + notifyObservers(); + } + + public SshParameters getSshParameters() { + return sshParameters; + } + + public void setSshParameters(SshParameters sshParameters) { + this.sshParameters = sshParameters; + } + + public QueueParameters getQueueParameters() { + return queueParameters; + } + + public void setQueueParameters(QueueParameters queueParameters) { + this.queueParameters = queueParameters; + } + + public void setQueue(boolean queue) { + this.queue = queue; + } + + public boolean isQueue() { + return queue; + } + + public void setRemote(boolean remote) { + this.remote = remote; + } + + public boolean isRemote() { + return remote; + } + + private void read(Model model) { + File file = model.getProject().getSystemFolder().getFileManager().getFile(RUN_DICT); + new SolverModelReader(model).loadFromRunDict(new Dictionary(file), this); + } + + // Called from Server, so you need to load runDict from disk + public void writeState(ServerState state, Model model) { + read(model); + setServerState(state); + write(model); + } + + public void writeServerID(String serverID, Model model) { + setServerID(serverID); + write(model); + } + + private void write(Model model) { + new SolverModelWriter(model).save(); + DictionaryUtils.writeDictionary(model.getProject().getSystemFolder().getFileManager().getFile(), model.getProject().getSystemFolder().getRunDict(), new SilentMonitor()); + } + + @Override + public String toString() { + return "SolverModel [" + "state=" + serverState + ", " + "logFile=" + logFile + ", " + "serverID=" + serverID + ", " + "sshParameters=" + sshParameters + ", " + "queueParameters=" + queueParameters + "]"; + } + +} diff --git a/src/eu/engys/core/project/SolverModelReader.java b/src/eu/engys/core/project/SolverModelReader.java new file mode 100644 index 0000000..1e8eb21 --- /dev/null +++ b/src/eu/engys/core/project/SolverModelReader.java @@ -0,0 +1,230 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +import static eu.engys.util.connection.SshParameters.APPLICATION_DIR; +import static eu.engys.util.connection.SshParameters.AUTHENTICATION; +import static eu.engys.util.connection.SshParameters.HOST; +import static eu.engys.util.connection.SshParameters.OPENFOAM_DIR; +import static eu.engys.util.connection.SshParameters.PARAVIEW_DIR; +import static eu.engys.util.connection.SshParameters.PORT; +import static eu.engys.util.connection.SshParameters.REMOTE_BASEDIR; +import static eu.engys.util.connection.SshParameters.REMOTE_BASEDIR_PARENT; +import static eu.engys.util.connection.SshParameters.SSH_KEY; +import static eu.engys.util.connection.SshParameters.SSH_PWD; +import static eu.engys.util.connection.SshParameters.USER; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.BeanToDict; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.system.RunDict; +import eu.engys.util.Util; +import eu.engys.util.connection.SshParameters; +import eu.engys.util.connection.SshParameters.AuthType; + +public class SolverModelReader { + + private static final Logger logger = LoggerFactory.getLogger(SolverModelReader.class); + private Model model; + + public SolverModelReader(Model model) { + this.model = model; + } + + void load() { + RunDict runDict = model.getProject().getSystemFolder().getRunDict(); + populateSolverModel(runDict); + } + + private void populateSolverModel(Dictionary runDict) { + SolverModel solverModel = model.getSolverModel(); + if (runDict != null) { + loadFromRunDict(runDict, solverModel); + } + } + + void loadFromRunDict(Dictionary runDict, SolverModel solverModel) { + BeanToDict.dictToBean(runDict, solverModel); + SolverModelWriter.decryptPassword(solverModel.getSshParameters()); +//// readRMIPort(runDict, solverModel); +//// readLOGPort(runDict, solverModel); +// readServerID(runDict, solverModel); +// readRemote(runDict, solverModel); +// readQueue(runDict, solverModel); +// readLogFile(runDict, solverModel); +// readState(runDict, solverModel); +// readSSHParameters(runDict, solverModel); +// readQueueParameters(runDict, solverModel); +// readMultiMachine(runDict, solverModel); +// readHostfilePath(runDict, solverModel); + } + +// private void readRemote(Dictionary runDict, SolverModel solverModel) { +// if (runDict.found(REMOTE)) { +// solverModel.setRemote(Boolean.valueOf(runDict.lookup(REMOTE))); +// } +// } +// +// private void readQueue(Dictionary runDict, SolverModel solverModel) { +// if (runDict.found(QUEUE)) { +// solverModel.setQueue(Boolean.valueOf(runDict.lookup(QUEUE))); +// } +// } +// +// private void readMultiMachine(Dictionary runDict, SolverModel solverModel) { +// if (runDict.found(MULTI_MACHINE)) { +// Boolean value = Boolean.valueOf(runDict.lookup(MULTI_MACHINE)); +// solverModel.setMultiMachine(value && !Util.isWindows()); +// } +// } +// +// private void readHostfilePath(Dictionary runDict, SolverModel solverModel) { +// if (runDict.found(HOSTFILE_PATH)) { +// solverModel.setHostfilePath(runDict.lookup(HOSTFILE_PATH)); +// } +// } +// +// private void readLogFile(Dictionary runDict, SolverModel solverModel) { +// if (runDict.found(LOG_FILE)) { +// solverModel.setLogFile(runDict.lookup(LOG_FILE)); +// } +// } + +// private void readRMIPort(Dictionary runDict, SolverModel solverModel) { +// if (runDict.found(RMI_PORT)) { +// solverModel.setRmiPort(runDict.lookupInt(RMI_PORT)); +// } +// } +// +// private void readLOGPort(Dictionary runDict, SolverModel solverModel) { +// if (runDict.found(LOG_PORT)) { +// solverModel.setLogPort(runDict.lookupInt(LOG_PORT)); +// } +// } + +// private void readServerID(Dictionary runDict, SolverModel solverModel) { +// if (runDict.found(SERVER_ID)) { +// solverModel.setServerID(runDict.lookup(SERVER_ID)); +// } +// } +// +// private void readState(Dictionary runDict, SolverModel solverModel) { +// Dictionary serverStateDict = runDict.found(SERVER_STATE) ? runDict.subDict(SERVER_STATE) : new Dictionary(SERVER_STATE); +// +// ServerState serverState = readServerStateFromDictionary(serverStateDict); +// solverModel.setServerState(serverState); +// } + +// public static ServerState readServerStateFromDictionary(Dictionary serverStateDict) { +// ServerState serverState = new ServerState(); +// +// if (serverStateDict.found(ServerState.COMMAND)) { +// serverState.setCommand(Command.valueOf(serverStateDict.lookup(ServerState.COMMAND))); +// } +// if (serverStateDict.found(ServerState.SOLVER_STATE)) { +// serverState.setSolverState(SolverState.valueOf(serverStateDict.lookup(ServerState.SOLVER_STATE))); +// } +// if (serverStateDict.found(ServerState.ERROR)) { +// serverState.setError(new ServerError(1, "message")); +// } +// return serverState; +// } + +// private void readSSHParameters(Dictionary runDict, SolverModel solverModel) { +// Dictionary sshParametersDict = runDict.found(SSH_PARAMETERS) ? runDict.subDict(SSH_PARAMETERS) : new Dictionary(SSH_PARAMETERS); +// +// SshParameters parameters = readSshParametersFromDictionary(sshParametersDict); +// solverModel.setSshParameters(parameters); +// } + + public static SshParameters readSshParametersFromDictionary(Dictionary sshParametersDict) { + SshParameters parameters = new SshParameters(); + if (sshParametersDict.found(USER)) { + parameters.setUser(sshParametersDict.lookup(USER)); + } + if (sshParametersDict.found(SSH_PWD)) { + parameters.setSshpwd(Util.decrypt(sshParametersDict.lookup(SSH_PWD))); + } + if (sshParametersDict.found(SSH_KEY)) { + parameters.setSshkey(sshParametersDict.lookup(SSH_KEY)); + } + if (sshParametersDict.found(HOST)) { + parameters.setHost(sshParametersDict.lookup(HOST)); + } + if (sshParametersDict.found(PORT)) { + parameters.setPort(Integer.parseInt(sshParametersDict.lookup(PORT))); + } + if (sshParametersDict.found(AUTHENTICATION)) { + parameters.setSshauth(AuthType.valueOf(sshParametersDict.lookup(AUTHENTICATION))); + } + if (sshParametersDict.found(REMOTE_BASEDIR)) { + parameters.setRemoteBaseDir(sshParametersDict.lookup(REMOTE_BASEDIR)); + } + if (sshParametersDict.found(REMOTE_BASEDIR_PARENT)) { + parameters.setRemoteBaseDirParent(sshParametersDict.lookup(REMOTE_BASEDIR_PARENT)); + } + if (sshParametersDict.found(APPLICATION_DIR)) { + parameters.setApplicationDir(sshParametersDict.lookup(APPLICATION_DIR)); + } + if (sshParametersDict.found(OPENFOAM_DIR)) { + parameters.setOpenFoamDir(sshParametersDict.lookup(OPENFOAM_DIR)); + } + if (sshParametersDict.found(PARAVIEW_DIR)) { + parameters.setParaviewDir(sshParametersDict.lookup(PARAVIEW_DIR)); + } + return parameters; + } + +// private void readQueueParameters(Dictionary runDict, SolverModel solverModel) { +// QueueParameters parameters = new QueueParameters(); +// Dictionary queueParametersDict = runDict.found(QUEUE_PARAMETERS) ? runDict.subDict(QUEUE_PARAMETERS) : new Dictionary(QUEUE_PARAMETERS); +// +// if (queueParametersDict.found(QUEUE_NODES)) { +// String nodes = queueParametersDict.lookup(QUEUE_NODES); +// parameters.setNumberOfNodes(Integer.parseInt(nodes)); +// } +// if (queueParametersDict.found(QUEUE_CPUS)) { +// String cpus = queueParametersDict.lookup(QUEUE_CPUS); +// parameters.setCpuPerNode(Integer.parseInt(cpus)); +// } +// if (queueParametersDict.found(QUEUE_TIMEOUT)) { +// String timeout = queueParametersDict.lookup(QUEUE_TIMEOUT); +// parameters.setTimeout(Integer.parseInt(timeout)); +// } +// if (queueParametersDict.found(QUEUE_FEATURE)) { +// String feature = queueParametersDict.lookup(QUEUE_FEATURE); +// parameters.setFeature(feature); +// } +// if (queueParametersDict.found(QUEUE_NAMES)) { +// String names = queueParametersDict.lookup(QUEUE_NAMES); +// parameters.setNodeNames(names); +// } +// +// solverModel.setQueueParameters(parameters); +// } +} diff --git a/src/eu/engys/core/project/SolverModelWriter.java b/src/eu/engys/core/project/SolverModelWriter.java new file mode 100644 index 0000000..10d1210 --- /dev/null +++ b/src/eu/engys/core/project/SolverModelWriter.java @@ -0,0 +1,61 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import eu.engys.core.project.system.RunDict; +import eu.engys.util.Util; +import eu.engys.util.connection.SshParameters; + +public class SolverModelWriter { + + private Model model; + + public SolverModelWriter(Model model) { + this.model = model; + } + + void save() { + SshParameters sshParameters = model.getSolverModel().getSshParameters(); + encryptPassword(sshParameters); + RunDict runDict = new RunDict(model.getSolverModel()); + model.getProject().getSystemFolder().setRunDict(runDict); + decryptPassword(sshParameters); + } + + public static void encryptPassword(SshParameters sshParameters) { + if (sshParameters != null) { + sshParameters.setSshpwd(Util.encrypt(sshParameters.getSshpwd())); + } + } + + public static void decryptPassword(SshParameters sshParameters) { + if (sshParameters != null) { + sshParameters.setSshpwd(Util.decrypt(sshParameters.getSshpwd())); + } + } + +} diff --git a/src/eu/engys/core/project/SolverState.java b/src/eu/engys/core/project/SolverState.java new file mode 100644 index 0000000..ec6ed83 --- /dev/null +++ b/src/eu/engys/core/project/SolverState.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +public enum SolverState { + + STARTED, RUNNING, FINISHED, MESHING, MESHED, INITIALISING, INITIALISED, ERROR; + + public boolean isStarted() { + return this == STARTED; + } + + public boolean isRunning() { + return this == RUNNING; + } + + public boolean isFinished() { + return this == FINISHED; + } + + public boolean isMeshed() { + return this == MESHED; + } + + public boolean isMeshing() { + return this == MESHING; + } + + public boolean isInitialising() { + return this == INITIALISING; + } + + public boolean isInitialised() { + return this == INITIALISED; + } + + public boolean isError() { + return this == ERROR; + } + + public boolean isDoingSomething() { + return this == STARTED || this == RUNNING || this == MESHING || this == INITIALISING; + } + +} diff --git a/src/eu/engys/core/project/TurbulenceModel.java b/src/eu/engys/core/project/TurbulenceModel.java new file mode 100644 index 0000000..501569e --- /dev/null +++ b/src/eu/engys/core/project/TurbulenceModel.java @@ -0,0 +1,125 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +public class TurbulenceModel { + + private String name; + private String description; + private boolean steady; + private boolean trans; + private boolean compressible; + private boolean incompressible; + + private TurbulenceModelType type; + + public TurbulenceModel() { + } + + public TurbulenceModel(String name) { + this.name = name; + } + + public TurbulenceModel(String name, String description) { + this.name = name; + this.description = description; + } + + public TurbulenceModel(String name, TurbulenceModelType type) { + this.name = name; + this.type = type; + } + + public boolean isTrans() { + return trans; + } + + public void setTrans(boolean trans) { + this.trans = trans; + } + + public boolean isIncompressible() { + return incompressible; + } + + public void setIncompressible(boolean incompressible) { + this.incompressible = incompressible; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean isSteady() { + return steady; + } + + public void setSteady(boolean steady) { + this.steady = steady; + } + + public boolean isCompressible() { + return compressible; + } + + public void setCompressible(boolean compressible) { + this.compressible = compressible; + } + + public void setType(TurbulenceModelType type) { + this.type = type; + } + + public TurbulenceModelType getType() { + return type; + } + + @Override + public String toString() { + return getName(); + } + + public boolean equals(Object obj) { + if (obj instanceof TurbulenceModel) { + TurbulenceModel tm = (TurbulenceModel) obj; + return name == null? tm.name == null : name.equals(tm.name); + } else + return super.equals(obj); + }; +} diff --git a/src/eu/engys/core/project/TurbulenceModelType.java b/src/eu/engys/core/project/TurbulenceModelType.java new file mode 100644 index 0000000..85a49b6 --- /dev/null +++ b/src/eu/engys/core/project/TurbulenceModelType.java @@ -0,0 +1,50 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project; + +public enum TurbulenceModelType { + K_Epsilon, K_Omega, Spalart_Allmaras, K_Equation_Eddy, LAMINAR; + + public boolean isSpalartAllmaras() { + return equals(Spalart_Allmaras); + } + + public boolean isKepsilon() { + return equals(K_Epsilon); + } + + public boolean isKomega() { + return equals(K_Omega); + } + + public boolean isKEquationeddy() { + return equals(K_Equation_Eddy); + } + + public boolean isLaminar() { + return equals(LAMINAR); + } +} diff --git a/src/eu/engys/core/project/TurbulenceModels.java b/src/eu/engys/core/project/TurbulenceModels.java new file mode 100644 index 0000000..e18cd31 --- /dev/null +++ b/src/eu/engys/core/project/TurbulenceModels.java @@ -0,0 +1,214 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.commons.lang.ArrayUtils; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.defaults.Defaults; +import eu.engys.core.project.state.Flow; +import eu.engys.core.project.state.Method; +import eu.engys.core.project.state.SolverType; +import eu.engys.core.project.zero.fields.Fields; + +public class TurbulenceModels { + + private final List compressibleRAS = new ArrayList<>(); + private final List incompressibleRAS = new ArrayList<>(); + private final List incompressibleLES = new ArrayList<>(); + private final List compressibleLES = new ArrayList<>(); + + private final Map> moduleModels = new HashMap<>(); + + @Inject + public TurbulenceModels(Defaults defaults) { + loadModelsFromDefaults(defaults.getDefaultTurbulenceProperties()); + } + + public Map> getModuleModels() { + return moduleModels; + } + + private void loadModelsFromDefaults(Dictionary turbulenceProperties) { + if (turbulenceProperties.isDictionary("compressibleRAS")) { + Dictionary d = turbulenceProperties.subDict("compressibleRAS"); + for (Dictionary m : d.getDictionaries()) { + compressibleRAS.add(dictToTurbulenceModel(m)); + } + } + if (turbulenceProperties.isDictionary("incompressibleRAS")) { + Dictionary d = turbulenceProperties.subDict("incompressibleRAS"); + for (Dictionary m : d.getDictionaries()) { + incompressibleRAS.add(dictToTurbulenceModel(m)); + } + } + if (turbulenceProperties.isDictionary("compressibleLES")) { + Dictionary d = turbulenceProperties.subDict("compressibleLES"); + for (Dictionary m : d.getDictionaries()) { + compressibleLES.add(dictToTurbulenceModel(m)); + } + } + if (turbulenceProperties.isDictionary("incompressibleLES")) { + Dictionary d = turbulenceProperties.subDict("incompressibleLES"); + for (Dictionary m : d.getDictionaries()) { + incompressibleLES.add(dictToTurbulenceModel(m)); + } + } + } + + public static TurbulenceModel dictToTurbulenceModel(Dictionary m) { + TurbulenceModel tm = new TurbulenceModel(); + tm.setName(nameFromDictionary(m)); + tm.setDescription(descriptionFromDictionary(m)); + tm.setType(typeFromDictionary(m)); + + return tm; + } + + private static String nameFromDictionary(Dictionary m) { + return m.getName().replace("Coeffs", ""); + } + + private static String descriptionFromDictionary(Dictionary m) { + return m.found("label") ? fromUnicode(m.lookup("label").replace("\"", "")) : m.getName(); + } + + private static TurbulenceModelType typeFromDictionary(Dictionary m) { + Dictionary fieldMaps = m.subDict("fieldMaps"); + if (fieldMaps == null) { + return TurbulenceModelType.LAMINAR; + } else if (fieldMaps.isField(Fields.K) && fieldMaps.isField(Fields.OMEGA)) { + return TurbulenceModelType.K_Omega; + } else if (fieldMaps.isField(Fields.K) && fieldMaps.isField(Fields.EPSILON)) { + return TurbulenceModelType.K_Epsilon; + } else if (fieldMaps.isField(Fields.NU_TILDA)) { + return TurbulenceModelType.Spalart_Allmaras; + } else if (fieldMaps.isField(Fields.K) && fieldMaps.isField(Fields.NU_SGS)) { + return TurbulenceModelType.K_Equation_Eddy; + } else { + return TurbulenceModelType.LAMINAR; + } + } + + public List getModelsForState(SolverType solverType, Method method, Flow flow) { + if (solverType.isCoupled()) { + if (moduleModels.containsKey("coupled")) { + return moduleModels.get("coupled"); + } else { + return Collections.emptyList(); + } + } else if (solverType.isSegregated()) { + if (flow.isCompressible()) { + if (method.isRans()) { + return compressibleRAS; + } else if (method.isLes()) { + return compressibleLES; + } else { + return Collections.emptyList(); + } + } else if (flow.isIncompressible()) { + if (method.isRans()) { + return incompressibleRAS; + } else if (method.isLes()) { + return incompressibleLES; + } else { + return Collections.emptyList(); + } + } else { + return Collections.emptyList(); + } + } else { + return Collections.emptyList(); + } + + } + + private static final char[] NUMBERS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + private static final char[] letters = { 'a', 'b', 'c', 'd', 'e', 'f' }; + private static final char[] LETTERS = { 'A', 'B', 'C', 'D', 'E', 'F' }; + private static final char U = 'u'; + private static final char BS = '\\'; + private static final char ZERO = '0'; + private static final char AL = 'a'; + private static final char AU = 'A'; + private static final char T = 't'; + private static final char R = 'r'; + private static final char N = 'n'; + private static final char F = 'f'; + private static final char TAB = '\t'; + private static final char FORM_FEED = '\f'; + private static final char RETURN = '\r'; + private static final char NEW_LINE = '\n'; + + private static String fromUnicode(String text) { + char c; + int lenght = text.length(); + StringBuffer buffer = new StringBuffer(lenght); + + for (int x = 0; x < lenght;) { + c = text.charAt(x++); + if (c == BS) { + c = text.charAt(x++); + if (c == U) { + int value = 0; + for (int i = 0; i < 4; i++) { + c = text.charAt(x++); + if (ArrayUtils.contains(NUMBERS, c)) { + value = (value << 4) + c - ZERO; + } else if (ArrayUtils.contains(letters, c)) { + value = (value << 4) + 10 + c - AL; + } else if (ArrayUtils.contains(LETTERS, c)) { + value = (value << 4) + 10 + c - AU; + } + } + buffer.append((char) value); + } else { + if (c == T) + c = TAB; + else if (c == R) + c = RETURN; + else if (c == N) + c = NEW_LINE; + else if (c == F) + c = FORM_FEED; + buffer.append(c); + } + } else + buffer.append(c); + } + return buffer.toString(); + } + +} diff --git a/src/eu/engys/core/project/constant/ConstantFolder.java b/src/eu/engys/core/project/constant/ConstantFolder.java new file mode 100644 index 0000000..a58dbd3 --- /dev/null +++ b/src/eu/engys/core/project/constant/ConstantFolder.java @@ -0,0 +1,217 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.constant; + +import java.io.File; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.files.DefaultFileManager; +import eu.engys.core.project.files.FileManager; +import eu.engys.core.project.files.Folder; +import eu.engys.core.project.materials.MaterialsWriter; +import eu.engys.core.project.state.State; +import eu.engys.util.progress.ProgressMonitor; + +public class ConstantFolder implements Folder { + + public static final String CONSTANT = "constant"; + + public static final String POLY_MESH = "polyMesh"; + public static final String TRISURFACE = "triSurface"; + public static final String G = "g"; + public static final String RADIATION_PROPERTIES = "radiationProperties"; + public static final String REGION_PROPERTIES = "regionProperties"; + public static final String LES_PROPERTIES = "LESProperties"; + public static final String RAS_PROPERTIES = "RASProperties"; + + //ECOMARINE + public static final String UFS_KEY = "Ufs"; + public static final String BEACH_KEY = "beach"; + public static final String FREE_SURFACE_PROPERTIES = "freeSurfaceProperties"; + + private final TriSurfaceFolder triSurface; + private final PolyMeshFolder polyMesh; + + private Dictionary g; + + private TurbulenceProperties turbulenceProperties; + private Dictionary RASProperties; + private Dictionary LESProperties; + private TransportProperties transportProperties; + private ThermophysicalProperties thermophysicalProperties; + + private final FileManager fileManager; + + public ConstantFolder(openFOAMProject prj) { + File constant = new File(prj.getBaseDir(), CONSTANT); + fileManager = new DefaultFileManager(constant); + triSurface = new TriSurfaceFolder(constant); + polyMesh = new PolyMeshFolder(constant); + } + + public ConstantFolder(File baseDir, ConstantFolder constantFolder) { + File constant = new File(baseDir, CONSTANT); + fileManager = new DefaultFileManager(constant); + triSurface = new TriSurfaceFolder(constant); + polyMesh = new PolyMeshFolder(constant); + + setG(constantFolder.g); + setTurbulenceProperties(constantFolder.turbulenceProperties); + setRASProperties(constantFolder.RASProperties); + setLESProperties(constantFolder.LESProperties); + setTransportProperties(constantFolder.transportProperties); + setThermophysicalProperties(constantFolder.thermophysicalProperties); + + // setPorousZones(constantFolder.porousZones); + // setMRFZones(constantFolder.MRFZones); + } + + @Override + public FileManager getFileManager() { + return fileManager; + } + + public Dictionary getG() { + return g; + } + + public void setG(Dictionary g) { + this.g = g; + } + + public TurbulenceProperties getTurbulenceProperties() { + return turbulenceProperties; + } + + public void setTurbulenceProperties(Dictionary turbulenceProperties) { + this.turbulenceProperties = new TurbulenceProperties(turbulenceProperties); + } + + public Dictionary getRASProperties() { + return RASProperties; + } + + public void setRASProperties(Dictionary rASProperties) { + RASProperties = rASProperties; + } + + public Dictionary getLESProperties() { + return LESProperties; + } + + public void setLESProperties(Dictionary lESProperties) { + LESProperties = lESProperties; + } + + public TransportProperties getTransportProperties() { + return transportProperties; + } + + public void setTransportProperties(Dictionary transportProperties) { + this.transportProperties = new TransportProperties(transportProperties); + } + + public ThermophysicalProperties getThermophysicalProperties() { + return thermophysicalProperties; + } + + public void setThermophysicalProperties(Dictionary thermophysicalProperties) { + this.thermophysicalProperties = new ThermophysicalProperties(thermophysicalProperties); + } + + public TriSurfaceFolder getTriSurface() { + return triSurface; + } + + public PolyMeshFolder getPolyMesh() { + return polyMesh; + } + + public List getAllDictionaries() { + List dictionaries = new ArrayList<>(); + dictionaries.add(getG()); + dictionaries.add(getLESProperties()); + dictionaries.add(getRASProperties()); + dictionaries.add(getThermophysicalProperties()); + dictionaries.add(getTransportProperties()); + dictionaries.add(getTurbulenceProperties()); + return dictionaries; + } + + public void write(Model model, MaterialsWriter materialsWriter, ProgressMonitor monitor) { + model.getMaterials().saveMaterials(model, materialsWriter); + + File constDir = fileManager.getFile(); + if (!constDir.exists()) + constDir.mkdir(); + + DictionaryUtils.writeDictionary(constDir, DictionaryUtils.header(CONSTANT, turbulenceProperties), monitor); + + State state = model.getState(); + if (state.isLES()) { + DictionaryUtils.writeDictionary(constDir, DictionaryUtils.header(CONSTANT, LESProperties), monitor); + DictionaryUtils.removeDictionary(constDir, DictionaryUtils.header(CONSTANT, RASProperties), monitor); + } else if (state.isRANS()) { + DictionaryUtils.writeDictionary(constDir, DictionaryUtils.header(CONSTANT, RASProperties), monitor); + DictionaryUtils.removeDictionary(constDir, DictionaryUtils.header(CONSTANT, LESProperties), monitor); + } + + if (state.isCompressible() && !state.getMultiphaseModel().isMultiphase()) { + DictionaryUtils.writeDictionary(constDir, DictionaryUtils.header(CONSTANT, thermophysicalProperties), monitor); + DictionaryUtils.removeDictionary(constDir, DictionaryUtils.header(CONSTANT, transportProperties), monitor); + } else if (state.isIncompressible() || (state.isCompressible() && state.getMultiphaseModel().isMultiphase())) { + DictionaryUtils.writeDictionary(constDir, DictionaryUtils.header(CONSTANT, transportProperties), monitor); + DictionaryUtils.removeDictionary(constDir, DictionaryUtils.header(CONSTANT, thermophysicalProperties), monitor); + } + + if (g == null && Files.exists(constDir.toPath().resolve(G))) { + DictionaryUtils.removeDictionary(constDir, DictionaryUtils.header(CONSTANT, new Dictionary(G)), monitor); + } else if (g != null && g.isEmpty()) { + DictionaryUtils.removeDictionary(constDir, DictionaryUtils.header(CONSTANT, g), monitor); + } else { + DictionaryUtils.writeDictionary(constDir, DictionaryUtils.header(CONSTANT, g), monitor); + } + + } + + public void load(Model model, ProgressMonitor monitor) { + if (fileManager.getFile().exists() && fileManager.getFile().isDirectory()) { + setTurbulenceProperties(DictionaryUtils.readDictionary(fileManager.getFile(TurbulenceProperties.TURBULENCE_PROPERTIES), monitor)); + setRASProperties(DictionaryUtils.readDictionary(fileManager.getFile(RAS_PROPERTIES), monitor)); + setLESProperties(DictionaryUtils.readDictionary(fileManager.getFile(LES_PROPERTIES), monitor)); + setThermophysicalProperties(DictionaryUtils.readDictionary(fileManager.getFile(ThermophysicalProperties.THERMOPHYSICAL_PROPERTIES), monitor)); + setTransportProperties(DictionaryUtils.readDictionary(fileManager.getFile(TransportProperties.TRANSPORT_PROPERTIES), monitor)); + setG(DictionaryUtils.readDictionary(fileManager.getFile(G), monitor)); + } + } +} diff --git a/src/eu/engys/core/project/constant/PolyMeshFolder.java b/src/eu/engys/core/project/constant/PolyMeshFolder.java new file mode 100644 index 0000000..69c9a5c --- /dev/null +++ b/src/eu/engys/core/project/constant/PolyMeshFolder.java @@ -0,0 +1,48 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.constant; + +import java.io.File; + +import eu.engys.core.project.files.DefaultFileManager; +import eu.engys.core.project.files.FileManager; +import eu.engys.core.project.files.Folder; + +public class PolyMeshFolder implements Folder { + + private FileManager fileManager; + + public PolyMeshFolder(File baseDir) { + fileManager = new DefaultFileManager(new File(baseDir, "polyMesh")); + } + + @Override + public FileManager getFileManager() { + return fileManager; + } + +} diff --git a/src/eu/engys/core/project/constant/ThermophysicalProperties.java b/src/eu/engys/core/project/constant/ThermophysicalProperties.java new file mode 100644 index 0000000..1eb7401 --- /dev/null +++ b/src/eu/engys/core/project/constant/ThermophysicalProperties.java @@ -0,0 +1,117 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.constant; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FoamFile; + +public class ThermophysicalProperties extends Dictionary { + + public static final String THERMOPHYSICAL_PROPERTIES = "thermophysicalProperties"; + + // Thermophysical Model + public static final String MATERIAL_NAME_KEY = "materialName"; + public static final String DEFAULT_MATERIAL_KEY = "defaultMaterial"; + public static final String MOL_WEIGHT_KEY = "molWeight"; + public static final String N_MOLES_KEY = "nMoles"; + + public static final String SENSIBLE_INTERNAL_ENERGY_KEY = "sensibleInternalEnergy"; + public static final String SENSIBLE_ENTHALPY_KEY = "sensibleEnthalpy"; + + + // Equation of State + public static final String EQUATION_OF_STATE_KEY = "equationOfState"; + public static final String ADIABATIC_PERFECT_FLUID_KEY = "adiabaticPerfectFluid"; + public static final String RHO_CONSTANT_KEY = "rhoConst"; + public static final String PERFECT_GAS_KEY = "perfectGas"; + public static final String PERFECT_FLUID_KEY = "perfectFluid"; + public static final String ICO_POLYNOMIAL_KEY = "icoPolynomial"; + public static final String INCOMPRESSIBLE_KEY = "incompressiblePerfectGas"; + public static final String P_REF_KEY = "pRef"; + public static final String RHO_COEFFS_KEY = "rhoCoeffs"; + public static final String R_KEY = "R"; + public static final String RHO_KEY = "rho"; + public static final String GAMMA_KEY = "gamma"; + public static final String P0_KEY = "p0"; + public static final String B_KEY = "B"; + public static final String RHO0_KEY = "rho0"; + + // Transport Properties + public static final String TS_KEY = "Ts"; + public static final String AS_KEY = "As"; + public static final String PR_KEY = "Pr"; + public static final String PRT_KEY = "Prt"; + public static final String MU_KEY = "mu"; + public static final String NU_KEY = "nu"; + public static final String TRANSPORT_KEY = "transport"; + public static final String TRANSPORT_MODEL_KEY = "transportModel"; + public static final String MIXTURE_KEY = "mixture"; + public static final String PURE_MIXTURE_KEY = "pureMixture"; + public static final String THERMODYNAMICS_KEY = "thermodynamics"; + public static final String SPECIE_KEY = "specie"; + public static final String ENERGY_KEY = "energy"; + public static final String MU_COEFFS_KEY = "muCoeffs"; + public static final String KAPPA_COEFFS_KEY = "kappaCoeffs"; + + // Thermodynamic Model + public static final String THERMO_TYPE_KEY = "thermoType"; + public static final String THERMO_MODEL_KEY = "thermoModel"; + public static final String HE_PSI_THERMO_KEY = "hePsiThermo"; + public static final String HE_RHO_THERMO_KEY = "heRhoThermo"; + public static final String LOW_CP_COEFFS_KEY = "lowCpCoeffs"; + public static final String HIGH_CP_COEFFS_KEY = "highCpCoeffs"; + public static final String CP_COEFFS_KEY = "CpCoeffs"; + public static final String TCOMMON_KEY = "Tcommon"; + public static final String THIGH_KEY = "Thigh"; + public static final String TLOW_KEY = "Tlow"; + public static final String HF_KEY = "Hf"; + public static final String SF_KEY = "Sf"; + public static final String CP_KEY = "Cp"; + public static final String T_REF_KEY = "TRef"; + public static final String BETA_OS_KEY = "beta"; + public static final String BETA_KEY = "Beta"; + public static final String LAMBDA_KEY = "lambda"; + + public static final String THERMO_KEY = "thermo"; + public static final String CONST_KEY = "const"; + public static final String POLYNOMIAL_KEY = "polynomial"; + public static final String SUTHERLAND_KEY = "sutherland"; + public static final String CONSTANT_CP_KEY = "hConst"; + public static final String JANAF_KEY = "janaf"; + public static final String H_POLYNOMIAL_KEY = "hPolynomial"; + public static final String[] A_KEYS = new String[] { "a0", "a1", "a2", "a3", "a4", "a5", "a6" }; + + public ThermophysicalProperties() { + super(THERMOPHYSICAL_PROPERTIES); + setFoamFile(FoamFile.getDictionaryFoamFile(ConstantFolder.CONSTANT, THERMOPHYSICAL_PROPERTIES)); + } + + public ThermophysicalProperties(Dictionary d) { + this(); + merge(d); + setFoamFile(FoamFile.getDictionaryFoamFile(ConstantFolder.CONSTANT, THERMOPHYSICAL_PROPERTIES)); + } +} diff --git a/src/eu/engys/core/project/constant/TransportProperties.java b/src/eu/engys/core/project/constant/TransportProperties.java new file mode 100644 index 0000000..c1da958 --- /dev/null +++ b/src/eu/engys/core/project/constant/TransportProperties.java @@ -0,0 +1,119 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.constant; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FoamFile; + +public class TransportProperties extends Dictionary { + + public static final String TRANSPORT_PROPERTIES = "transportProperties"; + + public static final String MATERIAL_NAME_KEY = "materialName"; + + public static final String NEWTONIAN_KEY = "Newtonian"; + public static final String CROSS_POWER_LAW_KEY = "CrossPowerLaw"; + public static final String BIRD_CARREAU_KEY = "BirdCarreau"; + public static final String HERSCHEL_BULKLEY_KEY = "HerschelBulkley"; + public static final String POWER_LAW_KEY = "powerLaw"; + + public static final String NEWTONIAN_COEFFS_KEY = "NewtonianCoeffs"; + public static final String CROSS_POWER_LAW_COEFFS_KEY = "CrossPowerLawCoeffs"; + public static final String BIRD_CARREAU_COEFFS_KEY = "BirdCarreauCoeffs"; + public static final String HERSCHEL_BULKLEY_COEFFS_KEY = "HerschelBulkleyCoeffs"; + public static final String POWER_LAW_COEFFS_KEY = "powerLawCoeffs"; + + public static final String SIGMAS_KEY = "sigmas"; + public static final String INTERFACE_COMPRESSION_KEY = "interfaceCompression"; + public static final String DRAG_KEY = "drag"; + public static final String VIRTUAL_MASS_KEY = "virtualMass"; + + public static final String PHASES_KEY = "phases"; + public static final String PHASE1_KEY = "phase1"; + public static final String PHASE2_KEY = "phase2"; + public static final String TRANSPORT_MODEL_KEY = "transportModel"; + public static final String SIGMA_KEY = "sigma"; + public static final String MU_KEY = "mu"; + public static final String NU_KEY = "nu"; + public static final String CP_KEY = "Cp"; + public static final String CP0_KEY = "Cp0"; + public static final String RHO_KEY = "rho"; + public static final String RHO_CP0_KEY = "rhoCp0"; + public static final String KAPPA_KEY = "kappa"; + public static final String PR_KEY = "Pr"; + public static final String PRT_KEY = "Prt"; + public static final String LAMBDA_KEY = "lambda"; + public static final String T_REF_KEY = "TRef"; + public static final String BETA_OS_KEY = "beta"; + public static final String BETA_KEY = "Beta"; + public static final String P_REF_KEY = "pRef"; + + + //Non newtonian coeffs + public static final String NU_0_KEY = "nu0"; + public static final String NU_INF_KEY = "nuInf"; + public static final String M_KEY = "m"; + public static final String N_KEY = "n"; + public static final String K_KEY = "k"; + public static final String TAU_0_KEY = "tau0"; + public static final String NU_MIN_KEY = "nuMin"; + public static final String NU_MAX_KEY = "nuMax"; + + + //Phases Euler + public static final String DIAMETER_MODEL_KEY = "diameterModel"; + public static final String CONSTANT_KEY = "constant"; + public static final String CONSTANT_COEFFS_KEY = "constantCoeffs"; + public static final String ISOTHERMAL_KEY = "isothermal"; + public static final String ISOTHERMAL_COEFFS_KEY = "isothermalCoeffs"; + public static final String P0_KEY = "p0"; + public static final String D0_KEY = "d0"; + public static final String D_KEY = "d"; + + public static final String ERGUN_KEY = "Ergun"; + public static final String GIBILARO_KEY = "Gibilaro"; + public static final String GIDASPOW_EEGUNWENYU_KEY = "GidasporEegunWenYu"; + public static final String GIDASPOW_SCHILLERNAUMANN_KEY = "GidaspowSchillerNaumann"; + public static final String SCHILLERNAUMANN_KEY = "SchillerNaumann"; + public static final String SYAMLAL_OBRIEN_KEY = "SyamlalOBrien"; + public static final String WENYU_KEY = "WenYu"; + public static final String BLENDED_KEY = "blended"; + public static final String INTERFACE_KEY = "interface"; + + public static final String RESIDUAL_PHASE_FRACTION_KEY = "residualPhaseFraction"; + public static final String RESIDUAL_SLIP_KEY = "residualSlip"; + + public TransportProperties() { + super(TRANSPORT_PROPERTIES); + setFoamFile(FoamFile.getDictionaryFoamFile(ConstantFolder.CONSTANT, TRANSPORT_PROPERTIES)); + } + + public TransportProperties(Dictionary d) { + this(); + merge(d); + setFoamFile(FoamFile.getDictionaryFoamFile(ConstantFolder.CONSTANT, TRANSPORT_PROPERTIES)); + } +} diff --git a/src/eu/engys/core/project/constant/TriSurfaceFolder.java b/src/eu/engys/core/project/constant/TriSurfaceFolder.java new file mode 100644 index 0000000..a15ad75 --- /dev/null +++ b/src/eu/engys/core/project/constant/TriSurfaceFolder.java @@ -0,0 +1,48 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.constant; + +import java.io.File; + +import eu.engys.core.project.files.DefaultFileManager; +import eu.engys.core.project.files.FileManager; +import eu.engys.core.project.files.Folder; + +public class TriSurfaceFolder implements Folder { + + public static final String TRISURFACE = "triSurface"; + private final FileManager fileManager; + + public TriSurfaceFolder(File baseDir) { + fileManager = new DefaultFileManager(new File(baseDir, TRISURFACE)); + } + + @Override + public FileManager getFileManager() { + return fileManager; + } +} diff --git a/src/eu/engys/core/project/constant/TurbulenceProperties.java b/src/eu/engys/core/project/constant/TurbulenceProperties.java new file mode 100644 index 0000000..35a74ca --- /dev/null +++ b/src/eu/engys/core/project/constant/TurbulenceProperties.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.constant; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FoamFile; + +public class TurbulenceProperties extends Dictionary { + + public static final String TURBULENCE_PROPERTIES = "turbulenceProperties"; + + public static final String SIMULATION_TYPE = "simulationType"; + public static final String RAS = "RAS"; + public static final String LES = "LES"; + public static final String LAMINAR = "laminar"; + + public static final String FIELD_MAPS_KEY = "fieldMaps"; + + public TurbulenceProperties() { + super(TURBULENCE_PROPERTIES); + setFoamFile(FoamFile.getDictionaryFoamFile(ConstantFolder.CONSTANT, TURBULENCE_PROPERTIES)); + } + + public TurbulenceProperties(Dictionary turbulenceProperties) { + this(); + merge(turbulenceProperties); + setFoamFile(FoamFile.getDictionaryFoamFile(ConstantFolder.CONSTANT, TURBULENCE_PROPERTIES)); + } +} diff --git a/src/eu/engys/core/project/custom/Custom.java b/src/eu/engys/core/project/custom/Custom.java new file mode 100644 index 0000000..71f6acf --- /dev/null +++ b/src/eu/engys/core/project/custom/Custom.java @@ -0,0 +1,225 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.custom; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.CustomNodeDict; +import eu.engys.util.progress.ProgressMonitor; + +public class Custom { + + public static final String HELYX_INTERNAL_TYPE = "helyx_type"; + + private static final Logger logger = LoggerFactory.getLogger(Custom.class); + + private final RootDirectory root = new RootDirectory(); + private final ZeroDirectory zero = new ZeroDirectory(); + private final ConstantDirectory constant = new ConstantDirectory(); + private final SystemDirectory system = new SystemDirectory(); + + private List files = new ArrayList<>(); + + public Custom() { + clear(); + add(root); + add(zero); + add(constant); + add(system); + } + + public void add(CustomFile file) { + CustomFile parent = file.getParent(); + if (parent != null) { + if (files.contains(parent) && parent.getType().isDirectory()) { + parent.add(file); + } + } + files.add(file); + } + + public void clear() { + zero.clear(); + constant.clear(); + system.clear(); + files.clear(); + } + + public void remove(CustomFile file) { + if (file.getType().isDirectory()) { + for (CustomFile child : new ArrayList(file.getChildren())) { + remove(child); + } + } + files.remove(file); + file.getParent().remove(file); + } + + public RootDirectory getRoot() { + return root; + } + + public ZeroDirectory getZero() { + return zero; + } + + public ConstantDirectory getConstant() { + return constant; + } + + public SystemDirectory getSystem() { + return system; + } + + public List getParentFiles() { + List parents = new ArrayList<>(); + for (CustomFile file : files) { + if (file != root && file.getType().isDirectory()) + parents.add(file); + } + return parents; + } + + public void read(Model model, CustomNodeDict customDict, ProgressMonitor monitor) { + if (customDict.found("system")) + readFromCustomDict(model, system, customDict.subDict("system")); + if (customDict.found("0")) + readFromCustomDict(model, zero, customDict.subDict("0")); + if (customDict.found("constant")) + readFromCustomDict(model, constant, customDict.subDict("constant")); + } + + private void readFromCustomDict(Model model, CustomFile parentFile, Dictionary dict) { + for (Dictionary d : dict.getDictionaries()) { + CustomFile customFile = null; + Dictionary copyDict = new Dictionary(d); + String type = copyDict.lookup(HELYX_INTERNAL_TYPE); + copyDict.remove(HELYX_INTERNAL_TYPE); + if (CustomFileType.DIRECTORY.getKey().equals(type)) { + customFile = new CustomFile(parentFile, CustomFileType.DIRECTORY, copyDict.getName()); + readFromCustomDict(model, customFile, copyDict); + } else if (CustomFileType.DICTIONARY.getKey().equals(type)) { + customFile = new CustomFile(parentFile, CustomFileType.DICTIONARY, copyDict.getName()); + customFile.getDictionary().merge(copyDict); + } else if (CustomFileType.FIELD.getKey().equals(type)) { + customFile = new CustomFile(parentFile, CustomFileType.FIELD, copyDict.getName()); + customFile.getDictionary().merge(copyDict); + } else if (CustomFileType.RAW.getKey().equals(type)) { + customFile = new CustomFile(parentFile, CustomFileType.RAW, copyDict.getName()); + File file = CustomUtils.getFiles(model, customFile).get(0); + customFile.getRawFileContent().clear(); + try { + customFile.getRawFileContent().addAll(FileUtils.readLines(file)); + } catch (IOException e) { + logger.error(e.getMessage()); + } + } else { + logger.error("Wrong dictionary type found: " + type); + } + if (customFile != null) { + parentFile.add(customFile); + } + } + } + + public void write(Model model, ProgressMonitor monitor) { + logger.info("--- Customise ---"); + system.write(model, monitor); + constant.write(model, monitor); + zero.write(model, monitor); + logger.info("-----------------"); + } + + public void saveCustomDict(Model model) { + CustomNodeDict customDict = new CustomNodeDict(); + saveCustomDict(root, customDict); + model.getProject().getSystemFolder().setCustomNodeDict(customDict); + } + + private void saveCustomDict(CustomFile file, Dictionary customDict) { + if (file.getType().isDirectory()) { + if (file instanceof RootDirectory) { + saveChildrenOf(file, customDict); + } else { + Dictionary subdict = new Dictionary(file.getName()); + subdict.add(HELYX_INTERNAL_TYPE, CustomFileType.DIRECTORY.getKey()); + customDict.add(subdict); + saveChildrenOf(file, subdict); + } + } else if (file.getType().isRaw()) { + Dictionary subdict = new Dictionary(file.getName()); + subdict.add(Custom.HELYX_INTERNAL_TYPE, file.getType().getKey()); + customDict.add(subdict); + } else { + Dictionary subdict = new Dictionary(file.getName(), file.getDictionary()); + subdict.add(Custom.HELYX_INTERNAL_TYPE, file.getType().getKey()); + customDict.add(subdict); + } + } + + private void saveChildrenOf(CustomFile file, Dictionary customDict) { + for (CustomFile child : file.getChildren()) { + if (child != null) { + saveCustomDict(child, customDict); + } else { + logger.error("NULL CHILD FOR: " + file.getName()); + } + } + } + + public class RootDirectory extends CustomFile { + public RootDirectory() { + super(null, CustomFileType.DIRECTORY, null); + } + } + + public class ZeroDirectory extends CustomFile { + public ZeroDirectory() { + super(root, CustomFileType.DIRECTORY, "0"); + } + } + + public class ConstantDirectory extends CustomFile { + public ConstantDirectory() { + super(root, CustomFileType.DIRECTORY, "constant"); + } + } + + public class SystemDirectory extends CustomFile { + public SystemDirectory() { + super(root, CustomFileType.DIRECTORY, "system"); + } + } +} diff --git a/src/eu/engys/core/project/custom/CustomFile.java b/src/eu/engys/core/project/custom/CustomFile.java new file mode 100644 index 0000000..60a20e0 --- /dev/null +++ b/src/eu/engys/core/project/custom/CustomFile.java @@ -0,0 +1,261 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.custom; + +import static eu.engys.core.project.system.ControlDict.CONTROL_DICT; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JOptionPane; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.ControlDict; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.util.LineSeparator; +import eu.engys.util.Util; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.UiUtil; + +public class CustomFile { + + private static final Logger logger = LoggerFactory.getLogger(CustomFile.class); + + private final CustomFile parent; + private Dictionary dictionary; + private List rawFileContent; + private CustomFileType type = CustomFileType.DICTIONARY; + private List children = new ArrayList<>(); + + private String name; + + private boolean changed; + + public CustomFile(CustomFile parent, CustomFileType type, String name) { + this.parent = parent; + this.type = type; + this.name = name; + this.rawFileContent = new LinkedList(); + if (CONTROL_DICT.equals(name)) { + this.dictionary = new ControlDict(); + } else { + this.dictionary = new Dictionary(name); + this.dictionary.setFoamFile(getFOAMFile(parent, name)); + } + } + + private FoamFile getFOAMFile(CustomFile parent, String name) { + if (type.isField()) { + return FoamFile.getFieldFoamFile(name); + } else if (type.isDictionary()) { + return FoamFile.getDictionaryFoamFile(parent != null ? parent.getName() : "", name); + } else { + return null; + } + } + + public void add(CustomFile child) { + children.add(child); + } + + public void clear() { + children.clear(); + dictionary.clear(); + rawFileContent.clear(); + } + + public void remove(CustomFile child) { + children.remove(child); + } + + public void remove(String childName) { + CustomFile child = getChildByName(childName); + if (child != null) { + children.remove(child); + } + } + + public Dictionary getDictionary() { + return dictionary; + } + + public List getRawFileContent() { + return rawFileContent; + } + + public CustomFileType getType() { + return type; + } + + public CustomFile getParent() { + return parent; + } + + public List getChildren() { + return children; + } + + public List getChildrenNames() { + List names = new ArrayList<>(); + for (CustomFile c : getChildren()) { + names.add(c.getName()); + } + return names; + } + + public CustomFile getChildByName(String name) { + for (CustomFile c : getChildren()) { + if (c.getName().equals(name)) { + return c; + } + } + return null; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } + + public void setChanged(boolean changed) { + this.changed = changed; + } + + public boolean hasChanged(){ + return changed; + } + + public void write(Model model, ProgressMonitor monitor) { + if (getType().isDirectory()) { + writeDirectory(model, monitor); + } else if (getType().isDictionary()) { + writeDictionary(model, monitor); + } else if (getType().isField()) { + writeField(model, monitor); + } else if (getType().isRaw()) { + writeRaw(model, monitor); + } + changed = false; + } + + private void writeRaw(Model model, ProgressMonitor monitor) { + for (File f : CustomUtils.getFiles(model, this)) { + try { + if (!f.exists()) { + f.createNewFile(); + } + String lineEnding = Util.isWindowsScriptStyle() ? LineSeparator.DOS.getSeparator() : LineSeparator.UNIX.getSeparator(); + FileUtils.writeLines(f, null, rawFileContent, lineEnding); + } catch (IOException e) { + logger.error("Cannot create new raw file: " + f); + return; + } + } + } + + private void writeDictionary(Model model, ProgressMonitor monitor) { + for (File f : CustomUtils.getFiles(model, this)) { + if (f.exists()) { + Dictionary existingDictionary = null; + if (CONTROL_DICT.equals(f.getName())) { + existingDictionary = new ControlDict(f); + } else { + existingDictionary = new Dictionary(f); + } + existingDictionary.merge(dictionary); + existingDictionary.setFoamFile(dictionary.getFoamFile()); + DictionaryUtils.writeDictionary(f.getParentFile(), existingDictionary, monitor); + } else { + DictionaryUtils.writeDictionary(f.getParentFile(), dictionary, monitor); + } + } + } + + private void writeDirectory(Model model, ProgressMonitor monitor) { + if (!children.isEmpty()) { + for (File f : CustomUtils.getFiles(model, this)) { + _writeDirectory(f); + } + for (CustomFile child : getChildren()) { + if (child != null) { + child.write(model, monitor); + } else { + logger.error("CustomNodeDict is currupted " + getName() + " has a NULL child!"); + } + } + } + } + + private void _writeDirectory(File f) { + try { + f.mkdirs(); + } catch (Exception e) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No writing permissions on " + parent, "File System error", JOptionPane.ERROR_MESSAGE); + } + } + + private void writeField(Model model, ProgressMonitor monitor) { + monitor.info(getName(), 1); + for (File f : CustomUtils.getFiles(model, this)) { + if (f.exists()) { + writeExistingField(f, monitor); + } else { + DictionaryUtils.writeDictionary(f.getParentFile(), getDictionary(), monitor); + } + } + } + + private void writeExistingField(File f, ProgressMonitor monitor) { + Dictionary existingDictionary = new Dictionary(f); + if (getDictionary().found(Field.BOUNDARY_FIELD)) { + Dictionary customBoundaryField = getDictionary().subDict(Field.BOUNDARY_FIELD); + if (existingDictionary.found(Field.BOUNDARY_FIELD)) { + Dictionary existingBoundaryField = existingDictionary.subDict(Field.BOUNDARY_FIELD); + existingBoundaryField.merge(customBoundaryField); + } else { + existingDictionary.add(customBoundaryField); + } + + } + existingDictionary.setFoamFile(getDictionary().getFoamFile()); + DictionaryUtils.writeDictionary(f.getParentFile(), existingDictionary, null); + } + +} diff --git a/src/eu/engys/core/project/custom/CustomFileType.java b/src/eu/engys/core/project/custom/CustomFileType.java new file mode 100644 index 0000000..b087a6e --- /dev/null +++ b/src/eu/engys/core/project/custom/CustomFileType.java @@ -0,0 +1,82 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.custom; + +public enum CustomFileType { + + DICTIONARY("dictionary", "Dictionary"), FIELD("field", "Field"), DIRECTORY("directory", "Directory"), RAW("raw", "Raw File"); + + private String key; + private String label; + + private CustomFileType(String key, String label) { + this.key = key; + this.label = label; + } + + public String getLabel() { + return label; + } + + public String getKey() { + return key; + } + + public boolean isDirectory() { + return key.equals(DIRECTORY.getKey()); + } + + public boolean isField() { + return key.equals(FIELD.getKey()); + } + + public boolean isDictionary() { + return key.equals(DICTIONARY.getKey()); + } + + public boolean isRaw() { + return key.equals(RAW.getKey()); + } + + public static String[] keys() { + CustomFileType[] all = values(); + String[] keys = new String[all.length]; + for (int i = 0; i < keys.length; i++) { + keys[i] = all[i].getKey(); + } + return keys; + } + + public static String[] labels() { + CustomFileType[] all = values(); + String[] labels = new String[all.length]; + for (int i = 0; i < labels.length; i++) { + labels[i] = all[i].getLabel(); + } + return labels; + } + +} diff --git a/src/eu/engys/core/project/custom/CustomUtils.java b/src/eu/engys/core/project/custom/CustomUtils.java new file mode 100644 index 0000000..d4e63b7 --- /dev/null +++ b/src/eu/engys/core/project/custom/CustomUtils.java @@ -0,0 +1,143 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.custom; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.custom.Custom.ConstantDirectory; +import eu.engys.core.project.custom.Custom.RootDirectory; +import eu.engys.core.project.custom.Custom.SystemDirectory; +import eu.engys.core.project.custom.Custom.ZeroDirectory; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.FieldReader; + +public class CustomUtils { + + private static final Logger logger = LoggerFactory.getLogger(CustomUtils.class); + + public static List getFiles(Model model, CustomFile customFile) { + openFOAMProject project = model.getProject(); + List files = new ArrayList<>(); + Path basePath = Paths.get(project.getBaseDir().getAbsolutePath()); + if (isInAVirtualPath(customFile) && project.isParallel()) { + for (int i = 0; i < project.getProcessors(); i++) { + Path initialPath = basePath.resolve("processor" + i); + files.add(getFile(model, customFile, initialPath)); + } + } else { + files.add(getFile(model, customFile, basePath)); + } + return files; + } + + private static File getFile(Model model, CustomFile customFile, Path initialPath) { + List path = new ArrayList<>(); + addParentsToList(path, customFile); + path.add(customFile.getName()); + + for (String p : path) { + initialPath = initialPath.resolve(p); + } + return initialPath.toFile(); + } + + private static void addParentsToList(List path, CustomFile file) { + CustomFile parentFile = file.getParent(); + if (parentFile instanceof RootDirectory) { + return; + } + boolean hasToStop = (parentFile instanceof ConstantDirectory) || (parentFile instanceof SystemDirectory) || (parentFile instanceof ZeroDirectory); + if (!hasToStop) { + addParentsToList(path, file.getParent()); + } + path.add(parentFile.getName()); + } + + private static boolean isInAVirtualPath(CustomFile file) { + if (file instanceof RootDirectory) { + return false; + } + if (isVirtualFolder(file)) { + return true; + } + return isInAVirtualPath(file.getParent()); + } + + public static boolean isVirtualFolder(CustomFile customFile) { + boolean isParentZeroDirectory = customFile instanceof ZeroDirectory; + boolean isParentPolyMeshOfConstantFolder = customFile.getType().isDirectory() && "polyMesh".equals(customFile.getName()) && (customFile.getParent() instanceof ConstantDirectory); + return isParentZeroDirectory || isParentPolyMeshOfConstantFolder; + } + + public static void loadFromDisk(String name, CustomFile customFile, File file) { + if (customFile.getType().isDictionary()) { + customFile.getDictionary().merge(new Dictionary(file)); + } else if (customFile.getType().isField()) { + Field field = new Field(name); + new FieldReader(field).read(file); + Dictionary dict = new Dictionary(name); + dict.add(getCleanBoundaryField(field)); + customFile.getDictionary().merge(dict); + } else if (customFile.getType().isRaw()) { + customFile.getRawFileContent().clear(); + try { + customFile.getRawFileContent().addAll(FileUtils.readLines(file)); + } catch (IOException e) { + } + } + } + + private static Dictionary getCleanBoundaryField(Field field) { + Dictionary boundaryField = field.getBoundaryField(); + List toRemoveList = new ArrayList<>(); + if (boundaryField != null) { + for (Dictionary dict : boundaryField.getDictionaries()) { + if (dict.getName().startsWith("procBoundary")) { + toRemoveList.add(dict); + } else { + dict.clear(); + } + } + } + for (Dictionary d : toRemoveList) { + boundaryField.remove(d.getName()); + } + return boundaryField; + } + +} diff --git a/src/eu/engys/core/project/defaults/AbstractDefaultsProvider.java b/src/eu/engys/core/project/defaults/AbstractDefaultsProvider.java new file mode 100644 index 0000000..5a56a81 --- /dev/null +++ b/src/eu/engys/core/project/defaults/AbstractDefaultsProvider.java @@ -0,0 +1,140 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.defaults; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.state.State; +import eu.engys.util.Util; + +public abstract class AbstractDefaultsProvider implements DefaultsProvider { + + private static final Logger logger = LoggerFactory.getLogger(AbstractDefaultsProvider.class); + + @Override + public Dictionary getDefaultsFor(State state) { + String primalState = toPrimalState(state); + if (primalState == null) { + String msg = "[ {} provider ]: No defaults for state: {}"; + logger.warn(msg, getName(), state.state2String()); + return new Dictionary(""); + } else { + logger.info("[ {} provider ]: Defaults FOUND for state: {}", getName(), state.state2String()); + } + + return mergeBase(primalState); + } + + @Override + public Dictionary getDefaultsFieldMapsFor(State state, String region) { + if (region != null) { + return getDefaultsFor(state).subDict("fieldMaps"+"."+region); + } else { + return getDefaultsFor(state).subDict("fieldMaps"); + } + + } + + /** + * + * @param stringOfState + * for example "(steady incompressible ras)" + * @return for example "simpleFoam" + */ + public String toPrimalState(State state) { + String state2String = state.state2String(); + + Dictionary statesDict = getStates(); + + // System.out.println("AbstractDefaultsProvider.toPrimalState() "+statesDict); + + if (statesDict != null) { + Map STATES = Util.invertMap(statesDict.getFieldsMap()); + + if (STATES.containsKey(state2String)) { + return STATES.get(state2String); + } else { + logger.warn("[ {} Provider ]: State '{}' NOT AVAILABLE", getName(), state2String); + return null; + } + } else { + logger.warn("[ {} Provider ]: State '{}' NOT AVAILABLE", getName(), state2String); + return null; + } + } + + private Dictionary mergeBase(String subDictID) { + Dictionary baseDict = new Dictionary(subDictID); + Dictionary stateData = getDefaultStateData(); + + if (stateData != null && stateData.found(subDictID)) { + baseDict.merge(stateData.subDict(subDictID)); + } else { + logger.warn("'" + subDictID + "' NOT FOUND"); + } + + // System.out.println("AbstractDefaultsProvider.mergeBase() "+baseDict); + + if (baseDict.found("base")) { + String baseName = baseDict.lookup("base"); + Dictionary bd = mergeBase(baseName); + bd.merge(baseDict); + return bd; + } + + return baseDict; + } + + static Dictionary extractModule(DefaultsProvider defaults, String encodedPrimalState, String moduleName) { + if (defaults.getDefaultStateData().found(moduleName)) { + Dictionary defaultModule = new Dictionary(defaults.getDefaultStateData().subDict(moduleName)); + Dictionary relativeToStateModule = extractRelativeToStateModule(encodedPrimalState, defaultModule); + if (relativeToStateModule != null) { + defaultModule.merge(relativeToStateModule); + } + return defaultModule; + } + return null; + } + + private static Dictionary extractRelativeToStateModule(String encodedPrimalState, Dictionary mDict) { + if (mDict.found("requirements")) { + Dictionary requirements = (Dictionary) mDict.remove("requirements"); + if (requirements.found("conditional")) { + if (requirements.subDict("conditional").found(encodedPrimalState)) { + Dictionary conditional = requirements.subDict("conditional").subDict(encodedPrimalState); + return conditional; + } + } + } + return null; + } + +} diff --git a/src/eu/engys/core/project/defaults/DefaultDictDataFolder.java b/src/eu/engys/core/project/defaults/DefaultDictDataFolder.java new file mode 100644 index 0000000..999c917 --- /dev/null +++ b/src/eu/engys/core/project/defaults/DefaultDictDataFolder.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.defaults; + +import java.io.File; + +import javax.inject.Inject; +import javax.inject.Named; + +import eu.engys.util.ApplicationInfo; + +public class DefaultDictDataFolder implements DictDataFolder { + + private final File dictDataFolder; + + @Inject + public DefaultDictDataFolder(@Named("Application") String applicationFolder) { + this.dictDataFolder = new File(new File(ApplicationInfo.getRootPath(), "dictData"), applicationFolder); + } + + public File getFile(String fileName) { + return new File(dictDataFolder, fileName); + } + + @Override + public File toFile() { + return dictDataFolder; + } +} diff --git a/src/eu/engys/core/project/defaults/Defaults.java b/src/eu/engys/core/project/defaults/Defaults.java new file mode 100644 index 0000000..aed40a7 --- /dev/null +++ b/src/eu/engys/core/project/defaults/Defaults.java @@ -0,0 +1,142 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.defaults; + +import javax.inject.Inject; + +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.system.BlockMeshDict; +import eu.engys.core.project.system.MapFieldsDict; +import eu.engys.core.project.system.SnappyHexMeshDict; + +public class Defaults extends AbstractDefaultsProvider { + + private DictDataFolder dictDataFolder; + private Dictionary defaultsDictionary; + + @Inject + public Defaults(DictDataFolder folder) { + this.dictDataFolder = folder; + this.defaultsDictionary = new Dictionary(folder.getFile("caseSetupDict.defaults")).subDict("defaults"); + LoggerFactory.getLogger(Defaults.class).info("-> Defaults"); + } + + @Override + public String getName() { + return "Main"; + } + + public DictDataFolder getDictDataFolder() { + return dictDataFolder; + } + + private Dictionary getDefaultsDict() { + return defaultsDictionary; + } + + @Override + public Dictionary getStates() { + return getDefaultsDict().subDict("states"); + } + + @Override + public Dictionary getDefaultStateData() { + return getDefaultsDict().subDict("stateData"); + } + + @Override + public Dictionary getDefaultFieldsData() { + return getDefaultsDict().subDict("fields"); + } + + public Dictionary getCompressibleMaterials() { + return new Dictionary(dictDataFolder.getFile("caseSetupDict.materialProperties.compressible")).subDict("materialProperties"); + } + + public Dictionary getIncompressibleMaterials() { + return new Dictionary(dictDataFolder.getFile("caseSetupDict.materialProperties.incompressible")).subDict("materialProperties"); + } + + @Override + public Dictionary getDefaultTurbulenceProperties() { + return getDefaultsDict().subDict("turbulenceProperties"); + } + + public Dictionary getDefaultFunctions() { + return getDefaultsDict().subDict("functions"); + } + + public Dictionary getDefaultSchemes() { + return getDefaultsDict().subDict("schemes"); + } + + public SnappyHexMeshDict getDefaultSnappyHexMeshDict() { + return new SnappyHexMeshDict(dictDataFolder.getFile("createCase.snappyHexMeshDict")); + } + + public BlockMeshDict getDefaultBlockMeshDict() { + return new BlockMeshDict(dictDataFolder.getFile("createCase.blockMeshDict")); + } + + public Dictionary getDefaultFvSchemes() { + return new Dictionary(dictDataFolder.getFile("createCase.fvSchemes")); + } + + public Dictionary getDefaultFvSolution() { + return new Dictionary(dictDataFolder.getFile("createCase.fvSolution")); + } + + public Dictionary getDefaultFvOptions() { + return new Dictionary(""); + } + + public Dictionary getDefaultControlDict() { + return new Dictionary(dictDataFolder.getFile("createCase.controlDict")); + } + + public Dictionary getDefaultRunDict() { + return new Dictionary(dictDataFolder.getFile("createCase.runDict")); + } + public MapFieldsDict getDefaultMapFieldsDict() { + return new MapFieldsDict(dictDataFolder.getFile("createCase.mapFieldsDict")); + } + + public Dictionary getDefaultDecomposeParDict() { + return new Dictionary(dictDataFolder.getFile("createCase.decomposeParDict")); + } + + public Dictionary getDefaultCustomNodeDict() { + return new Dictionary(dictDataFolder.getFile("createCase.customNodeDict")); + } + + public Dictionary getDefaultShapes() { + return new Dictionary(dictDataFolder.getFile("createCase.shapes")); + } + +} diff --git a/src/eu/engys/core/project/defaults/DefaultsProvider.java b/src/eu/engys/core/project/defaults/DefaultsProvider.java new file mode 100644 index 0000000..4a14a9c --- /dev/null +++ b/src/eu/engys/core/project/defaults/DefaultsProvider.java @@ -0,0 +1,48 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.defaults; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.state.State; + +public interface DefaultsProvider { + + Dictionary getDefaultTurbulenceProperties(); + + Dictionary getDefaultFieldsData(); + + Dictionary getDefaultStateData(); + + Dictionary getStates(); + + Dictionary getDefaultsFor(State state); + + Dictionary getDefaultsFieldMapsFor(State state, String region); + + String getName(); + +} diff --git a/src/eu/engys/core/project/defaults/DictDataFolder.java b/src/eu/engys/core/project/defaults/DictDataFolder.java new file mode 100644 index 0000000..70df012 --- /dev/null +++ b/src/eu/engys/core/project/defaults/DictDataFolder.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.defaults; + +import java.io.File; + +public interface DictDataFolder { + + public File getFile(String fileName); + public File toFile(); + +} diff --git a/src/eu/engys/core/project/defaults/JarDictDataFolder.java b/src/eu/engys/core/project/defaults/JarDictDataFolder.java new file mode 100644 index 0000000..e84360e --- /dev/null +++ b/src/eu/engys/core/project/defaults/JarDictDataFolder.java @@ -0,0 +1,118 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.defaults; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.ArchiveUtils; +import eu.engys.util.TempFolder; + +public class JarDictDataFolder implements DictDataFolder { + + private static final Logger logger = LoggerFactory.getLogger(JarDictDataFolder.class); + + private File dictDataFolder; + private String applicationFolder; + + @Inject + public JarDictDataFolder(@Named("Application") String applicationFolder) throws IOException { + this.applicationFolder = applicationFolder; + } + + @Override + public File toFile() { + return dictDataFolder; + } + + private String getRootPath() { + URL appJarURL = JarDictDataFolder.class.getProtectionDomain().getCodeSource().getLocation(); + File appJarFile; + try { + appJarFile = new File(appJarURL.toURI()); + } catch (URISyntaxException e) { + appJarFile = new File(appJarURL.getPath()); + } + return appJarFile.getParentFile().getParent(); + } + + public File getFile(String fileName) { + if (dictDataFolder == null) { + extractDictData(); + } + return new File(dictDataFolder, fileName); + } + + public void extractDictData() { + extractToTemp(); + } + + public void extractToTemp() { + this.dictDataFolder = TempFolder.get("dictData", applicationFolder); + if (dictDataFolder.exists()) { + FileUtils.deleteQuietly(dictDataFolder); + } + logger.info("Extract to temp"); + dictDataFolder.mkdirs(); + Path pathToLibFile = Paths.get(getRootPath(), "lib", applicationFolder+"-data.jar"); + if (Files.exists(pathToLibFile)) { + logger.info("Extract to temp: File is {}", pathToLibFile); + ArchiveUtils.unzip(pathToLibFile.toFile(), dictDataFolder.getParentFile()); + } else { + logger.info("Extract to temp: File {} not found", pathToLibFile); + Path pathToDistFile = Paths.get(getRootPath(), "dist", applicationFolder+"-data.jar"); + if (Files.exists(pathToDistFile)){ + logger.info("Extract to temp: File is {}", pathToDistFile); + ArchiveUtils.unzip(pathToDistFile.toFile(), dictDataFolder.getParentFile()); + } else { + logger.info("Extract to temp: File {} not found", pathToDistFile); + } + } + } + +// public void extractToRoot() { +// this.dictDataFolder = new File(new File(getRootPath(), "dictData"), applicationFolder); +// if (!dictDataFolder.exists()) { +// logger.warn("Extract to root"); +// dictDataFolder.mkdirs(); +// Path path = Paths.get(getRootPath(), "lib", applicationFolder+"-data.jar"); +// IOUtils.unzip(dictDataFolder.getParentFile(), path.toFile()); +// } +// } + +} diff --git a/src/eu/engys/core/project/files/DefaultFileManager.java b/src/eu/engys/core/project/files/DefaultFileManager.java new file mode 100644 index 0000000..699c5c4 --- /dev/null +++ b/src/eu/engys/core/project/files/DefaultFileManager.java @@ -0,0 +1,136 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.files; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.Util; + +public class DefaultFileManager implements FileManager { + + protected static final Logger logger = LoggerFactory.getLogger(Folder.class); + + private File file; + + public DefaultFileManager(File file) { + setFile(file); + } + + private void setFile(File file) { + this.file = file; + if (!file.exists()) { + logger.warn("-> New Folder {}", file); + file.mkdirs(); + } + } + + public File getFile() { + return file; + } + + public File getFile(String fileName) { + return new File(file, fileName); + } + + public File newFile(String fileName) { + return new File(file, fileName); + } + + public File copyHere(File source, String newName, boolean overwrite) { + String name = Util.replaceForbiddenCharacters(newName); + File target; + if (overwrite) { + target = newFile(name); + } else { + target = getACopy(name); + } + + if (target.equals(source)) + return target; + + try { + FileUtils.copyFile(source, target); + logger.info("File {} copied to {}", source, target); + } catch (IOException e) { + e.printStackTrace(); + logger.error("Error copying", e); + } + + return target; + } + + // public File moveHere(File file, boolean overwrite) { + // Path source = file.toPath(); + // Path target = file.toPath().resolve(file.getName()); + // try { + // Files.move(source, target); + // } catch (IOException e) { + // e.printStackTrace(); + // } + // + // return target.toFile(); + // } + + public void rename(String oldFileName, String newFileName) { + Path source = file.toPath().resolve(oldFileName); + try { + Files.move(source, source.resolveSibling(newFileName)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public String[] list() { + return file.list(); + } + + private File getACopy(String name) { + String finalName = name; + String finalNameNoExtension = FilenameUtils.removeExtension(finalName); + + int counter = 0; + File file; + while ((file = newFile(finalName)).exists()) { + finalName = finalNameNoExtension + (counter++) + ".stl"; + } + + return file; + } + + public void deleteAll() { + FileUtils.deleteQuietly(file); + file.mkdir(); + } +} diff --git a/src/eu/engys/core/project/files/FileManager.java b/src/eu/engys/core/project/files/FileManager.java new file mode 100644 index 0000000..457b9ee --- /dev/null +++ b/src/eu/engys/core/project/files/FileManager.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.files; + +import java.io.File; + +public interface FileManager { + public File getFile(); + + public File getFile(String fileName); + + public File newFile(String fileName); + + public File copyHere(File file, String newName, boolean overwrite); + + public void deleteAll(); + +} diff --git a/src/eu/engys/core/project/files/Folder.java b/src/eu/engys/core/project/files/Folder.java new file mode 100644 index 0000000..af9ec47 --- /dev/null +++ b/src/eu/engys/core/project/files/Folder.java @@ -0,0 +1,33 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.files; + +public interface Folder { + public FileManager getFileManager(); +} + + diff --git a/src/eu/engys/core/project/geometry/BlockReader.java b/src/eu/engys/core/project/geometry/BlockReader.java new file mode 100644 index 0000000..b12a5ed --- /dev/null +++ b/src/eu/engys/core/project/geometry/BlockReader.java @@ -0,0 +1,221 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry; + +import static eu.engys.core.project.geometry.Surface.MAX_KEY; +import static eu.engys.core.project.geometry.Surface.MIN_KEY; +import static eu.engys.core.project.system.BlockMeshDict.BLOCKS_KEY; +import static eu.engys.core.project.system.BlockMeshDict.ELEMENTS_KEY; +import static eu.engys.core.project.system.BlockMeshDict.PATCHES_KEY; +import static eu.engys.core.project.system.BlockMeshDict.VERTICES_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.ADD_LAYERS_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.LAYERS_KEY; + +import java.util.ArrayList; +import java.util.List; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.dictionary.parser.ListField2; +import eu.engys.core.project.geometry.surface.MultiPlane; +import eu.engys.core.project.geometry.surface.PlaneRegion; +import eu.engys.core.project.system.BlockMeshDict; +import eu.engys.core.project.system.SnappyHexMeshDict; + +public class BlockReader { + + private static final String DEFAULT_MAX_VALUE = "(1 1 1)"; + private static final String DEFAULT_MIN_VALUE = "(-1 -1 -1)"; + private static final String DEFAULT_ELEMENTS_VALUE = "(10 10 10)"; + private Geometry geometry; + + public BlockReader(Geometry geometry) { + this.geometry = geometry; + } + + /* + * Here the user has selected a block mesh of type: user defined. I need to load the data from blockMeshDict to visualise the block. + */ + public MultiPlane loadBlock(BlockMeshDict blockMeshDict, SnappyHexMeshDict snappyHexMeshDict) { + Dictionary blockDict = new Dictionary("block"); + MultiPlane block = null; + loadBlocksFromBlockMeshDict(blockMeshDict, blockDict); + loadVerticesFromBlockMeshDict(blockMeshDict, blockDict); + if (blockMeshDict.found(PATCHES_KEY)) { + ListField2 patches = blockMeshDict.getList2(PATCHES_KEY); + String[] patchesList = extractPatches(patches); + if (patchesList.length == 6) { + block = loadPatches(patchesList, blockDict); + } else { + block = loadDefaultPatches(); + } + } else { + block = loadDefaultPatches(); + } + block.setGeometryDictionary(blockDict); + + loadLayers(snappyHexMeshDict, block); + geometry.setBlock(block); + geometry.setCellSize(block.getDelta()); + return block; + } + + /* + * Patches + */ + + private MultiPlane loadPatches(String[] patchesList, Dictionary blockDict) { + MultiPlane block = new MultiPlane("BoundingBox"); + for (int i = 0; i < patchesList.length; i++) { + blockDict.add("patch" + i, patchesList[i]); + block.addPlane(patchesList[i]); + } + return block; + } + + private MultiPlane loadDefaultPatches() { + MultiPlane block = new MultiPlane("BoundingBox"); + block.addPlane("ffminx"); + block.addPlane("ffmaxx"); + block.addPlane("ffminy"); + block.addPlane("ffmaxy"); + block.addPlane("ffminz"); + block.addPlane("ffmaxz"); + return block; + } + + /* + * Vertices + */ + + private void loadVerticesFromBlockMeshDict(BlockMeshDict blockMeshDict, Dictionary d) { + if (blockMeshDict.found(VERTICES_KEY)) { + ListField2 vertices = blockMeshDict.getList2(VERTICES_KEY); + d.add(MIN_KEY, extractMin(vertices)); + d.add(MAX_KEY, extractMax(vertices)); + } else { + loadDefaultVertices(d); + } + } + + private void loadDefaultVertices(Dictionary d) { + d.add(MIN_KEY, DEFAULT_MIN_VALUE); + d.add(MAX_KEY, DEFAULT_MAX_VALUE); + } + + /* + * Blocks + */ + + private void loadBlocksFromBlockMeshDict(BlockMeshDict blockMeshDict, Dictionary d) { + if (blockMeshDict.found(BLOCKS_KEY)) { + ListField2 blocks = blockMeshDict.getList2(BLOCKS_KEY); + d.add(ELEMENTS_KEY, extractElements(blocks)); + } else { + loadDefaultBlocks(d); + } + } + + private void loadDefaultBlocks(Dictionary d) { + d.add(ELEMENTS_KEY, DEFAULT_ELEMENTS_VALUE); + } + + private void loadLayers(SnappyHexMeshDict snappyHexMeshDict, MultiPlane block) { + if (snappyHexMeshDict.isDictionary(ADD_LAYERS_CONTROLS_KEY) && snappyHexMeshDict.subDict(ADD_LAYERS_CONTROLS_KEY).isDictionary(LAYERS_KEY)) { + Dictionary layers = snappyHexMeshDict.subDict(ADD_LAYERS_CONTROLS_KEY).subDict(LAYERS_KEY); + for (PlaneRegion plane : block.getPlanes()) { + if (layers.isDictionary(plane.getName())) { + plane.getLayerDictionary().merge(layers.subDict(plane.getName())); + } + } + } + } + + /* + * Utils + */ + + private String extractElements(ListField2 blocks) { + if (blocks.isEmpty()) { + return DEFAULT_ELEMENTS_VALUE; + } else { + StringBuffer sb = new StringBuffer("("); + ListField2 element = (ListField2) blocks.getListElements().get(2); + FieldElement x = ((FieldElement) element.getListElements().get(0)); + FieldElement y = ((FieldElement) element.getListElements().get(1)); + FieldElement z = ((FieldElement) element.getListElements().get(2)); + sb.append(x.getValue() + " "); + sb.append(y.getValue() + " "); + sb.append(z.getValue() + " "); + sb.append(")"); + return sb.toString(); + } + } + + private String extractMin(ListField2 vertices) { + if (vertices.isEmpty()) { + return DEFAULT_MIN_VALUE; + } else { + StringBuffer sb = new StringBuffer("("); + ListField2 firstElement = (ListField2) vertices.getListElements().get(0); + FieldElement x = ((FieldElement) firstElement.getListElements().get(0)); + FieldElement y = ((FieldElement) firstElement.getListElements().get(1)); + FieldElement z = ((FieldElement) firstElement.getListElements().get(2)); + sb.append(x.getValue() + " "); + sb.append(y.getValue() + " "); + sb.append(z.getValue() + " "); + sb.append(")"); + return sb.toString(); + } + } + + private String extractMax(ListField2 vertices) { + if (vertices.isEmpty()) { + return DEFAULT_MAX_VALUE; + } else { + StringBuffer sb = new StringBuffer("("); + ListField2 firstElement = (ListField2) vertices.getListElements().get(vertices.getListElements().size() - 2); + FieldElement x = ((FieldElement) firstElement.getListElements().get(0)); + FieldElement y = ((FieldElement) firstElement.getListElements().get(1)); + FieldElement z = ((FieldElement) firstElement.getListElements().get(2)); + sb.append(x.getValue() + " "); + sb.append(y.getValue() + " "); + sb.append(z.getValue() + " "); + sb.append(")"); + return sb.toString(); + } + } + + private String[] extractPatches(ListField2 patches) { + List tokens = new ArrayList(); + for (int i = 0; i < patches.getListElements().size(); i++) { + if (i % 3 == 1) { + tokens.add(((FieldElement) patches.getListElements().get(i)).getValue()); + } + } + return tokens.toArray(new String[0]); + } +} diff --git a/src/eu/engys/core/project/geometry/BlockSaver.java b/src/eu/engys/core/project/geometry/BlockSaver.java new file mode 100644 index 0000000..c363a4a --- /dev/null +++ b/src/eu/engys/core/project/geometry/BlockSaver.java @@ -0,0 +1,169 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry; + +import static eu.engys.core.project.geometry.Surface.MAX_KEY; +import static eu.engys.core.project.geometry.Surface.MIN_KEY; +import static eu.engys.core.project.system.BlockMeshDict.BLOCKS_KEY; +import static eu.engys.core.project.system.BlockMeshDict.ELEMENTS_KEY; +import static eu.engys.core.project.system.BlockMeshDict.HEX_KEY; +import static eu.engys.core.project.system.BlockMeshDict.PATCHES_KEY; +import static eu.engys.core.project.system.BlockMeshDict.SIMPLE_GRADING_KEY; +import static eu.engys.core.project.system.BlockMeshDict.VERTICES_KEY; +import static eu.engys.core.project.system.BlockMeshDict.WALL_KEY; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.dictionary.parser.ListField2; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.surface.PlaneRegion; +import eu.engys.core.project.system.BlockMeshDict; + +public class BlockSaver { + + private Model model; + private Geometry geometry; + + public BlockSaver(Model model, Geometry geometry) { + this.model = model; + this.geometry = geometry; + } + + public void saveAutomaticBlock() { + BlockMeshDict blockMeshDict = model.getProject().getSystemFolder().getBlockMeshDict(); + if(blockMeshDict != null){ + blockMeshDict.setBoundingBox(model.getGeometry().computeBoundingBox()); + } + } + /* + * Here I take the user defined block mesh parameters from the GUI and I + * save them in blockMeshDict. If the current blockMeshDict has been + * imported from external file I need to clean its data because there can be + * stuff I cannot visualise in the GUI + */ + public void saveUserDefinedBlock(Dictionary userDefinedDictionary) { + BlockMeshDict blockMeshDict = model.getProject().getSystemFolder().getBlockMeshDict(); + if (blockMeshDict.isFromFile()) { + blockMeshDict = new BlockMeshDict(); + } + saveBlocks(blockMeshDict, userDefinedDictionary); + saveVertices(blockMeshDict, userDefinedDictionary); + savePatches(blockMeshDict); + } + + + private void saveBlocks(BlockMeshDict blockMeshDict, Dictionary userDefinedDictionary) { + ListField2 blocksList = new ListField2(BLOCKS_KEY); + + // 1 + blocksList.add(new FieldElement("", HEX_KEY)); + + // 2 + ListField2 hexList = new ListField2(""); + hexList.add("0", "1", "2", "3", "4", "5", "6", "7"); + blocksList.add(hexList); + + // 3 + ListField2 elementsList = new ListField2(""); + int[] elements = userDefinedDictionary.lookupIntArray(ELEMENTS_KEY); + for (int el : elements) { + elementsList.add(new FieldElement("", String.valueOf(el))); + } + blocksList.add(elementsList); + + // 4 + blocksList.add(new FieldElement("", SIMPLE_GRADING_KEY)); + + // 5 + ListField2 lastList = new ListField2(""); + lastList.add("1", "1", "1"); + blocksList.add(lastList); + + blockMeshDict.add(blocksList); + } + + private void savePatches(BlockMeshDict blockMeshDict) { + PlaneRegion[] regions = geometry.getBlock().getPlanes(); + + ListField2 patchesList = new ListField2(PATCHES_KEY); + + patchesList.add(WALL_KEY, regions[0].getName()); + patchesList.add(getValuesList("0", "4", "7", "3")); + + patchesList.add(WALL_KEY, regions[1].getName()); + patchesList.add(getValuesList("1", "2", "6", "5")); + + patchesList.add(WALL_KEY, regions[2].getName()); + patchesList.add(getValuesList("0", "1", "5", "4")); + + patchesList.add(WALL_KEY, regions[3].getName()); + patchesList.add(getValuesList("3", "7", "6", "2")); + + patchesList.add(WALL_KEY, regions[4].getName()); + patchesList.add(getValuesList("0", "3", "2", "1")); + + patchesList.add(WALL_KEY, regions[5].getName()); + patchesList.add(getValuesList("4", "5", "6", "7")); + + blockMeshDict.add(patchesList); + } + + private void saveVertices(BlockMeshDict blockMeshDict, Dictionary d) { + String[] min = d.lookupArray(MIN_KEY); + String[] max = d.lookupArray(MAX_KEY); + + ListField2 verticesList = new ListField2(VERTICES_KEY); + verticesList.add(getPointList(min[0], min[1], min[2])); + verticesList.add(getPointList(max[0], min[1], min[2])); + verticesList.add(getPointList(max[0], max[1], min[2])); + verticesList.add(getPointList(min[0], max[1], min[2])); + verticesList.add(getPointList(min[0], min[1], max[2])); + verticesList.add(getPointList(max[0], min[1], max[2])); + verticesList.add(getPointList(max[0], max[1], max[2])); + verticesList.add(getPointList(min[0], max[1], max[2])); + + blockMeshDict.add(verticesList); + } + + /* + * Utils + */ + + private ListField2 getValuesList(String v1, String v2, String v3, String v4) { + ListField2 valuesList = new ListField2(""); + valuesList.add(v1, v2, v3, v4); + ListField2 valuesContainerList = new ListField2(""); + valuesContainerList.add(valuesList); + return valuesContainerList; + } + + private ListField2 getPointList(String x, String y, String z) { + ListField2 list = new ListField2(""); + list.add(x, y, z); + return list; + } + +} diff --git a/src/eu/engys/core/project/geometry/BoundingBox.java b/src/eu/engys/core/project/geometry/BoundingBox.java new file mode 100644 index 0000000..df85055 --- /dev/null +++ b/src/eu/engys/core/project/geometry/BoundingBox.java @@ -0,0 +1,140 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry; + +import java.util.Arrays; + +import javax.vecmath.Point3d; + +public class BoundingBox { + + private double xmin = Double.MAX_VALUE; + private double xmax = -Double.MAX_VALUE; + private double ymin = Double.MAX_VALUE; + private double ymax = -Double.MAX_VALUE; + private double zmin = Double.MAX_VALUE; + private double zmax = -Double.MAX_VALUE; + private Point3d center = new Point3d(0, 0, 0); + + public BoundingBox() { + } + + public BoundingBox(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) { + this.xmin = xmin; + this.xmax = xmax; + this.ymin = ymin; + this.ymax = ymax; + this.zmin = zmin; + this.zmax = zmax; + } + + public double getXmin() { + return xmin; + } + + public void setXmin(double xmin) { + this.xmin = xmin; + } + + public double getXmax() { + return xmax; + } + + public void setXmax(double xmax) { + this.xmax = xmax; + } + + public double getYmin() { + return ymin; + } + + public void setYmin(double ymin) { + this.ymin = ymin; + } + + public double getYmax() { + return ymax; + } + + public void setYmax(double ymax) { + this.ymax = ymax; + } + + public double getZmin() { + return zmin; + } + + public void setZmin(double zmin) { + this.zmin = zmin; + } + + public double getZmax() { + return zmax; + } + + public void setZmax(double zmax) { + this.zmax = zmax; + } + + public double[] getCenter() { + double centerX = (xmin + xmax) / 2; + double centerY = (ymin + ymax) / 2; + double centerZ = (zmin + zmax) / 2; + return new double[]{centerX, centerY, centerZ}; + } + + public double getWidth() { + return xmax - xmin; + } + + public double getHeight() { + return ymax - ymin; + } + + public double getDepth() { + return zmax - zmin; + } + + public double getDiagonal() { + return Math.sqrt(Math.pow(xmax - xmin, 2) + Math.pow(ymax - ymin, 2) + Math.pow(zmax - zmin, 2)); + } + + @Override + public String toString() { + return "Bounding Box: xmin (" + getXmin() + "), xmax (" + getXmax() + "), ymin (" + getYmin()+ "), ymax (" + getYmax()+ "), zmin (" + getZmin()+ "), zmax (" + getZmax() + "), centre " + Arrays.toString(getCenter()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof BoundingBox) { + BoundingBox b = (BoundingBox) obj; + return b.getWidth() == getWidth() && b.getHeight() == getHeight(); + } + return false; + } + +} diff --git a/src/eu/engys/core/project/geometry/FeatureLine.java b/src/eu/engys/core/project/geometry/FeatureLine.java new file mode 100644 index 0000000..a38c6e4 --- /dev/null +++ b/src/eu/engys/core/project/geometry/FeatureLine.java @@ -0,0 +1,178 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry; + +import static eu.engys.core.project.system.SnappyHexMeshDict.FILE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.LEVELS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.REFINE_FEATURE_EDGES_ONLY_KEY; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; + +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.surface.BaseSurface; + +public class FeatureLine extends BaseSurface { + + public static class Refinement { + + private double distance; + private int level; + + public Refinement(double distance, int level) { + this.distance = distance; + this.level = level; + } + public double getDistance() { + return distance; + } + public int getLevel() { + return level; + } + } + + private boolean refineOnly; + private List refinements; + private vtkPolyData dataSet; + private Color color; + private boolean modified; + + public FeatureLine(String name) { + super(name); + this.refineOnly = false; + this.refinements = new ArrayList<>(); + this.refinements.add(new Refinement(0.0, 0)); + this.color = Color.BLUE; + } + + public boolean isRefineOnly() { + return refineOnly; + } + public void setRefineOnly(boolean refineOnly) { + this.refineOnly = refineOnly; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public List getRefinements() { + return refinements; + } + public void setRefinements(List refinements) { + this.refinements = refinements; + } + + @Override + public Type getType() { + return Type.LINE; + } + @Override + public Surface cloneSurface() { + return new FeatureLine(getName()); + } + @Override + public vtkPolyData getDataSet() { + return dataSet; + } + public void setDataSet(vtkPolyData dataSet) { + this.dataSet = dataSet; + } + @Override + public boolean isAppendRegionName() { + return false; + } + @Override + public boolean hasSurfaceRefinement() { + return false; + } + @Override + public boolean hasVolumeRefinement() { + return false; + } + @Override + public boolean hasLayers() { + return false; + } + + public void setColor(Color color) { + this.color = color; + } + + public Color getColor() { + return color; + } + + @Override + public Dictionary toDictionary() { + Dictionary d = new Dictionary(""); + d.add(FILE_KEY, "\"" + getName() + ".eMesh" + "\""); + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (Refinement r : refinements) { + sb.append("("); + sb.append(r.distance); + sb.append(" "); + sb.append(r.level); + sb.append(")"); + } + sb.append(")"); + d.add(LEVELS_KEY, sb.toString()); + d.add(REFINE_FEATURE_EDGES_ONLY_KEY, String.valueOf(refineOnly)); + return d; + } + + @Override + public void fromDictionary(Dictionary d) { + refinements.clear(); + if (d.found(LEVELS_KEY)) { + double[][] levels = d.lookupDoubleMatrix(LEVELS_KEY); + for (int i = 0; i < levels.length; i++) { + if (levels[i].length == 2) { + double distance = levels[i][0]; + int level = (int) levels[i][1]; + refinements.add(new Refinement(distance, level)); + } + } + } + if (d.found(REFINE_FEATURE_EDGES_ONLY_KEY) ) { + this.refineOnly = Boolean.parseBoolean(d.lookup(REFINE_FEATURE_EDGES_ONLY_KEY)); + } + } + + public void setModified(boolean modified) { + this.modified = modified; + } + + public boolean isModified() { + return modified; + } +} diff --git a/src/eu/engys/core/project/geometry/FeatureLines.java b/src/eu/engys/core/project/geometry/FeatureLines.java new file mode 100644 index 0000000..9a11b30 --- /dev/null +++ b/src/eu/engys/core/project/geometry/FeatureLines.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class FeatureLines implements Iterable { + + private List list = new ArrayList<>(); + + public void addLine(FeatureLine line) { + list.add(line); + } + + public void remove(FeatureLine line) { + list.remove(line); + } + + @Override + public Iterator iterator() { + return list.iterator(); + } + + public int size() { + return list.size(); + } + + public FeatureLine getLine(int index) { + return list.get(index); + } + + public FeatureLine getLine(String name) { + for (FeatureLine line : list) { + if (line.getName().equals(name)) { + return line; + } + } + return null; + } + + public FeatureLine[] toArray() { + return list.toArray(new FeatureLine[0]); + } + +} diff --git a/src/eu/engys/core/project/geometry/Geometry.java b/src/eu/engys/core/project/geometry/Geometry.java new file mode 100644 index 0000000..fdbb908 --- /dev/null +++ b/src/eu/engys/core/project/geometry/Geometry.java @@ -0,0 +1,335 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry; + +import java.util.ArrayList; +import java.util.List; + +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.factory.GeometryFactory; +import eu.engys.core.project.geometry.surface.Box; +import eu.engys.core.project.geometry.surface.Cylinder; +import eu.engys.core.project.geometry.surface.MultiPlane; +import eu.engys.core.project.geometry.surface.Plane; +import eu.engys.core.project.geometry.surface.Ring; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.core.project.geometry.surface.Sphere; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.core.project.system.BlockMeshDict; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.util.Util; +import eu.engys.util.progress.ProgressMonitor; + +public class Geometry { + + public static MultiPlane FAKE_BLOCK = new MultiPlane(""); + + private final List surfaces = new ArrayList(); + private final FeatureLines lines = new FeatureLines(); + private MultiPlane block = FAKE_BLOCK; + private GeometryFactory geometryFactory; + + private boolean autoBoundingBox = true; + private double[] cellSize; + + public Geometry(GeometryFactory geometryFactory) { + this.geometryFactory = geometryFactory; + surfaces.clear(); + } + + public BoundingBox computeBoundingBox() { + if (Util.isVarArgsNotNull(surfaces.toArray(new Surface[0]))) { + double xmin = Double.MAX_VALUE; + double xmax = -Double.MAX_VALUE; + double ymin = Double.MAX_VALUE; + double ymax = -Double.MAX_VALUE; + double zmin = Double.MAX_VALUE; + double zmax = -Double.MAX_VALUE; + + for (Surface surface : getAllSurfaces()) { + vtkPolyData dataSet = surface.getTransformedDataSet(); + if (dataSet != null) { + double[] bounds = dataSet.GetBounds(); + xmin = Math.min(xmin, bounds[0]); + xmax = Math.max(xmax, bounds[1]); + ymin = Math.min(ymin, bounds[2]); + ymax = Math.max(ymax, bounds[3]); + zmin = Math.min(zmin, bounds[4]); + zmax = Math.max(zmax, bounds[5]); + } + } + return new BoundingBox(xmin, xmax, ymin, ymax, zmin, zmax); + } else { + return new BoundingBox(0, 0, 0, 0, 0, 0); + } + } + + private List getAllSurfaces() { + List allSurfaces = new ArrayList(); + for (Surface surface : surfaces) { + if (surface.getType().isPlane()) { + continue; + } else if (surface.getType().isStl()) { + Solid[] l = (((Stl) surface).getSolids()); + for (Solid solid : l) { + allSurfaces.add(solid); + } + } else { + allSurfaces.add(surface); + } + } + return allSurfaces; + } + + public FeatureLines getLines() { + return lines; + } + + public Surface[] getSurfaces() { + return surfaces.toArray(new Surface[surfaces.size()]); + } + + public void loadGeometry(Model model, ProgressMonitor monitor) { + new GeometryReader(this).loadGeometry(model, monitor); + } + + public void saveGeometry(Model model) { + new GeometrySaver(model, this).save(); + } + + public void writeGeometry(Model model, ProgressMonitor monitor) { + new GeometryWriter(model, this, monitor).write(); + } + + public void loadBlock(BlockMeshDict blockMeshDict, SnappyHexMeshDict snappyHexMeshDict) { + new BlockReader(this).loadBlock(blockMeshDict, snappyHexMeshDict); + } + + public void saveUserDefinedBlock(Model model, Dictionary d) { + new BlockSaver(model, this).saveUserDefinedBlock(d); + } + + public void saveAutoBlock(Model model) { + new BlockSaver(model, this).saveAutomaticBlock(); + } + + public GeometryFactory getFactory() { + return geometryFactory; + } + + public void addSurface(Surface... surfaces) { + for (Surface surface : surfaces) { + this.surfaces.add(surface); + } + } + + public void addLine(FeatureLine... lines) { + for (FeatureLine line : lines) { + this.lines.addLine(line); + } + } + + public void removeSurfaces(Model model, Surface... surfaces) { + for (Surface surface : surfaces) { + geometryFactory.deleteSurface(model, surface); + this.surfaces.remove(surface); + } + } + + public void removeLines(FeatureLine... lines) { + for (FeatureLine line : lines) { + this.lines.remove(line); + } + } + + public boolean contains(Surface surface) { + return surfaces.contains(surface); + } + + public boolean isAutoBoundingBox() { + return autoBoundingBox; + } + + public void setAutoBoundingBox(boolean autoBoundingBox) { + this.autoBoundingBox = autoBoundingBox; + } + + public Surface getABox() { + return geometryFactory.newSurface(Box.class, getAName("box")); + } + + public Surface getASphere() { + return geometryFactory.newSurface(Sphere.class, getAName("sphere")); + } + + public FeatureLine getALine() { + return geometryFactory.newSurface(FeatureLine.class, getALineName("line")); + } + + public Surface getARing() { + return geometryFactory.newSurface(Ring.class, getAName("ring")); + } + + public Surface getAPlane() { + return geometryFactory.newSurface(Plane.class, getAName("plane")); + } + + public Surface getACylinder() { + return geometryFactory.newSurface(Cylinder.class, getAName("cylinder")); + } + + public String getAName(String name) { + List surfacesNames = new ArrayList(); + for (Surface surface : surfaces) { + surfacesNames.add(surface.getName()); + } + + String finalName = name; + int counter = 0; + while (surfacesNames.contains(finalName)) { + finalName = name + counter++; + } + + return finalName; + } + + public String getALineName(String name) { + List linesNames = new ArrayList(); + for (FeatureLine line : lines) { + linesNames.add(line.getName()); + } + + String finalName = name; + int counter = 0; + while (linesNames.contains(finalName)) { + finalName = name + counter++; + } + + return finalName; + } + + public MultiPlane getBlock() { + return block; + } + + public void setBlock(MultiPlane block) { + this.block = block; + } + + public boolean hasBlock() { + return block != null && block != FAKE_BLOCK; + } + + public void clear() { + surfaces.clear(); + } + + public boolean isEmpty() { + return !hasBlock() && surfaces.isEmpty(); + } + + public void hideSurfaces() { + for (Surface surface : surfaces) { + surface.setVisible(false); + } + for (FeatureLine line : lines) { + line.setVisible(false); + } + if (hasBlock()) { + block.setVisible(false); + } + } + + public Surface getSurfaceByPatchName(String patchName) { + for (Surface surface : surfaces) { + if (surface.getPatchName().equals(patchName)) { + return surface; + } + if (surface.hasRegions()) { + for (Surface region : surface.getRegions()) { + if (region.getPatchName().equals(patchName)) { + return region; + } + } + } + } + return null; + } + + public Surface getSurfaceByName(String name) { + for (Surface surface : surfaces) { + if (surface.getName().equals(name)) { + return surface; + } + if (surface.hasRegions()) { + for (Surface region : surface.getRegions()) { + if (region.getName().equals(name)) { + return region; + } + } + } + } + return null; + } + + public boolean contains(String name) { + for (Surface surface : surfaces) { + if (surface.getName().equals(name)) { + return true; + } + if (surface.hasRegions()) { + for (Surface region : surface.getRegions()) { + if (region.getName().equals(name)) { + return true; + } + } + } + } + + for (Surface region : block.getRegions()) { + if (region.getName().equals(name)) { + return true; + } + } + + return false; + } + + public double[] getCellSize(int level) { + if (cellSize != null) { + return new double[] { cellSize[0] / Math.pow(2, level), cellSize[1] / Math.pow(2, level), cellSize[2] / Math.pow(2, level) }; + } else { + return new double[3]; + } + } + + + public void setCellSize(double[] cellSize) { + this.cellSize = cellSize; + } +} diff --git a/src/eu/engys/core/project/geometry/GeometryReader.java b/src/eu/engys/core/project/geometry/GeometryReader.java new file mode 100644 index 0000000..f6500f2 --- /dev/null +++ b/src/eu/engys/core/project/geometry/GeometryReader.java @@ -0,0 +1,304 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry; + +import static eu.engys.core.dictionary.DictionaryUtils.copyIfFound; +import static eu.engys.core.project.system.SnappyHexMeshDict.ADD_LAYERS_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.AUTO_BLOCK_MESH_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.BLOCK_DATA_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.CASTELLATED_MESH_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.CELL_ZONE_INSIDE; +import static eu.engys.core.project.system.SnappyHexMeshDict.CELL_ZONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_TYPE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_ZONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FEATURES_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.GEOMETRY_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.LAYERS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.LEVEL_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_CELLS_ACROSS_GAP_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.PROXIMITY_INCREMENT_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.REFINEMENTS_REGIONS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.REFINEMENTS_SURFACES_KEY; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.ListField; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.factory.DefaultGeometryFactory; +import eu.engys.core.project.geometry.surface.Region; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.core.project.system.BlockMeshDict; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.util.progress.ProgressMonitor; + +public class GeometryReader { + + private static final Logger logger = LoggerFactory.getLogger(GeometryReader.class); + + private Geometry geometry; + + private SnappyHexMeshDict snappyHexMeshDict; + private Dictionary castellatedDict; + private Dictionary refinementSurfaces; + private Dictionary refinementRegions; + private Dictionary geometryDict; + private Dictionary layers; + + public GeometryReader(Geometry geometry) { + this.geometry = geometry; + } + + public void loadGeometry(Model model, ProgressMonitor monitor) { + snappyHexMeshDict = model.getProject().getSystemFolder().getSnappyHexMeshDict(); + + if (hasAValidStructure(snappyHexMeshDict)) { + initDictionaries(); + loadFeatureLines(model, monitor); + loadSurfaces(model, monitor); + } + + if (snappyHexMeshDict == null) { + return; + } + + if (!snappyHexMeshDict.found(AUTO_BLOCK_MESH_KEY) || !snappyHexMeshDict.lookup(AUTO_BLOCK_MESH_KEY).equals("true")) { + BlockMeshDict blockMeshDict = model.getProject().getSystemFolder().getBlockMeshDict(); + if (blockMeshDict != null) { + geometry.setAutoBoundingBox(false); + if (!blockMeshDict.isFromFile()) { + new BlockReader(geometry).loadBlock(blockMeshDict, snappyHexMeshDict); + } + } else { + logger.warn("No patches found in blockMeshDict"); + } + } else { + geometry.setAutoBoundingBox(true); + if (snappyHexMeshDict.found(BLOCK_DATA_KEY)) { + double[] blockData = snappyHexMeshDict.lookupDoubleArray(BLOCK_DATA_KEY); + geometry.setCellSize(new double[] { blockData[0], blockData[0], blockData[0] }); + } + } + model.geometryChanged(); + } + + private boolean hasAValidStructure(SnappyHexMeshDict snappyHexMeshDict) { + if (snappyHexMeshDict != null && snappyHexMeshDict.found(GEOMETRY_KEY) && snappyHexMeshDict.found(CASTELLATED_MESH_CONTROLS_KEY)) { + Dictionary castellatedDict = snappyHexMeshDict.subDict(CASTELLATED_MESH_CONTROLS_KEY); + if (castellatedDict.found(REFINEMENTS_SURFACES_KEY)) { + if (castellatedDict.found(REFINEMENTS_REGIONS_KEY)) { + if (snappyHexMeshDict.found(ADD_LAYERS_CONTROLS_KEY) && snappyHexMeshDict.subDict(ADD_LAYERS_CONTROLS_KEY).found(LAYERS_KEY)) { + return true; + } else { + logger.error("SnappyHexMeshDict bad structure: addLayersControls is missing."); + } + } else { + logger.error("SnappyHexMeshDict bad structure: refinementRegions is missing."); + } + } else { + logger.error("SnappyHexMeshDict bad structure: refinementSurfaces is missing."); + } + } else { + logger.error("SnappyHexMeshDict missing or with bad structure"); + } + return false; + } + + private void initDictionaries() { + geometryDict = snappyHexMeshDict.subDict(GEOMETRY_KEY); + castellatedDict = snappyHexMeshDict.subDict(CASTELLATED_MESH_CONTROLS_KEY); + refinementSurfaces = castellatedDict.subDict(REFINEMENTS_SURFACES_KEY); + refinementRegions = castellatedDict.subDict(REFINEMENTS_REGIONS_KEY); + layers = snappyHexMeshDict.subDict(ADD_LAYERS_CONTROLS_KEY).subDict(LAYERS_KEY); + } + + private void loadFeatureLines(final Model model, final ProgressMonitor monitor) { + if (castellatedDict.found(FEATURES_KEY) && castellatedDict.isList(FEATURES_KEY)) { +// Dictionary lines = new Dictionary(""); +// lines.add(new ListField(castellatedDict.getList(FEATURES_KEY))); + ListField list = castellatedDict.getList(FEATURES_KEY); + for (DefaultElement el : list.getListElements()) { + if (el instanceof Dictionary) { + Dictionary dict = (Dictionary) el; + final FeatureLine line = (FeatureLine) geometry.getFactory().loadSurface(dict, model, monitor); + line.fromDictionary(dict); + + logger.info("LINE: " + line.getName()); + geometry.addLine( line); + } + + } + } + } + + private void loadSurfaces(final Model model, final ProgressMonitor monitor) { + DefaultGeometryFactory.clearSTLCache(); + List dictionaries = geometryDict.getDictionaries(); + + final List surfaces = Collections.synchronizedList(new ArrayList()); + + monitor.setTotal(dictionaries.size()); + monitor.info("STLS:", 1); + + for (int i = 0; i < dictionaries.size(); i++) { + final Dictionary dict = dictionaries.get(i); + surfaces.add(geometry.getFactory().loadSurface(dict, model, monitor)); + } + + String[] surfaceNames = new String[surfaces.size()]; + for (int i = 0; i < surfaces.size(); i++) { + Surface surface = surfaces.get(i); + if (surface != null) { + surfaceNames[i] = surface.getName(); + loadSurface(surface); + } else { + logger.warn("A surface is null"); + } + } + monitor.info("Surfaces:" + Arrays.toString(surfaceNames), 1); + } + + private void loadSurface(Surface surface) { + geometry.addSurface(surface); + readRefinementSurfaces(surface); + readRefinementRegions(surface); + readLayers(surface); + } + + void readRefinementSurfaces(Surface surface) { + String name = surface.getName(); + if (refinementSurfaces.found(name)) { + logger.info("SURFACE: " + name); + Dictionary surfaceDict = refinementSurfaces.subDict(name); + if (isAFaceZone(surfaceDict)) { + readSurfaceAsACellZone(surface, surfaceDict); + } else { + readSurface(surface, surfaceDict); + } + } + } + + private void readSurface(Surface surface, Dictionary surfaceDict) { + surface.setSurfaceDictionary(surfaceDict); + if (surfaceDict.found("regions") && surface.getType().isStl()) { + Dictionary regionsDict = surfaceDict.subDict("regions"); + Stl stl = (Stl) surface; + for (Region region : stl.getRegions()) { + if (regionsDict.found(region.getName())) { + region.setSurfaceDictionary(regionsDict.subDict(region.getName())); + } + } + } + } + + private void readSurfaceAsACellZone(Surface surface, Dictionary surfaceDict) { + + surface.setZoneDictionary(surfaceDict); + if (isACellZone(surfaceDict)) { + surfaceDict.add("isCellZone", "true"); + } else { + surfaceDict.add("isCellZone", "false"); + } + if (!surfaceDict.found(FACE_TYPE_KEY)) { + surfaceDict.add(FACE_TYPE_KEY, "internal"); + } + surfaceDict.add(CELL_ZONE_INSIDE, "inside"); + + Dictionary sd = surface.getSurfaceDictionary(); + copyIfFound(sd, surfaceDict, LEVEL_KEY); + copyIfFound(sd, surfaceDict, PROXIMITY_INCREMENT_KEY); + copyIfFound(sd, surfaceDict, MAX_CELLS_ACROSS_GAP_KEY); + } + + private boolean isACellZone(Dictionary surfaceDict) { + return surfaceDict.found(CELL_ZONE_KEY); + } + + private boolean isAFaceZone(Dictionary surfaceDict) { + return surfaceDict.found(FACE_ZONE_KEY); + } + + void readRefinementRegions(Surface surface) { + String name = surface.getName(); + if (refinementRegions.found(name)) { + logger.info("VOLUME: " + name); + Dictionary volumeDict = refinementRegions.subDict(name); + + String mode = volumeDict.lookup("mode"); + if ("inside".equals(mode) || "outside".equals(mode) || "distance".equals(mode)) { + surface.setVolumeDictionary(volumeDict); + } else { + logger.error("Volume dictionary does not contain a valid ('inside', 'outside' or 'distance') mode"); + } + } else { + surface.getVolumeDictionary().add("mode", "none"); + } + } + + void readLayers(Surface surface) { + if (surface.hasRegions()) { + if (surface.isSingleton()) { + if (surface.isAppendRegionName()) { + Region region = surface.getRegions()[0]; + if (layers.found(region.getPatchName())) { + region.setLayerDictionary(layers.subDict(region.getPatchName())); + } + } else { + if (layers.found(surface.getPatchName())) { + surface.setLayerDictionary(layers.subDict(surface.getPatchName())); + } + } + } else { + for (Region region : surface.getRegions()) { + if (layers.found(region.getPatchName())) { + region.setLayerDictionary(layers.subDict(region.getPatchName())); + } + } + } + } else { + if (layers.found(surface.getPatchName())) { + surface.setLayerDictionary(layers.subDict(surface.getPatchName())); + } + } + } + + // private boolean levelNotZeroZero(Dictionary surfaceDictionary) { + // if (surfaceDictionary.found("level")) { + // String[] level = surfaceDictionary.lookupArray("level"); + // return Integer.parseInt(level[0]) != 0 || Integer.parseInt(level[1]) != + // 0; + // } + // return false; + // } +} diff --git a/src/eu/engys/core/project/geometry/GeometrySaver.java b/src/eu/engys/core/project/geometry/GeometrySaver.java new file mode 100644 index 0000000..f612413 --- /dev/null +++ b/src/eu/engys/core/project/geometry/GeometrySaver.java @@ -0,0 +1,345 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry; + +import static eu.engys.core.dictionary.DictionaryUtils.copyIfFound; +import static eu.engys.core.project.system.SnappyHexMeshDict.ADD_LAYERS_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.BAFFLE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.BOUNDARY_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.CASTELLATED_MESH_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.CELL_ZONE_INSIDE; +import static eu.engys.core.project.system.SnappyHexMeshDict.CELL_ZONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.DISTANCE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.EXPANSION_RATIO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_TYPE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_ZONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FCH_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FEATURES_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FINAL_LAYER_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.GEOMETRY_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.GROWN_UP_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.INSIDE; +import static eu.engys.core.project.system.SnappyHexMeshDict.IS_CELL_ZONE; +import static eu.engys.core.project.system.SnappyHexMeshDict.LAYERS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.LEVELS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.LEVEL_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_CELLS_ACROSS_GAP_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_LAYER_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MODE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.NONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SURFACE_LAYERS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.OUTSIDE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.PROXIMITY_INCREMENT_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.REFINEMENTS_REGIONS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.REFINEMENTS_SURFACES_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.REGIONS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.TWO_SIDED_KEY; + +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.ListField; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.geometry.surface.Region; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.util.Util; + +public class GeometrySaver { + + private Logger logger = LoggerFactory.getLogger(GeometrySaver.class); + + private Model model; + private Geometry geometry; + + private Dictionary geometryDict; + private Dictionary castellatedDict; + private Dictionary refinementSurfaces; + private Dictionary refinementRegions; + private Dictionary layers; + + public GeometrySaver(Model model, Geometry geometry) { + this.model = model; + this.geometry = geometry; + } + + public void save() { + SnappyHexMeshDict snappyHexMeshDict = model.getProject().getSystemFolder().getSnappyHexMeshDict(); + + if (snappyHexMeshDict == null) { + return; + } + initDictionaries(snappyHexMeshDict); + + saveFeatureLines(model); + saveSurfaces(model); + saveBlock(); + + // logger.info("Geometry: \n {}", snappyHexMeshDict); + } + + private void initDictionaries(SnappyHexMeshDict snappyHexMeshDict) { + geometryDict = snappyHexMeshDict.subDict(GEOMETRY_KEY); + castellatedDict = snappyHexMeshDict.subDict(CASTELLATED_MESH_CONTROLS_KEY); + refinementSurfaces = castellatedDict.subDict(REFINEMENTS_SURFACES_KEY); + refinementRegions = castellatedDict.subDict(REFINEMENTS_REGIONS_KEY); + layers = snappyHexMeshDict.subDict(ADD_LAYERS_CONTROLS_KEY).subDict(LAYERS_KEY); + + geometryDict.clear(); + refinementSurfaces.clear(); + refinementRegions.clear(); + layers.clear(); + } + + private void saveFeatureLines(Model model) { + ListField lines = new ListField(FEATURES_KEY); + for (FeatureLine line : geometry.getLines()) { + lines.add(line.toDictionary()); + } + castellatedDict.add(lines); + } + + private void saveSurfaces(Model model) { + for (Surface surface : geometry.getSurfaces()) { + if (surface.getType().isStl()) { + saveSTL((Stl) surface); + } + saveToGeometry(surface); + if (isACellZone(surface)) { + saveToRefinementSurfacesAsCellZone(surface); + } else if (hasSurfaceRefinement(surface)) { + saveToRefinementSurfaces(surface); + } + saveToRefinementRegions(surface); + + saveToLayers(surface); + + fixEmptySurfacesToZeroLevel(surface); + } + } + + private void saveSTL(Stl stl) { + AffineTransform transformation = stl.getTransformation(); + if (stl.getTransformMode() == TransfromMode.TO_DICTIONARY) { + if (!transformation.isIdentity()) { + ListField transforms = transformation.toDictionary(); + stl.getGeometryDictionary().add(transforms); + } + } + } + + private void saveToGeometry(Surface surface) { + Dictionary geometryDictionary = surface.getGeometryDictionary(); + if (geometryDictionary != null && geometryDictionary.found(Dictionary.TYPE)) { + geometryDict.add(geometryDictionary); + } + } + + private void saveToRefinementSurfacesAsCellZone(Surface surface) { + Dictionary surfaceDictionary = surface.getSurfaceDictionary(); + if (surfaceDictionary.found(LEVEL_KEY)) { + Dictionary zoneDictionary = surface.getZoneDictionary(); + Dictionary sd = new Dictionary(zoneDictionary); + + copyIfFound(sd, surfaceDictionary, LEVEL_KEY); + copyIfFound(sd, surfaceDictionary, PROXIMITY_INCREMENT_KEY); + copyIfFound(sd, surfaceDictionary, MAX_CELLS_ACROSS_GAP_KEY); + + if (sd.found(FACE_ZONE_KEY)) { + sd.add(CELL_ZONE_INSIDE, INSIDE); + if (sd.found(IS_CELL_ZONE)) { + if (sd.lookup(IS_CELL_ZONE).equals("true")) { + if (sd.found(CELL_ZONE_KEY)) { + sd.add(CELL_ZONE_KEY, sd.lookup(CELL_ZONE_KEY)); + } else { + sd.add(CELL_ZONE_KEY, sd.lookup(FACE_ZONE_KEY)); + } + } else { + sd.remove(CELL_ZONE_KEY); + } + sd.remove(IS_CELL_ZONE); + } + sd.remove(REGIONS_KEY); + } + refinementSurfaces.add(sd); + } + } + + private void saveToRefinementSurfaces(Surface surface) { + Dictionary surfaceDictionary = surface.getSurfaceDictionary(); + if (surface.getType().isStl()) { + Stl stl = (Stl) surface; + Dictionary regions = null; + + if (surfaceDictionary.found(REGIONS_KEY)) { + regions = surfaceDictionary.subDict(REGIONS_KEY); + } else { + regions = new Dictionary(REGIONS_KEY); + surfaceDictionary.add(regions); + } + + for (Region region : stl.getRegions()) { + Dictionary regionDictionary = region.getSurfaceDictionary(); + if (!surfaceRefinementIsZero(region)) { + regions.add(regionDictionary); + } + } + + if (regions.isEmpty()) { + surfaceDictionary.remove(REGIONS_KEY); + } + + if (surfaceDictionary.found(REGIONS_KEY) && !surfaceDictionary.found(LEVEL_KEY)) { + surfaceDictionary.add(LEVEL_KEY, "(0 0)"); + } + } + + if (!surfaceDictionary.isEmpty()) { + refinementSurfaces.add(surfaceDictionary); + } else { + refinementSurfaces.remove(surfaceDictionary.getName()); + } + } + + private void saveToRefinementRegions(Surface surface) { + Dictionary volumeDictionary = surface.getVolumeDictionary(); + if (volumeDictionary.found(LEVELS_KEY)) { + String mode = volumeDictionary.lookup(MODE_KEY); + if (mode != null && (mode.equals(INSIDE) || mode.equals(OUTSIDE_KEY) || mode.equals(DISTANCE_KEY))) { + refinementRegions.add(new Dictionary(volumeDictionary)); + } + } + } + + private void saveToLayers(Surface surface) { + if (surface.hasRegions()) { + if (surface.isSingleton()) { + Region region = surface.getRegions()[0]; + if (hasLayers(region)) { + addToLayers(region.getPatchName(), region); + } else if (hasLayers(surface)) { + addToLayers(region.getPatchName(), surface); + } + } else { + for (Region region : surface.getRegions()) { + if (hasLayers(region)) { + addToLayers(region.getPatchName(), region); + if (isBoundaryOrBaffleZone(surface.getZoneDictionary())) { + addToLayers(region.getPatchName() + "_slave", region); + } + } else if (hasLayers(surface)) { + addToLayers(region.getPatchName(), surface); + if (isBoundaryOrBaffleZone(surface.getZoneDictionary())) { + addToLayers(region.getPatchName() + "_slave", surface); + } + } + } + } + } else { + if (hasLayers(surface)) { + addToLayers(surface.getPatchName(), surface); + if (isBoundaryOrBaffleZone(surface.getZoneDictionary())) { + addToLayers(surface.getPatchName() + "_slave", surface); + } + } + } + } + + private void saveBlock() { + if (geometry.hasBlock()) { + saveToLayers(geometry.getBlock()); + } + } + + private void addToLayers(String patchName, Surface surface) { + if (isGrownUpLayers(surface)) { + Dictionary layerDict = new Dictionary(patchName); + layerDict.add(GROWN_UP_KEY, "true"); + layerDict.add(N_SURFACE_LAYERS_KEY, "0"); + layers.add(layerDict); + } else { + Dictionary layerDict = new Dictionary(surface.getLayerDictionary()); + layerDict.setName(patchName); + layers.add(layerDict); + } + } + + private boolean hasSurfaceRefinement(Surface surface) { + Dictionary volumeDictionary = surface.getVolumeDictionary(); + return volumeDictionary == null || !volumeDictionary.found(MODE_KEY) || volumeDictionary.lookup(MODE_KEY).equals(DISTANCE_KEY) || volumeDictionary.lookup(MODE_KEY).equals(NONE_KEY); + } + + private void fixEmptySurfacesToZeroLevel(Surface surface) { + if (!refinementSurfaces.found(surface.getName()) && !refinementRegions.found(surface.getName())) { + Dictionary surfaceDictionary = surface.getSurfaceDictionary(); + surfaceDictionary.add(LEVEL_KEY, "(0 0)"); + refinementSurfaces.add(surfaceDictionary); + } + } + + private boolean surfaceRefinementIsZero(Surface surface) { + Dictionary surfaceDictionary = surface.getSurfaceDictionary(); + return surfaceDictionary.isEmpty() || (surfaceDictionary.found(LEVEL_KEY) && Arrays.equals(surfaceDictionary.lookupIntArray(LEVEL_KEY), new int[2])); + } + + private boolean isACellZone(Surface surface) { + Dictionary zoneDictionary = surface.getZoneDictionary(); + return zoneDictionary != null && zoneDictionary.found(FACE_TYPE_KEY) && !zoneDictionary.lookup(FACE_TYPE_KEY).equals(NONE_KEY); + } + + private boolean isGrownUpLayers(Surface surface) { + Dictionary layerDictionary = surface.getLayerDictionary(); + return layerDictionary.found(GROWN_UP_KEY) && layerDictionary.lookup(GROWN_UP_KEY).equals("true"); + } + + private boolean hasNSurfaceLayers(Surface surface) { + Dictionary layerDictionary = surface.getLayerDictionary(); + return layerDictionary.found(N_SURFACE_LAYERS_KEY) && !layerDictionary.lookup(N_SURFACE_LAYERS_KEY).equals("0"); + } + + private boolean hasLayers(Surface surface) { + Dictionary layerDictionary = surface.getLayerDictionary(); + int total = checkValue(layerDictionary, N_SURFACE_LAYERS_KEY) + checkValue(layerDictionary, MAX_LAYER_THICKNESS_KEY) + checkValue(layerDictionary, FINAL_LAYER_THICKNESS_KEY) + checkValue(layerDictionary, EXPANSION_RATIO_KEY) + checkValue(layerDictionary, FCH_KEY); + + return isGrownUpLayers(surface) || hasNSurfaceLayers(surface) || (total > 0 && total == 3); + } + + private int checkValue(Dictionary d, String key) { + return Util.boolToInt(d.found(key) && d.lookupDouble(key) != 0); + } + + private boolean isTwoSided(Dictionary surfaceDictionary) { + return surfaceDictionary.found(TWO_SIDED_KEY) && Boolean.parseBoolean(surfaceDictionary.lookup(TWO_SIDED_KEY)); + } + + private boolean isBoundaryOrBaffleZone(Dictionary zoneDictionary) { + return zoneDictionary.found(FACE_TYPE_KEY) && (zoneDictionary.lookup(FACE_TYPE_KEY).equals(BAFFLE_KEY) || zoneDictionary.lookup(FACE_TYPE_KEY).equals(BOUNDARY_KEY)); + } +} diff --git a/src/eu/engys/core/project/geometry/GeometryWriter.java b/src/eu/engys/core/project/geometry/GeometryWriter.java new file mode 100644 index 0000000..4e486fa --- /dev/null +++ b/src/eu/engys/core/project/geometry/GeometryWriter.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry; + +import eu.engys.core.project.Model; +import eu.engys.util.progress.ProgressMonitor; + +public class GeometryWriter { + + private Model model; + private Geometry geometry; + private ProgressMonitor monitor; + + public GeometryWriter(Model model, Geometry geometry, ProgressMonitor monitor) { + this.model = model; + this.geometry = geometry; + this.monitor = monitor; + } + + public void write() { + writeFeatureLines(); + writeSurfaces(); + } + + private void writeFeatureLines() { + for (FeatureLine line : geometry.getLines()) { + geometry.getFactory().writeSurface(line, model, monitor); + } + } + + private void writeSurfaces() { + for (Surface surface : geometry.getSurfaces()) { + + if (surface.getType().isStl()) { + geometry.getFactory().writeSurface(surface, model, monitor); + } + } + } + +} diff --git a/src/eu/engys/core/project/geometry/Surface.java b/src/eu/engys/core/project/geometry/Surface.java new file mode 100644 index 0000000..d5e1b60 --- /dev/null +++ b/src/eu/engys/core/project/geometry/Surface.java @@ -0,0 +1,374 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry; + +import static eu.engys.core.project.system.SnappyHexMeshDict.EXPANSION_RATIO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_TYPE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FINAL_LAYER_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.LEVEL_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.NONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SURFACE_LAYERS_KEY; +import vtk.vtkPolyData; +import vtk.vtkTransform; +import vtk.vtkTransformFilter; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.geometry.surface.Region; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public abstract class Surface implements VisibleItem { + + public static final String MAX_KEY = "max"; + public static final String MIN_KEY = "min"; + public static final String POINT1_KEY = "point1"; + public static final String POINT2_KEY = "point2"; + public static final String RADIUS_KEY = "radius"; + public static final String CENTRE_KEY = "centre"; + public static final String OUTER_RADIUS_KEY = "outerRadius"; + public static final String INNER_RADIUS_KEY = "innerRadius"; + public static final String PLANE_TYPE_KEY = "planeType"; + public static final String NORMAL_VECTOR_KEY = "normalVector"; + public static final String BASE_POINT_KEY = "basePoint"; + public static final String POINT_AND_NORMAL_KEY = "pointAndNormal"; + public static final String POINT_AND_NORMAL_DICT_KEY = "pointAndNormalDict"; + + public static final String TRI_SURFACE_MESH_KEY = "triSurfaceMesh"; + public static final String SEARCHABLE_RING_KEY = "searchableRing"; + public static final String SEARCHABLE_PLANE_KEY = "searchablePlane"; + public static final String SEARCHABLE_SPHERE_KEY = "searchableSphere"; + public static final String SEARCHABLE_CYLINDER_KEY = "searchableCylinder"; + public static final String SEARCHABLE_BOX_KEY = "searchableBox"; + + private Dictionary geometryDictionary; + private Dictionary surfaceDictionary; + private Dictionary volumeDictionary; + private Dictionary layerDictionary; + private Dictionary zoneDictionary; + + protected String name; + + private boolean visible = true; + private AffineTransform transformation; + private TransfromMode transformMode; + + public static final Dictionary surfaceDefault = new Dictionary("") { + { + add(LEVEL_KEY, "(0 0)"); + } + }; + public static final Dictionary volumeDefault = new Dictionary("") { + { + add("mode", "none"); + } + }; + public static final Dictionary zonesDefault = new Dictionary("") { + { + add(FACE_TYPE_KEY, NONE_KEY); + } + }; + public static final Dictionary layerDefault = new Dictionary("") { + { + add(N_SURFACE_LAYERS_KEY, "0"); + add(EXPANSION_RATIO_KEY, "1.25"); + add(FINAL_LAYER_THICKNESS_KEY, "0.4"); + } + }; + + public static final Dictionary stl = new Dictionary("name.stl") { + { + add(TYPE, TRI_SURFACE_MESH_KEY); + add("name", "name"); + } + }; + public static final Dictionary box = new Dictionary("box") { + { + add(TYPE, SEARCHABLE_BOX_KEY); + add(MIN_KEY, "(0 0 0)"); + add(MAX_KEY, "(2 2 1)"); + } + }; + public static final Dictionary cylinder = new Dictionary("cylinder") { + { + add(TYPE, SEARCHABLE_CYLINDER_KEY); + add(POINT1_KEY, "(0 0 0)"); + add(POINT2_KEY, "(1 0 0)"); + add(RADIUS_KEY, "1.0"); + } + }; + public static final Dictionary sphere = new Dictionary("sphere") { + { + add(TYPE, SEARCHABLE_SPHERE_KEY); + add(CENTRE_KEY, "(0 0 0)"); + add(RADIUS_KEY, "1.0"); + } + }; + public static final Dictionary plane = new Dictionary("plane") { + { + add(TYPE, SEARCHABLE_PLANE_KEY); + add(PLANE_TYPE_KEY, POINT_AND_NORMAL_KEY); + Dictionary dict = new Dictionary(POINT_AND_NORMAL_DICT_KEY); +// dict.add(BASE_POINT_KEY, "(0 0 0)"); + dict.add(NORMAL_VECTOR_KEY, "(0 0 1)"); + add(dict); + } + }; + public static final Dictionary planeWithCenter = new Dictionary("plane") { + { + add(TYPE, SEARCHABLE_PLANE_KEY); + add(PLANE_TYPE_KEY, POINT_AND_NORMAL_KEY); + Dictionary dict = new Dictionary(POINT_AND_NORMAL_DICT_KEY); + dict.add(BASE_POINT_KEY, "(0 0 0)"); + dict.add(NORMAL_VECTOR_KEY, "(0 0 1)"); + add(dict); + } + }; + public static final Dictionary ring = new Dictionary("ring") { + { + add(TYPE, SEARCHABLE_RING_KEY); + add(POINT1_KEY, "(0 0 0)"); + add(POINT2_KEY, "(0.05 0 0)"); + add(INNER_RADIUS_KEY, "0.2"); + add(OUTER_RADIUS_KEY, "0.5"); + } + }; + + public Surface(String name) { + this.name = name; + + this.surfaceDictionary = new Dictionary(name, surfaceDefault); + this.volumeDictionary = new Dictionary(name, volumeDefault); + this.layerDictionary = new Dictionary(name, layerDefault); + this.zoneDictionary = new Dictionary(name, zonesDefault); + + this.transformation = new AffineTransform(); +// this.transformMode = TransfromMode.TO_DICTIONARY; + this.transformMode = TransfromMode.TO_FILE; + } + + public boolean isAppendRegionName() { + return geometryDictionary.found("appendRegionName") && geometryDictionary.lookup("appendRegionName").equals("true"); + } + + public String getName() { + return name; + } + + public abstract String getPatchName(); + + public String getZoneName() { + return zoneDictionary.lookup("cellZone"); + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public void setVisible(boolean visible) { + this.visible = visible; + } + + public abstract Type getType(); + + public abstract boolean isSingleton(); + + public abstract boolean hasRegions(); + + public abstract Region[] getRegions(); + + public abstract boolean hasSurfaceRefinement(); + + public abstract boolean hasVolumeRefinement(); + + public abstract boolean hasLayers(); + + public abstract boolean hasZones(); + + public abstract Surface cloneSurface(); + + protected abstract vtkPolyData getDataSet(); + + public vtkPolyData getTransformedDataSet() { + vtkPolyData dataSet = getDataSet(); + if (dataSet != null) { + if (getTransformation() != null) { + vtkTransformFilter tFilter = new vtkTransformFilter(); + tFilter.SetTransform(getTransformation().toVTK(new vtkTransform())); + tFilter.SetInputData(dataSet); + tFilter.Update(); + + return (vtkPolyData) tFilter.GetOutput(); + } else { + return dataSet; + } + } else { + return null; + } + } + + public void setGeometryDictionary(Dictionary geometryDictionary) { + this.geometryDictionary = geometryDictionary; + } + + public Dictionary getGeometryDictionary() { + return geometryDictionary; + } + + public void setSurfaceDictionary(Dictionary surfaceDictionary) { + this.surfaceDictionary = surfaceDictionary; + } + + public Dictionary getSurfaceDictionary() { + return surfaceDictionary; + } + + public void setVolumeDictionary(Dictionary volumeDictionary) { + this.volumeDictionary = volumeDictionary; + } + + public Dictionary getVolumeDictionary() { + return volumeDictionary; + } + + public void setLayerDictionary(Dictionary layerDictionary) { + this.layerDictionary = layerDictionary; + } + + public Dictionary getLayerDictionary() { + return layerDictionary; + } + + public void setZoneDictionary(Dictionary zoneDictionary) { + this.zoneDictionary = zoneDictionary; + } + + public Dictionary getZoneDictionary() { + return zoneDictionary; + } + + public Dictionary toDictionary() { + Dictionary d = new Dictionary(getName()); + d.add(new Dictionary("surface", surfaceDictionary)); + d.add(new Dictionary("volume", volumeDictionary)); + d.add(new Dictionary("layer", layerDictionary)); + d.add(new Dictionary("zone", zoneDictionary)); + + return d; + } + + public void fromDictionary(Dictionary d) { + buildSurfaceDictionary(d.subDict("surface")); + buildVolumeDictionary(d.subDict("volume")); + buildLayerDictionary(d.subDict("layer")); + buildZoneDictionary(d.subDict("zone")); + } + + @Override + public String toString() { + return String.format("[ name: %s, patch_name: %s, type: %s, singleton: %s, visible: %s] ", getName(), getPatchName(), getType(), isSingleton(), isVisible()); + } + + public void rename(String newName) { + String oldName = getName(); + if (oldName.equals(newName)) + return; + + this.name = newName; + getSurfaceDictionary().setName(getName()); + getVolumeDictionary().setName(getName()); + getLayerDictionary().setName(getName()); + getZoneDictionary().setName(getName()); + } + + public void buildGeometryDictionary(Dictionary dictionary) { + Dictionary geometryDict = new Dictionary(dictionary); + geometryDict.setName(getName()); + getSurfaceDictionary().setName(getName()); + getVolumeDictionary().setName(getName()); + getLayerDictionary().setName(getName()); + getZoneDictionary().setName(getName()); + setGeometryDictionary(geometryDict); + } + + public void buildSurfaceDictionary(Dictionary dictionary) { + Dictionary surfaceDict = new Dictionary(dictionary); + surfaceDict.setName(getName()); + setSurfaceDictionary(surfaceDict); + } + + public void buildVolumeDictionary(Dictionary dictionary) { + Dictionary volumeDict = new Dictionary(dictionary); + volumeDict.setName(getName()); + setVolumeDictionary(volumeDict); + } + + public void buildLayerDictionary(Dictionary dictionary) { + Dictionary layerDict = new Dictionary(dictionary); + layerDict.setName(getName()); + setLayerDictionary(layerDict); + } + + public void buildZoneDictionary(Dictionary dictionary) { + Dictionary zoneDict = new Dictionary(dictionary); + zoneDict.setName(getName()); + setZoneDictionary(zoneDict); + } + + public boolean willBePatch() { + return (getType().isSolid() && !((Solid) this).getParent().isSingleton()) || (getType().isStl() && isSingleton()); + } + + protected void cloneSurface(Surface surface) { + if (this.geometryDictionary != null) { + surface.geometryDictionary = new Dictionary(this.geometryDictionary); + } + surface.surfaceDictionary = new Dictionary(this.surfaceDictionary); + surface.volumeDictionary = new Dictionary(this.volumeDictionary); + surface.layerDictionary = new Dictionary(this.layerDictionary); + surface.zoneDictionary = new Dictionary(this.zoneDictionary); + + surface.visible = this.visible; + surface.transformation = new AffineTransform(this.transformation); + //System.out.println("Surface.cloneSurface() HASH: "+surface.hashCode()+surfaceDictionary+surface.surfaceDictionary); + } + + public AffineTransform getTransformation() { + return transformation; + } + public void setTransformation(AffineTransform transformation) { + this.transformation = transformation; + } + + public TransfromMode getTransformMode() { + return transformMode; + } + public void setTransformMode(TransfromMode transformMode) { + this.transformMode = transformMode; + } +} diff --git a/src/eu/engys/core/project/geometry/TransfromMode.java b/src/eu/engys/core/project/geometry/TransfromMode.java new file mode 100644 index 0000000..8f3db8b --- /dev/null +++ b/src/eu/engys/core/project/geometry/TransfromMode.java @@ -0,0 +1,31 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry; + +public enum TransfromMode { + TO_DICTIONARY, TO_FILE; + +} diff --git a/src/eu/engys/core/project/geometry/Type.java b/src/eu/engys/core/project/geometry/Type.java new file mode 100644 index 0000000..04be117 --- /dev/null +++ b/src/eu/engys/core/project/geometry/Type.java @@ -0,0 +1,77 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry; + +public enum Type { + STL, BOX, CYLINDER, SPHERE, REGION, SOLID, PLANE, MULTI, RING, LINE; + + public boolean isStl() { + return equals(STL); + } + + public boolean isBox() { + return equals(BOX); + } + + public boolean isCylinder() { + return equals(CYLINDER); + } + + public boolean isSphere() { + return equals(SPHERE); + } + + public boolean isRing() { + return equals(RING); + } + + public boolean isRegion() { + return equals(REGION); + } + + public boolean isMulti() { + return equals(MULTI); + } + + public boolean isSolid() { + return equals(SOLID); + } + + public boolean isPlane() { + return equals(PLANE); + } + + public boolean isLine() { + return equals(LINE); + } + + public boolean isBaseShape() { + return isBox() ||isPlane() ||isSphere() || isRing(); + } + + +} diff --git a/src/eu/engys/core/project/geometry/factory/DefaultGeometryFactory.java b/src/eu/engys/core/project/geometry/factory/DefaultGeometryFactory.java new file mode 100644 index 0000000..dcb89bb --- /dev/null +++ b/src/eu/engys/core/project/geometry/factory/DefaultGeometryFactory.java @@ -0,0 +1,311 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.factory; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.project.geometry.Surface.SEARCHABLE_BOX_KEY; +import static eu.engys.core.project.geometry.Surface.SEARCHABLE_CYLINDER_KEY; +import static eu.engys.core.project.geometry.Surface.SEARCHABLE_PLANE_KEY; +import static eu.engys.core.project.geometry.Surface.SEARCHABLE_RING_KEY; +import static eu.engys.core.project.geometry.Surface.SEARCHABLE_SPHERE_KEY; +import static eu.engys.core.project.geometry.Surface.TRI_SURFACE_MESH_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FILE_KEY; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.TransfromMode; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.geometry.stl.STLReader; +import eu.engys.core.project.geometry.stl.STLWriter; +import eu.engys.core.project.geometry.surface.Box; +import eu.engys.core.project.geometry.surface.Cylinder; +import eu.engys.core.project.geometry.surface.NullSurface; +import eu.engys.core.project.geometry.surface.Plane; +import eu.engys.core.project.geometry.surface.Ring; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.core.project.geometry.surface.Sphere; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.util.ColorUtil; +import eu.engys.util.progress.ProgressMonitor; + +public class DefaultGeometryFactory implements GeometryFactory { + + private static final Logger logger = LoggerFactory.getLogger(DefaultGeometryFactory.class); + private static final Map STLCache = new HashMap<>(); + + @Override + public void deleteSurface(Model model, Surface surface) { + if(surface instanceof Stl) { + File file = model.getProject().getConstantFolder().getTriSurface().getFileManager().getFile(surface.getName()+".stl"); + if (file.exists()) { + FileUtils.deleteQuietly(file); + } + file = model.getProject().getConstantFolder().getTriSurface().getFileManager().getFile(surface.getName()+".STL"); + if (file.exists()) { + FileUtils.deleteQuietly(file); + } + } + } + + @Override + public void writeSurface(Surface surface, Model model, ProgressMonitor monitor) { + if (surface.getType().isStl()) { + writeSTL((Stl) surface, model, monitor); + } else if (surface.getType().isLine()) { + writeFeatureLine((FeatureLine) surface, model, monitor); + } + } + + private void writeFeatureLine(FeatureLine line, Model model, ProgressMonitor monitor) { + String fileName = line.getName() + ".eMesh"; + File file = model.getProject().getConstantFolder().getTriSurface().getFileManager().getFile(fileName); + if (!file.exists()|| line.isModified()) { + new EMESHWriter(file, line).run(); + } + } + + private void writeSTL(Stl stl, Model model, ProgressMonitor monitor) { + String fileName = stl.getFileName(); + File file = model.getProject().getConstantFolder().getTriSurface().getFileManager().getFile(fileName); + AffineTransform transformation = stl.getTransformation(); + + if (stl.getTransformMode() == TransfromMode.TO_DICTIONARY) { + if (!file.exists() || stl.isModified()) { + new STLWriter(file, stl, monitor).run(); + } + } else { + if (!file.exists() || !transformation.isIdentity() || stl.isModified()) { + new STLWriter(file, stl, monitor).run(); + } + } + } + + + + @Override + public Surface loadSurface(Dictionary g, Model model, ProgressMonitor monitor) { + Surface surface; + if (isSTL(g)) { + surface = loadSTL(g, model, monitor); + } else if (isBox(g)) { + surface = loadBox(g); + } else if (isCylinder(g)) { + surface = loadCylinder(g); + } else if (isSphere(g)) { + surface = loadSphere(g); + } else if (isPlane(g)) { + surface = loadPlane(g); + } else if (isRing(g)) { + surface = loadRing(g); + } else if (isLine(g)) { + surface = loadLine(g, model, monitor); + } else { + if (g.isField(Dictionary.TYPE)) + logger.error("Unknown geometry type: {}.", g.lookup(Dictionary.TYPE)); + else + logger.error("Bad geometry dictionary format: {}.", g); + surface = new NullSurface(); + } + if (monitor != null) { + monitor.setCurrent(null, monitor.getCurrent() + 1); + } + return surface; + } + + @Override + public S newSurface(Class type, String name) { + try { + return type.getDeclaredConstructor(String.class).newInstance(name); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /* + * LOAD + */ + + @SuppressWarnings("deprecation") + protected Surface loadBox(Dictionary g) { + Surface box = new Box(g.getName()); + box.setGeometryDictionary(g); + return box; + } + + @SuppressWarnings("deprecation") + protected Cylinder loadCylinder(Dictionary g) { + Cylinder cyl = new Cylinder(g.getName()); + cyl.setGeometryDictionary(g); + return cyl; + } + + @SuppressWarnings("deprecation") + protected Plane loadPlane(Dictionary g) { + Plane plane = new Plane(g.getName()); + plane.setGeometryDictionary(g); + return plane; + } + + @SuppressWarnings("deprecation") + protected Ring loadRing(Dictionary g) { + Ring ring = new Ring(g.getName()); + ring.setGeometryDictionary(g); + return ring; + } + + @SuppressWarnings("deprecation") + protected Sphere loadSphere(Dictionary g) { + Sphere sphere = new Sphere(g.getName()); + sphere.setGeometryDictionary(g); + return sphere; + } + + @SuppressWarnings("deprecation") + protected Stl loadSTL(Dictionary g, Model model, ProgressMonitor monitor) { + Stl stl = new Stl(g.lookup("name")); + stl.setGeometryDictionary(g); + + loadStl(stl, model, monitor); + + stl.setTransformation(AffineTransform.fromGeometryDictionary(g)); + return stl; + } + + private void loadStl(Stl stl, Model model, ProgressMonitor monitor) { + String fileName = stl.getGeometryDictionary().getName(); + File file = model.getProject().getConstantFolder().getTriSurface().getFileManager().getFile(fileName); + stl.setFileName(file); + + if (STLCache.containsKey(fileName)) { + Stl cached = STLCache.get(fileName); + Solid[] cachedSolids = cached.getSolids(); + List solids = new ArrayList<>(); + for (Solid cachedSolid : cachedSolids) { + solids.add((Solid)cachedSolid.cloneSurface()); + } + stl.setSolids(solids); + } else { + STLReader reader = new STLReader(file, monitor); + reader.run(); + List solids = reader.getSolids(); + stl.setSolids(solids); + } + + if (!STLCache.containsKey(fileName)) { + STLCache.put(fileName, stl); + } + } + + @Override + public Stl readSTL(File file, ProgressMonitor monitor) { + String fileName = file.getName(); + String name = FilenameUtils.removeExtension(fileName); + Dictionary g = new Dictionary(fileName, Surface.stl); + g.setName(fileName); + g.add("name", name); + + Stl stl = new Stl(name); + stl.setGeometryDictionary(g); + stl.setFileName(file); + + STLReader reader = new STLReader(file, monitor); + reader.run(); + List solids = reader.getSolids(); + stl.setSolids(solids); + + return stl; + } + + private FeatureLine loadLine(Dictionary g, Model model, ProgressMonitor monitor) { + String fileName = g.lookup("file").replace("\"", ""); + File file = model.getProject().getConstantFolder().getTriSurface().getFileManager().getFile(fileName); + FeatureLine line = readLine(file); + line.setColor(ColorUtil.getColor(model.getGeometry().getLines().size())); + return line; + } + + @Override + public FeatureLine readLine(File file) { + FeatureLine featureLine = new FeatureLine(FilenameUtils.removeExtension(file.getName())); + featureLine.setModified(false); + vtkPolyData dataSet = new EMESHReader(file).run(); + featureLine.setDataSet(dataSet); + + return featureLine; + } + + /* + * IS + */ + + public static boolean isBox(Dictionary g) { + return g.isField(TYPE) && SEARCHABLE_BOX_KEY.equals(g.lookup(TYPE)); + } + + public static boolean isCylinder(Dictionary g) { + return g.isField(TYPE) && SEARCHABLE_CYLINDER_KEY.equals(g.lookup(TYPE)); + } + + public static boolean isSphere(Dictionary g) { + return g.isField(TYPE) && SEARCHABLE_SPHERE_KEY.equals(g.lookup(TYPE)); + } + + public static boolean isPlane(Dictionary g) { + return g.isField(TYPE) && SEARCHABLE_PLANE_KEY.equals(g.lookup(TYPE)); + } + + public static boolean isRing(Dictionary g) { + return g.isField(TYPE) && SEARCHABLE_RING_KEY.equals(g.lookup(TYPE)); + } + + public static boolean isLine(Dictionary g) { + return g.isField(FILE_KEY) && g.lookup(FILE_KEY).contains(".eMesh"); + } + + public static boolean isSTL(Dictionary g) { + return g.isField(TYPE) && TRI_SURFACE_MESH_KEY.equals(g.lookup(TYPE)); + } + + public static void clearSTLCache() { + STLCache.clear(); + } +} diff --git a/src/eu/engys/core/project/geometry/factory/EMESHReader.java b/src/eu/engys/core/project/geometry/factory/EMESHReader.java new file mode 100644 index 0000000..4466100 --- /dev/null +++ b/src/eu/engys/core/project/geometry/factory/EMESHReader.java @@ -0,0 +1,94 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry.factory; + +import java.io.File; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkCellArray; +import vtk.vtkLine; +import vtk.vtkPoints; +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.parser.ListField2; +import eu.engys.util.VTKSettings; + +public class EMESHReader { + + private static final Logger logger = LoggerFactory.getLogger(EMESHReader.class); + private File file; + + public EMESHReader(File file) { + this.file = file; + } + + public vtkPolyData run() { + if (file.exists()) { + if (VTKSettings.librariesAreLoaded()) { + logger.info("Read eMesh " + file.getName() + " [ASCII]"); + Dictionary linesDict = DictionaryUtils.readDictionary2(file); + List listFields = linesDict.getListFields2(); + vtkPolyData dataSet = new vtkPolyData(); + if (listFields.size() == 2) { + ListField2 pointsList = listFields.get(0); + ListField2 linesList = listFields.get(1); + + List pointsArray = pointsList.getElementsAsVectorList(); + List linesArray = linesList.getElementsAsVectorList(); + + vtkPoints points = new vtkPoints(); + for (double[] point : pointsArray) { + points.InsertNextPoint(point); + } + + vtkCellArray lines = new vtkCellArray(); + for (double[] line : linesArray) { + vtkLine cell = new vtkLine(); + cell.GetPointIds().SetId(0, (int) line[0]); + cell.GetPointIds().SetId(1, (int) line[1]); + + lines.InsertNextCell(cell); + } + + dataSet.SetPoints(points); + dataSet.SetLines(lines); + } + + return dataSet; + } else { + logger.warn("Read eMesh: no VTK"); + return null; + } + } else { + logger.warn("Read eMesh " + file.getName() + " does not exist"); + return null; + } + } +} diff --git a/src/eu/engys/core/project/geometry/factory/EMESHWriter.java b/src/eu/engys/core/project/geometry/factory/EMESHWriter.java new file mode 100644 index 0000000..938a99a --- /dev/null +++ b/src/eu/engys/core/project/geometry/factory/EMESHWriter.java @@ -0,0 +1,88 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry.factory; + +import java.io.File; + +import vtk.vtkIdList; +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.dictionary.parser.ListField2; +import eu.engys.core.project.geometry.FeatureLine; + +public class EMESHWriter { + + private File file; + private FeatureLine line; + + public EMESHWriter(File file, FeatureLine line) { + this.file = file; + this.line = line; + } + + public void run() { + vtkPolyData dataSet = line.getDataSet(); + if (dataSet != null) { + + Dictionary d = new Dictionary(""); + d.setFoamFile(FoamFile.getDictionaryFoamFile("classe", "parent", "name")); + + ListField2 points = new ListField2(String.valueOf(dataSet.GetNumberOfPoints())); + ListField2 lines = new ListField2(String.valueOf(dataSet.GetNumberOfLines())); + + for (int i = 0; i < dataSet.GetNumberOfPoints(); i++) { + double[] point = dataSet.GetPoint(i); + ListField2 pointField = new ListField2(""); + pointField.add(new FieldElement("", String.valueOf(point[0]))); + pointField.add(new FieldElement("", String.valueOf(point[1]))); + pointField.add(new FieldElement("", String.valueOf(point[2]))); + + points.add(pointField); + } + + dataSet.GetLines().InitTraversal(); + for (int i = 0; i < dataSet.GetNumberOfLines(); i++) { + ListField2 lineField = new ListField2(""); + vtkIdList idList = new vtkIdList(); + dataSet.GetLines().GetNextCell(idList); + for (int j = 0; j < idList.GetNumberOfIds(); j++) { + int id = idList.GetId(j); + lineField.add(new FieldElement("", String.valueOf(id))); + + } + lines.add(lineField); + } + + d.add(points); + d.add(lines); + + DictionaryUtils.writeDictionaryFile(file, d); + } + } +} diff --git a/src/eu/engys/core/project/geometry/factory/EngysGeometryFactory.java b/src/eu/engys/core/project/geometry/factory/EngysGeometryFactory.java new file mode 100644 index 0000000..856b5f9 --- /dev/null +++ b/src/eu/engys/core/project/geometry/factory/EngysGeometryFactory.java @@ -0,0 +1,104 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry.factory; + +import java.io.File; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.Cylinder; +import eu.engys.core.project.geometry.surface.Plane; +import eu.engys.core.project.geometry.surface.Ring; +import eu.engys.core.project.geometry.surface.Sphere; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.util.progress.ProgressMonitor; + +public class EngysGeometryFactory extends DefaultGeometryFactory { + + @Override + public S newSurface(Class type, String name) { + S surface = super.newSurface(type, name); + setAppendRegionName(surface, true); + return surface; + } + + public void setAppendRegionName(Surface surface, boolean b) { + if (surface.getGeometryDictionary() != null) { + surface.getGeometryDictionary().add("appendRegionName", Boolean.toString(b)); + } + } + + @Override + protected Surface loadBox(Dictionary g) { + Surface box = super.loadBox(g); + setAppendRegionName(box, true); + return box; + } + + @Override + protected Cylinder loadCylinder(Dictionary g) { + Cylinder cylinder = super.loadCylinder(g); + setAppendRegionName(cylinder, true); + return cylinder; + } + + @Override + protected Plane loadPlane(Dictionary g) { + Plane plane = super.loadPlane(g); + setAppendRegionName(plane, true); + return plane; + } + + @Override + protected Ring loadRing(Dictionary g) { + Ring ring = super.loadRing(g); + setAppendRegionName(ring, true); + return ring; + } + + @Override + protected Sphere loadSphere(Dictionary g) { + Sphere sphere = super.loadSphere(g); + setAppendRegionName(sphere, true); + return sphere; + } + + @Override + protected Stl loadSTL(Dictionary g, Model model, ProgressMonitor monitor) { + Stl stl = super.loadSTL(g, model, monitor); + setAppendRegionName(stl, !stl.isSingleton()); + return stl; + } + + @Override + public Stl readSTL(File file, ProgressMonitor monitor) { + Stl stl = super.readSTL(file, monitor); + setAppendRegionName(stl, !stl.isSingleton()); + return stl; + } + +} diff --git a/src/eu/engys/core/project/geometry/factory/GeometryFactory.java b/src/eu/engys/core/project/geometry/factory/GeometryFactory.java new file mode 100644 index 0000000..1122245 --- /dev/null +++ b/src/eu/engys/core/project/geometry/factory/GeometryFactory.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry.factory; + +import java.io.File; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.util.progress.ProgressMonitor; + +public interface GeometryFactory { + + Surface loadSurface(Dictionary g, Model model, ProgressMonitor monitor); + + void writeSurface(Surface surface, Model model, ProgressMonitor monitor); + + S newSurface(Class type, String name); + + Stl readSTL(File file, ProgressMonitor monitor); + + FeatureLine readLine(File file); + + void deleteSurface(Model model, Surface surface); + +} diff --git a/src/eu/engys/core/project/geometry/stl/AffineTransform.java b/src/eu/engys/core/project/geometry/stl/AffineTransform.java new file mode 100644 index 0000000..8f5a797 --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/AffineTransform.java @@ -0,0 +1,356 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.stl; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +import javax.vecmath.Matrix3d; +import javax.vecmath.Vector3d; + +import vtk.vtkTransform; +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.ListField; + + +public class AffineTransform { + + public static final String YAW_PITCH_ROLL_KEY = "yawPitchRoll"; + public static final String ROLL_PITCH_YAW_KEY = "rollPitchYaw"; + public static final String TRANSFORMS_KEY = "transforms"; + public static final String TRANSLATE_VEC_KEY = "translateVec"; + public static final String TRANSLATE_KEY = "translate"; + public static final String N1N2_KEY = "n1n2"; + public static final String ROTATE_KEY = "rotate"; + public static final String ABOUT_POINT_KEY = "aboutPoint"; + public static final String SCALE_VEC_KEY = "scaleVec"; + public static final String SCALE_KEY = "scale"; + public static final String TYPE_KEY = "type"; + + private double originX = 0; + private double originY = 0; + private double originZ = 0; + + private double scaleX = 1; + private double scaleY = 1; + private double scaleZ = 1; + + private double rotX = 0; + private double rotY = 0; + private double rotZ = 0; + + private double posX = 0; + private double posY = 0; + private double posZ = 0; + + public AffineTransform() {} + + public AffineTransform(AffineTransform t) { + setOrigin(t.getOrigin()); + setScale(t.getScale()); + setTranslate(t.getTranslation()); + setRotation(t.getRotation()); + } + + public void setOrigin(double[] origin) { + originX = origin[0]; + originY = origin[1]; + originZ = origin[2]; + } + + public void setScale(double[] scale) { + scaleX = scale[0]; + scaleY = scale[1]; + scaleZ = scale[2]; + } + + public void setTranslate(double[] translate) { + posX = translate[0]; + posY = translate[1]; + posZ = translate[2]; + } + + public void setRotation(double[] rotation) { + rotX = rotation[0]; + rotY = rotation[1]; + rotZ = rotation[2]; + } + + @Override + public String toString() { + return String.format("Scale: %f %f %f, Rot: %f %f %f, Pos: %f %f %f", scaleX, scaleY, scaleZ, rotX, rotY, rotZ, posX, posY, posZ); + } + + public boolean isIdentity() { + return scaleX==1 && scaleY==1 && scaleZ==1 && rotX==0 && rotY==0 && rotZ==0 && posX==0 && posY==0 && posZ==0; + } + + public double[] getTranslation() { + return new double[] {posX, posY, posZ}; + } + public double[] getScale() { + return new double[] {scaleX, scaleY, scaleZ}; + } + public double[] getRotation() { + return new double[] {rotX, rotY, rotZ}; + } + public double getRotationX() { + return rotX; + } + public double getRotationY() { + return rotY; + } + public double getRotationZ() { + return rotZ; + } + public double[] getOrigin() { + return new double[] {originX, originY, originZ}; + } + + public static AffineTransform getTranslation(double dx, double dy, double dz) { + AffineTransform t = new AffineTransform(); + t.posX = dx; + t.posY = dy; + t.posZ = dz; + + return t; + } + + public static AffineTransform getScale(double dx, double dy, double dz) { + AffineTransform t = new AffineTransform(); + t.scaleX = dx; + t.scaleY = dy; + t.scaleZ = dz; + + return t; + } + + public static AffineTransform getRotateX(double dx) { + AffineTransform t = new AffineTransform(); + t.rotX = dx; + return t; + } + public static AffineTransform getRotateY(double dx) { + AffineTransform t = new AffineTransform(); + t.rotY = dx; + return t; + } + public static AffineTransform getRotateZ(double dx) { + AffineTransform t = new AffineTransform(); + t.rotZ = dx; + return t; + } + + public static AffineTransform fromVTK(vtkTransform t) { + AffineTransform transform = new AffineTransform(); + transform.setOrigin(new double[]{0, 0, 0}); + transform.setRotation(t.GetOrientation()); + transform.setScale(t.GetScale()); + transform.setTranslate(t.GetPosition()); + + return transform; + } + + public vtkTransform toVTK(vtkTransform current) { + vtkTransform transform = new vtkTransform(); + transform.PostMultiply(); + transform.SetInput(current); + transform.Scale(scaleX, scaleY, scaleZ); + transform.Translate(-originX, -originY, -originZ); + transform.RotateY(rotY); + transform.RotateX(rotX); + transform.RotateZ(rotZ); + transform.Translate(originX, originY, originZ); + transform.Translate(posX, posY, posZ); + + return transform; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AffineTransform) { + AffineTransform t = (AffineTransform) obj; + return posX == t.posX && posY == t.posY && posZ == t.posZ && scaleX == t.scaleX && scaleY == t.scaleY && scaleZ == t.scaleZ && rotX == t.rotX && rotY == t.rotY && rotZ == t.rotZ; + } + return super.equals(obj); + } + + public static AffineTransform fromGeometryDictionary(Dictionary g) { + AffineTransform t = new AffineTransform(); + if (g.isList(TRANSFORMS_KEY)) { + ListField transforms = g.getList(TRANSFORMS_KEY); + for (DefaultElement el : transforms.getListElements()) { + if (el instanceof Dictionary) { + Dictionary d = (Dictionary) el; + if (d.found(TYPE_KEY)) { + String type = d.lookup(TYPE_KEY); + switch (type) { + case TRANSLATE_KEY: + double[] translate = d.lookupDoubleArray(TRANSLATE_VEC_KEY); + t.setTranslate(translate); + break; + case ROTATE_KEY: + if (d.found(N1N2_KEY)) { + double[][] n1n2 = d.lookupDoubleMatrix(N1N2_KEY); + double[] n1 = n1n2[0]; + double[] n2 = n1n2[1]; + t.setRotation(new double[] {getRotX(n1, n2), getRotY(n1, n2), getRotZ(n1, n2)}); + } else if (d.found(ROLL_PITCH_YAW_KEY)) { + double[] rollPitchYaw = d.lookupDoubleArray(ROLL_PITCH_YAW_KEY); + double roll = rollPitchYaw[0]; + double pitch = rollPitchYaw[1]; + double yaw = rollPitchYaw[2]; + t.setRotation(new double[] { roll, pitch, yaw}); + } else if (d.found(YAW_PITCH_ROLL_KEY)) { + double[] yawPitchRoll = d.lookupDoubleArray(YAW_PITCH_ROLL_KEY); + double yaw = yawPitchRoll[0]; + double pitch = yawPitchRoll[1]; + double roll = yawPitchRoll[2]; + t.setRotation(new double[] { roll, pitch, yaw}); + } + break; + case SCALE_KEY: + double[] value = d.lookupDoubleArray(SCALE_VEC_KEY); + t.setScale(value); + break; + + default: + break; + } + } + } + } + } + return t; + } + + public ListField toDictionary() { + ListField transforms = new ListField(TRANSFORMS_KEY); + if (scaleX != 1 || scaleY != 1 || scaleZ != 1) { + Dictionary d = new Dictionary(""); + d.add(TYPE_KEY, SCALE_KEY); + d.add(SCALE_VEC_KEY, format(getScale())); + d.add(ABOUT_POINT_KEY, format(getOrigin())); + + transforms.add(d); + } + if (rotX != 0 || rotY != 0 || rotZ != 0) { + Dictionary d = new Dictionary(""); + d.add(TYPE_KEY, ROTATE_KEY); + d.add(ROLL_PITCH_YAW_KEY, format(getRotation())); + d.add(ABOUT_POINT_KEY, format(getOrigin())); + + transforms.add(d); + } + if (posX != 0 || posY != 0 || posZ != 0) { + Dictionary d = new Dictionary(""); + d.add(TYPE_KEY, TRANSLATE_KEY); + d.add(TRANSLATE_VEC_KEY, format(getTranslation())); + + transforms.add(d); + } + return transforms; + } + + private static final DecimalFormat formatter = new DecimalFormat("0.0##", new DecimalFormatSymbols(Locale.US)); + + private String[] format(double[] d) { + return new String[] { formatter.format(d[0]), formatter.format(d[1]), formatter.format(d[2])} ; + } + + private String getN1N2() { + Matrix3d R = getRotationMatrix(rotX, rotY, rotZ); + + Vector3d axis1 = new Vector3d(1, 0, 0); + Vector3d axis2 = new Vector3d(); + R.transform(axis1, axis2); + + StringBuffer sb = new StringBuffer("("); + sb.append("("); + sb.append(formatter.format(axis1.x) + " " + formatter.format(axis1.y) + " " + formatter.format(axis1.z) + " "); + sb.append(")"); + sb.append("("); + sb.append(formatter.format(axis2.x) + " " + formatter.format(axis2.y) + " " + formatter.format(axis2.z) + " "); + sb.append(")"); + sb.append(")"); + + return sb.toString(); + } + + public Matrix3d getRotationMatrix(double rotX, double rotY, double rotZ) { + + Matrix3d X = new Matrix3d(); + X.rotX(Math.toRadians(rotX)); + + Matrix3d Y = new Matrix3d(); + Y.rotY(Math.toRadians(rotY)); + + Matrix3d Z = new Matrix3d(); + Z.rotZ(Math.toRadians(rotZ)); + + Matrix3d R = new Matrix3d(); + R.mul(Y, X); + R.mul(Z, R); + + return R; + } + + public static double getRotX(double[] n1, double[] n2) { + Vector3d v1 = new Vector3d(n1); + Vector3d v2 = new Vector3d(n2); + v1.normalize(); + v2.normalize(); + Vector3d v1_yz = new Vector3d(0, v1.y, v1.z); + Vector3d v2_yz = new Vector3d(0, v2.y, v2.z); + + return Math.toDegrees(v1_yz.angle(v2_yz)); + } + + public static double getRotY(double[] n1, double[] n2) { + Vector3d v1 = new Vector3d(n1); + Vector3d v2 = new Vector3d(n2); + v1.normalize(); + v2.normalize(); + Vector3d v1_xz = new Vector3d(v1.x, 0, v1.z); + Vector3d v2_xz = new Vector3d(v2.x, 0, v2.z); + + return Math.toDegrees(v1_xz.angle(v2_xz)); + } + + public static double getRotZ(double[] n1, double[] n2) { + Vector3d v1 = new Vector3d(n1); + Vector3d v2 = new Vector3d(n2); + v1.normalize(); + v2.normalize(); + Vector3d v1_xy = new Vector3d(v1.x, v1.y, 0); + Vector3d v2_xy = new Vector3d(v2.x, v2.y, 0); + + return Math.toDegrees(v1_xy.angle(v2_xy)); + } +} diff --git a/src/eu/engys/core/project/geometry/stl/ImportIGES.java b/src/eu/engys/core/project/geometry/stl/ImportIGES.java new file mode 100644 index 0000000..a227909 --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/ImportIGES.java @@ -0,0 +1,124 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry.stl; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.loadEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.printHeader; +import static eu.engys.core.OpenFOAMEnvironment.printVariables; +import static eu.engys.core.project.openFOAMProject.LOG; +import static eu.engys.util.OpenFOAMCommands.CAD_TOOL; + +import java.io.File; +import java.nio.file.Paths; + +import eu.engys.core.controller.ScriptBuilder; +import eu.engys.core.controller.actions.AbstractRunCommand; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorHook; +import eu.engys.core.executor.ExecutorListener.ExecutorState; +import eu.engys.core.executor.ExecutorMonitor; +import eu.engys.core.executor.ExecutorTerminal; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.util.IOUtils; +import eu.engys.util.Util; + +public class ImportIGES extends AbstractRunCommand { + + public static final String ACTION_NAME = "Import IGES"; + public static final String LOG_NAME = "importIGES.log"; + + private static final String IMPORT_IGES_RUN = "importIGES.run"; + private static final String IMPORT_IGES_BAT = "importIGES.bat"; + + private File[] input; + private File[] output; + + private boolean split; + private double precision; + private File logFile; + private Runnable loadSTLRunnable; + + public ImportIGES(Model model, Runnable loadSTLRunnable, File[] input, File[] output, boolean split, double precision) { + super(model, null); + this.input = input; + this.output = output; + this.split = split; + this.precision = precision; + this.loadSTLRunnable = loadSTLRunnable; + this.logFile = Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, LOG_NAME).toFile(); + } + + @Override + public void beforeExecute() { + IOUtils.clearFile(logFile); + } + + @Override + public void executeClient() { + File script = getScript(); + + ExecutorTerminal terminal = new TerminalExecutorMonitor(logFile); + ExecutorMonitor monitor = new ExecutorMonitor(); + monitor.addHook(ExecutorState.FINISH, new FinishHook()); + + this.executor = Executor.script(script).description(ACTION_NAME).inFolder(input[0].getParentFile()).env(getEnvironment(model, LOG_NAME)).inTerminal(terminal).withMonitors(monitor); + executor.exec(); + } + + private File getScript() { + File file = new File(model.getProject().getBaseDir(), Util.isWindows() ? IMPORT_IGES_BAT : IMPORT_IGES_RUN); + ScriptBuilder sb = new ScriptBuilder(); + writeScript(sb); + + IOUtils.writeLinesToFile(file, sb.getLines()); + file.setExecutable(true); + return file; + } + + private void writeScript(ScriptBuilder sb) { + printHeader(sb, ACTION_NAME.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + writeCommand(sb); + } + + private void writeCommand(ScriptBuilder sb) { + for (int i = 0; i < input.length; i++) { + sb.append(CAD_TOOL(split, precision, input[i], output[i])); + } + } + + private class FinishHook implements ExecutorHook { + + @Override + public void run(ExecutorMonitor monitor) { + loadSTLRunnable.run(); + } + } + +} diff --git a/src/eu/engys/core/project/geometry/stl/NastranReader.java b/src/eu/engys/core/project/geometry/stl/NastranReader.java new file mode 100644 index 0000000..8a37cbd --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/NastranReader.java @@ -0,0 +1,105 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.stl; + +public class NastranReader { + + /* +Step 1 Indexing the BDF file. +The first thing I do is read the BDF file once and indexing every BDF +card in the file. The result is a list with entries (line_id, card +label, card format (either comma, small (8 chars) or large (16 +chars)). I also return an the file contents as a list of strings so we +don't need the file anymore. + +Step 2 Parsing the card information +In this step I start digesting the card data based on the result from +the indexing routine. The first thing I do is start looking for +coordinate system information. I need this in case nodes are defined +in a local coordinate system. I translate all information (including +results like displacement fields) to the global coordinate system; +maybe not the best, but I am not sure how vtk/paraview handles local +coordinate systems). +Next I check if I have a handler for all cells in the BDF (CQUAD4, +CTRIA3 etc.). If not I issue a warning. Handlers are simple pieces of +Python code that receive a block of BDF text for a single card, digest +the information contained inside and returns an object representing +the card (for example a vtkCell instance). + +Next I parse all the grid cards translating to the global coordinate +system if necessary. The VTK classes you need are +- vtkPoints, vtkCellArray, vtkUnstructuredGrid +- vtkQuad, vtkTria etc. Note that you need only one instance of these; +they serve primarily to provide you with information like its element +type id, and the number of nodes for the element. You need this to +fill the cell datastructures later. You can ofcourse hardcode this +information directly, but I don't recommend this +- vtkIntArray, vtkFloatArray etc. for storing results, or any kind of +other information; for example I typically store the original cell and +grid identification numbers, property/material id and the thickness +- vtkXMLUnstructuredGridWriter (if you want to export to vtu) + +A typical (simple) code structure would be: + +points = vtkPoints() +cells = vtkCellArray() +grid = vtkUnstructuredGrid() + +Fill the points with points.InsertNextPoint(..) or similar +Fill the cells with cells.InsertNextCell(..) or grid.InsertNextCell(..) + +Assign points and possibly cells to the grid: + +grid.SetPoints(points) +grid.SetCells(cells) + +# Create some data +displacements = vtkFloatArray() +displacements.SetName('displacements) +displacements.SetNumberOfComponents(3) +Fill with displacement information + +# Assign the displacement data to the grid +grid.GetPointData().AddArray(displacements) + +A final remark. By far the hardest part is to properly parse the BDF +file. Some of the gotchas: +- Properly catching line termination in case of long formatted lines +- Parsing cards with variable length (like MPC cards) +- Parsing the unconventional floating point representation (e.g. 1.0-1 +instead of 1.0e-1) +- Handling include statements in different sections of the file +- Detecting card start and end points +etc. + +I hope this helps a little, feel free to ask more questions. + +Regards, + +Marco + */ +} diff --git a/src/eu/engys/core/project/geometry/stl/RemoveDuplicates.java b/src/eu/engys/core/project/geometry/stl/RemoveDuplicates.java new file mode 100644 index 0000000..0d66ae8 --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/RemoveDuplicates.java @@ -0,0 +1,162 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry.stl; + +import java.util.Arrays; + +import vtk.vtkCell; +import vtk.vtkCellArray; +import vtk.vtkIdList; +import vtk.vtkMergePoints; +import vtk.vtkPoints; +import vtk.vtkPolyData; +import vtk.vtkTriangle; + +public class RemoveDuplicates { + + private vtkPolyData dataset; + private vtkMergePoints PointsLocator; + private vtkMergePoints CellsLocator; + + public RemoveDuplicates(vtkPolyData dataset) { + this.dataset = dataset; + this.PointsLocator = new vtkMergePoints(); + this.CellsLocator = new vtkMergePoints(); + } + + public vtkPolyData execute() { + vtkPolyData input = dataset; + vtkPolyData output = new vtkPolyData(); + + if (input.GetNumberOfCells() == 0) + { + // set up a ugrid with same data arrays as input, but + // no points, cells or data. + output.Allocate(1, 0); +// output.GetPointData().CopyAllocate(input.GetPointData(), 0, 0); +// output.GetCellData().CopyAllocate(input.GetCellData(), 0, 0); + vtkPoints pts = new vtkPoints(); + output.SetPoints(pts); + pts.Delete(); + return output; + } + +// output.GetPointData().CopyAllocate(input.GetPointData(), 0, 0); +// output.GetCellData().PassData(input.GetCellData()); + + // First, create a new points array that eliminate duplicate points. + // Also create a mapping from the old point id to the new. + vtkPoints newPts = new vtkPoints(); + int num = input.GetNumberOfPoints(); + int newId; + int[] ptMap = new int[num]; + double[] pt = new double[3]; + + this.PointsLocator.InitPointInsertion(newPts, input.GetBounds(), num); + +// int progressStep = num / 100; +// if (progressStep == 0) +// { +// progressStep = 1; +// } + for (int id = 0; id < num; ++id) + { +// if (id % progressStep == 0) +// { +// this.UpdateProgress(0.8*((float)id/num)); +// } + input.GetPoint(id, pt); + if ( (newId = this.PointsLocator.IsInsertedPoint(pt)) < 0) + { + newId = this.PointsLocator.InsertNextPoint(pt); + output.GetPointData().CopyData(input.GetPointData(),id,newId); + } + ptMap[id] = newId; + } + output.SetPoints(newPts); + newPts.Delete(); + + + // New copy the cells. + int newCenterId; + vtkPoints newCenterPts = new vtkPoints(); + vtkIdList cellPoints = new vtkIdList(); + num = input.GetNumberOfCells(); +// output.Allocate(num, 0); + + this.CellsLocator.InitPointInsertion(newCenterPts, input.GetBounds(), num); + + vtkCellArray cells = new vtkCellArray(); + output.SetPolys(cells); + + System.out.println("RemoveDuplicates.execute() " + output.GetNumberOfCells()); + + for (int id = 0; id < num; ++id) + { +// if (id % progressStep == 0) +// { +// this.UpdateProgress(0.8+0.2*((float)id/num)); +// } +// input.GetCell(id).GetParametricCenter(id0); + + vtkCell cell = input.GetCell(id); + + if (cell instanceof vtkTriangle) { + vtkTriangle tri = (vtkTriangle) cell; + vtkPoints verices = tri.GetPoints(); + double[] center = new double[3]; + tri.TriangleCenter(verices.GetPoint(0), verices.GetPoint(1), verices.GetPoint(2), center); + + newCenterId = this.CellsLocator.IsInsertedPoint(center); + System.out.println("RemoveDuplicates.execute() center: " + Arrays.toString(center) + ", id: " + newCenterId); + if ( newCenterId < 0) + { + newCenterId = this.CellsLocator.InsertNextPoint(center); + + input.GetCellPoints(id, cellPoints); + for (int i=0; i < cellPoints.GetNumberOfIds(); i++) + { + int cellPtId = cellPoints.GetId(i); + newId = ptMap[cellPtId]; + cellPoints.SetId(i, newId); + } + cells.InsertNextCell(cell); + } else { + System.err.println("Duplicated!"); + } + } else { + System.err.println("Cell isn't a TRIANGLE"); + } + } + + output.SetPolys(cells); + +// delete [] ptMap; + cellPoints.Delete(); + output.Squeeze(); + return output; + } +} diff --git a/src/eu/engys/core/project/geometry/stl/STLJoiner.java b/src/eu/engys/core/project/geometry/stl/STLJoiner.java new file mode 100644 index 0000000..abeaf41 --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/STLJoiner.java @@ -0,0 +1,122 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.stl; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import eu.engys.util.progress.ProgressMonitor; + +public class STLJoiner implements Runnable { + + private final ProgressMonitor monitor; + + private BufferedWriter flatWriter = null; + + private int lineCounter = 0; + + private File destination; + private List children; + + public STLJoiner(File destination, List children, ProgressMonitor monitor) { + this.destination = destination; + this.children = children; + this.monitor = monitor; + } + + @Override + public void run() { + try { + joinFiles(); + } catch (Exception e) { + monitor.error(e.getMessage()); + } finally { + } + } + + public void joinFiles() throws Exception { + monitor.setIndeterminate(true); + String line = null; + try { + flatWriter = new BufferedWriter(new FileWriter(destination)); + for (File child : children) { + monitor.info("Copying " + child.getAbsolutePath()); + try (BufferedReader reader = new BufferedReader(new FileReader(child), 2000);) { + if (reader.ready()) { + while ((line = reader.readLine()) != null && !line.isEmpty()) { + writeln(line); + increaseCounter(); + } + } + } catch (Exception e) { + + } + } + } finally { + if (flatWriter != null) + flatWriter.close(); + } + } + + private void writeln(String string) throws IOException { + if (flatWriter != null) + flatWriter.write(string + "\n"); + } + + + protected void increaseCounter() { + lineCounter++; + if (lineCounter % 30000 == 0) + monitor.setCurrent(null, lineCounter); + } + + public int count(File file) throws IOException { + InputStream is = new BufferedInputStream(new FileInputStream(file)); + try { + byte[] c = new byte[1024]; + int count = 0; + int readChars = 0; + while ((readChars = is.read(c)) != -1) { + for (int i = 0; i < readChars; ++i) { + if (c[i] == '\n') + ++count; + } + } + return count; + } finally { + is.close(); + } + } +} diff --git a/src/eu/engys/core/project/geometry/stl/STLManager.java b/src/eu/engys/core/project/geometry/stl/STLManager.java new file mode 100644 index 0000000..ec8c89b --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/STLManager.java @@ -0,0 +1,76 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.stl; + +import java.io.File; + +import javax.inject.Inject; + +import org.apache.commons.io.FilenameUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.constant.TriSurfaceFolder; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.util.progress.ProgressMonitor; + +public class STLManager { + + public static final String COPY_OF_PREFIX = "CopyOf"; + + private static final Logger logger = LoggerFactory.getLogger(STLManager.class); + + private ProgressMonitor monitor; + private TriSurfaceFolder triSurface; + private Model model; + + @Inject + public STLManager(Model model, ProgressMonitor monitor) { + this.monitor = monitor; + this.model = model; + this.triSurface = model.getProject().getConstantFolder().getTriSurface(); + } + + private Stl loadFromTriSurface(String fileName) { + Dictionary g = new Dictionary(fileName, Surface.stl); + g.setName(fileName); + g.add("name", FilenameUtils.removeExtension(fileName)); + + Stl stl = (Stl) model.getGeometry().getFactory().loadSurface(g, model, monitor); + return stl; + } + + public Stl copyAndLoadFile(File file, String name, boolean overwrite) { + triSurface.getFileManager().copyHere(file, name, overwrite); + return loadFromTriSurface(name); + } + + +} diff --git a/src/eu/engys/core/project/geometry/stl/STLReader.java b/src/eu/engys/core/project/geometry/stl/STLReader.java new file mode 100644 index 0000000..c988c29 --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/STLReader.java @@ -0,0 +1,470 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.stl; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; + +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +import org.apache.commons.io.FileUtils; +import org.apache.log4j.Level; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkCleanPolyData; +import vtk.vtkPolyData; +import vtk.vtkSTLReader; +import eu.engys.core.LoggerUtil; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.util.TempFolder; +import eu.engys.util.Util; +import eu.engys.util.VTKSettings; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.progress.SilentMonitor; +import eu.engys.util.ui.ExecUtil; + +public class STLReader implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(STLReader.class); + + private static final long CHAR_PER_ROW = 30; + private static final int SIZE = 8192; + private static final int NP = 4; + + private final File sourceFile; + private final String fileName; + private final File tmp; + private final ProgressMonitor monitor; + + private BufferedReader reader = null; + private PrintWriter regionWriter = null; + + private int lineCounter = 0; + private int counter = 0; + private boolean Ascii; + + private List solids; + private List regionFiles; + + private ExecutorService executor; + + public STLReader(File source, ProgressMonitor monitor) { + this.sourceFile = source; + this.fileName = source.getName(); + this.monitor = monitor; + this.solids = new ArrayList(); + this.regionFiles = new ArrayList<>(); + this.tmp = TempFolder.get(STLReader.class.getSimpleName()); + } + + @Override + public void run() { + try { + initMonitor(); + initFilesIO(); + readFile(); + } catch (Exception e) { + logAnError(e); + } finally { + monitor.setCurrent(null, monitor.getTotal()); + FileUtils.deleteQuietly(tmp); + } + } + + void initMonitor() throws IOException { + int totalLines = count(sourceFile); + monitor.setTotal(totalLines); + monitor.setIndeterminate(false); + } + + void initFilesIO() throws IOException { + reader = new BufferedReader(new FileReader(sourceFile), SIZE); + } + + void logAnError(Exception e) { + monitor.error(e.getMessage(), 1); + logger.error("Error reading STL file ", e); + solids.clear(); + } + + void readFile() throws Exception { + if (reader.ready()) { + String line = reader.readLine(); + detectType(line); + + try { + executor = ExecUtil.createParallelExecutor(NP); + if (isAscii()) { + logger.info("Read STL " + sourceFile.getName() + " [ASCII]"); + monitor.info(sourceFile.getName() + " [ASCII]", 2); + + parseLine(line); + while ((line = reader.readLine()) != null && !line.isEmpty()) { + parseLine(line); + increaseCounter(); + } + + } else { + logger.info("Read STL " + sourceFile.getName() + " [BINARY]"); + monitor.info(sourceFile.getName() + " [BINARY]", 2); + readBinary(); + } + ExecUtil.awaitTermination(executor); + } finally { + closeFilesIO(); + } + } + } + + private void increaseCounter() { + lineCounter++; + if (lineCounter % 50000 == 0) + monitor.setCurrent(null, lineCounter); + } + + void closeFilesIO() throws IOException { + if (reader != null) + reader.close(); + if (regionWriter != null) + regionWriter.close(); + + reader = null; + regionWriter = null; + } + + private void detectType(String line) { + if (line.startsWith("solid")) { + this.setAscii(true); + } else { + // If the first word is not "solid" then we consider the file is binary + // Can give us problems if the comment of the binary file begins by "solid" + this.setAscii(false); + } + } + + private String regionName = ""; + private File regionFile; + private Solid solid; + + private String parseLine(String line) throws IOException { + if (line.startsWith("solid")) { + setValidRegionName(line); + + newRegionFile(); + + startRegionWriter(); + } else if (line.startsWith("endsolid")) { + flushRegionWriter(); + } else { + writeln(line); + } + + return regionName; + } + + private File newRegionFile() { + regionFile = new File(tmp, fileName + "_" + regionName); + regionFiles.add(regionFile); + solid = new Solid(regionName); + solids.add(solid); + return regionFile; + } + + private void startRegionWriter() throws IOException { + regionWriter = new PrintWriter(new FileWriter(regionFile)); + writeln("solid " + regionName); + } + + private void writeln(String string) throws IOException { + if (regionWriter != null) + regionWriter.write(string.replace(',', '.') + "\n"); + } + + private void write(String string) throws IOException { + if (regionWriter != null) + regionWriter.write(string.replace(',', '.')); + } + + private void flushRegionWriter() throws IOException { + write("endsolid " + regionName); + if (regionWriter != null) { + regionWriter.flush(); + regionWriter.close(); + regionWriter = null; + } + + executor.submit(new SolidReader(regionFile, solid)); + + regionFile = null; + } + + class SolidReader implements Runnable { + + private File regionFile; + private Solid solid; + + public SolidReader(File regionFile, Solid solid) { + this.regionFile = regionFile; + this.solid = solid; + } + + @Override + public void run() { + if (VTKSettings.librariesAreLoaded()) { + vtkSTLReader reader = new vtkSTLReader(); + reader.SetFileName(regionFile.getAbsolutePath()); + reader.Update(); + + this.solid.setDataSet(reader.GetOutput()); + + reader.Delete(); + } + this.regionFile.delete(); + + } + } + +// public static vtkPolyData repairDataSet(vtkPolyData dataset) { +// System.out.println("STLReader.repairDataSet() POINTS: " + dataset.GetNumberOfPoints()); +// System.out.println("STLReader.repairDataSet() LINES: " + dataset.GetNumberOfLines()); +// System.out.println("STLReader.repairDataSet() CELLS: " + dataset.GetNumberOfCells()); +// +// vtkPolyData pippo = new RemoveDuplicates(dataset).execute(); +// +// System.out.println("STLReader.repairDataSet() POINTS: " + repaired.GetNumberOfPoints()); +// System.out.println("STLReader.repairDataSet() LINES: " + repaired.GetNumberOfLines()); +// System.out.println("STLReader.repairDataSet() CELLS: " + repaired.GetNumberOfCells()); +// return pippo; +// } + + public static vtkPolyData repairDataSet(vtkPolyData dataset) { + System.out.println("STLReader.repairDataSet() POINTS: " + dataset.GetNumberOfPoints()); + System.out.println("STLReader.repairDataSet() LINES: " + dataset.GetNumberOfLines()); + System.out.println("STLReader.repairDataSet() CELLS: " + dataset.GetNumberOfCells()); + + vtkCleanPolyData clean = new vtkCleanPolyData(); + // clean.ConvertLinesToPointsOff(); //def: on + // clean.ConvertPolysToLinesOff(); //def: on + // clean.ConvertStripsToPolysOff(); //def: on + // clean.PieceInvariantOff(); //def: on + // clean.PointMergingOff(); //def: on + // clean.SetAbsoluteTolerance(0); //def: 1.0 + // clean.SetTolerance(0);//def: 0.0 + // clean.ToleranceIsAbsoluteOn(); //def: off + clean.SetInputData(dataset); + clean.Update(); + + vtkPolyData repaired = clean.GetOutput(); + System.out.println("STLReader.repairDataSet() POINTS: " + repaired.GetNumberOfPoints()); + System.out.println("STLReader.repairDataSet() LINES: " + repaired.GetNumberOfLines()); + System.out.println("STLReader.repairDataSet() CELLS: " + repaired.GetNumberOfCells()); + + return repaired; + } + + private void setValidRegionName(String line) { + int startIndex = line.indexOf(" "); + if (startIndex < 0) { + regionName = "solid" + counter++; + logger.info("- " + "Found empty name. Set to " + regionName, 1); + return; + } + String name = line.substring(startIndex).trim(); + if (name.isEmpty()) { + regionName = "solid" + counter++; + logger.info("- " + "Found empty name. Set to " + regionName, 1); + return; + } + regionName = Util.replaceForbiddenCharacters(name); + regionName = uniqueNameAmongSolids(regionName); + if (regionName.equals(name)) { + logger.info("- " + regionName + " found", 1); + } else { + logger.info(String.format("- " + "Found invalid name \"%s\". Set to \"%s\".", name, regionName), 1); + } + } + + private String uniqueNameAmongSolids(String name) { + for (Solid solid : solids) { + if (solid.getName().equals(name)) { + return uniqueNameAmongSolids(name + counter++); + } + } + return name; + } + + private int count(File file) throws IOException { + int i = (int) (file.length() / CHAR_PER_ROW); + return i; + } + + private void readBinary() throws Exception { + ByteBuffer dataBuffer; // For reading in the correct endian + byte[] Info = new byte[80]; // Header data + byte[] Array_number = new byte[4]; // Holds the number of faces + byte[] Temp_Info; // Intermediate array + + int Number_faces; // First info (after the header) on the file + + FileInputStream data = new FileInputStream(sourceFile); + + // First 80 bytes aren't important + if (80 != data.read(Info)) { + // File is incorrect + // System.out.println("Format Error: 80 bytes expected"); + data.close(); + throw new Exception("Incorrect Format"); + } else { + // We must first read the number of faces -> 4 bytes int + // It depends on the endian so.. + + data.read(Array_number); // We get the 4 bytes + dataBuffer = ByteBuffer.wrap(Array_number); // ByteBuffer for reading correctly the int + dataBuffer.order(ByteOrder.nativeOrder()); // Set the right order + + Number_faces = dataBuffer.getInt(); + + Temp_Info = new byte[50 * Number_faces]; // Each face has 50 bytes of data + + data.read(Temp_Info); // We get the rest of the file + + dataBuffer = ByteBuffer.wrap(Temp_Info); // Now we have all the data in this ByteBuffer + dataBuffer.order(ByteOrder.nativeOrder()); + + // We can create that array directly as we know how big it's going to be + // coordArray = new Point3f[Number_faces * 3]; // Each face has 3 vertices + // normArray = new Vector3f[Number_faces]; + + setValidRegionName(""); + + // we create an ascii file -> an stl surface + + newRegionFile(); + + startRegionWriter(); + + int[] stripCounts = new int[Number_faces]; + for (int i = 0; i < Number_faces; i++) { + stripCounts[i] = 3; + try { + readFacetB(dataBuffer, i); + // After each facet there are 2 bytes without information + // In the last iteration we don't have to skip those bytes.. + if (i != Number_faces - 1) { + dataBuffer.get(); + dataBuffer.get(); + } + } catch (IOException e) { + // Quit + System.out.println("Format Error: iteration number " + i); + data.close(); + throw new Exception("Incorrect Format"); + } + } + flushRegionWriter(); + } + + data.close(); + } + + private void readFacetB(ByteBuffer in, int index) throws IOException { + Vector3f normal = new Vector3f(in.getFloat(), in.getFloat(), in.getFloat()); + Point3f vertex1 = new Point3f(in.getFloat(), in.getFloat(), in.getFloat()); + Point3f vertex2 = new Point3f(in.getFloat(), in.getFloat(), in.getFloat()); + Point3f vertex3 = new Point3f(in.getFloat(), in.getFloat(), in.getFloat()); + + /* + * facet normal -1 0 0 + * outer loop + * vertex 5 15 10 + * vertex 5 5 10 + * vertex 5 15 15 + * endloop + * endfacet + */ + writeln(String.format("facet normal %f %f %f", normal.x, normal.y, normal.z)); + writeln(" outer loop"); + writeln(String.format(" vertex %f %f %f", vertex1.x, vertex1.y, vertex1.z)); + writeln(String.format(" vertex %f %f %f", vertex2.x, vertex2.y, vertex2.z)); + writeln(String.format(" vertex %f %f %f", vertex3.x, vertex3.y, vertex3.z)); + writeln(" endloop"); + writeln("endfacet"); + } + + public List getSolids() { + return solids; + } + + public boolean isAscii() { + return this.Ascii; + } + + public void setAscii(boolean b) { + this.Ascii = b; + } + + public static void main(String[] args) { + LoggerUtil.initTestLogger(Level.DEBUG); + VTKSettings.LoadAllNativeLibraries(); + new STLReader(new File("/home/stefano/ENGYS/examples/STL/plateExchanger.stl"), new SilentMonitor()).run(); + +// long fileLenght = 40 * 1024 * 1024; +// int i = (int) (fileLenght / CHAR_PER_ROW); +// System.out.println(fileLenght + " Byte -> " + i + " rows"); + +// System.out.println("**************"); +// System.out.println("* SERIAL *"); +// System.out.println("**************"); +// NP = 1; +// for (int i=0; i<10; i++) { +// long start = System.currentTimeMillis(); +// new STLReader(new File("/home/stefano/ENGYS/examples/STL/Bravo/car.stl"), new SilentMonitor()).run(); +// System.err.println("Time: " + (System.currentTimeMillis() - start)/1000.0 ); +// } +// NP = 4; +// System.out.println("**************"); +// System.out.println("* PARALLEL "+NP+" *"); +// System.out.println("**************"); +// for (int i=0; i<10; i++) { +// long start = System.currentTimeMillis(); +// new STLReader(new File("/home/stefano/ENGYS/examples/STL/Bravo/car.stl"), new SilentMonitor()).run(); +// System.err.println("Time: " + (System.currentTimeMillis() - start)/1000.0 ); +// } + } +} diff --git a/src/eu/engys/core/project/geometry/stl/STLReplacer.java b/src/eu/engys/core/project/geometry/stl/STLReplacer.java new file mode 100644 index 0000000..4a8b4bd --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/STLReplacer.java @@ -0,0 +1,204 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.stl; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; + +import eu.engys.util.Util; +import eu.engys.util.progress.ProgressMonitor; + +public class STLReplacer implements Runnable { + + private final ProgressMonitor monitor; + + private BufferedReader reader = null; + private BufferedWriter flatWriter = null; + + private int lineCounter = 0; + + private File source; + private String solidName; + private File replacement; + + public STLReplacer(File source, String name, File replacement, ProgressMonitor monitor) { + this.source = source; + this.solidName = name; + this.replacement = replacement; + this.monitor = monitor; + } + + @Override + public void run() { + try { + replaceFile(); + } catch (Exception e) { + monitor.error(e.getMessage()); + } finally { + } + } + + public void replaceFile() throws Exception { + String sourceName = source.getName(); + File source_org = new File(source.getParent(), sourceName + ".org"); + source.renameTo(source_org); + File replacedFile = new File(source.getParent(), sourceName); + monitor.info(source.getAbsolutePath() + " -> " + source_org.getAbsolutePath()); + + int totalLines = count(source_org); + monitor.setTotal(totalLines); + monitor.setIndeterminate(false); + monitor.info("Reading " + source.getAbsolutePath()); + + String line = null; + try { + reader = new BufferedReader(new FileReader(source_org), 2000); + flatWriter = new BufferedWriter(new FileWriter(replacedFile)); + + // writeln("solid "+flattenedFile.getName()); + if (reader.ready()) { + while ((line = reader.readLine()) != null && !line.isEmpty()) { + exceptionIfLineIsntSolid(lineCounter, line); + parseLine(line); + increaseCounter(); + } + } + // write("endsolid "+flattenedFile.getName()); + } finally { + if (reader != null) + reader.close(); + if (flatWriter != null) + flatWriter.close(); + } + } + + private String regionName = ""; + + private boolean replacing; + + protected void parseLine(String line) throws IOException { + if (line.startsWith("solid " + solidName)) { + replacing = true; + writeReplacement(); + return; + } else if (line.startsWith("endsolid") && replacing) { + replacing = false; + } else if (!replacing) { + // System.out.println("STLReplacer.parseLine() COPY: "+line); + writeln(line); + } + } + + private void writeReplacement() throws FileNotFoundException, IOException { + String line = null; + int lineCounter = 0; + try (BufferedReader reader = new BufferedReader(new FileReader(replacement), 2000)) { + writeln("solid " + solidName); + if (reader.ready()) { + while ((line = reader.readLine()) != null && !line.isEmpty()) { + //exceptionIfLineIsntSolid(lineCounter, line); + // System.out.println("STLReplacer.parseLine() REPLACE: "+line); + if (line.startsWith("solid") || line.startsWith("endsolid")) + continue; + writeln(line); + lineCounter++; + } + } + write("endsolid " + solidName); + } + } + + private void writeln(String string) throws IOException { + if (flatWriter != null) + flatWriter.write(string + "\n"); + } + + private void write(String string) throws IOException { + if (flatWriter != null) + flatWriter.write(string); + } + + protected void increaseCounter() { + lineCounter++; + if (lineCounter % 30000 == 0) + monitor.setCurrent(null, lineCounter); + } + + protected void exceptionIfLineIsntSolid(int counter, String line) { + if (counter == 0 && !line.startsWith("solid")) + throw new IllegalArgumentException("Binary STL format not supported"); + } + + private int counter = 0; + + public void setValidRegionName(String line) { + int startIndex = line.indexOf(" "); + if (startIndex < 0) { + regionName = "solid" + counter++; + monitor.info(" - " + "Found empty name. Set to " + regionName); + return; + } + String name = line.substring(startIndex).trim(); + if (name.isEmpty()) { + regionName = "solid" + counter++; + monitor.info(" - " + "Found empty name. Set to " + regionName); + return; + } + regionName = Util.replaceForbiddenCharacters(name); + if (regionName.equals(name)) { + monitor.info(" - " + regionName + " found"); + } else { + monitor.info(String.format(" - " + "Found invalid name \"%s\". Set to \"%s\".", name, regionName)); + } + } + + public int count(File file) throws IOException { + InputStream is = new BufferedInputStream(new FileInputStream(file)); + try { + byte[] c = new byte[1024]; + int count = 0; + int readChars = 0; + while ((readChars = is.read(c)) != -1) { + for (int i = 0; i < readChars; ++i) { + if (c[i] == '\n') + ++count; + } + } + return count; + } finally { + is.close(); + } + } +} diff --git a/src/eu/engys/core/project/geometry/stl/STLWriter.java b/src/eu/engys/core/project/geometry/stl/STLWriter.java new file mode 100644 index 0000000..a8c020f --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/STLWriter.java @@ -0,0 +1,132 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.stl; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.util.TempFolder; +import eu.engys.util.VTKSettings; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; + +public class STLWriter implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(STLWriter.class); + private static final int SIZE = 8192; + + private final File targetFile; + private final String fileName; + private final File tmp; + private final ProgressMonitor monitor; + + private Stl stl; + + public STLWriter(File target, Stl stl, ProgressMonitor monitor) { + this.targetFile = target; + this.stl = stl; + this.fileName = target.getName(); + this.monitor = monitor; + this.tmp = TempFolder.get(STLWriter.class.getSimpleName()); + } + + @Override + public void run() { + try { + initMonitor(); + writeFile(); + } catch (Exception e) { + logAnError(e); + } finally { + monitor.setCurrent(null, monitor.getTotal()); + FileUtils.deleteQuietly(tmp); + } + } + + void initMonitor() throws IOException { + int totalLines = stl.getSolids().length; + monitor.setTotal(totalLines); + monitor.setCurrent(null, 0); + monitor.setIndeterminate(false); + } + + void logAnError(Exception e) { + monitor.error(e.getMessage(), 1); + logger.error("Error writing STL file ", e); + } + + void writeFile() throws Exception { + monitor.info(targetFile.getName() + " [ASCII]", 2); + logger.info("Write STL " + targetFile.getName() + " [ASCII]"); + + if (VTKSettings.librariesAreLoaded()) { + try (FileWriter writer = new FileWriter(targetFile)) { + Solid[] solids = stl.getSolids(); + SolidWriter[] solidWriters = new SolidWriter[solids.length]; + for (int i = 0; i < solidWriters.length; i++) { + solidWriters[i] = new SolidWriter(tmp, fileName, solids[i]); + } + + ExecUtil.execSerial(solidWriters); + + for (SolidWriter solidWriter : solidWriters) { + try (BufferedReader reader = new BufferedReader(new FileReader(solidWriter.getFile()))) { + String line = ""; + while ((line = reader.readLine()) != null) { + if (line.startsWith("solid")) { + writer.write("solid " + solidWriter.getSolid().getName() + "\n"); + } else if (line.startsWith("endsolid")) { + writer.write("endsolid " + solidWriter.getSolid().getName() + "\n"); + } else { + writer.write(line + "\n"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + monitor.setCurrent(null, monitor.getCurrent()); + } + writer.flush(); + } finally { + + } + } else { + logger.info("Write STL SKIPPED: no 3D"); + } + + } + +} diff --git a/src/eu/engys/core/project/geometry/stl/SolidWriter.java b/src/eu/engys/core/project/geometry/stl/SolidWriter.java new file mode 100644 index 0000000..549dd73 --- /dev/null +++ b/src/eu/engys/core/project/geometry/stl/SolidWriter.java @@ -0,0 +1,91 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry.stl; + +import java.io.File; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkSTLWriter; +import vtk.vtkTransform; +import vtk.vtkTransformFilter; +import eu.engys.core.project.geometry.TransfromMode; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.util.Util; + +public class SolidWriter implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(SolidWriter.class); + + private Solid solid; + private File file; + private String fileName; + private File tmp; + + public SolidWriter(File tmp, String fileName, Solid solid) { + this.tmp = tmp; + this.fileName = fileName; + this.solid = solid; + } + + public File getFile() { + return file; + } + + public Solid getSolid() { + return solid; + } + + @Override + public void run() { + String regionName = solid.getName(); + logger.info("- " + regionName + " written", 1); + + this.file = new File(tmp, fileName + "_" + Util.generateID()); + + if (solid.getTransformMode() == TransfromMode.TO_FILE) { + vtkTransform transform = solid.getTransformation().toVTK(new vtkTransform()); + + vtkTransformFilter tFilter = new vtkTransformFilter(); + tFilter.SetTransform(transform); + tFilter.SetInputData(solid.getDataSet()); + tFilter.Update(); + + vtkSTLWriter write = new vtkSTLWriter(); + // write.SetFileTypeToASCII(); + write.SetFileName(file.getAbsolutePath()); + write.SetInputData(tFilter.GetOutput()); + write.Write(); + } else { + vtkSTLWriter write = new vtkSTLWriter(); + // write.SetFileTypeToASCII(); + write.SetFileName(file.getAbsolutePath()); + write.SetInputData(solid.getDataSet()); + write.Write(); + } + } +} diff --git a/src/eu/engys/core/project/geometry/surface/BaseSurface.java b/src/eu/engys/core/project/geometry/surface/BaseSurface.java new file mode 100644 index 0000000..76153c0 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/BaseSurface.java @@ -0,0 +1,78 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import eu.engys.core.project.geometry.Surface; + +public abstract class BaseSurface extends Surface { + + private static final String _REGION0 = "_region0"; + + public BaseSurface(String name) { + super(name); + } + + @Override + public String getPatchName() { + return isAppendRegionName() ? getName() + _REGION0 : getName(); + } + + @Override + public boolean hasRegions() { + return false; + } + + @Override + public Region[] getRegions() { + return new Region[0]; + } + + @Override + public boolean isSingleton() { + return true; + } + + @Override + public boolean hasLayers() { + return true; + } + + @Override + public boolean hasSurfaceRefinement() { + return true; + } + + @Override + public boolean hasVolumeRefinement() { + return true; + } + + @Override + public boolean hasZones() { + return true; + } +} diff --git a/src/eu/engys/core/project/geometry/surface/Box.java b/src/eu/engys/core/project/geometry/surface/Box.java new file mode 100644 index 0000000..f9b1f06 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/Box.java @@ -0,0 +1,84 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import vtk.vtkCubeSource; +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; + +public class Box extends BaseSurface { + + /** + * @deprecated Use GeometryFactory!! + */ + @Deprecated + public Box(String name) { + super(name); + Dictionary geometryDictionary = new Dictionary(box); + geometryDictionary.setName(name); + setGeometryDictionary(geometryDictionary); + } + + @Override + public Type getType() { + return Type.BOX; + } + + public double[] getMin() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(MIN_KEY)) + return getGeometryDictionary().lookupDoubleArray(MIN_KEY); + else + return new double[] { 0, 0, 0 }; + } + + public double[] getMax() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(MAX_KEY)) + return getGeometryDictionary().lookupDoubleArray(MAX_KEY); + else + return new double[] { 0, 0, 0 }; + } + + @Override + public Surface cloneSurface() { + Surface box = new Box(name); + cloneSurface(box); + return box; + } + + @Override + public vtkPolyData getDataSet() { + double[] min = getMin(); + double[] max = getMax(); + + vtkCubeSource cubeSource = new vtkCubeSource(); + cubeSource.SetBounds(min[0], max[0], min[1], max[1], min[2], max[2]); + cubeSource.Update(); + return cubeSource.GetOutput(); + } +} diff --git a/src/eu/engys/core/project/geometry/surface/Cylinder.java b/src/eu/engys/core/project/geometry/surface/Cylinder.java new file mode 100644 index 0000000..2ae8d18 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/Cylinder.java @@ -0,0 +1,102 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import vtk.vtkLineSource; +import vtk.vtkPolyData; +import vtk.vtkTubeFilter; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; + +public class Cylinder extends BaseSurface { + + /** + * @deprecated Use GeometryFactory!! + */ + @Deprecated + public Cylinder(String name) { + super(name); + Dictionary geometryDictionary = new Dictionary(cylinder); + geometryDictionary.setName(name); + setGeometryDictionary(geometryDictionary); + } + + @Override + public Type getType() { + return Type.CYLINDER; + } + + public double[] getPoint1() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(POINT1_KEY)) + return getGeometryDictionary().lookupDoubleArray(POINT1_KEY); + else + return new double[] { 0, 0, 0 }; + } + + public double[] getPoint2() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(POINT2_KEY)) + return getGeometryDictionary().lookupDoubleArray(POINT2_KEY); + else + return new double[] { 0, 0, 0 }; + } + + public double getRadius() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(RADIUS_KEY)) + return Double.valueOf(getGeometryDictionary().lookup(RADIUS_KEY)); + else + return 0; + } + + @Override + public Surface cloneSurface() { + Surface box = new Cylinder(name); + cloneSurface(box); + return box; + } + + @Override + public vtkPolyData getDataSet() { + double[] point1 = getPoint1(); + double[] point2 = getPoint2(); + double radius = getRadius(); + + vtkLineSource lineSource = new vtkLineSource(); + lineSource.SetPoint1(point1); + lineSource.SetPoint2(point2); + + // Create a tube (cylinder) around the line + vtkTubeFilter tubeFilter = new vtkTubeFilter(); + tubeFilter.SetInputConnection(lineSource.GetOutputPort()); + tubeFilter.SetCapping(1); + tubeFilter.SetRadius(radius); + tubeFilter.SetNumberOfSides(50); + tubeFilter.Update(); + + return tubeFilter.GetOutput(); + } +} diff --git a/src/eu/engys/core/project/geometry/surface/MultiPlane.java b/src/eu/engys/core/project/geometry/surface/MultiPlane.java new file mode 100644 index 0000000..972ff8d --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/MultiPlane.java @@ -0,0 +1,137 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import static eu.engys.core.project.system.BlockMeshDict.ELEMENTS_KEY; +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; + +public class MultiPlane extends MultiRegion { + + public MultiPlane(String name) { + super(name); + } + + public void addPlane(String name) { + if (!regionsMap.containsKey(name)) { + PlaneRegion newPlane = new PlaneRegion(name); + super.addRegion(newPlane); + } + } + + public void setPlane(String name, double[] origin, double[] point1, double[] point2, int resX, int resY) { + if (regionsMap.containsKey(name)) { + PlaneRegion plane = (PlaneRegion) regionsMap.get(name); + plane.origin = origin; + plane.point1 = point1; + plane.point2 = point2; + plane.resolutionX = resX; + plane.resolutionY = resY; + } else { + System.err.println(String.format("Plane %s not found.", name)); + } + } + + public PlaneRegion[] getPlanes() { + return regions.toArray(new PlaneRegion[0]); + } + + @Override + public Type getType() { + return Type.MULTI; + } + + @Override + public void setGeometryDictionary(Dictionary d) { + super.setGeometryDictionary(d); + + double[] min = d.lookupDoubleArray(MIN_KEY); + double[] max = d.lookupDoubleArray(MAX_KEY); + int[] res = d.lookupIntArray(ELEMENTS_KEY); + + if (regions.size() == 6) { + setPlane(regions.get(0).getName(), new double[] { min[0], min[1], min[2] }, new double[] { min[0], max[1], min[2] }, new double[] { min[0], min[1], max[2] }, res[1], res[2]); + setPlane(regions.get(1).getName(), new double[] { max[0], min[1], min[2] }, new double[] { max[0], max[1], min[2] }, new double[] { max[0], min[1], max[2] }, res[1], res[2]); + + setPlane(regions.get(2).getName(), new double[] { min[0], min[1], min[2] }, new double[] { max[0], min[1], min[2] }, new double[] { min[0], min[1], max[2] }, res[0], res[2]); + setPlane(regions.get(3).getName(), new double[] { min[0], max[1], min[2] }, new double[] { max[0], max[1], min[2] }, new double[] { min[0], max[1], max[2] }, res[0], res[2]); + + setPlane(regions.get(4).getName(), new double[] { min[0], min[1], min[2] }, new double[] { max[0], min[1], min[2] }, new double[] { min[0], max[1], min[2] }, res[0], res[1]); + setPlane(regions.get(5).getName(), new double[] { min[0], min[1], max[2] }, new double[] { max[0], min[1], max[2] }, new double[] { min[0], max[1], max[2] }, res[0], res[1]); + } + } + + @Override + public boolean hasLayers() { + return false; + } + + @Override + public boolean hasSurfaceRefinement() { + return false; + } + + @Override + public boolean hasVolumeRefinement() { + return false; + } + + @Override + public boolean hasZones() { + return false; + } + + public double[] getDelta() { + double[] delta = new double[3]; + + if (getGeometryDictionary() != null) { + double[] min = getGeometryDictionary().lookupDoubleArray(MIN_KEY); + double[] max = getGeometryDictionary().lookupDoubleArray(MAX_KEY); + int[] res = getGeometryDictionary().lookupIntArray(ELEMENTS_KEY); + + for (int i = 0; i < delta.length; i++) { + delta[i] = (max[i] - min[i]) / res[i]; + } + } + + return delta; + } + + @Override + public Surface cloneSurface() { + Surface s = new MultiPlane(name); + cloneSurface(s); + return s; + } + + @Override + public vtkPolyData getDataSet() { + return null; + } +} diff --git a/src/eu/engys/core/project/geometry/surface/MultiRegion.java b/src/eu/engys/core/project/geometry/surface/MultiRegion.java new file mode 100644 index 0000000..b5e10b5 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/MultiRegion.java @@ -0,0 +1,134 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.TransfromMode; +import eu.engys.core.project.geometry.stl.AffineTransform; + +public abstract class MultiRegion extends Surface { + + protected Map regionsMap = new HashMap(); + protected List regions = new ArrayList(); + private boolean modified = false; + + public MultiRegion(String name) { + super(name); + } + + public void addRegion(Region region) { + setName(region); + region.setParent(this); + regions.add(region); + regionsMap.put(region.getName(), region); + } + + private void setName(Region region) { + String name = region.getName(); + int counter = 0; + while (regionsMap.containsKey(name)) { + name += counter++; + } + + region.rename(name); + } + + public Region[] getRegions() { + return regions.toArray(new Region[regions.size()]); + } + + @Override + public boolean hasRegions() { + return true; + } + + protected void clearRegions() { + regions.clear(); + } + + @Override + public String getPatchName() { + return getName(); + } + + public void renameRegion(String oldName, String newName) { + regionsMap.put(newName, regionsMap.remove(oldName)); + } + + public void removeRegion(String name) { + regions.remove(regionsMap.remove(name)); + } + + public boolean isSingleton() { + return regions.size() == 1; + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + for (Region region : regions) { + region.setVisible(visible); + } + } + + @Override + public void setTransformation(AffineTransform transformation) { + super.setTransformation(transformation); + for (Region region : regions) { + region.setTransformation(transformation); + } + } + + @Override + public void setTransformMode(TransfromMode transformMode) { + super.setTransformMode(transformMode); + for (Region region : regions) { + region.setTransformMode(transformMode); + } + } + + @Override + protected void cloneSurface(Surface surface) { + super.cloneSurface(surface); + MultiRegion mr = (MultiRegion) surface; + for (Region region : regions) { + mr.addRegion((Region) region.cloneSurface()); + } + } + + public void setModified(boolean modified) { + this.modified = modified; + } + public boolean isModified() { + return modified; + } +} diff --git a/src/eu/engys/core/project/geometry/surface/NullSurface.java b/src/eu/engys/core/project/geometry/surface/NullSurface.java new file mode 100644 index 0000000..3650db6 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/NullSurface.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.geometry.surface; + +import vtk.vtkPolyData; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; + +public class NullSurface extends Surface { + + public NullSurface() { + super(""); + } + + public NullSurface(String name) { + super(name); + } + + @Override + public String getPatchName() { + return ""; + } + + @Override + public Type getType() { + return Type.BOX; + } + + @Override + public boolean isSingleton() { + return false; + } + + @Override + public boolean hasRegions() { + return false; + } + + @Override + public Region[] getRegions() { + return null; + } + + @Override + public boolean hasSurfaceRefinement() { + return false; + } + + @Override + public boolean hasVolumeRefinement() { + return false; + } + + @Override + public boolean hasLayers() { + return false; + } + + @Override + public boolean hasZones() { + return false; + } + + @Override + public Surface cloneSurface() { + return new NullSurface(name); + } + + @Override + public vtkPolyData getDataSet() { + return null; + } +} diff --git a/src/eu/engys/core/project/geometry/surface/Plane.java b/src/eu/engys/core/project/geometry/surface/Plane.java new file mode 100644 index 0000000..9f53e2f --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/Plane.java @@ -0,0 +1,112 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import vtk.vtkPlaneSource; +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; + +public class Plane extends BaseSurface { + + private double diagonal = 1; + + /** + * @deprecated Use GeometryFactory!! + */ + @Deprecated + public Plane(String name) { + super(name); + Dictionary geometryDictionary = new Dictionary(plane); + geometryDictionary.setName(name); + setGeometryDictionary(geometryDictionary); + } + + @Override + public Type getType() { + return Type.PLANE; + } + + public double[] getCenter() { + if (getGeometryDictionary() != null && getGeometryDictionary().subDict(POINT_AND_NORMAL_DICT_KEY) != null && getGeometryDictionary().subDict(POINT_AND_NORMAL_DICT_KEY).found(BASE_POINT_KEY)) + return getGeometryDictionary().subDict(POINT_AND_NORMAL_DICT_KEY).lookupDoubleArray(BASE_POINT_KEY); + else + return null; + } + + public void setCenter(double[] center) { + if (getGeometryDictionary() != null && getGeometryDictionary().isDictionary(POINT_AND_NORMAL_DICT_KEY)){ + Dictionary dict = getGeometryDictionary().subDict(POINT_AND_NORMAL_DICT_KEY); + dict.add(BASE_POINT_KEY, center); + } + } + + public double[] getNormal() { + if (getGeometryDictionary() != null && getGeometryDictionary().subDict(POINT_AND_NORMAL_DICT_KEY) != null && getGeometryDictionary().subDict(POINT_AND_NORMAL_DICT_KEY).found(NORMAL_VECTOR_KEY)) + return getGeometryDictionary().subDict(POINT_AND_NORMAL_DICT_KEY).lookupDoubleArray(NORMAL_VECTOR_KEY); + else + return null; + } + + public void setNormal(double[] normal) { + if (getGeometryDictionary() != null && getGeometryDictionary().isDictionary(POINT_AND_NORMAL_DICT_KEY)){ + Dictionary dict = getGeometryDictionary().subDict(POINT_AND_NORMAL_DICT_KEY); + dict.add(NORMAL_VECTOR_KEY, normal); + } + } + + public void setDiagonal(double diagonal) { + this.diagonal = diagonal; + } + + public double getDiagonal() { + return diagonal; + } + + @Override + public Surface cloneSurface() { + Plane plane = new Plane(name); + cloneSurface(plane); + plane.diagonal = this.diagonal; + return plane; + } + + @Override + public vtkPolyData getDataSet() { + + vtkPlaneSource planeSource = new vtkPlaneSource(); + planeSource.SetOrigin(0, 0, 0); + planeSource.SetPoint1(diagonal, 0, 0); + planeSource.SetPoint2(0, diagonal, 0); + planeSource.SetCenter(getCenter()); + planeSource.SetNormal(getNormal()); + planeSource.Update(); + + return planeSource.GetOutput(); + } +} diff --git a/src/eu/engys/core/project/geometry/surface/PlaneRegion.java b/src/eu/engys/core/project/geometry/surface/PlaneRegion.java new file mode 100644 index 0000000..b8c82e6 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/PlaneRegion.java @@ -0,0 +1,117 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import vtk.vtkPlaneSource; +import vtk.vtkPolyData; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; + + +public class PlaneRegion extends Region { + + double[] origin; + double[] point1; + double[] point2; + + int resolutionX; + int resolutionY; + + public PlaneRegion(String name) { + super(name); + } + + public double[] getPoint1() { + return point1; + } + + public double[] getPoint2() { + return point2; + } + + public double[] getOrigin() { + return origin; + } + + @Override + public Type getType() { + return Type.PLANE; + } + @Override + public String getPatchName() { + return getName(); + } + + @Override + public boolean hasLayers() { + return true; + } + + @Override + public boolean hasSurfaceRefinement() { + return false; + } + + @Override + public boolean hasVolumeRefinement() { + return false; + } + + public int getResolutionX() { + return resolutionX; + } + + public int getResolutionY() { + return resolutionY; + } + + @Override + public vtkPolyData getDataSet() { + vtkPlaneSource planeSource = new vtkPlaneSource(); + planeSource.SetOrigin(getOrigin()); + planeSource.SetPoint1(getPoint1()); + planeSource.SetPoint2(getPoint2()); + planeSource.SetXResolution(getResolutionX()); + planeSource.SetYResolution(getResolutionY()); + planeSource.Update(); + return planeSource.GetOutput(); + } + + @Override + public Surface cloneSurface() { + PlaneRegion region = new PlaneRegion(name); + cloneSurface(region); + region.origin = origin; + region.point1 = point1; + region.point2 = point2; + + region.resolutionX = resolutionX; + region.resolutionY = resolutionY; + + return region; + } +} diff --git a/src/eu/engys/core/project/geometry/surface/Region.java b/src/eu/engys/core/project/geometry/surface/Region.java new file mode 100644 index 0000000..29c6f22 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/Region.java @@ -0,0 +1,69 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import eu.engys.core.project.geometry.Type; + +public abstract class Region extends BaseSurface { + + private MultiRegion parent; + + public Region(String name) { + super(name); + } + + public void setParent(MultiRegion parent) { + this.parent = parent; + } + + public MultiRegion getParent() { + return parent; + } + + @Override + public Type getType() { + return Type.REGION; + } + + @Override + public String getPatchName() { +// System.out.println("Region.getPatchName() "+getName()+", is singleton: "+parent.isSingleton()+", append: "+parent.isAppendRegionName()); + if (parent.isSingleton() && !parent.isAppendRegionName()) { + return parent.getPatchName(); + } else { + return parent.getPatchName() + "_" + getName(); + } + } + +// @Override +// public Surface cloneSurface() { +// Surface region = new Region(name); +// cloneSurface(region); +// return region; +// } + +} diff --git a/src/eu/engys/core/project/geometry/surface/Ring.java b/src/eu/engys/core/project/geometry/surface/Ring.java new file mode 100644 index 0000000..50363d1 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/Ring.java @@ -0,0 +1,159 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import vtk.vtkAppendPolyData; +import vtk.vtkCellArray; +import vtk.vtkIdList; +import vtk.vtkLineSource; +import vtk.vtkPolyData; +import vtk.vtkPolyDataNormals; +import vtk.vtkTubeFilter; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; + +public class Ring extends BaseSurface { + + /** + * @deprecated Use GeometryFactory!! + */ + @Deprecated + public Ring(String name) { + super(name); + Dictionary geometryDictionary = new Dictionary(ring); + geometryDictionary.setName(name); + setGeometryDictionary(geometryDictionary); + } + + @Override + public Type getType() { + return Type.RING; + } + + public double[] getPoint1() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(POINT1_KEY)) + return getGeometryDictionary().lookupDoubleArray(POINT1_KEY); + else + return new double[] { 0, 0, 0 }; + } + + public double[] getPoint2() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(POINT2_KEY)) + return getGeometryDictionary().lookupDoubleArray(POINT2_KEY); + else + return new double[] { 0, 0, 0 }; + } + + public double getInnerRadius() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(INNER_RADIUS_KEY)) + return Double.valueOf(getGeometryDictionary().lookup(INNER_RADIUS_KEY)); + else + return 0; + } + + public double getOuterRadius() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(OUTER_RADIUS_KEY)) + return Double.valueOf(getGeometryDictionary().lookup(OUTER_RADIUS_KEY)); + else + return 0; + } + + @Override + public Surface cloneSurface() { + Surface box = new Ring(name); + cloneSurface(box); + return box; + } + + @Override + public vtkPolyData getDataSet() { + + vtkLineSource lineSource = new vtkLineSource(); + lineSource.SetPoint1(getPoint1()); + lineSource.SetPoint2(getPoint2()); + + vtkTubeFilter internalTubeFilter = new vtkTubeFilter(); + internalTubeFilter.SetInputConnection(lineSource.GetOutputPort()); + internalTubeFilter.SetCapping(0); + internalTubeFilter.SetRadius(getInnerRadius()); + internalTubeFilter.SetNumberOfSides(50); + internalTubeFilter.Update(); + + vtkTubeFilter externalTubeFilter = new vtkTubeFilter(); + externalTubeFilter.SetInputConnection(lineSource.GetOutputPort()); + externalTubeFilter.SetCapping(0); + externalTubeFilter.SetRadius(getOuterRadius()); + externalTubeFilter.SetNumberOfSides(50); + externalTubeFilter.Update(); + + vtkAppendPolyData append = new vtkAppendPolyData(); + append.AddInputConnection(internalTubeFilter.GetOutputPort()); + append.AddInputConnection(externalTubeFilter.GetOutputPort()); + append.Update(); + + vtkPolyData outputMesh = new vtkPolyData(); + outputMesh.DeepCopy(append.GetOutput()); + vtkCellArray outputTriangles = outputMesh.GetPolys(); + + int length = internalTubeFilter.GetOutput().GetNumberOfPoints(); + for (int ptId = 0; ptId < 50; ptId++) { + // Triangle one extremity + vtkIdList triangle = new vtkIdList(); + triangle.InsertNextId(ptId); + triangle.InsertNextId(ptId + length); + triangle.InsertNextId((ptId + 1) % 50 + length); + outputTriangles.InsertNextCell(triangle); + + triangle = new vtkIdList(); + triangle.InsertNextId(ptId); + triangle.InsertNextId((ptId + 1) % 50 + length); + triangle.InsertNextId((ptId + 1) % 50); + outputTriangles.InsertNextCell(triangle); + + // Triangle the other extremity + int offset = length - 50; + triangle = new vtkIdList(); + triangle.InsertNextId(ptId + offset); + triangle.InsertNextId(ptId + +offset + length); + triangle.InsertNextId((ptId + 1) % 50 + offset + length); + outputTriangles.InsertNextCell(triangle); + + triangle = new vtkIdList(); + triangle.InsertNextId((ptId + 1) % 50 + length + offset); + triangle.InsertNextId((ptId + 1) % 50 + offset); + triangle.InsertNextId(ptId + offset); + outputTriangles.InsertNextCell(triangle); + } + + vtkPolyDataNormals normals = new vtkPolyDataNormals(); + normals.SetInputData(outputMesh); + normals.Update(); + + return normals.GetOutput(); + } +} diff --git a/src/eu/engys/core/project/geometry/surface/Solid.java b/src/eu/engys/core/project/geometry/surface/Solid.java new file mode 100644 index 0000000..04534c0 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/Solid.java @@ -0,0 +1,87 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import vtk.vtkPolyData; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; +import eu.engys.util.VTKSettings; + +public class Solid extends Region { + private vtkPolyData dataSet; + + public Solid(String name) { + super(name); + } + + @Override + public Type getType() { + return Type.SOLID; + } + + @Override + public boolean hasLayers() { + return true; + } + + @Override + public boolean hasSurfaceRefinement() { + return true; + } + + @Override + public boolean hasVolumeRefinement() { + return false; + } + + @Override + public boolean hasZones() { + return false; + } + + @Override + public Surface cloneSurface() { + Solid solid = new Solid(name); + cloneSurface(solid); + + if (VTKSettings.librariesAreLoaded()) { + solid.dataSet = new vtkPolyData(); + solid.dataSet.ShallowCopy(dataSet); + } + + return solid; + } + + public void setDataSet(vtkPolyData dataSet) { + this.dataSet = dataSet; + } + + @Override + public vtkPolyData getDataSet() { + return dataSet; + } +} diff --git a/src/eu/engys/core/project/geometry/surface/Sphere.java b/src/eu/engys/core/project/geometry/surface/Sphere.java new file mode 100644 index 0000000..25e4fef --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/Sphere.java @@ -0,0 +1,88 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import vtk.vtkPolyData; +import vtk.vtkSphereSource; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; + +public class Sphere extends BaseSurface { + + /** + * @deprecated Use GeometryFactory!! + */ + @Deprecated + public Sphere(String name) { + super(name); + Dictionary geometryDictionary = new Dictionary(sphere); + geometryDictionary.setName(name); + setGeometryDictionary(geometryDictionary); + } + + @Override + public Type getType() { + return Type.SPHERE; + } + + public double[] getCenter() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(CENTRE_KEY)) + return getGeometryDictionary().lookupDoubleArray(CENTRE_KEY); + else + return new double[] { 0, 0, 0 }; + } + + public double getRadius() { + if (getGeometryDictionary() != null && getGeometryDictionary().found(RADIUS_KEY)) + return Double.valueOf(getGeometryDictionary().lookup(RADIUS_KEY)); + else + return 0; + } + + @Override + public Surface cloneSurface() { + Surface box = new Sphere(name); + cloneSurface(box); + return box; + } + + @Override + public vtkPolyData getDataSet() { + double[] center = getCenter(); + double radius = getRadius(); + + vtkSphereSource sphereSource = new vtkSphereSource(); + sphereSource.SetCenter(center); + sphereSource.SetRadius(radius); + sphereSource.SetPhiResolution(20); + sphereSource.SetThetaResolution(20); + sphereSource.Update(); + + return sphereSource.GetOutput(); + } +} diff --git a/src/eu/engys/core/project/geometry/surface/Stl.java b/src/eu/engys/core/project/geometry/surface/Stl.java new file mode 100644 index 0000000..14f2577 --- /dev/null +++ b/src/eu/engys/core/project/geometry/surface/Stl.java @@ -0,0 +1,151 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.geometry.surface; + +import java.io.File; +import java.util.List; + +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.TransfromMode; +import eu.engys.core.project.geometry.Type; + +public class Stl extends MultiRegion { + + private String fileName; + + /** + * @deprecated Use GeometryFactory!! + */ + @Deprecated + public Stl(String name) { + super(name); + this.fileName = getName() + ".stl"; + Dictionary defaultSTLDictionary = new Dictionary(stl); + defaultSTLDictionary.setName(fileName); + defaultSTLDictionary.add("name", getName()); + defaultSTLDictionary.add("appendRegionName", "false"); + setGeometryDictionary(defaultSTLDictionary); + } + + public String getFileName() { + return fileName; + } + + public void setFileName(File file) { + this.fileName = file.getName(); + } + + @Override + public Type getType() { + return Type.STL; + } + + public Solid[] getSolids() { + return regions.toArray(new Solid[0]); + } + + @Override + public boolean isSingleton() { + return regions.size() == 1; + } + + public void setSolids(List solids) { + for (Solid solid : solids) { + addRegion(solid); + } + } + + @Override + public void rename(String newName) { + super.rename(newName); + if (getGeometryDictionary() != null && getGeometryDictionary().isField("name")) { + getGeometryDictionary().add("name", newName); + + if (getTransformMode() == TransfromMode.TO_FILE) { + String dictName = getGeometryDictionary().getName(); + if (dictName.endsWith(".stl")) { + this.fileName = newName + ".stl"; + } else if (dictName.endsWith(".STL")) { + this.fileName = newName + ".STL"; + } + + getGeometryDictionary().setName(fileName); + setModified(true); + } + } + } + + @Override + public boolean hasLayers() { + return true; + } + + @Override + public boolean hasSurfaceRefinement() { + return true; + } + + @Override + public boolean hasVolumeRefinement() { + return true; + } + + @Override + public boolean hasZones() { + return true; + } + + public void buildGeometryDictionary(Dictionary dictionary) { + Dictionary geometryDict = new Dictionary(dictionary); + geometryDict.setName(fileName); + setGeometryDictionary(geometryDict); + } + + @Override + public String getPatchName() { + if (getGeometryDictionary().found("name")) { + return getGeometryDictionary().lookup("name"); + } else { + return super.getPatchName(); + } + } + + @Override + public Surface cloneSurface() { + Stl s = new Stl(name); + s.fileName = this.fileName; + cloneSurface(s); + return s; + } + + @Override + public vtkPolyData getDataSet() { + return null; + } +} diff --git a/src/eu/engys/core/project/materials/Material.java b/src/eu/engys/core/project/materials/Material.java new file mode 100644 index 0000000..29ea64e --- /dev/null +++ b/src/eu/engys/core/project/materials/Material.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.materials; + +import eu.engys.core.dictionary.Dictionary; + +public class Material { + + private String name; + private Dictionary dictionary; + + public Material(String name, Dictionary dictionary) { + this.name = name; + this.dictionary = dictionary; + } + + public String getName() { + return name; + } + + public Dictionary getDictionary() { + return dictionary; + } + + @Override + public String toString() { + return name; + } + + public void setDictionary(Dictionary d) { + this.dictionary = d; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/eu/engys/core/project/materials/Materials.java b/src/eu/engys/core/project/materials/Materials.java new file mode 100644 index 0000000..d3ea4b2 --- /dev/null +++ b/src/eu/engys/core/project/materials/Materials.java @@ -0,0 +1,98 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.materials; + +import java.util.LinkedList; + +import eu.engys.core.project.Model; +import eu.engys.core.project.constant.ThermophysicalProperties; +import eu.engys.core.project.constant.TransportProperties; +import eu.engys.util.progress.ProgressMonitor; + +public class Materials extends LinkedList { + + public Materials() { + super(); + } + + public static String materialsToString(Materials materials) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (Material material : materials) { + sb.append(material.getName()); + sb.append(" "); + } + sb.append(")"); + return sb.toString(); + } + + public String getFirstMaterialName() { + if (size() > 1) { + return get(0).getName(); + } + return ""; + } + + public void loadMaterials(Model model, MaterialsReader reader, ProgressMonitor monitor) { + clear(); + TransportProperties transProp = model.getProject().getConstantFolder().getTransportProperties(); + ThermophysicalProperties thermoProp = model.getProject().getConstantFolder().getThermophysicalProperties(); + + if (!model.getState().getMultiphaseModel().isMultiphase()) { + if (model.getState().isIncompressible()) { + reader.readSingle_Material(this, transProp, monitor); + } else { + reader.readSingle_Material(this, thermoProp, monitor); + } + model.materialsChanged(); + } + } + + public void saveMaterials(Model model, MaterialsWriter writer) { + TransportProperties transProp = new TransportProperties(); + ThermophysicalProperties thermoProp = new ThermophysicalProperties(); + + if (!model.getState().getMultiphaseModel().isMultiphase()) { + if (model.getState().isIncompressible()) { + writer.writeSingle_IncompressibleMaterial(this, transProp); + } else { + writer.writeSingle_CompressibleMaterial(this, thermoProp); + } + model.getProject().getConstantFolder().setTransportProperties(transProp); + model.getProject().getConstantFolder().setThermophysicalProperties(thermoProp); + } else { + // ECOMARINE + if (model.getState().isIncompressible() && model.getMaterials().size() == 1) { + writer.writeSingle_IncompressibleMaterial(this, transProp); + model.getProject().getConstantFolder().setTransportProperties(transProp); + model.getProject().getConstantFolder().setThermophysicalProperties(thermoProp); + } else { + /**/ + } + } + } +} diff --git a/src/eu/engys/core/project/materials/Materials200To210Converter.java b/src/eu/engys/core/project/materials/Materials200To210Converter.java new file mode 100644 index 0000000..c8ca584 --- /dev/null +++ b/src/eu/engys/core/project/materials/Materials200To210Converter.java @@ -0,0 +1,262 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.materials; + +import static eu.engys.core.project.constant.ThermophysicalProperties.AS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CONSTANT_CP_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CONST_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CP_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.ENERGY_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.EQUATION_OF_STATE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HF_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HIGH_CP_COEFFS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.JANAF_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.LOW_CP_COEFFS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MATERIAL_NAME_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MIXTURE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MOL_WEIGHT_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MU_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.N_MOLES_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PR_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PURE_MIXTURE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SENSIBLE_ENTHALPY_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SPECIE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SUTHERLAND_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TCOMMON_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMODYNAMICS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_MODEL_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_TYPE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THIGH_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TLOW_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TRANSPORT_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TS_KEY; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.constant.ThermophysicalProperties; + +public class Materials200To210Converter { + + /* + * thermoType + * thermoModel>>>>; + * thermoType + * hRhoThermo>>>>; + * + * mixture { specie { nMoles 1; molWeight 28.9; } thermodynamics { Cp 1000; + * Hf 0; } transport { mu 1.8e-05; Pr 0.7; } } + */ + public ThermophysicalProperties convert(Dictionary oldDictionary) { + ThermophysicalProperties thermophysicalProperties = new ThermophysicalProperties(); + + Dictionary materialGUIDict = toGUIFormat(oldDictionary); + + String type = materialGUIDict.lookup(THERMO_MODEL_KEY); + String energy = SENSIBLE_ENTHALPY_KEY; + String thermo = materialGUIDict.found(THERMO_KEY) ? materialGUIDict.lookup(THERMO_KEY) : ""; + String transport = materialGUIDict.found(TRANSPORT_KEY) ? materialGUIDict.lookup(TRANSPORT_KEY) : ""; + + Dictionary thermoDict = new Dictionary(THERMO_TYPE_KEY); + thermoDict.add(Dictionary.TYPE, type); + thermoDict.add(MIXTURE_KEY, PURE_MIXTURE_KEY); + thermoDict.add(TRANSPORT_KEY, transport); + thermoDict.add(THERMO_KEY, thermo); + thermoDict.add(EQUATION_OF_STATE_KEY, materialGUIDict.lookup(EQUATION_OF_STATE_KEY)); + thermoDict.add(SPECIE_KEY, SPECIE_KEY); + thermoDict.add(ENERGY_KEY, energy); + + /* SPECIES */ + Dictionary specieDict = new Dictionary(SPECIE_KEY); + specieDict.add(N_MOLES_KEY, materialGUIDict.lookup(N_MOLES_KEY)); + specieDict.add(MOL_WEIGHT_KEY, materialGUIDict.lookup(MOL_WEIGHT_KEY)); + + /* THERMODYNAMICS */ + Dictionary thermodynamicsDict = new Dictionary(THERMODYNAMICS_KEY); + if (thermo.equals(CONSTANT_CP_KEY)) { + thermodynamicsDict.add(CP_KEY, materialGUIDict.lookup(CP_KEY)); + thermodynamicsDict.add(HF_KEY, materialGUIDict.lookup(HF_KEY)); + } else if (thermo.equals(JANAF_KEY)) { + thermodynamicsDict.add(TLOW_KEY, materialGUIDict.lookup(TLOW_KEY)); + thermodynamicsDict.add(THIGH_KEY, materialGUIDict.lookup(THIGH_KEY)); + thermodynamicsDict.add(TCOMMON_KEY, materialGUIDict.lookup(TCOMMON_KEY)); + thermodynamicsDict.add(HIGH_CP_COEFFS_KEY, materialGUIDict.lookup(HIGH_CP_COEFFS_KEY)); + thermodynamicsDict.add(LOW_CP_COEFFS_KEY, materialGUIDict.lookup(LOW_CP_COEFFS_KEY)); + } + + /* TRANSPORT */ + Dictionary transportDict = new Dictionary(TRANSPORT_KEY); + if (transport.equals(CONST_KEY)) { + transportDict.add(MU_KEY, materialGUIDict.lookup(MU_KEY)); + transportDict.add(PR_KEY, materialGUIDict.lookup(PR_KEY)); + } else if (transport.equals(SUTHERLAND_KEY)) { + transportDict.add(AS_KEY, materialGUIDict.lookup(AS_KEY)); + transportDict.add(TS_KEY, materialGUIDict.lookup(TS_KEY)); + } + + Dictionary mixtureDict = new Dictionary(MIXTURE_KEY); + mixtureDict.add(specieDict); + mixtureDict.add(thermodynamicsDict); + mixtureDict.add(transportDict); + + thermophysicalProperties.add(MATERIAL_NAME_KEY, materialGUIDict.lookup(MATERIAL_NAME_KEY)); + thermophysicalProperties.add(thermoDict); + thermophysicalProperties.add(mixtureDict); + + // System.out.println("MaterialsBuilder.saveCompressible() "+thermophysicalProperties); + return thermophysicalProperties; + + } + + // @Override + // public Dictionary loadCompressible(Model model) { + // return + // toGUIFormat(model.getProject().getConstantFolder().getThermophysicalProperties()); + // } + + // @Override + public Dictionary toGUIFormat(Dictionary thermophysicalProperties) { + Dictionary d = new Dictionary(""); + + if (thermophysicalProperties.isField("thermoType")) { + String thermoType = thermophysicalProperties.lookup("thermoType"); + String[] tokens = thermoType.replace(">", "").trim().split("<"); + + String transport = tokens[2]; + String thermo = tokens[4]; + + d.add("thermoModel", tokens[0]); + d.add("transport", transport); + d.add("thermo", thermo); + d.add("equationOfState", tokens[5]); + } + + if (thermophysicalProperties.found("materialName")) + d.add("materialName", thermophysicalProperties.lookup("materialName")); + else + d.add("materialName", "defaultMaterial"); + + if (thermophysicalProperties.found("mixture")) { + Dictionary mixture = thermophysicalProperties.subDict("mixture"); + + /* SPECIES */ + Dictionary speciesDict = mixture.subDict("specie"); + d.merge(speciesDict); + + /* THERMODYNAMICS */ + Dictionary thermodynamicsDict = mixture.subDict("thermodynamics"); + d.merge(thermodynamicsDict); + + /* TRANSPORT */ + Dictionary transportDict = mixture.subDict("transport"); + d.merge(transportDict); + } + + return d; + } + + // @Override + // public Dictionary saveIncompressible(Model model, Dictionary + // materialDict) { + // + // Dictionary transportProperties = new Dictionary("transportProperties"); + // + // transportProperties.add("materialName", + // materialDict.lookup("materialName")); + // + // String transportModel = materialDict.lookup("transportModel"); + // transportProperties.add("transportModel", transportModel); + // + // if (materialDict.found(transportModel + "Coeffs")) { + // transportProperties.add(materialDict.subDict(transportModel + "Coeffs")); + // } + // + // if (materialDict.found("rho")) { + // transportProperties.add(materialDict.lookupScalar("rho")); + // } + // + // if (materialDict.found("mu")) { + // transportProperties.add(materialDict.lookupScalar("mu")); + // } + // + // if (materialDict.found("nu")) { + // transportProperties.add(materialDict.lookupScalar("nu")); + // } else if (materialDict.found("rho") && materialDict.found("mu")) { + // DimensionedScalar rho = materialDict.lookupScalar("rho"); + // DimensionedScalar mu = materialDict.lookupScalar("mu"); + // + // double nuValue = mu.doubleValue() / rho.doubleValue(); + // Dimensions nuDimensions = mu.getDimensions().divide(rho.getDimensions()); + // + // DimensionedScalar nu = new DimensionedScalar("nu", + // Double.toString(nuValue), nuDimensions); + // + // transportProperties.add(nu); + // } + // + // if (materialDict.found("Cp")) { + // DimensionedScalar cp = materialDict.lookupScalar("Cp"); + // transportProperties.add(cp); + // transportProperties.add("Cp0", cp.getValue()); + // } + // if (materialDict.found("Prt")) { + // transportProperties.add(materialDict.lookupScalar("Prt")); + // } + // if (materialDict.found("Pr")) { + // transportProperties.add(materialDict.lookupScalar("Pr")); + // } + // if (materialDict.found("lambda")) { + // transportProperties.add(materialDict.lookupScalar("lambda")); + // } + // + // if (materialDict.found("pRef")) { + // transportProperties.add(materialDict.lookupScalar("pRef")); + // } + // if (materialDict.found("beta")) { + // transportProperties.add(materialDict.lookupScalar("beta")); + // } + // if (materialDict.found("TRef")) { + // transportProperties.add(materialDict.lookupScalar("TRef")); + // } + // + // // + // System.out.println("MaterialsBuilder.saveIncompressible() "+transportProperties); + // + // return transportProperties; + // } + + // @Override + // public Dictionary saveSigma(Model model, Dictionary sigmaDict) { + // Dictionary transportProperties = new Dictionary("sigma"); + // if (model.getState().isMultiphase()) { + // if (sigmaDict.found("sigma")) { + // transportProperties.add(sigmaDict.lookupScalar("sigma")); + // } + // } + // return transportProperties; + // } + +} diff --git a/src/eu/engys/core/project/materials/MaterialsReader.java b/src/eu/engys/core/project/materials/MaterialsReader.java new file mode 100644 index 0000000..571f09b --- /dev/null +++ b/src/eu/engys/core/project/materials/MaterialsReader.java @@ -0,0 +1,38 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.materials; + +import eu.engys.core.project.constant.ThermophysicalProperties; +import eu.engys.core.project.constant.TransportProperties; +import eu.engys.util.progress.ProgressMonitor; + +public interface MaterialsReader { + + void readSingle_Material(Materials materials, TransportProperties tpp, ProgressMonitor monitor); + + void readSingle_Material(Materials materials, ThermophysicalProperties tfp, ProgressMonitor monitor); + +} diff --git a/src/eu/engys/core/project/materials/MaterialsWriter.java b/src/eu/engys/core/project/materials/MaterialsWriter.java new file mode 100644 index 0000000..8379648 --- /dev/null +++ b/src/eu/engys/core/project/materials/MaterialsWriter.java @@ -0,0 +1,37 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.materials; + +import eu.engys.core.project.constant.ThermophysicalProperties; +import eu.engys.core.project.constant.TransportProperties; + +public interface MaterialsWriter { + + void writeSingle_IncompressibleMaterial(Materials materials, TransportProperties tpp); + + void writeSingle_CompressibleMaterial(Materials materials, ThermophysicalProperties tfp); + +} diff --git a/src/eu/engys/core/project/materials/Phase.java b/src/eu/engys/core/project/materials/Phase.java new file mode 100644 index 0000000..285afc0 --- /dev/null +++ b/src/eu/engys/core/project/materials/Phase.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.materials; + +import eu.engys.core.dictionary.Dictionary; + +public class Phase { + + private String name; + private Dictionary dictionary; + + public Phase(String name, Dictionary dictionary) { + this.name = name; + this.dictionary = dictionary; + } + + public String getName() { + return name; + } + + public Dictionary getDictionary() { + return dictionary; + } + + @Override + public String toString() { + return name; + } + + public void setDictionary(Dictionary d) { + this.dictionary = d; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/eu/engys/core/project/mesh/FieldItem.java b/src/eu/engys/core/project/mesh/FieldItem.java new file mode 100644 index 0000000..771133d --- /dev/null +++ b/src/eu/engys/core/project/mesh/FieldItem.java @@ -0,0 +1,133 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.mesh; + +import static eu.engys.core.project.mesh.ScalarBarType.BLUE_TO_RED_RAINBOW; + +public class FieldItem { + + public static final int DEFAULT_RESOLUTION = 256; + public static final String SOLID = "Solid Color"; + public static final String INDEXED = "Index"; + public static final String[] COMPONENTS = new String[] { "Magnitude", "X", "Y", "Z" }; + + private int component; + private String name; + private DataType dataType; + private double[] range; + private ScalarBarType scalarBarType; + private int resolution; + private boolean automaticRange; + + public FieldItem(String fieldName, DataType dataType, int component) { + this.name = fieldName; + this.dataType = dataType; + this.component = component; + this.range = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE }; + this.scalarBarType = BLUE_TO_RED_RAINBOW; + this.resolution = DEFAULT_RESOLUTION; + this.automaticRange = true; + } + + public int getComponent() { + return component; + } + + public String getName() { + return name; + } + + public DataType getDataType() { + return dataType; + } + + public void setAutomaticRange(boolean automaticRange) { + this.automaticRange = automaticRange; + } + + public boolean isAutomaticRange() { + return automaticRange; + } + + public void setRange(double[] range) { + this.range = range; + } + + public double[] getRange() { + return range; + } + + public ScalarBarType getScalarBarType() { + return scalarBarType; + } + + public void setScalarBarType(ScalarBarType scalarBarType) { + this.scalarBarType = scalarBarType; + } + + public int getResolution() { + return resolution; + } + + public void setResolution(int resolution) { + this.resolution = resolution; + } + + public enum DataType { + POINT, CELL, NONE; + + public boolean isPoint() { + return this.equals(POINT); + } + + public boolean isCell() { + return this.equals(CELL); + } + + public boolean isNone() { + return this.equals(NONE); + } + } + + @Override + public String toString() { + return name; + } + + public boolean isScalar() { + return ! SOLID.equals(name) && ! INDEXED.equals(name); + } + + public boolean isSolid() { + return SOLID.equals(name); + } + + public boolean isIndexed() { + return INDEXED.equals(name); + } + +} diff --git a/src/eu/engys/core/project/mesh/Mesh.java b/src/eu/engys/core/project/mesh/Mesh.java new file mode 100644 index 0000000..36d87dc --- /dev/null +++ b/src/eu/engys/core/project/mesh/Mesh.java @@ -0,0 +1,201 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.mesh; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.input.ReversedLinesFileReader; + +import eu.engys.core.controller.actions.RunMesh; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.util.RegexpUtils; + +public class Mesh { + + private static final String HELYXOS_MESH_START_TAG = "Layer mesh : "; + private static final String HELYX_MESH_START_TAG = "Final mesh : "; + private long numberOfPoints = 0; + private long numberOfCells = 0; + private long numberOfFaces = 0; + private double meshTime = 0; + + private List cellsPerRefinementLevel = new ArrayList<>(); + + private int memorySize = 0; + private double[] bounds = new double[6]; + + private List timeSteps = new LinkedList<>(); + + private Map cellFieldMap = new LinkedHashMap<>(); + private Map pointFieldMap = new LinkedHashMap<>(); + + private Map> timeStepCellFieldsMap = new HashMap>(); + private Map> timeStepPointFieldsMap = new HashMap>(); + private List regions; + + public long getNumberOfPoints() { + return numberOfPoints; + } + + public void setNumberOfPoints(int numberOfPoints) { + this.numberOfPoints = numberOfPoints; + } + + public long getNumberOfCells() { + return numberOfCells; + } + + public void setNumberOfCells(int numberOfCells) { + this.numberOfCells = numberOfCells; + } + + public long getNumberOfFaces() { + return this.numberOfFaces; + } + + public void setNumberOfFaces(int numberOfFaces) { + this.numberOfFaces = numberOfFaces; + } + + public double getMeshTime() { + return meshTime; + } + + public List getCellsPerRefinementLevel() { + return cellsPerRefinementLevel; + } + + public int getMemorySize() { + return memorySize; + } + + public void setMemorySize(int memorySize) { + this.memorySize = memorySize; + } + + public double[] getBounds() { + return bounds; + } + + public void setBounds(double[] bounds) { + this.bounds = bounds; + } + + public List getTimeSteps() { + return timeSteps; + } + + public void setTimeSteps(List timeSteps) { + this.timeSteps = timeSteps; + } + + public List getRegions() { + return regions; + } + public void setRegions(List regions) { + this.regions = regions; + } + + public Map getCellFieldMap() { + return cellFieldMap; + } + + public Map getPointFieldMap() { + return pointFieldMap; + } + + public Map> getTimeStepCellFieldsMap() { + return timeStepCellFieldsMap; + } + + public Map> getTimeStepPointFieldsMap() { + return timeStepPointFieldsMap; + } + + public void readStatistics(Model model) { + Path log = model.getProject().getBaseDir().toPath().resolve(openFOAMProject.LOG).resolve(RunMesh.LOG_NAME); + if (Files.exists(log)) { + try (ReversedLinesFileReader reader = new ReversedLinesFileReader(log.toFile())) { + Stack stack = new Stack<>(); + while (true) { + String line = reader.readLine(); + stack.push(line); + if (stack.peek().startsWith(HELYX_MESH_START_TAG)) { + read(stack, HELYX_MESH_START_TAG); + break; + } else if (stack.peek().startsWith(HELYXOS_MESH_START_TAG)) { + read(stack, HELYXOS_MESH_START_TAG); + break; + } + } + } catch (Exception e) { + } + } + } + + private void read(Stack stack, String startTag) { + while (!stack.isEmpty()) { + String line = stack.pop(); + Pattern pattern1 = Pattern.compile(startTag + "cells:(\\d+)\\s+faces:(\\d+)\\s+points:(\\d+)"); + Matcher matcher1 = pattern1.matcher(line); + if (matcher1.matches()) { + this.numberOfCells = Integer.valueOf(matcher1.group(1)); + this.numberOfFaces = Integer.valueOf(matcher1.group(2)); + this.numberOfPoints = Integer.valueOf(matcher1.group(3)); + } else if (line.startsWith("Cells per refinement level:")) { + this.cellsPerRefinementLevel.clear(); + String row = stack.pop(); + while (!row.startsWith("Writing mesh")) { + Pattern pattern2 = Pattern.compile("\\s+(\\d)\\s+(\\d+)"); + Matcher matcher2 = pattern2.matcher(row); + if (matcher2.matches()) { + this.cellsPerRefinementLevel.add(Integer.valueOf(matcher2.group(2))); + } + row = stack.pop(); + } + } else if (line.startsWith("Finished meshing in")) { + Pattern pattern3 = Pattern.compile("Finished meshing in =\\s+(" + RegexpUtils.DOUBLE + ")\\s+s."); + Matcher matcher3 = pattern3.matcher(line); + if (matcher3.matches()) { + this.meshTime = Double.valueOf(matcher3.group(1)); + } + } + } + } + +} diff --git a/src/eu/engys/core/project/mesh/ScalarBarType.java b/src/eu/engys/core/project/mesh/ScalarBarType.java new file mode 100644 index 0000000..c0371bc --- /dev/null +++ b/src/eu/engys/core/project/mesh/ScalarBarType.java @@ -0,0 +1,350 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.mesh; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.Icon; + +import com.google.common.collect.Lists; + +import eu.engys.util.ui.ResourcesUtil; + +public enum ScalarBarType { + + BLUE_TO_RED_RAINBOW("Rainbow (Blue to Red)", ResourcesUtil.getIcon("scalarbar.rainbow.icon")), + RED_TO_BLUE_RAINBOW("Rainbow (Red to Blue)", ResourcesUtil.getIcon("scalarbar.rainbow.inverted.icon")), + + BLUE_TO_RED_HSV("Blue to Red (HSV)", ResourcesUtil.getIcon("scalarbar.bluetored.hsv.icon")), + RED_TO_BLUE_HSV("Red to Blue (HSV)", ResourcesUtil.getIcon("scalarbar.redtoblue.hsv.icon")), + BLUE_TO_RED_RGB("Blue to Red (RGB)", ResourcesUtil.getIcon("scalarbar.bluetored.rgb.icon")), + RED_TO_BLUE_RGB("Red to Blue (RGB)", ResourcesUtil.getIcon("scalarbar.redtoblue.rgb.icon")), + BLUE_TO_RED_DIV("Blue to Red (Diverging)", ResourcesUtil.getIcon("scalarbar.bluetored.div.icon")), + RED_TO_BLUE_DIV("Red to Blue (Diverging)", ResourcesUtil.getIcon("scalarbar.redtoblue.div.icon")), + + BLUE_TO_YELLOW_HSV("Blue to Yellow (HSV)", ResourcesUtil.getIcon("scalarbar.bluetoyellow.hsv.icon")), + YELLOW_TO_BLUE_HSV("Yellow to Blue (HSV)", ResourcesUtil.getIcon("scalarbar.yellowtoblue.hsv.icon")), + BLUE_TO_YELLOW_RGB("Blue to Yellow (RGB)", ResourcesUtil.getIcon("scalarbar.bluetoyellow.rgb.icon")), + YELLOW_TO_BLUE_RGB("Yellow to Blue (RGB)", ResourcesUtil.getIcon("scalarbar.yellowtoblue.rgb.icon")), + BLUE_TO_YELLOW_DIV("Blue to Yellow (Diverging)", ResourcesUtil.getIcon("scalarbar.bluetoyellow.div.icon")), + YELLOW_TO_BLUE_DIV("Yellow to Blue (Diverging)", ResourcesUtil.getIcon("scalarbar.yellowtoblue.div.icon")), + + BLACK_TO_WHITE("Black to White", ResourcesUtil.getIcon("scalarbar.blacktowhite.icon")), + WHITE_TO_BLACK("White to Black", ResourcesUtil.getIcon("scalarbar.whitetoblack.icon")); + + private String label; + private Icon icon; + + private ScalarBarType(String label, Icon icon) { + this.label = label; + this.icon = icon; + } + + public String getLabel() { + return label; + } + + public List getColors(int resolution) { + switch (label) { + // RAINBOW + case "Rainbow (Blue to Red)": + return getRainbowColors(); + case "Rainbow (Red to Blue)": + return getRainbowColorsInverted(); + // RED TO BLUE + case "Blue to Red (HSV)": + return getBlueToRedHSVColors(resolution); + case "Red to Blue (HSV)": + return getRedToBlueHSVColors(resolution); + case "Blue to Red (RGB)": + return getBlueToRedRGBColors(resolution); + case "Red to Blue (RGB)": + return getRedToBlueRGBColors(resolution); + case "Blue to Red (Diverging)": + return getBlueToRedDivergingColors(resolution); + case "Red to Blue (Diverging)": + return getRedToBlueDivergingColors(resolution); + // BLUE TO YELLOW + case "Blue to Yellow (HSV)": + return getBlueToYellowHSVColors(resolution); + case "Yellow to Blue (HSV)": + return getYellowToBlueHSVColors(resolution); + case "Blue to Yellow (RGB)": + return getBlueToYellowRGBColors(resolution); + case "Yellow to Blue (RGB)": + return getYellowToBlueRGBColors(resolution); + case "Blue to Yellow (Diverging)": + return getBlueToYellowDivergingColors(resolution); + case "Yellow to Blue (Diverging)": + return getYellowToBlueDivergingColors(resolution); + // GRAYSCALE + case "Black to White": + return getBlackToWhiteColors(resolution); + case "White to Black": + return getWhiteToBlackColors(resolution); + default: + return new ArrayList(); + } + } + + public Icon getIcon() { + return icon; + } + + /* + * Utils + */ + + public static Icon getIconByLabel(String label) { + ScalarBarType[] all = values(); + for (ScalarBarType type : all) { + if (type.getLabel().equals(label)) { + return type.getIcon(); + } + } + return null; + } + + public static ScalarBarType getTypeByLabel(String label) { + ScalarBarType[] all = values(); + for (ScalarBarType type : all) { + if (type.getLabel().equals(label)) { + return type; + } + } + return null; + + } + + public static String[] labels() { + ScalarBarType[] all = values(); + String[] labels = new String[all.length]; + for (int i = 0; i < labels.length; i++) { + labels[i] = all[i].getLabel(); + } + return labels; + } + + /***** COLORS *****/ + + /* + * RED TO BLUE + */ + + // HSV (rainbow) + private static List getRainbowColors() { + List colors = new ArrayList<>(); + colors.add(new double[] { 0.667, 0 }); + return colors; + } + + private static List getRainbowColorsInverted() { + List colors = new ArrayList<>(); + colors.add(new double[] { 0, 0.667 }); + return colors; + } + + // HSV (red -> pink -> blue) + private static List getBlueToRedHSVColors(int resolution) { + List colors = new LinkedList<>(); + if (resolution == 1) { + colors.add(new double[] { 0, 0, 1 }); + } else if (resolution == 2) { + colors.add(new double[] { 0, 0, 1 }); + colors.add(new double[] { 1, 0, 0 }); + } else if (resolution > 2) { + int limit1 = (resolution % 2 == 0) ? (resolution / 2) : (resolution - 1)/2; + int limit2 = (resolution - 1)/2; + colors.add(new double[] { 0, 0, 1 }); + for (float i = 1; i < limit1; i++) { + colors.add(new double[] { i / limit1, 0, 1 }); + } + colors.add(new double[] { 1, 0, 1 }); + for (float i = 1; i < limit2; i++) { + colors.add(new double[] { 1, 0, 1 - (i / limit2) }); + } + colors.add(new double[] { 1, 0, 0 }); + } + return colors; + } + + private static List getRedToBlueHSVColors(int resolution) { + return Lists.reverse(getBlueToRedHSVColors(resolution)); + } + + // RGB (red -> blue) + private static List getBlueToRedRGBColors(int resolution) { + List colors = new LinkedList<>(); + if (resolution == 1) { + colors.add(new double[] { 0, 0, 1 }); + } else if (resolution > 1) { + int limit = resolution -1; + colors.add(new double[] { 0, 0, 1 }); + for (float i = 1; i < limit; i++) { + colors.add(new double[] { i / limit, 0, 1 - (i / limit) }); + } + colors.add(new double[] { 1, 0, 0 }); + } + return colors; + } + + private static List getRedToBlueRGBColors(int resolution) { + return Lists.reverse(getBlueToRedRGBColors(resolution)); + } + + // DIVERGING (red -> white -> blue) + private static List getBlueToRedDivergingColors(int resolution) { + List colors = new LinkedList<>(); + if (resolution == 1) { + colors.add(new double[] { 0, 0, 1 }); + } else if (resolution == 2) { + colors.add(new double[] { 0, 0, 1 }); + colors.add(new double[] { 1, 0, 0 }); + } else if (resolution > 2) { + int limit1 = (resolution % 2 == 0) ? (resolution / 2) : (resolution - 1)/2; + int limit2 = (resolution - 1)/2; + colors.add(new double[] { 0, 0, 1 }); + for (float i = 1; i < limit1; i++) { + colors.add(new double[] { i / limit1, i / limit1, 1 }); + } + colors.add(new double[] { 1, 1, 1 }); + for (float i = 1; i < limit2; i++) { + colors.add(new double[] { 1, 1 - (i / limit2), 1 - (i / limit2) }); + } + colors.add(new double[] { 1, 0, 0 }); + } + return colors; + } + + private static List getRedToBlueDivergingColors(int resolution) { + return Lists.reverse(getBlueToRedDivergingColors(resolution)); + } + + /* + * BLUE TO YELLOW + */ + + // HSV (blue -> green -> yellow) + private static List getBlueToYellowHSVColors(int resolution) { + List colors = new LinkedList<>(); + if (resolution == 1) { + colors.add(new double[] { 0, 0, 1 }); + } else if (resolution == 2) { + colors.add(new double[] { 0, 0, 1 }); + colors.add(new double[] { 1, 1, 0 }); + } else if (resolution > 2) { + int limit1 = (resolution % 2 == 0) ? (resolution / 2) : (resolution - 1)/2; + int limit2 = (resolution - 1)/2; + colors.add(new double[] { 0, 0, 1 }); + for (float i = 1; i < limit1; i++) { + colors.add(new double[] { 0, i / limit1, 1 - (i / limit1) }); + } + colors.add(new double[] { 0, 1, 0 }); + for (float i = 1; i < limit2; i++) { + colors.add(new double[] { 1 - (i / limit2), 1, 0 }); + } + colors.add(new double[] { 1, 1, 0 }); + } + return colors; + } + + private static List getYellowToBlueHSVColors(int resolution) { + return Lists.reverse(getBlueToYellowHSVColors(resolution)); + } + + // RGB (blue -> yellow) + private static List getBlueToYellowRGBColors(int resolution) { + List colors = new LinkedList<>(); + if (resolution == 1) { + colors.add(new double[] { 0, 0, 1 }); + } else if (resolution > 1) { + int limit = resolution - 1; + colors.add(new double[] { 0, 0, 1 }); + for (float i = 1; i < limit; i++) { + colors.add(new double[] { i / limit, i / limit, 1 - (i / limit) }); + } + colors.add(new double[] { 1, 1, 0 }); + } + return colors; + } + + private static List getYellowToBlueRGBColors(int resolution) { + return Lists.reverse(getBlueToYellowRGBColors(resolution)); + } + + // DIVERGING (blue -> white -> yellow) + private static List getBlueToYellowDivergingColors(int resolution) { + List colors = new LinkedList<>(); + if (resolution == 1) { + colors.add(new double[] { 0, 0, 1 }); + } else if (resolution == 2) { + colors.add(new double[] { 0, 0, 1 }); + colors.add(new double[] { 1, 1, 0 }); + } else if (resolution > 2) { + int limit1 = (resolution % 2 == 0) ? (resolution / 2) : (resolution - 1)/2; + int limit2 = (resolution - 1)/2; + colors.add(new double[] { 0, 0, 1 }); + for (float i = 1; i < limit1; i++) { + colors.add(new double[] { i / limit1, i / limit1, 1 }); + } + colors.add(new double[] { 1, 1, 1 }); + for (float i = 1; i < limit2; i++) { + colors.add(new double[] { 1, 1, 1 - (i / limit2) }); + } + colors.add(new double[] { 1, 1, 0 }); + } + return colors; + } + + private static List getYellowToBlueDivergingColors(int resolution) { + return Lists.reverse(getBlueToYellowDivergingColors(resolution)); + } + + /* + * GRAYSCALE + */ + private static List getBlackToWhiteColors(int resolution) { + List colors = new LinkedList<>(); + if (resolution == 1) { + colors.add(new double[] { 0, 0, 0 }); + } else if (resolution > 1) { + int limit = resolution - 1; + colors.add(new double[] { 0, 0, 0 }); + for (float i = 1; i < limit; i++) { + colors.add(new double[] { i / (limit), i / (limit), i / (limit) }); + } + colors.add(new double[] { 1, 1, 1 }); + } + return colors; + } + + private static List getWhiteToBlackColors(int resolution) { + return Lists.reverse(getBlackToWhiteColors(resolution)); + } + +} diff --git a/src/eu/engys/core/project/openFOAMProject.java b/src/eu/engys/core/project/openFOAMProject.java new file mode 100644 index 0000000..8c1311d --- /dev/null +++ b/src/eu/engys/core/project/openFOAMProject.java @@ -0,0 +1,159 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project; + +import java.io.File; + +import eu.engys.core.project.constant.ConstantFolder; +import eu.engys.core.project.defaults.Defaults; +import eu.engys.core.project.system.SystemFolder; +import eu.engys.core.project.zero.ZeroFolder; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.progress.SilentMonitor; + +public class openFOAMProject { + + public static final String LOG = "log"; + public static final String HOSTFILE = "hostfile"; + public static final String POST_PROC = "postProcessing"; + public static final String MACHINEFILE = "machinefile"; + + private final File baseDir; + private final boolean parallel; + private final int processors; + + private final SystemFolder system; + private final ConstantFolder constant; + private final ZeroFolder zero; + + public static openFOAMProject createProject(File baseDir, ProgressMonitor monitor) { + ProjectFolderAnalyzer pa = new ProjectFolderAnalyzer(baseDir, monitor); + ProjectFolderStructure structure = pa.checkAll(); + + return structure.isParallel() ? openFOAMProject.newParallelProject(baseDir, structure.getProcessors()) : openFOAMProject.newSerialProject(baseDir); + } + + public static openFOAMProject createProject(CaseParameters parameters) { + return parameters.isParallel() ? openFOAMProject.newParallelProject(parameters.getBaseDir(), parameters.getnProcessors()) : openFOAMProject.newSerialProject(parameters.getBaseDir()); + } + + public static openFOAMProject newSerialProject(File baseDir) { + return new openFOAMProject(baseDir, false, -1); + } + + public static openFOAMProject newDefaultSerialProject(File baseDir, Defaults defaults) { + CreateCase createCase = new CreateCase(defaults, new SilentMonitor()); + CaseParameters caseParams = new CaseParameters(); + caseParams.setParallel(false); + caseParams.setnHierarchy(new int[] { 1, 1, 1 }); + caseParams.setnProcessors(1); + caseParams.setBaseDir(baseDir); + return createCase.create(caseParams); + } + + public static openFOAMProject newParallelProject(File baseDir) { + return new openFOAMProject(baseDir, true, new ProjectFolderAnalyzer(baseDir, null).findProcessorsFolders()); + } + + public static openFOAMProject newParallelProject(File baseDir, int nProcessors) { + return new openFOAMProject(baseDir, true, nProcessors); + } + + public static openFOAMProject newCopy(openFOAMProject project) { + return new openFOAMProject(project); + } + + public static openFOAMProject newCopy(File baseDir, openFOAMProject project) { + return new openFOAMProject(baseDir, project); + } + + private openFOAMProject(File baseDir, boolean parallel, int processors) { + this.baseDir = baseDir; + this.parallel = parallel; + this.processors = processors; + + this.system = new SystemFolder(this); + this.constant = new ConstantFolder(this); + this.zero = new ZeroFolder(this); + } + + private openFOAMProject(File baseDir, openFOAMProject prj) { + this.baseDir = baseDir; + this.parallel = prj.parallel; + this.processors = prj.processors; + + this.system = new SystemFolder(baseDir, prj.getSystemFolder()); + this.constant = new ConstantFolder(baseDir, prj.getConstantFolder()); + this.zero = new ZeroFolder(baseDir, prj.getZeroFolder()); + } + + private openFOAMProject(openFOAMProject prj) { + this.baseDir = prj.baseDir; + this.parallel = prj.parallel; + this.processors = prj.processors; + + this.system = new SystemFolder(baseDir, prj.getSystemFolder()); + this.constant = new ConstantFolder(baseDir, prj.getConstantFolder()); + this.zero = new ZeroFolder(baseDir, prj.getZeroFolder()); + } + + public File getBaseDir() { + return baseDir; + } + public boolean isParallel() { + return parallel; + } + public boolean isSerial() { + return !isParallel(); + } + + public boolean isMeshOnZero() { + ProjectFolderAnalyzer analyzer = new ProjectFolderAnalyzer(getBaseDir(), null).checkSerialOrParallel(); + return analyzer.isParallel_zero() || analyzer.isSerial_zero(); + } + + public int getProcessors() { + return processors; + } + + public ConstantFolder getConstantFolder() { + return constant; + } + + public SystemFolder getSystemFolder() { + return system; + } + + public ZeroFolder getZeroFolder() { + return zero; + } + + @Override + public String toString() { + return "PROJECT [ basedir: " + baseDir + " ] - [ parallel: " + parallel + " ] - [ processors: " + processors + "]"; + } +} diff --git a/src/eu/engys/core/project/runtimefields/RuntimeField.java b/src/eu/engys/core/project/runtimefields/RuntimeField.java new file mode 100644 index 0000000..5fc19ae --- /dev/null +++ b/src/eu/engys/core/project/runtimefields/RuntimeField.java @@ -0,0 +1,40 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.runtimefields; + +public class RuntimeField { + + private String name; + + public RuntimeField(String name) { + this.name = name; + } + + public String getName() { + return name; + } + +} diff --git a/src/eu/engys/core/project/runtimefields/RuntimeFields.java b/src/eu/engys/core/project/runtimefields/RuntimeFields.java new file mode 100644 index 0000000..1d4d584 --- /dev/null +++ b/src/eu/engys/core/project/runtimefields/RuntimeFields.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.runtimefields; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.project.system.ControlDict.FUNCTIONS_KEY; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.ListField; +import eu.engys.core.project.system.ControlDict; +import eu.engys.util.progress.ProgressMonitor; + +public class RuntimeFields extends LinkedHashMap { + + public RuntimeFields() { + super(); + } + + public List fields() { + return new ArrayList<>(values()); + } + + public void load(ControlDict controlDict, ProgressMonitor monitor) { + if (controlDict != null && controlDict.isDictionary(FUNCTIONS_KEY)) { + List functions = controlDict.subDict(FUNCTIONS_KEY).getDictionaries(); + for (Dictionary dictionary : functions) { + loadRuntimeField(dictionary); + } + } else if (controlDict != null && controlDict.isList(FUNCTIONS_KEY)) { + List functions = controlDict.getList(FUNCTIONS_KEY).getListElements(); + for (DefaultElement el : functions) { + if (el instanceof Dictionary) { + Dictionary dictionary = (Dictionary) el; + loadRuntimeField(dictionary); + } + } + } + } + + private void loadRuntimeField(Dictionary dictionary) { + if (dictionary.found(TYPE)) { + String type = dictionary.lookup(TYPE); + if (type.equals("fieldProcess")) { + ListField operations = dictionary.getList("operations"); + for (DefaultElement de : operations.getListElements()) { + if (de instanceof Dictionary) { + Dictionary opDict = (Dictionary) de; + String fieldName = opDict.lookup("fieldName"); + put(fieldName, new RuntimeField(fieldName)); + } + } + } + } + } + + public void removeFields(Dictionary dictionary) { + ListField operations = dictionary.getList("operations"); + for (DefaultElement de : operations.getListElements()) { + if (de instanceof Dictionary) { + Dictionary opDict = (Dictionary) de; + String fieldName = opDict.lookup("fieldName"); + remove(fieldName); + } + } + } + +} diff --git a/src/eu/engys/core/project/state/BuoyancyBuilder.java b/src/eu/engys/core/project/state/BuoyancyBuilder.java new file mode 100644 index 0000000..4e9a147 --- /dev/null +++ b/src/eu/engys/core/project/state/BuoyancyBuilder.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; + +public class BuoyancyBuilder { + + public static void save(Model model, double[] gValue) { + Dictionary g = model.getProject().getConstantFolder().getG(); + if (g != null) { + if (model.getState().getMultiphaseModel().isOn()) { + g.add("value", "(" + gValue[0] + " " + gValue[1] + " " + gValue[2] + ")"); + g.add("dimensions", "[0 1 -2 0 0 0 0]"); + } else if (model.getState().isEnergy()) { + if (model.getState().isBuoyant()) { + g.add("value", "(" + gValue[0] + " " + gValue[1] + " " + gValue[2] + ")"); + } else { + g.add("value", "(0 0 0)"); + } + g.add("dimensions", "[0 1 -2 0 0 0 0]"); + } else { + g.remove("value"); + g.remove("dimensions"); + } + } + // System.out.println("BuoyancyBuilder.save() "+g); + } + +} diff --git a/src/eu/engys/core/project/state/EngysTable15.java b/src/eu/engys/core/project/state/EngysTable15.java new file mode 100644 index 0000000..d2a08bd --- /dev/null +++ b/src/eu/engys/core/project/state/EngysTable15.java @@ -0,0 +1,129 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import java.util.Set; + +import javax.inject.Inject; + +public class EngysTable15 implements Table15 { + + public static final String RHO_CENTRAL_FOAM = "rhoCentralFoam"; + + @Inject + public EngysTable15() { + } + + @Override + public void updateSolverFamilies(State state, Set families) { + if (state.getSolverType().isSegregated()) { + if (state.isLowMach()) { + if (state.isSteady()) { + if (state.getMultiphaseModel().isMultiphase()) { + // NONE + } else { + families.add(SolverFamily.SIMPLE); + } + } else if (state.isTransient()) { + if (state.isCompressible()) { + families.add(SolverFamily.PIMPLE); + } else if (state.isIncompressible()) { + if (state.isEnergy() || state.getMultiphaseModel().isMultiphase()) { + families.add(SolverFamily.PIMPLE); + } else { + families.add(SolverFamily.PIMPLE); + families.add(SolverFamily.PISO); + } + } else { + // NONE + } + } else { + // NONE + } + } else if (state.isHighMach()) { + families.add(SolverFamily.PIMPLE); + families.add(SolverFamily.CENTRAL); + } else { + // NONE + } + } else { + // NONE + } + } + + @Override + public void updateSolver(State state) { + if (state.getSolverType().isSegregated()) { + String solverName = ""; + + if (state.getMultiphaseModel().isMultiphase()) { + /* in modules */ + } else if (state.getSolverFamily().isSimple() && state.isRANS()) { + if (state.isCompressible()) { + if (state.isBuoyant()) { + solverName = BUOYANT_SIMPLE_FOAM; + } else { + solverName = RHO_SIMPLE_FOAM; + } + } else if (state.isIncompressible()) { + if (state.isEnergy()) { + solverName = BUOYANT_BOUSSINESQ_SIMPLE_FOAM; + } else { + solverName = SIMPLE_FOAM; + } + } + } else if (state.getSolverFamily().isPiso()) { + if (state.isIncompressible()) { + solverName = PISO_FOAM; + } + } else if (state.getSolverFamily().isPimple()) { + if (state.isCompressible()) { + if (state.isBuoyant()) { + if (state.isRANS()) { + solverName = BUOYANT_PIMPLE_FOAM; + } + } else { + if (state.isHighMach()) { + solverName = SONIC_FOAM; + } else { + solverName = RHO_PIMPLE_FOAM; + } + } + } else if (state.isIncompressible()) { + if (state.isEnergy()) { + solverName = BUOYANT_BOUSSINESQ_PIMPLE_FOAM; + } else { + solverName = PIMPLE_FOAM; + } + } + } else if (state.getSolverFamily().isCentral()) { + solverName = RHO_CENTRAL_FOAM; + } + state.setSolver(new Solver(solverName)); + } + } + +} diff --git a/src/eu/engys/core/project/state/Flow.java b/src/eu/engys/core/project/state/Flow.java new file mode 100644 index 0000000..116296d --- /dev/null +++ b/src/eu/engys/core/project/state/Flow.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public enum Flow { + COMPRESSIBLE("Compressible"), INCOMPRESSIBLE("Incompressible"), NONE("None"); + + private String text; + + private Flow(String text) { + this.text = text; + } + + public boolean isCompressible() { + return this == COMPRESSIBLE; + } + + public boolean isIncompressible() { + return this == INCOMPRESSIBLE; + } + + public boolean isNone() { + return this == NONE; + } + + @Override + public String toString() { + return text; + } +} diff --git a/src/eu/engys/core/project/state/Mach.java b/src/eu/engys/core/project/state/Mach.java new file mode 100644 index 0000000..1e2dbee --- /dev/null +++ b/src/eu/engys/core/project/state/Mach.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public enum Mach { + LOW("Low"), HIGH("High"), NONE("None"); + + private String text; + + private Mach(String text) { + this.text = text; + } + + public boolean isLow() { + return this == LOW; + } + + public boolean isHigh() { + return this == HIGH; + } + + public boolean isNone() { + return this == NONE; + } + + @Override + public String toString() { + return text; + } +} diff --git a/src/eu/engys/core/project/state/Method.java b/src/eu/engys/core/project/state/Method.java new file mode 100644 index 0000000..386463d --- /dev/null +++ b/src/eu/engys/core/project/state/Method.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public enum Method { + LES("Les"), RANS("Rans"), NONE("None"); + + private String text; + + private Method(String text) { + this.text = text; + } + + public boolean isLes() { + return this == LES; + } + + public boolean isRans() { + return this == RANS; + } + + public boolean isNone() { + return this == NONE; + } + + @Override + public String toString() { + return text; + } +} diff --git a/src/eu/engys/core/project/state/MultiphaseModel.java b/src/eu/engys/core/project/state/MultiphaseModel.java new file mode 100644 index 0000000..7ae2c35 --- /dev/null +++ b/src/eu/engys/core/project/state/MultiphaseModel.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public class MultiphaseModel { + + public static final String OFF_LABEL = "Off"; + public static final MultiphaseModel OFF = new MultiphaseModel(OFF_LABEL, "", false, false); + + private String label; + private boolean multiphase; + private PhasesNumber phasesNumber; + private boolean dynamic; + private String key; + + public MultiphaseModel(String label, String key, boolean multiphase, boolean dynamic) { + this.label = label; + this.key = key; + this.multiphase = multiphase; + this.dynamic = dynamic; + } + + public String getLabel() { + return label; + } + + public String getKey() { + return key; + } + + public boolean isMultiphase() { + return multiphase; + } + + public boolean isDynamic() { + return dynamic; + } + + public boolean isOff() { + return label.equals(OFF_LABEL); + } + + public boolean isOn() { + return ! label.equals(OFF_LABEL); + } + + public PhasesNumber getPhasesNumber() { + return phasesNumber; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MultiphaseModel) { + return label.equals(((MultiphaseModel) obj).label); + } + return super.equals(obj); + } +} diff --git a/src/eu/engys/core/project/state/PhaseBuilder.java b/src/eu/engys/core/project/state/PhaseBuilder.java new file mode 100644 index 0000000..72e3b84 --- /dev/null +++ b/src/eu/engys/core/project/state/PhaseBuilder.java @@ -0,0 +1,99 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import static eu.engys.core.modules.materials.MaterialsDatabase.AIR; +import static eu.engys.core.modules.materials.MaterialsDatabase.MERCURY; +import static eu.engys.core.modules.materials.MaterialsDatabase.OIL; +import static eu.engys.core.modules.materials.MaterialsDatabase.WATER; +import eu.engys.core.project.Model; +import eu.engys.core.project.materials.Material; +import eu.engys.core.project.materials.Materials; + +public class PhaseBuilder { + + public static void saveDefaultMaterialsToProject(Model model) { + model.getMaterials().clear(); + if (model.getState().getMultiphaseModel().isMultiphase()) { + checkMultiMaterials(model); + } else { + check1Material(model); + } + } + + private static void check1Material(Model model) { + Materials materials = model.getMaterials(); + if (materials.isEmpty()) { + materials.add(getMaterial(model, AIR)); + } else if (materials.size() > 1) { + int airIndex = 0; + for (int i = 0; i < materials.size(); i++) { + if (materials.get(i).getName().equals(AIR)) { + airIndex = i; + break; + } + } + for (int i = 0; i < materials.size(); i++) { + if (i != airIndex) { + materials.remove(i); + } + } + } + model.materialsChanged(); + } + + private static void checkMultiMaterials(Model model) { + Materials materials = model.getMaterials(); + materials.clear(); + + Material[] knownMaterials = null; + if(model.getState().isIncompressible()){ + knownMaterials = new Material[] { getMaterial(model, AIR), getMaterial(model, WATER), getMaterial(model, OIL), getMaterial(model, MERCURY) }; + } else { + knownMaterials = new Material[] { getMaterial(model, AIR), getMaterial(model, WATER) }; + } + + int phases = model.getState().getPhases(); + + for (int i = 0; i < Math.min(phases, knownMaterials.length); i++) { + materials.add(knownMaterials[i]); + } + for (int i = Math.min(phases, knownMaterials.length); i < phases; i++) { + materials.add(new Material("Air" + i, knownMaterials[0].getDictionary())); + } + + model.materialsChanged(); + } + + public static Material getMaterial(Model model, String materialName) { + if (model.getState().isCompressible()) { + return new Material(materialName, model.getMaterialsDatabase().getCompressibleMaterial(materialName)); + } else { + return new Material(materialName, model.getMaterialsDatabase().getIncompressibleMaterial(materialName)); + } + } + +} diff --git a/src/eu/engys/core/project/state/PhasesNumber.java b/src/eu/engys/core/project/state/PhasesNumber.java new file mode 100644 index 0000000..0a1d32f --- /dev/null +++ b/src/eu/engys/core/project/state/PhasesNumber.java @@ -0,0 +1,45 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public class PhasesNumber { + private int preferredPhases; + private boolean changePhases; + + public PhasesNumber(int preferredPhases, boolean changePhases) { + this.preferredPhases = preferredPhases; + this.changePhases = changePhases; + } + + public int getPreferredPhases() { + return preferredPhases; + } + + public boolean canChangePhases() { + return changePhases; + } + +} diff --git a/src/eu/engys/core/project/state/ServerState.java b/src/eu/engys/core/project/state/ServerState.java new file mode 100644 index 0000000..c67ae7a --- /dev/null +++ b/src/eu/engys/core/project/state/ServerState.java @@ -0,0 +1,100 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import java.io.Serializable; + +import eu.engys.core.controller.Command; +import eu.engys.core.executor.ExecutorError; +import eu.engys.core.project.SolverState; + +public class ServerState implements Serializable { + + public static final String SOLVER_STATE = "solverState"; + public static final String COMMAND = "command"; + public static final String ERROR = "error"; + + private Command command = Command.NONE; + private SolverState solverState = SolverState.FINISHED; + private ExecutorError error = null; + + public ServerState() { + } + + public ServerState(Command command, SolverState solverState) { + this.command = command; + this.solverState = solverState; + } + + public ServerState(Command command, SolverState solverState, ExecutorError error) { + this.command = command; + this.solverState = solverState; + this.error = error; + } + + public ServerState(ServerState remoteState) { + this.command = remoteState.getCommand(); + this.solverState = remoteState.getSolverState(); + } + + public Command getCommand() { + return command; + } + + public void setCommand(Command command) { + this.command = command; + } + + public SolverState getSolverState() { + return solverState; + } + + public void setSolverState(SolverState solverState) { + this.solverState = solverState; + } + + public ExecutorError getError() { + return error; + } + + public void setError(ExecutorError error) { + this.error = error; + } + + @Override + public String toString() { + return command + " [State: " + solverState + ", Exit Value: " + (error != null ? error : "") + "]"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ServerState) { + ServerState state = (ServerState) obj; + return this.command.equals(state.command) && this.solverState.equals(state.solverState); + } + return super.equals(obj); + } +} diff --git a/src/eu/engys/core/project/state/SolutionState.java b/src/eu/engys/core/project/state/SolutionState.java new file mode 100644 index 0000000..2855250 --- /dev/null +++ b/src/eu/engys/core/project/state/SolutionState.java @@ -0,0 +1,122 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import eu.engys.util.ui.ChooserPanel; + +public class SolutionState { + + public static final String NONE = "NONE"; + public static final String TRANSIENT = "Transient"; + public static final String STEADY = "Steady"; + public static final String INCOMPRESSIBLE = "Incompressible"; + public static final String COMPRESSIBLE = "Compressible"; + public static final String SEGREGATED = "Segregated"; + public static final String COUPLED = "Coupled"; + public static final String LES_DES = "LES/DES"; + public static final String RANS = "RANS"; + public static final String HI_MACH = "High"; + public static final String LO_MACH = "Low"; + + public String time; + public String flow; + public String turbulence; + public String solver; + public String mach; + + public SolutionState() { + this.time = NONE; + this.flow = NONE; + this.turbulence = NONE; + this.solver = NONE; + this.mach = NONE; + } + + public SolutionState(State state) { + this.time = state.isSteady() ? STEADY : state.isTransient() ? TRANSIENT : NONE; + this.flow = state.isCompressible() ? COMPRESSIBLE : state.isIncompressible() ? INCOMPRESSIBLE : NONE; + this.turbulence = state.isRANS() ? RANS : state.isLES() ? LES_DES : NONE; + this.solver = state.isCoupled() ? COUPLED : state.isSegregated() ? SEGREGATED : NONE; + this.mach = state.isHighMach() ? SolutionState.HI_MACH : state.isLowMach() ? SolutionState.LO_MACH : NONE; + } + + public boolean areSolverTypeAndTimeAndFlowAndTurbulenceChoosen() { + boolean timeChoosen = time != ChooserPanel.NONE; + boolean flowChoosen = flow != ChooserPanel.NONE; + boolean turbulenceChoosen = turbulence != ChooserPanel.NONE; + boolean solverTypeChoosen = solver != ChooserPanel.NONE; + return solverTypeChoosen && timeChoosen && flowChoosen && turbulenceChoosen; + } + + public boolean isLowMach() { + return mach.equals(SolutionState.LO_MACH); + } + public boolean isHighMach() { + return mach.equals(SolutionState.HI_MACH); + } + public boolean isMachNone() { + return mach.equals(NONE); + } + + public boolean isLES() { + return turbulence.equals(SolutionState.LES_DES); + } + public boolean isRANS() { + return turbulence.equals(SolutionState.RANS); + } + + public boolean isTransient() { + return time.equals(SolutionState.TRANSIENT); + } + public boolean isSteady() { + return time.equals(SolutionState.STEADY); + } + public boolean isTimeNone() { + return time.equals(NONE); + } + + + public boolean isSegregated() { + return solver == SolutionState.SEGREGATED; + } + public boolean isCoupled() { + return solver == SolutionState.COUPLED; + } + public boolean isSolverNone() { + return solver == NONE; + } + + public boolean isIncompressible() { + return flow == SolutionState.INCOMPRESSIBLE; + } + public boolean isCompressible() { + return flow == SolutionState.COMPRESSIBLE; + } + public boolean isFlowNone() { + return flow == NONE; + } + +} diff --git a/src/eu/engys/core/project/state/Solver.java b/src/eu/engys/core/project/state/Solver.java new file mode 100644 index 0000000..a0c9df3 --- /dev/null +++ b/src/eu/engys/core/project/state/Solver.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public class Solver { + + private final String name; + + public static Solver NONE = new Solver(""); + + public Solver(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } + + public boolean isNone() { + return name.isEmpty(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Solver) { + if (obj == this) { + return true; + } + Solver solver = (Solver) obj; + return solver.getName().equals(name); + } + return false; + } + +} diff --git a/src/eu/engys/core/project/state/SolverFamily.java b/src/eu/engys/core/project/state/SolverFamily.java new file mode 100644 index 0000000..f7923ae --- /dev/null +++ b/src/eu/engys/core/project/state/SolverFamily.java @@ -0,0 +1,75 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public enum SolverFamily { + + COUPLED("Coupled"), + SIMPLE("Simple"), + PISO("Piso"), + PIMPLE("Pimple"), + CENTRAL("Central"), + NONE("None"); + + private String text; + + private SolverFamily(String text) { + this.text = text; + } + + public boolean isCoupled() { + return this == COUPLED; + } + + public boolean isSimple() { + return this == SIMPLE; + } + + public boolean isPimple() { + return this == PIMPLE; + } + + public boolean isPiso() { + return this == PISO; + } + + public boolean isCentral() { + return this == CENTRAL; + } + + public boolean isNone() { + return this == NONE; + } + + public String getKey() { + return text.toUpperCase(); + } + + @Override + public String toString() { + return text; + } +} diff --git a/src/eu/engys/core/project/state/SolverType.java b/src/eu/engys/core/project/state/SolverType.java new file mode 100644 index 0000000..2591787 --- /dev/null +++ b/src/eu/engys/core/project/state/SolverType.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public enum SolverType { + COUPLED("Coupled"), SEGREGATED("Segregated"), NONE("None"); + + private String text; + + private SolverType(String text) { + this.text = text; + } + + public boolean isCoupled() { + return this == COUPLED; + } + + public boolean isSegregated() { + return this == SEGREGATED; + } + + public boolean isNone() { + return this == NONE; + } + + @Override + public String toString() { + return text; + } +} diff --git a/src/eu/engys/core/project/state/State.java b/src/eu/engys/core/project/state/State.java new file mode 100644 index 0000000..59118ef --- /dev/null +++ b/src/eu/engys/core/project/state/State.java @@ -0,0 +1,405 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import eu.engys.core.project.TurbulenceModel; + +public class State { + + public State() { + + } + + private Time time = Time.NONE; + private Flow flow = Flow.NONE; + private Method method = Method.NONE; + private Mach mach = Mach.NONE; + private Solver solver = Solver.NONE; + private SolverType solverType = SolverType.NONE; + private SolverFamily solverFamily = SolverFamily.NONE; + + private boolean energy; + private boolean buoyant; + private MultiphaseModel multiphaseModel = MultiphaseModel.OFF; + + private int phases = 1; + + private TurbulenceModel turbulenceModel; + + @Override + public String toString() { + return solver + " - " + solverFamily + " - " + time + " - " + flow + " - " + method + (energy ? " - energy" : "") + (buoyant ? " - buoyant" : "") + " - multiphase: "+ multiphaseModel.getLabel() + " with " + phases + " phases" + " - " + mach + "_MACH"; + } + + public Mach getMach() { + return mach; + } + + public void setMach(Mach mach) { + this.mach = mach; + } + + public Method getMethod() { + return method; + } + + public void setMethod(Method method) { + this.method = method; + } + + public Time getTime() { + return time; + } + + public void setTime(Time time) { + this.time = time; + } + + public Flow getFlow() { + return flow; + } + + public void setFlow(Flow flow) { + this.flow = flow; + } + + public void setTimeToSteady() { + this.time = Time.STEADY; + } + + public void setTimeToTransient() { + this.time = Time.TRANSIENT; + } + + public void setTimeToNone() { + this.time = Time.NONE; + } + + public boolean isSteady() { + return time.isSteady(); + } + + public boolean isTransient() { + return time.isTransient(); + } + + public void setFlowToCompressible() { + this.flow = Flow.COMPRESSIBLE; + } + + public void setFlowToIncompressible() { + this.flow = Flow.INCOMPRESSIBLE; + } + + public void setFlowToNONE() { + this.flow = Flow.NONE; + } + + public boolean isCompressible() { + return flow.isCompressible(); + } + + public boolean isIncompressible() { + return flow.isIncompressible(); + } + + public void setMethodToLES() { + this.method = Method.LES; + } + + public void setMethodToRANS() { + this.method = Method.RANS; + } + + public void setMethodToNONE() { + this.method = Method.NONE; + } + + public boolean isLES() { + return method.isLes(); + } + + public boolean isRANS() { + return method.isRans(); + } + + public void setEnergy(boolean energy) { + this.energy = energy; + } + + public boolean isEnergy() { + return energy; + } + + public void setToHighMach() { + this.mach = Mach.HIGH; + } + + public void setToLowMach() { + this.mach = Mach.LOW; + } + + public boolean isLowMach() { + return mach.isLow(); + } + + public boolean isHighMach() { + return mach.isHigh(); + } + + public void setBuoyant(boolean buoyant) { + this.buoyant = buoyant; + } + + public boolean isBuoyant() { + return buoyant; + } + + public TurbulenceModel getTurbulenceModel() { + return turbulenceModel; + } + + public void setTurbulenceModel(TurbulenceModel turbulenceModel) { + this.turbulenceModel = turbulenceModel; + } + + public MultiphaseModel getMultiphaseModel() { + return multiphaseModel; + } + + public void setMultiphaseModel(MultiphaseModel multiphase) { + this.multiphaseModel = multiphase; + } + + public int getPhases() { + return phases; + } + + public void setPhases(int phases) { + this.phases = phases; + } + + public boolean areTimeAndFlowAndTurbulenceChoosen() { + boolean timeChoosen = !time.isNone(); + boolean flowChoosen = !flow.isNone(); + boolean turbulenceChoosen = !method.isNone(); + return timeChoosen && flowChoosen && turbulenceChoosen; + } + + public Solver getSolver() { + return solver; + } + + public void setSolver(Solver solver) { + this.solver = solver; + } + + public SolverType getSolverType() { + return solverType; + } + + public void setSolverType(SolverType solverType) { + this.solverType = solverType; + } + + public boolean isCoupled() { + return solverType.isCoupled(); + } + + public boolean isSegregated() { + return solverType.isSegregated(); + } + + public SolverFamily getSolverFamily() { + return solverFamily; + } + + public void setSolverFamily(SolverFamily solverFamily) { + this.solverFamily = solverFamily; + } + + public void stringToState(String string) { + String[] tokens = string.replace("(", "").replace(")", "").split("\\s+"); + + for (String token : tokens) { + switch (token.trim()) { + case "COUPLED": + setSolverType(SolverType.COUPLED); + setSolverFamily(SolverFamily.COUPLED); + break; + case "SIMPLE": + setTimeToSteady(); + setSolverType(SolverType.SEGREGATED); + setSolverFamily(SolverFamily.SIMPLE); + break; + case "PISO": + setTimeToTransient(); + setSolverType(SolverType.SEGREGATED); + setSolverFamily(SolverFamily.PISO); + break; + case "PIMPLE": + setTimeToTransient(); + setSolverType(SolverType.SEGREGATED); + setSolverFamily(SolverFamily.PIMPLE); + break; + case "CENTRAL": + setTimeToTransient(); + setSolverType(SolverType.SEGREGATED); + setSolverFamily(SolverFamily.CENTRAL); + break; + + case "steady": + setTimeToSteady(); + setSolverType(SolverType.SEGREGATED); + setSolverFamily(SolverFamily.SIMPLE); + break; + case "transient": + setTimeToTransient(); + setSolverType(SolverType.SEGREGATED); + setSolverFamily(SolverFamily.PIMPLE); + break; + + case "compressible": + setEnergy(true); + setFlowToCompressible(); + break; + case "incompressible": + setFlowToIncompressible(); + break; + + case "hiMach": + setToHighMach(); + break; + + case "buoyant": + setBuoyant(true); + setEnergy(true); + break; + +// case "multiphase": +// setMultiphase(true); +// setBuoyant(true); +// break; + + case "ras": + setMethodToRANS(); + setToLowMach(); + break; + case "les": + setMethodToLES(); + setToLowMach(); + break; + + default: + break; + } + } + Solver solver = new Solver(""); + setSolver(solver); + } + + private static final String SPACE = " "; + + /** + * + * @param state + * + * @return (steady incompressible ras) + */ + public String state2String() { + StringBuffer sb = new StringBuffer(); + + sb.append("( "); + + appendState(sb); + + sb.append(")"); + + return sb.toString(); + } + + public void appendState(StringBuffer sb) { + if (isSteady()) { + if (solverType.isCoupled()) { + sb.append("steady"); + sb.append(SPACE); + sb.append("COUPLED"); + } else { + sb.append("SIMPLE"); + } + } else if (isTransient()) { + if (solverType.isCoupled()) { + sb.append("transient"); + sb.append(SPACE); + sb.append("COUPLED"); + } else { + if (solverFamily.isPimple()) { + sb.append("PIMPLE"); + } else if (solverFamily.isCentral()) { + sb.append("CENTRAL"); + } else if (solverFamily.isPiso()) { + sb.append("PISO"); + } + } + } + + sb.append(SPACE); + + if (isCompressible()) + sb.append("compressible"); + else if (isIncompressible()) + sb.append("incompressible"); + + sb.append(SPACE); + + if (isLES()) + sb.append("les"); + else if (isRANS()) + sb.append("ras"); + + if (isHighMach()) { + sb.append(SPACE); + sb.append("hiMach"); + } + + if (getMultiphaseModel().isOn()) { + sb.append(SPACE); + sb.append(getMultiphaseModel().getKey()); + } else { + if (isCompressible()) { + if (isBuoyant()) { + sb.append(SPACE); + sb.append("buoyant"); + } + } else { + if (isEnergy()) { + sb.append(SPACE); + sb.append("buoyant"); + } + } + } + } +} diff --git a/src/eu/engys/core/project/state/StateBuilder.java b/src/eu/engys/core/project/state/StateBuilder.java new file mode 100644 index 0000000..f770c66 --- /dev/null +++ b/src/eu/engys/core/project/state/StateBuilder.java @@ -0,0 +1,542 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import static eu.engys.core.project.constant.ConstantFolder.CONSTANT; +import static eu.engys.core.project.constant.ConstantFolder.FREE_SURFACE_PROPERTIES; +import static eu.engys.core.project.constant.ConstantFolder.G; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMOPHYSICAL_PROPERTIES; +import static eu.engys.core.project.constant.TransportProperties.MATERIAL_NAME_KEY; +import static eu.engys.core.project.constant.TransportProperties.PHASE1_KEY; +import static eu.engys.core.project.constant.TransportProperties.PHASE2_KEY; +import static eu.engys.core.project.constant.TransportProperties.PHASES_KEY; +import static eu.engys.core.project.constant.TransportProperties.TRANSPORT_MODEL_KEY; +import static eu.engys.core.project.constant.TransportProperties.TRANSPORT_PROPERTIES; +import static eu.engys.core.project.constant.TurbulenceProperties.TURBULENCE_PROPERTIES; +import static eu.engys.core.project.system.ControlDict.CONTROL_DICT; +import static eu.engys.core.project.system.FvSchemes.BACKWARD; +import static eu.engys.core.project.system.FvSchemes.DEFAULT; +import static eu.engys.core.project.system.FvSchemes.EULER; +import static eu.engys.core.project.system.FvSchemes.FV_SCHEMES; +import static eu.engys.core.project.system.FvSchemes.LOCAL_EULER_RDELTAT; +import static eu.engys.core.project.system.FvSchemes.STEADY_STATE; +import static eu.engys.core.project.system.FvSolution.FV_SOLUTION; +import static eu.engys.core.project.system.SystemFolder.SYSTEM; + +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.TurbulenceModel; +import eu.engys.core.project.TurbulenceModels; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.constant.ConstantFolder; +import eu.engys.core.project.constant.ThermophysicalProperties; +import eu.engys.core.project.constant.TransportProperties; +import eu.engys.core.project.constant.TurbulenceProperties; +import eu.engys.core.project.defaults.DefaultsProvider; +import eu.engys.core.project.system.FvSchemes; +import eu.engys.core.project.system.FvSolution; +import eu.engys.core.project.system.SystemFolder; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.fields.FieldsDefaults; +import eu.engys.core.project.zero.patches.BoundaryConditionsDefaults; +import eu.engys.util.progress.ProgressMonitor; + +public class StateBuilder { + + private static final Logger logger = LoggerFactory.getLogger(StateBuilder.class); + + public static void changeState(Model model, Set modules) { + logger.info("Project: clear"); + clearProject(model); + + logger.info("Turbulence: saveDefaultsToProject"); + TurbulenceBuilder.saveDefaultsToProject(model, model.getDefaults()); + + logger.info("Modules: saveDefaultsTurbulenceModelsToProject"); + ModulesUtil.saveDefaultsTurbulenceModelsToProject(modules); + + logger.info("State: saveDefaultsToProject"); + StateBuilder.saveDefaultsToProject(model, model.getDefaults()); + + logger.info("Modules: saveDefaultsToProject"); + ModulesUtil.saveDefaultsToProject(modules); + + logger.info("Materials: saveMaterialsToProject"); + PhaseBuilder.saveDefaultMaterialsToProject(model); + + logger.info("Modules: saveMaterialsToProject"); + ModulesUtil.saveDefaultMaterialsToProject(modules); + + logger.info("Fields: clear"); + FieldsDefaults.prepareFields(model.getFields()); + + Fields fields = new Fields(); + if (model.getProject().isParallel()) { + fields.newParallelFields(model.getProject().getProcessors()); + } + + logger.info("Fields: loadFieldsFromDefaults"); + fields.merge(FieldsDefaults.loadFieldsFromDefaults(model.getState(), model.getDefaults(), model.getPatches(), null)); + + logger.info("Modules: loadFieldsFromDefaults"); + fields.merge(ModulesUtil.loadFieldsFromDefaults(modules, null)); + + fields.fixPVisibility(model.getState()); + + model.setFields(fields); + + logger.info("Boundary Conditions: loadBoundaryConditionsFromFields"); + BoundaryConditionsDefaults.loadBoundaryConditionsFromFields(model.getPatches(), model.getFields()); + + logger.info("Boundary Conditions: updateBoundaryConditionsDefaultsByFields"); + BoundaryConditionsDefaults.updateBoundaryConditionsDefaultsByFields(model); + + logger.info("Fire State Changed"); + model.stateChanged(); + + logger.info("FINISHED"); + } + + public static void changeMaterial(Model model, Set modules) { + logger.info("Modules: saveMaterialsToProject"); + ModulesUtil.saveDefaultMaterialsToProject(modules); + + logger.info("Fields: clear"); + FieldsDefaults.prepareFields(model.getFields()); + + Fields fields = new Fields(); + + logger.info("Fields: loadFieldsFromDefaults"); + fields.merge(FieldsDefaults.loadFieldsFromDefaults(model.getState(), model.getDefaults(), model.getPatches(), null)); + + logger.info("Modules: loadFieldsFromDefaults"); + fields.merge(ModulesUtil.loadFieldsFromDefaults(modules, null)); + + fields.fixPVisibility(model.getState()); + + model.setFields(fields); + + logger.info("Boundary Conditions: loadBoundaryConditionsFromFields"); + BoundaryConditionsDefaults.loadBoundaryConditionsFromFields(model.getPatches(), model.getFields()); + + logger.info("Boundary Conditions: updateBoundaryConditionsDefaultsByFields"); + BoundaryConditionsDefaults.updateBoundaryConditionsDefaultsByFields(model); + + logger.info("Fire Materials Changed"); + model.materialsChanged(); + + logger.info("FINISHED"); + } + + public static void saveDefaultsToProject(Model model, DefaultsProvider defaults) { + Dictionary stateDictionary = defaults.getDefaultsFor(model.getState()); + saveToProject(model, stateDictionary); + } + + private static void saveToProject(Model model, Dictionary stateDict) { + if (stateDict == null) + return; + + openFOAMProject prj = model.getProject(); + if (stateDict.found(SYSTEM)) { + Dictionary systemDict = stateDict.subDict(SYSTEM); + if (systemDict.isDictionary(CONTROL_DICT)) { + if (prj.getSystemFolder().getControlDict() == null) + prj.getSystemFolder().setControlDict(systemDict.subDict(CONTROL_DICT)); + else + prj.getSystemFolder().getControlDict().merge(systemDict.subDict(CONTROL_DICT)); + } else { + /* error */ + } + if (systemDict.isDictionary(FV_SCHEMES)) { + if (prj.getSystemFolder().getFvSchemes() == null) + prj.getSystemFolder().setFvSchemes(systemDict.subDict(FV_SCHEMES)); + else + prj.getSystemFolder().getFvSchemes().merge(systemDict.subDict(FV_SCHEMES)); + } else { + /* error */ + } + if (systemDict.isDictionary(FV_SOLUTION)) { + if (prj.getSystemFolder().getFvSolution() == null) { + prj.getSystemFolder().setFvSolution(systemDict.subDict(FV_SOLUTION)); + } else { + prj.getSystemFolder().getFvSolution().merge(systemDict.subDict(FV_SOLUTION)); + } + } else { + /* error */ + } + } + + if (stateDict.found(CONSTANT)) { + Dictionary constantDict = stateDict.subDict(CONSTANT); + + if (constantDict.isDictionary(G)) { + if (prj.getConstantFolder().getG() == null) + prj.getConstantFolder().setG(constantDict.subDict(G)); + else + prj.getConstantFolder().getG().merge(constantDict.subDict(G)); + } + if (constantDict.isDictionary(THERMOPHYSICAL_PROPERTIES)) { + if (prj.getConstantFolder().getThermophysicalProperties() == null) + prj.getConstantFolder().setThermophysicalProperties(constantDict.subDict(THERMOPHYSICAL_PROPERTIES)); + else + prj.getConstantFolder().getThermophysicalProperties().merge(constantDict.subDict(THERMOPHYSICAL_PROPERTIES)); + } + if (constantDict.isDictionary(TRANSPORT_PROPERTIES)) { + if (prj.getConstantFolder().getTransportProperties() == null) + prj.getConstantFolder().setTransportProperties(constantDict.subDict(TRANSPORT_PROPERTIES)); + else + prj.getConstantFolder().getTransportProperties().merge(constantDict.subDict(TRANSPORT_PROPERTIES)); + } + if (constantDict.isDictionary(TURBULENCE_PROPERTIES)) { + if (prj.getConstantFolder().getTurbulenceProperties() == null) + prj.getConstantFolder().setTurbulenceProperties(constantDict.subDict(TURBULENCE_PROPERTIES)); + else + prj.getConstantFolder().getTurbulenceProperties().merge(constantDict.subDict(TURBULENCE_PROPERTIES)); + } + } + } + + /* + * Load + */ + + public static void loadState(Model model, Table15 solversTable, ProgressMonitor monitor) { + SystemFolder systemFolder = model.getProject().getSystemFolder(); + + if (systemFolder != null) { + FvSchemes fvSchemes = systemFolder.getFvSchemes(); + FvSolution fvSolution = systemFolder.getFvSolution(); + + SolverType solverType = readSolverType(fvSolution); + model.getState().setSolverType(solverType); + + Time time = readTime(model, solverType, fvSchemes, monitor); + model.getState().setTime(time); + + Mach mach = readMach(fvSolution, monitor); + model.getState().setMach(mach); + } + + ConstantFolder constantFolder = model.getProject().getConstantFolder(); + if (constantFolder != null) { + Method method = readMethod(constantFolder); + model.getState().setMethod(method); + + ThermophysicalProperties compressible = constantFolder.getThermophysicalProperties(); + TransportProperties incompressible = constantFolder.getTransportProperties(); + + Flow flow = readFlow(compressible, incompressible); + model.getState().setFlow(flow); + + model.getState().setMultiphaseModel(MultiphaseModel.OFF); + + boolean multiphase = readMultiphase(constantFolder); + + boolean energy = readEnergy(model.getState(), constantFolder, multiphase); + model.getState().setEnergy(energy); + + boolean buoyancy = readBuoyancy(model.getState(), constantFolder, multiphase); + model.getState().setBuoyant(buoyancy); + + TurbulenceModel turbulenceModel = readTurbulenceModel(model, model.getState().getSolverType(), constantFolder, monitor); + model.getState().setTurbulenceModel(turbulenceModel); + } + + if (systemFolder != null) { + FvSolution fvSolution = systemFolder.getFvSolution(); + + SolverFamily solverFamily = readSolverFamily(model.getState(), fvSolution); + model.getState().setSolverFamily(solverFamily); + } + + monitor.info(model.getState().toString(), 1); + } + + private static SolverType readSolverType(FvSolution fvSolution) { + if (fvSolution != null) { + if (fvSolution.found(FvSolution.COUPLED)) { + return SolverType.COUPLED; + } else { + return SolverType.SEGREGATED; + } + } else { + return SolverType.NONE; + } + } + + private static SolverFamily readSolverFamily(State state, FvSolution fvSolution) { + if (state.getSolverType().isSegregated()) { + if (state.isLowMach()) { + if (state.isSteady()) { + if (fvSolution != null && fvSolution.found(FvSolution.PIMPLE)) { + return SolverFamily.PIMPLE; + } else { + return SolverFamily.SIMPLE; + } + } else if (state.isTransient()) { + if (state.isCompressible()) { + return SolverFamily.PIMPLE; + } else if (state.isIncompressible()) { + if (state.isEnergy() || state.getMultiphaseModel().isMultiphase()) { + return SolverFamily.PIMPLE; + } else { + if (fvSolution != null && fvSolution.found(FvSolution.PISO)) { + return SolverFamily.PISO; + } else { + return SolverFamily.PIMPLE; + } + } + } else { + return SolverFamily.NONE; + } + } else { + return SolverFamily.NONE; + } + } else if (state.isHighMach()) { + if (fvSolution != null && fvSolution.found(FvSolution.PIMPLE)) { + return SolverFamily.PIMPLE; + } else { + return SolverFamily.CENTRAL; + } + } else { + return SolverFamily.NONE; + } + } else if (state.getSolverType().isCoupled()) { + return SolverFamily.COUPLED; + } else { + return SolverFamily.NONE; + } + } + + private static Time readTime(Model model, SolverType solverType, FvSchemes fvSchemes, ProgressMonitor monitor) { + if (fvSchemes != null) { + Dictionary ddtSchemes = fvSchemes.getDdtSchemes(); + if (ddtSchemes != null) { + if (ddtSchemes.found(DEFAULT)) { + String timeField = ddtSchemes.lookup(DEFAULT); + if (solverType.isCoupled()) { + if (timeField.equals(EULER)) { + return Time.STEADY; + } else if (timeField.equals(BACKWARD)) { + return Time.TRANSIENT; + } + } else if (solverType.isSegregated()) { + if (timeField.equals(STEADY_STATE) || timeField.equals(LOCAL_EULER_RDELTAT)) { + return Time.STEADY; + } else { + return Time.TRANSIENT; + } + } + } else { + monitor.warning("ddtSchemes: bad file structure", 1); + } + } else { + monitor.warning("fvSchemes: no ddtScheme found.", 1); + } + } else { + monitor.warning("fvSchemes: not found", 1); + } + return Time.NONE; + } + + private static Mach readMach(FvSolution fvSolution, ProgressMonitor monitor) { + if (fvSolution != null) { + String sonic = fvSolution.lookup("sonic"); + if ("true".equals(sonic)) { + return Mach.HIGH; + } else { + return Mach.LOW; + } + } else { + monitor.warning("fvSolution: not found", 1); + return Mach.LOW; + } + } + + private static Method readMethod(ConstantFolder constantFolder) { + Dictionary turbPropDict = constantFolder.getTurbulenceProperties(); + if (turbPropDict != null && turbPropDict.found(TurbulenceProperties.SIMULATION_TYPE)) { + String turbType = turbPropDict.lookup(TurbulenceProperties.SIMULATION_TYPE); + if (turbType.startsWith(TurbulenceProperties.RAS)) { + return Method.RANS; + } else if (turbType.startsWith(TurbulenceProperties.LES)) { + return Method.LES; + } else if (turbType.startsWith(TurbulenceProperties.LAMINAR)) { + Dictionary RASProperties = constantFolder.getRASProperties(); + Dictionary LESProperties = constantFolder.getLESProperties(); + if (RASProperties != null && !RASProperties.isEmpty()) { + return Method.RANS; + } else if (LESProperties != null && !LESProperties.isEmpty()) { + return Method.LES; + } + } + } + return Method.NONE; + } + + private static Flow readFlow(ThermophysicalProperties compressible, TransportProperties incompressible) { + if (compressible != null && compressible.found(ThermophysicalProperties.THERMO_TYPE_KEY)) { + return Flow.COMPRESSIBLE; + } else if (incompressible != null) { + if (incompressible.found(TRANSPORT_MODEL_KEY) || incompressible.found(PHASE1_KEY) || incompressible.found(PHASES_KEY)) { + return Flow.INCOMPRESSIBLE; + } + } + return Flow.NONE; + } + + private static boolean readMultiphase(ConstantFolder constantFolder) { + TransportProperties incompressible = constantFolder.getTransportProperties(); + if (incompressible != null) { + if ((incompressible.found(PHASE1_KEY) && incompressible.found(PHASE2_KEY)) || incompressible.found(PHASES_KEY)) { + return true; + } else if (constantFolder.getFileManager().getFile(FREE_SURFACE_PROPERTIES).exists()) { + return true; + } else if (incompressible.found(MATERIAL_NAME_KEY)) { + return false; + } + } + return false; + } + + private static boolean readEnergy(State state, ConstantFolder constantFolder, boolean isMultiphase) { + Dictionary g = constantFolder.getG(); + if (g != null && g.found("value")) { + if (isMultiphase) { + return false; + } else { + return true; + } + } else { + return state.isCompressible(); + } + } + + private static boolean readBuoyancy(State state, ConstantFolder constantFolder, boolean isMultiphase) { + Dictionary g = constantFolder.getG(); + if (g != null && g.found("value")) { + if (isMultiphase) { + return false; + } else { + return isBuoyant(g); + } + } else { + return false; + } + } + + private static TurbulenceModel readTurbulenceModel(Model model, SolverType solverType, ConstantFolder constantFolder, ProgressMonitor monitor) { + if (model.getState().isLES()) { + Dictionary LESProperties = constantFolder.getLESProperties(); + if (LESProperties != null) { + String lesModel = LESProperties.lookup("LESModel"); + return readTurbulenceModelFromState(model, solverType, lesModel, monitor); + } + } else if (model.getState().isRANS()) { + Dictionary RASProperties = constantFolder.getRASProperties(); + if (RASProperties != null) { + String rasModel = RASProperties.lookup("RASModel"); + return readTurbulenceModelFromState(model, solverType, rasModel, monitor); + } + } + return null; + } + + public static TurbulenceModel readTurbulenceModelFromState(Model model, SolverType solverType, String modelName, ProgressMonitor monitor) { + TurbulenceModels turbulenceModels = model.getTurbulenceModels(); + Method method = model.getState().getMethod(); + Flow flow = model.getState().getFlow(); + logger.info("Loading Turbulence model for {} {} {}", solverType, method, flow); + List modelsForState = turbulenceModels.getModelsForState(solverType, method, flow); + if (modelsForState != null && !modelsForState.isEmpty()) { + + TurbulenceModel turbulenceModel = new TurbulenceModel(); + turbulenceModel.setName(modelName); + + int index = modelsForState.indexOf(turbulenceModel); + if (index >= 0) { + return modelsForState.get(index); + } else { + TurbulenceModel firstTurbulenceModel = modelsForState.get(0); + monitor.warning(String.format("%s not found. Changed to %s", modelName, firstTurbulenceModel), 1); + return firstTurbulenceModel; + } + } else { + monitor.warning("Turbulence models not loaded", 1); + return null; + } + } + + private static boolean isBuoyant(Dictionary g) { + String[] gValues = g.lookupArray("value"); + try { + double x = Double.parseDouble(gValues[0]); + double y = Double.parseDouble(gValues[1]); + double z = Double.parseDouble(gValues[2]); + + if (x == 0 && y == 0 && z == 0) { + return false; + } else { + return true; + } + } catch (Exception e) { + return true; + } + } + + /* + * Other + */ + + private static void clearProject(Model model) { + openFOAMProject prj = model.getProject(); + if (prj.getSystemFolder().getControlDict() != null) + prj.getSystemFolder().getControlDict().clear(); + if (prj.getSystemFolder().getFvSchemes() != null) + prj.getSystemFolder().getFvSchemes().clear(); + if (prj.getSystemFolder().getFvSolution() != null) + prj.getSystemFolder().getFvSolution().clear(); + + prj.getConstantFolder().setG(null); + + if (prj.getConstantFolder().getThermophysicalProperties() != null) + prj.getConstantFolder().getThermophysicalProperties(); + if (prj.getConstantFolder().getTransportProperties() != null) + prj.getConstantFolder().getTransportProperties(); + if (prj.getConstantFolder().getTurbulenceProperties() != null) + prj.getConstantFolder().getTurbulenceProperties().clear(); + } + +} diff --git a/src/eu/engys/core/project/state/StateComposer.java b/src/eu/engys/core/project/state/StateComposer.java new file mode 100644 index 0000000..748bac6 --- /dev/null +++ b/src/eu/engys/core/project/state/StateComposer.java @@ -0,0 +1,175 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import eu.engys.core.project.TurbulenceModel; +import eu.engys.core.project.TurbulenceModelType; + +public class StateComposer { + + private State state; + + public static StateComposer newState() { + StateComposer composer = new StateComposer(); + composer.state = new State(); + composer.state.setSolverType(SolverType.SEGREGATED); + return composer; + } + + public StateComposer coupled() { + state.setSolverType(SolverType.COUPLED); + state.setSolverFamily(SolverFamily.COUPLED); + state.setToLowMach(); + return this; + } + + public StateComposer segregated() { + state.setSolverType(SolverType.SEGREGATED); + return this; + } + + public StateComposer steady() { + state.setTimeToSteady(); + return this; + } + + public StateComposer trans() { + state.setTimeToTransient(); + return this; + } + + public StateComposer compressible() { + state.setFlowToCompressible(); + return this; + } + + public StateComposer incompressible() { + state.setFlowToIncompressible(); + return this; + } + + public StateComposer les() { + state.setMethodToLES(); + state.setToLowMach(); + return this; + } + + public StateComposer rans() { + state.setMethodToRANS(); + state.setToLowMach(); + return this; + } + + public StateComposer hiMach() { + state.setToHighMach(); + return this; + } + + public StateComposer buoyant() { + state.setBuoyant(true); + return this; + } + + public StateComposer energy() { + state.setEnergy(true); + return this; + } + + public StateComposer simple() { + state.setSolverFamily(SolverFamily.SIMPLE); + return this; + } + + public StateComposer pimple() { + state.setSolverFamily(SolverFamily.PIMPLE); + return this; + } + + public StateComposer central() { + state.setSolverFamily(SolverFamily.CENTRAL); + return this; + } + + public StateComposer piso() { + state.setSolverFamily(SolverFamily.PISO); + return this; + } + + public StateComposer multiphaseVOF() { + state.setMultiphaseModel(new MultiphaseModel("VOF", "VOF", true, true)); + return this; + } + + public StateComposer multiphaseEuler() { + state.setMultiphaseModel(new MultiphaseModel("Euler-Euler", "MEF", true, false)); + return this; + } + + public StateComposer multiphaseHydro() { + state.setMultiphaseModel(new MultiphaseModel("Hydro", "HYDRO", true, false)); + return this; + } + + public StateComposer multiphaseECOMARINE() { + state.setMultiphaseModel(new MultiphaseModel("ECOMARINE", "ECOMARINE", false, false)); + return this; + } + + public StateComposer laminar() { + state.setTurbulenceModel(new TurbulenceModel("laminar", TurbulenceModelType.LAMINAR)); + return this; + } + + public StateComposer kEquationEddy() { + state.setTurbulenceModel(new TurbulenceModel("k-Equation Eddy", TurbulenceModelType.K_Equation_Eddy)); + return this; + } + + public StateComposer kOmega() { + state.setTurbulenceModel(new TurbulenceModel("kOmegaSST", TurbulenceModelType.K_Omega)); + return this; + } + + public StateComposer kEpsilon() { + state.setTurbulenceModel(new TurbulenceModel("kEpsilon", TurbulenceModelType.K_Epsilon)); + return this; + } + + public StateComposer spalartAllmaras() { + state.setTurbulenceModel(new TurbulenceModel("SpalartAllmaras", TurbulenceModelType.Spalart_Allmaras)); + return this; + } + + public StateComposer phases(int i) { + state.setPhases(i); + return this; + } + + public State getState() { + return state; + } + +} diff --git a/src/eu/engys/core/project/state/Table15.java b/src/eu/engys/core/project/state/Table15.java new file mode 100644 index 0000000..277e844 --- /dev/null +++ b/src/eu/engys/core/project/state/Table15.java @@ -0,0 +1,48 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import java.util.Set; + +public interface Table15 { + + public static final String BUOYANT_BOUSSINESQ_PIMPLE_FOAM = "buoyantBoussinesqPimpleFoam"; + public static final String BUOYANT_BOUSSINESQ_SIMPLE_FOAM = "buoyantBoussinesqSimpleFoam"; + public static final String BUOYANT_PIMPLE_FOAM = "buoyantPimpleFoam"; + public static final String BUOYANT_SIMPLE_FOAM = "buoyantSimpleFoam"; + public static final String COMPRESSIBLE_INTER_FOAM = "compressibleInterFoam"; + public static final String PIMPLE_FOAM = "pimpleFoam"; + public static final String PISO_FOAM = "pisoFoam"; + public static final String RHO_PIMPLE_FOAM = "rhoPimpleFoam"; + public static final String RHO_SIMPLE_FOAM = "rhoSimpleFoam"; + public static final String SIMPLE_FOAM = "simpleFoam"; + public static final String SONIC_FOAM = "sonicFoam"; + + public void updateSolver(State state); + + public void updateSolverFamilies(State state, Set families); + +} diff --git a/src/eu/engys/core/project/state/ThermalState.java b/src/eu/engys/core/project/state/ThermalState.java new file mode 100644 index 0000000..3fea48f --- /dev/null +++ b/src/eu/engys/core/project/state/ThermalState.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + + +public class ThermalState { + private boolean energy; + private boolean buoyancy; + + public ThermalState() { + this.setEnergy(false); + this.setBuoyancy(false); + } + + public ThermalState(State state) { + this.setEnergy(state.isEnergy()); + this.setBuoyancy(state.isBuoyant()); + } + + public boolean isEnergy() { + return energy; + } + public boolean isBuoyancy() { + return buoyancy; + } + + public void setEnergy(boolean energy) { + this.energy = energy; + } + + public void setBuoyancy(boolean buoyancy) { + this.buoyancy = buoyancy; + } + + @Override + public String toString() { + return "Energy: " + (isEnergy()? "ON" : "OFF") + ", Buoyancy: " + (isBuoyancy()? "ON" : "OFF"); + } +} diff --git a/src/eu/engys/core/project/state/Time.java b/src/eu/engys/core/project/state/Time.java new file mode 100644 index 0000000..ade0d81 --- /dev/null +++ b/src/eu/engys/core/project/state/Time.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +public enum Time { + STEADY("Steady"), TRANSIENT("Transient"), NONE("None"); + + private String text; + + private Time(String text) { + this.text = text; + } + + public boolean isSteady() { + return this == STEADY; + } + + public boolean isTransient() { + return this == TRANSIENT; + } + + public boolean isNone() { + return this == NONE; + } + + @Override + public String toString() { + return text; + } +} diff --git a/src/eu/engys/core/project/state/TurbulenceBuilder.java b/src/eu/engys/core/project/state/TurbulenceBuilder.java new file mode 100644 index 0000000..4e6912a --- /dev/null +++ b/src/eu/engys/core/project/state/TurbulenceBuilder.java @@ -0,0 +1,113 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.state; + +import static eu.engys.core.project.constant.TurbulenceProperties.FIELD_MAPS_KEY; +import static eu.engys.core.project.constant.TurbulenceProperties.LES; +import static eu.engys.core.project.constant.TurbulenceProperties.RAS; +import static eu.engys.core.project.constant.TurbulenceProperties.TURBULENCE_PROPERTIES; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.constant.ConstantFolder; +import eu.engys.core.project.defaults.DefaultsProvider; + +public class TurbulenceBuilder { + + private static final Logger logger = LoggerFactory.getLogger(TurbulenceBuilder.class); + + public static void saveDefaultsToProject(Model model, DefaultsProvider defaults) { + State state = model.getState(); + openFOAMProject project = model.getProject(); + + Dictionary turbPropDict = new Dictionary(TURBULENCE_PROPERTIES); + String turbType = RAS; + if (state.isLES()) { + turbType = LES; + } + turbPropDict.add("simulationType", turbType + "Model"); + + if (state.getTurbulenceModel() != null) { + String modelName = state.getTurbulenceModel().getName(); + + Dictionary turbTypeProp = new Dictionary(turbType + "Properties"); + turbTypeProp.add(turbType + "Model", modelName); + turbTypeProp.add("turbulence", "on"); + turbTypeProp.add("printCoeffs", "on"); + + String dictName = ""; + if (state.getSolverType().isCoupled()) { + dictName = "coupledIncompressibleRAS"; + } else if (state.getSolverType().isSegregated()) { + dictName = (state.isCompressible() ? "compressible" : "incompressible") + turbType; + } + + Dictionary tpp = defaults.getDefaultTurbulenceProperties(); + if (tpp != null && tpp.isDictionary(dictName)) { + logger.info("[ {} provider ]: FOUND {} dictionary", defaults.getName(), dictName); + Dictionary subDict = tpp.subDict(dictName); + + if (subDict.isDictionary(modelName + "Coeffs")) { + // prendo i coefficienti del model dal file dei defaults + logger.info("[ {} provider ]: FOUND {} dictionary", defaults.getName(), modelName); + Dictionary defCoeff = subDict.subDict(modelName + "Coeffs"); + + turbTypeProp.add(new Dictionary(defCoeff)); + turbTypeProp.remove(FIELD_MAPS_KEY); + } else { + logger.warn("[ {} provider ]: Cannot find {} dictionary", defaults.getName(), modelName); + } + } else { + logger.warn("[ {} provider ]: Cannot find {} dictionary", defaults.getName(), dictName); + } + + if (state.isLES()) { + String deltaType = turbTypeProp.subDict(modelName + "Coeffs").lookup("delta"); + // System.out.println("TurbulenceBuilder.build() delta: "+deltaType); + turbTypeProp.add("delta", deltaType); + turbTypeProp.subDict(modelName + "Coeffs").remove("delta"); + + turbTypeProp.add(tpp.subDict(deltaType + "Coeffs")); + } + + ConstantFolder constantFolder = project.getConstantFolder(); + constantFolder.setTurbulenceProperties(turbPropDict); + + if (state.isLES()) { + constantFolder.setLESProperties(turbTypeProp); + } else { + constantFolder.setRASProperties(turbTypeProp); + } + } else { + logger.error("Turbulence Model is NULL!"); + } + + } +} diff --git a/src/eu/engys/core/project/system/BlockMeshDict.java b/src/eu/engys/core/project/system/BlockMeshDict.java new file mode 100644 index 0000000..229ab40 --- /dev/null +++ b/src/eu/engys/core/project/system/BlockMeshDict.java @@ -0,0 +1,198 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.system; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.io.FileUtils; + +import eu.engys.core.dictionary.BlockMeshWriter; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.dictionary.parser.DictionaryReader2; +import eu.engys.core.dictionary.parser.ListField2; +import eu.engys.core.project.geometry.BoundingBox; + +public class BlockMeshDict extends Dictionary { + + public static final String BLOCK_DICT = "blockMeshDict"; + + public static final String BLOCKS_KEY = "blocks"; + public static final String VERTICES_KEY = "vertices"; + public static final String PATCHES_KEY = "patches"; + public static final String SPACING_KEY = "spacing"; + // public static final String FROM_FILE_KEY = "fromFile"; + public static final String BOUNDARY_KEY = "boundary"; + public static final String ELEMENTS_KEY = "elements"; + + public static final String HEX_KEY = "hex"; + public static final String SIMPLE_GRADING_KEY = "simpleGrading"; + public static final String WALL_KEY = "wall"; + public static final String FROM_FILE_LINE = "fromFile true;"; + + private boolean fromFile; + + public BlockMeshDict() { + super(BLOCK_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, BLOCK_DICT)); + } + + public BlockMeshDict(File blockMeshFile) { + super(BLOCK_DICT, blockMeshFile); + } + + public void check() throws DictionaryException { + } + + @Override + protected void readDictionaryFromString(String text) { + new DictionaryReader2(this).read(text); + } + + @Override + public void readDictionary(File file) { + new DictionaryReader2(this).read(file); + } + + @Override + protected String write() { + return new BlockMeshWriter(this).write(); + } + + public void setBoundingBox(BoundingBox boundingBox) { + double xmin = boundingBox.getXmin(); + double xmax = boundingBox.getXmax(); + double ymin = boundingBox.getYmin(); + double ymax = boundingBox.getYmax(); + double zmin = boundingBox.getZmin(); + double zmax = boundingBox.getZmax(); + + if (found(SPACING_KEY)) {// only HELYX-OS + double spacing = Double.valueOf(lookup(SPACING_KEY)); + + boolean emptyBoundingBox = (xmin == 0) && (xmax == 0) && (ymin == 0) && (ymax == 0) && (zmin == 0) && (zmax == 0); + + /* aggiungo un po'di spacing */ + xmin -= spacing; + xmax += spacing; + ymin -= spacing; + ymax += spacing; + zmin -= spacing; + zmax += spacing; + + double xDelta = Math.abs(xmax - xmin); + double yDelta = Math.abs(ymax - ymin); + double zDelta = Math.abs(zmax - zmin); + + int xElements = emptyBoundingBox ? 10 : (int) Math.ceil(xDelta / spacing); + int yElements = emptyBoundingBox ? 10 : (int) Math.ceil(yDelta / spacing); + int zElements = emptyBoundingBox ? 10 : (int) Math.ceil(zDelta / spacing); + + // BLOCKS + + ListField2 blocksList = new ListField2(BLOCKS_KEY); + blocksList.add(new FieldElement("", HEX_KEY)); + + ListField2 hexList = new ListField2(""); + hexList.add(new FieldElement("", "0")); + hexList.add(new FieldElement("", "1")); + hexList.add(new FieldElement("", "2")); + hexList.add(new FieldElement("", "3")); + hexList.add(new FieldElement("", "4")); + hexList.add(new FieldElement("", "5")); + hexList.add(new FieldElement("", "6")); + hexList.add(new FieldElement("", "7")); + blocksList.add(hexList); + + ListField2 elementsList = new ListField2(""); + elementsList.add(new FieldElement("", String.valueOf(xElements))); + elementsList.add(new FieldElement("", String.valueOf(yElements))); + elementsList.add(new FieldElement("", String.valueOf(zElements))); + blocksList.add(elementsList); + + blocksList.add(new FieldElement("", SIMPLE_GRADING_KEY)); + + ListField2 lastList = new ListField2(""); + lastList.add(new FieldElement("", "1")); + lastList.add(new FieldElement("", "1")); + lastList.add(new FieldElement("", "1")); + blocksList.add(lastList); + + add(blocksList); + + // VERTICES + + double[] min = new double[] { xmin, ymin, zmin }; + double[] max = emptyBoundingBox ? new double[] { xmax, ymax, zmax } : new double[] { xmin + xElements * spacing, ymin + yElements * spacing, zmin + zElements * spacing }; + + ListField2 verticesList = new ListField2(VERTICES_KEY); + verticesList.add(getPointList(min[0], min[1], min[2])); + verticesList.add(getPointList(max[0], min[1], min[2])); + verticesList.add(getPointList(max[0], max[1], min[2])); + verticesList.add(getPointList(min[0], max[1], min[2])); + verticesList.add(getPointList(min[0], min[1], max[2])); + verticesList.add(getPointList(max[0], min[1], max[2])); + verticesList.add(getPointList(max[0], max[1], max[2])); + verticesList.add(getPointList(min[0], max[1], max[2])); + + add(verticesList); + } + } + + private ListField2 getPointList(double x, double y, double z) { + ListField2 list = new ListField2(""); + list.add(new FieldElement("", String.valueOf(x))); + list.add(new FieldElement("", String.valueOf(y))); + list.add(new FieldElement("", String.valueOf(z))); + return list; + } + + public boolean isFromFile() { + return fromFile; + } + + public void setFromFile(boolean fromFile) { + this.fromFile = fromFile; + } + + public static boolean containsFromFileLine(File file) { + try { + List lines = FileUtils.readLines(file); + for (String line : lines) { + if (line.trim().equals(BlockMeshDict.FROM_FILE_LINE)) { + return true; + } + } + } catch (IOException e) { + return false; + } + return false; + } +} diff --git a/src/eu/engys/core/project/system/CaseSetupDict.java b/src/eu/engys/core/project/system/CaseSetupDict.java new file mode 100644 index 0000000..fc27318 --- /dev/null +++ b/src/eu/engys/core/project/system/CaseSetupDict.java @@ -0,0 +1,48 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.system; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; + +public class CaseSetupDict extends Dictionary { + + public static final String CASE_SETUP_DICT = "caseSetupDict"; + + public static final String MATERIALS_KEY = "materials"; + public static final String BINARY_PAIR_DATA_KEY = "binaryPairData"; + + public static final String GLOBAL_KEY = "global"; + + public CaseSetupDict() { + super(CASE_SETUP_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, CASE_SETUP_DICT)); + } + + public void check() throws DictionaryException { + } +} diff --git a/src/eu/engys/core/project/system/ControlDict.java b/src/eu/engys/core/project/system/ControlDict.java new file mode 100644 index 0000000..70fa657 --- /dev/null +++ b/src/eu/engys/core/project/system/ControlDict.java @@ -0,0 +1,202 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import java.io.File; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.dictionary.ListField; + +public class ControlDict extends Dictionary { + + public static final String CONTROL_DICT = "controlDict"; + +// public static final String JPLOT_VALUE = "jplot"; +// public static final String XMGR_VALUE = "xmgr"; +// public static final String GNUPLOT_VALUE = "gnuplot"; + public static final String RAW_VALUE = "raw"; +// public static final String SCIENTIFIC_VALUE = "scientific"; +// public static final String FIXED_VALUE = "fixed"; + public static final String GENERAL_VALUE = "general"; + public static final String COMPRESSED_VALUE = "compressed"; + public static final String UNCOMPRESSED_VALUE = "uncompressed"; +// public static final String BINARY_VALUE = "binary"; + public static final String ASCII_VALUE = "ascii"; + public static final String CLOCK_TIME_VALUE = "clockTime"; + public static final String CPU_TIME_VALUE = "cpuTime"; + public static final String TIME_STEP_VALUE = "timeStep"; + public static final String FIRST_TIME_VALUE = "firstTime"; + public static final String LATEST_TIME_VALUE = "latestTime"; + public static final String FUNCTIONS_KEY = "functions"; + public static final String ADJUSTABLE_RUN_TIME_KEY = "adjustableRunTime"; + public static final String RUN_TIME_VALUE = "runTime"; + public static final String WRITE_INTERVAL_KEY = "writeInterval"; + public static final String WRITE_CONTROL_KEY = "writeControl"; + public static final String PURGE_WRITE_KEY = "purgeWrite"; + public static final String WRITE_FORMAT_KEY = "writeFormat"; + public static final String WRITE_PRECISION_KEY = "writePrecision"; + public static final String WRITE_COMPRESSION_KEY = "writeCompression"; + public static final String TIME_FORMAT_KEY = "timeFormat"; + public static final String TIME_PRECISION_KEY = "timePrecision"; + public static final String GRAPH_FORMAT_KEY = "graphFormat"; + public static final String MAX_DELTA_T_KEY = "maxDeltaT"; + public static final String MAX_ALPHA_CO_KEY = "maxAlphaCo"; + public static final String MAX_CO_KEY = "maxCo"; + public static final String ADJUST_TIME_STEP_KEY = "adjustTimeStep"; + public static final String DELTA_T_KEY = "deltaT"; + public static final String END_TIME_KEY = "endTime"; + public static final String WRITE_NOW_KEY = "writeNow"; + public static final String START_TIME_KEY = "startTime"; + public static final String START_TIME_VALUE = "startTime"; + public static final String START_FROM_KEY = "startFrom"; + public static final String STOP_AT_KEY = "stopAt"; + public static final String RUNTIME_MODIFIABLE_KEY = "runTimeModifiable"; + public static final String INCLUDE_KEY = "include"; + public static final String[] START_FROM_VALUES = { FIRST_TIME_VALUE, LATEST_TIME_VALUE, START_TIME_VALUE }; + public static final String[] WRITE_CONTROL_VALUES = { TIME_STEP_VALUE, RUN_TIME_VALUE, CPU_TIME_VALUE, CLOCK_TIME_VALUE }; +// public static final String[] WRITE_FORMAT_VALUES = { ASCII_VALUE, BINARY_VALUE }; + public static final String[] WRITE_FORMAT_VALUES = { ASCII_VALUE }; + public static final String[] WRITE_COMPRESSION_VALUES = { UNCOMPRESSED_VALUE, COMPRESSED_VALUE }; + public static final String[] TIME_FORMAT_VALUES = { GENERAL_VALUE }; +// public static final String[] TIME_FORMAT_VALUES = { GENERAL_VALUE, FIXED_VALUE, SCIENTIFIC_VALUE }; + public static final String[] GRAPH_FORMAT_VALUE = { RAW_VALUE }; +// public static final String[] GRAPH_FORMAT_VALUE = { RAW_VALUE, GNUPLOT_VALUE, XMGR_VALUE, JPLOT_VALUE }; + + /* + * Radiation + */ + public static final String RADIATION = "radiation"; + public static final String REGION_KEY = "region"; + public static final String FUNCTION_OBJECTS_LIBS_KEY = "functionObjectLibs"; + public static final String SOLVER_OBJECTS_SO_KEY = "( \"libsolverFunctionObjects.so\" )"; + public static final String NON_PARTICIPATING_RADIATION_KEY = "nonParticipatingRadiation"; + + + public static final String SOLAR = "solar"; + public static final String SOLAR_RADIATION_KEY = "solarRadiation"; + public static final String SOURCES_KEY = "sources"; + public static final String TRANSMISSIVITY_KEY = "transmissivity"; + public static final String OUTPUT_CONTROL_KEY = "outputControl"; + public static final String OUTPUT_INTERVAL_KEY = "outputInterval"; + public static final String SOLAR_INTENSITY_KEY = "solarIntensity"; + public static final String SOLAR_DIRECTION_KEY = "solarDirection"; + + + /* + * ELEMENTS + */ + public static final String FA1 = "FA1"; + public static final String LDXZ = "LDxz"; + public static final String AVERAGING_START_TIME = "averagingStartTime"; + public static final String RHO_INF = "rhoInf"; + public static final String U_INF = "Uinf"; + + public ControlDict() { + super(CONTROL_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, CONTROL_DICT)); + } + + public ControlDict(ControlDict controlDict) { + super(controlDict); + } + + public ControlDict(File controlDictFile) { + this(); + readDictionary(controlDictFile); + } + + public void check() throws DictionaryException { + } + + public boolean isBinary() { + return found("writeFormat") && lookup("writeFormat").equals("binary"); + } + + @Override + public void merge(Dictionary dict) { + if (dict instanceof ControlDict) { + ((ControlDict) dict).functionObjectsToDict(); + } + functionObjectsToDict(); + super.merge(dict); + functionObjectsToList(); + if (dict instanceof ControlDict) { + ((ControlDict) dict).functionObjectsToList(); + } + } + + public void functionObjectsToDict() { + if (found(FUNCTIONS_KEY) && isList(FUNCTIONS_KEY)) { + ListField functionsList = getList(FUNCTIONS_KEY); + Dictionary functionsDict = new Dictionary(FUNCTIONS_KEY); + for (DefaultElement el : functionsList.getListElements()) { + functionsDict.add(el); + } + remove(FUNCTIONS_KEY); + add(functionsDict); + } + } + + public void functionObjectsToList() { + if (found(FUNCTIONS_KEY) && isDictionary(FUNCTIONS_KEY)) { + Dictionary functionsDict = subDict(FUNCTIONS_KEY); + remove(FUNCTIONS_KEY); + for (Dictionary dict : functionsDict.getDictionaries()) { + addToList(FUNCTIONS_KEY, dict); + } + } + } + + public String getValueOnFunctionObject(String foName, String key) { + if (isList(FUNCTIONS_KEY)) { + ListField functions = getList(FUNCTIONS_KEY); + Dictionary foDict = functions.getDictionary(foName); + if (foDict != null) { + if (foDict.found(key)) { + return foDict.lookup(key); + } + } + } else if (isDictionary(FUNCTIONS_KEY)) { + Dictionary functions = subDict(FUNCTIONS_KEY); + Dictionary foDict = functions.subDict(foName); + if (foDict != null) { + if (foDict.found(key)) { + return foDict.lookup(key); + } + } + } + return null; + } + + public void startFromZero() { + add(START_FROM_KEY, START_TIME_VALUE); + add(START_TIME_KEY, "0"); + } +} diff --git a/src/eu/engys/core/project/system/CustomNodeDict.java b/src/eu/engys/core/project/system/CustomNodeDict.java new file mode 100644 index 0000000..4f32cf5 --- /dev/null +++ b/src/eu/engys/core/project/system/CustomNodeDict.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import java.io.File; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; + +public class CustomNodeDict extends Dictionary { + + public static final String CUSTOM_NODE_DICT = "customNodeDict"; + + public CustomNodeDict() { + super(CUSTOM_NODE_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, CUSTOM_NODE_DICT)); + } + + public CustomNodeDict(File customDictFile) { + this(); + readDictionary(customDictFile); + } + + @Override + public void check() throws DictionaryException { + } +} diff --git a/src/eu/engys/core/project/system/DecomposeParDict.java b/src/eu/engys/core/project/system/DecomposeParDict.java new file mode 100644 index 0000000..2f0bf62 --- /dev/null +++ b/src/eu/engys/core/project/system/DecomposeParDict.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.system; + +import java.io.File; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.project.Model; +import eu.engys.util.Util; + +public class DecomposeParDict extends Dictionary { + + public static final String DECOMPOSE_PAR_DICT = "decomposeParDict"; + + public static final String NUMBER_OF_SUBDOMAINS_KEY = "numberOfSubdomains"; + public static final String HIERARCHICAL_COEFFS_KEY = "hierarchicalCoeffs"; + public static final String METHOD_KEY = "method"; + public static final String DELTA_KEY = "delta"; + public static final String ORDER_KEY = "order"; + public static final String YXZ_KEY = "yxz"; + public static final String DISTRIBUTED_KEY = "distributed"; + public static final String N_KEY = "n"; + + public static final String HIERARCHICAL_KEY = "hierarchical"; + public static final String SCOTCH_KEY = "scotch"; + + public static final String[] TYPE_KEYS = { HIERARCHICAL_KEY, SCOTCH_KEY }; + + public DecomposeParDict() { + super(DECOMPOSE_PAR_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, DECOMPOSE_PAR_DICT)); + } + + public DecomposeParDict(DecomposeParDict newDict) { + super(newDict); + } + + public DecomposeParDict(File file) { + this(); + readDictionary(file); + } + + public void check() throws DictionaryException { + } + + public void toHierarchical(Model model) { + if (methodIsScotch()) { + Dictionary newHCDict = new Dictionary(model.getDefaults().getDefaultDecomposeParDict().subDict(HIERARCHICAL_COEFFS_KEY)); + int[] subdomainValues = calculateSubdomainValues(); + int x = subdomainValues[0]; + int y = subdomainValues[1]; + int z = subdomainValues[2]; + newHCDict.add(N_KEY, "(" + x + " " + y + " " + z + ")"); + + add(METHOD_KEY, HIERARCHICAL_KEY); + add(newHCDict); + DictionaryUtils.writeDictionary(model.getProject().getSystemFolder().getFileManager().getFile(), this, null); + } + } + + private int[] calculateSubdomainValues() { + int numberOfSubdomains = Integer.parseInt(lookup(NUMBER_OF_SUBDOMAINS_KEY)); + int[] subdomainValues = Util.getFactorsFor(numberOfSubdomains); + return subdomainValues; + } + + private boolean methodIsScotch() { + return found(METHOD_KEY) && SCOTCH_KEY.equals(lookup(METHOD_KEY)); + } +} diff --git a/src/eu/engys/core/project/system/FvOptions.java b/src/eu/engys/core/project/system/FvOptions.java new file mode 100644 index 0000000..18992a8 --- /dev/null +++ b/src/eu/engys/core/project/system/FvOptions.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; + +public class FvOptions extends Dictionary { + public static final String FV_OPTIONS = "fvOptions"; + + public FvOptions() { + super(FV_OPTIONS); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, FV_OPTIONS)); + } + + @Override + public void check() throws DictionaryException { + } +} diff --git a/src/eu/engys/core/project/system/FvSchemes.java b/src/eu/engys/core/project/system/FvSchemes.java new file mode 100644 index 0000000..3660c94 --- /dev/null +++ b/src/eu/engys/core/project/system/FvSchemes.java @@ -0,0 +1,111 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; + +public class FvSchemes extends Dictionary { + + public static final String FV_SCHEMES = "fvSchemes"; + public static final String SN_GRAD_SCHEMES = "snGradSchemes"; + public static final String INTERPOLATION_SCHEMES = "interpolationSchemes"; + public static final String LAPLACIAN_SCHEMES = "laplacianSchemes"; + public static final String DIV_SCHEMES = "divSchemes"; + public static final String GRAD_SCHEMES = "gradSchemes"; + public static final String DDT_SCHEMES = "ddtSchemes"; + public static final String DEFAULT = "default"; + public static final String STEADY_STATE = "steadyState"; + public static final String EULER = "Euler"; + public static final String BACKWARD = "backward"; + public static final String LOCAL_EULER_RDELTAT = "localEuler rDeltaT";//LTSInterfoam + + public FvSchemes() { + super(FV_SCHEMES); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, FV_SCHEMES)); + } + + public Dictionary getDdtSchemes() { + return subDict(DDT_SCHEMES); + } + + public Dictionary getGradSchemes() { + return subDict(GRAD_SCHEMES); + } + + public Dictionary getDivSchemes() { + return subDict(DIV_SCHEMES); + } + + public Dictionary getLaplacianSchemes() { + return subDict(LAPLACIAN_SCHEMES); + } + + public Dictionary getInterpolationSchemes() { + return subDict(INTERPOLATION_SCHEMES); + } + + public Dictionary getSnGradSchemes() { + return subDict(SN_GRAD_SCHEMES); + } + + @Override + public void check() throws DictionaryException { + if (found(DDT_SCHEMES)) { + + } else { + throw new DictionaryException(DDT_SCHEMES + " not found"); + } + if (found(GRAD_SCHEMES)) { + + } else { + throw new DictionaryException(GRAD_SCHEMES + " not found"); + } + if (found(DIV_SCHEMES)) { + + } else { + throw new DictionaryException(DIV_SCHEMES + " not found"); + } + if (found(LAPLACIAN_SCHEMES)) { + ; + } else { + throw new DictionaryException(LAPLACIAN_SCHEMES + " not found"); + } + if (found(INTERPOLATION_SCHEMES)) { + ; + } else { + throw new DictionaryException(INTERPOLATION_SCHEMES + " not found"); + } + if (found(SN_GRAD_SCHEMES)) { + ; + } else { + throw new DictionaryException(SN_GRAD_SCHEMES + " not found"); + } + } + +} diff --git a/src/eu/engys/core/project/system/FvSolution.java b/src/eu/engys/core/project/system/FvSolution.java new file mode 100644 index 0000000..62733ff --- /dev/null +++ b/src/eu/engys/core/project/system/FvSolution.java @@ -0,0 +1,67 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; + +public class FvSolution extends Dictionary { + + public static final String FV_SOLUTION = "fvSolution"; + + public static final String SIMPLE = "SIMPLE"; + public static final String PIMPLE = "PIMPLE"; + public static final String PISO = "PISO"; + public static final String COUPLED = "COUPLED"; + + public static final String N_OUTER_CORRECTORS_KEY = "nOuterCorrectors"; + public static final String N_NON_ORTHOGONAL_CORRECTORS_KEY = "nNonOrthogonalCorrectors"; + public static final String N_CORRECTORS_KEY = "nCorrectors"; + public static final String RHO_MIN_KEY = "rhoMin"; + public static final String RHO_MAX_KEY = "rhoMax"; + public static final String RELAXATION_FACTORS_KEY = "relaxationFactors"; + public static final String RESIDUAL_CONTROL_KEY = "residualControl"; + public static final String REL_TOLERANCE_KEY = "relTol"; + public static final String TOLERANCE_KEY = "tolerance"; + + public static final String SONIC_KEY = "sonic"; + public static final String HYDRO_KEY = "hydro"; + + public static final String FIELDS_KEY = "fields"; + public static final String EQUATIONS_KEY = "equations"; + public static final String SOLVERS_KEY = "solvers"; + + public FvSolution() { + super(FV_SOLUTION); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, FV_SOLUTION)); + } + + @Override + public void check() throws DictionaryException { + } +} diff --git a/src/eu/engys/core/project/system/MapFieldsDict.java b/src/eu/engys/core/project/system/MapFieldsDict.java new file mode 100644 index 0000000..5108da5 --- /dev/null +++ b/src/eu/engys/core/project/system/MapFieldsDict.java @@ -0,0 +1,128 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import static eu.engys.core.project.system.SystemFolder.SYSTEM; + +import java.io.File; +import java.util.Map; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.dictionary.FoamFile; + +public class MapFieldsDict extends Dictionary { + + public static final String MAP_FIELDS_DICT = "mapFieldsDict"; + + public static final String PATCH_MAP_KEY = "patchMap"; + public static final String CUTTING_PATCHES_KEY = "cuttingPatches"; + public static final String SOURCE_CASE_KEY = "sourceCase"; + public static final String PARALLEL_SOURCE_KEY = "parallelSource"; + public static final String SOURCE_TIME_OPTION_KEY = "sourceTimeOption"; + public static final String SOURCE_TIME_VALUE_KEY = "sourceTimeValue"; + public static final String TARGET_TIME_OPTION_KEY = "targetTimeOption"; + public static final String TARGET_TIME_VALUE_KEY = "targetTimeValue"; + public static final String CONSISTENT_KEY = "consistent"; + + public static final String LATEST_TIME_KEY = "latestTime"; + public static final String ALL_TIMES_KEY = "allTimes"; + public static final String[] SOURCE_TIME_OPTION_KEYS = new String[] { LATEST_TIME_KEY, SOURCE_TIME_VALUE_KEY, ALL_TIMES_KEY }; + public static final String[] TARGET_TIME_OPTION_KEYS = new String[] { LATEST_TIME_KEY, TARGET_TIME_VALUE_KEY, SOURCE_TIME_VALUE_KEY }; + + public MapFieldsDict() { + super(MAP_FIELDS_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SYSTEM, MAP_FIELDS_DICT)); + } + + public MapFieldsDict(File file) { + super(file); + } + + public MapFieldsDict(Dictionary dict) { + super(dict); + setFoamFile(FoamFile.getDictionaryFoamFile(SYSTEM, MAP_FIELDS_DICT)); + } + + @Override + public void check() throws DictionaryException { + } + + @Override + public void merge(Dictionary dict) { + if (dict instanceof MapFieldsDict) { + ((MapFieldsDict) dict).functionObjectsToDict(); + } + functionObjectsToDict(); + super.merge(dict); + functionObjectsToList(); + if (dict instanceof MapFieldsDict) { + ((MapFieldsDict) dict).functionObjectsToList(); + } + + } + + private void functionObjectsToDict() { + if (found(PATCH_MAP_KEY)) { + // () is recognized as empty list + boolean isEmptyList = isList(PATCH_MAP_KEY) && getList(PATCH_MAP_KEY).isEmpty(); + boolean isField = isField(PATCH_MAP_KEY); + if (isEmptyList || isField) { + Dictionary functionsDict = new Dictionary(PATCH_MAP_KEY); + if (isField) { + String patchMap = lookup(PATCH_MAP_KEY); + String[] patches = DictionaryUtils.string2StringArray(patchMap); + for (int i = 0; i < patches.length; i += 2) { + String el1 = patches[i]; + String el2 = patches[i + 1]; + functionsDict.add(new FieldElement(el1, el2)); + } + } + remove(PATCH_MAP_KEY); + add(functionsDict); + } + } + } + + private void functionObjectsToList() { + if (found(PATCH_MAP_KEY) && isDictionary(PATCH_MAP_KEY)) { + Dictionary functionsDict = subDict(PATCH_MAP_KEY); + remove(PATCH_MAP_KEY); + Map fieldsMap = functionsDict.getFieldsMap(); + StringBuilder sb = new StringBuilder("("); + for (String key : fieldsMap.keySet()) { + sb.append(key + " "); + sb.append(fieldsMap.get(key) + " "); + } + sb.append(")"); + add(PATCH_MAP_KEY, sb.toString()); + } + } + +} diff --git a/src/eu/engys/core/project/system/RunDict.java b/src/eu/engys/core/project/system/RunDict.java new file mode 100644 index 0000000..b83a2d4 --- /dev/null +++ b/src/eu/engys/core/project/system/RunDict.java @@ -0,0 +1,71 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import java.io.File; + +import eu.engys.core.dictionary.BeanToDict; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.project.SolverModel; + +public class RunDict extends Dictionary { + public static final String RUN_DICT = "runDict"; +// public static final String POST_PROC_FILE_MAP = "postProcFileMap"; + public static final String SERVER_STATE = "serverState"; + public static final String REMOTE = "remote"; + public static final String QUEUE = "queue"; + public static final String SERVER_ID = "serverID"; + public static final String LOG_FILE = "logFile"; + public static final String RMI_PORT = "rmiPort"; + public static final String LOG_PORT = "logPort"; + public static final String SSH_PARAMETERS = "sshParameters"; + public static final String QUEUE_PARAMETERS = "queueParameters"; + public static final String MULTI_MACHINE = "multiMachine"; + public static final String HOSTFILE_PATH = "hostfilePath"; + + public RunDict() { + super(RUN_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, RUN_DICT)); + } + + public RunDict(SolverModel solverModel) { + this(); + merge(BeanToDict.beanToDict(solverModel)); + } + + public RunDict(File runDictFile) { + this(); + readDictionary(runDictFile); + } + + @Override + public void check() throws DictionaryException { + } + +} diff --git a/src/eu/engys/core/project/system/SetFieldsDict.java b/src/eu/engys/core/project/system/SetFieldsDict.java new file mode 100644 index 0000000..744ab07 --- /dev/null +++ b/src/eu/engys/core/project/system/SetFieldsDict.java @@ -0,0 +1,72 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import static eu.engys.core.project.system.SystemFolder.SYSTEM; + +import java.io.File; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; + +public class SetFieldsDict extends Dictionary { + + public static final String SET_FIELDS_DICT = "setFieldsDict"; + + public static final String CELL_SET_KEY = "cellSet"; + public static final String VOL_SCALAR_FIELD_VALUE_KEY = "volScalarFieldValue"; + public static final String FIELD_VALUES_KEY = "fieldValues"; + public static final String REGIONS_KEY = "regions"; + public static final String SET_SOURCES_KEY = "setSources"; + public static final String DEFAULT_FIELD_VALUES_KEY = "defaultFieldValues"; + public static final String DEFAULT_VALUE_KEY = "defaultValue"; + + public static final String BOX_TO_CELL_KEY ="boxToCell"; + public static final String SPHERE_TO_CELL_KEY ="sphereToCell"; + public static final String CYLINDER_TO_CELL_KEY ="cylinderToCell"; + public static final String RING_TO_CELL_KEY ="ringToCell"; + + public SetFieldsDict() { + super(SET_FIELDS_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SYSTEM, SET_FIELDS_DICT)); + } + + public SetFieldsDict(File file) { + super(file); + } + + public SetFieldsDict(Dictionary dict) { + super(dict); + setFoamFile(FoamFile.getDictionaryFoamFile(SYSTEM, SET_FIELDS_DICT)); + } + + @Override + public void check() throws DictionaryException { + } + +} diff --git a/src/eu/engys/core/project/system/SnappyHexMeshDict.java b/src/eu/engys/core/project/system/SnappyHexMeshDict.java new file mode 100644 index 0000000..5975651 --- /dev/null +++ b/src/eu/engys/core/project/system/SnappyHexMeshDict.java @@ -0,0 +1,288 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import java.io.File; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.FoamFile; + +public class SnappyHexMeshDict extends Dictionary { + + + public static final String SNAPPY_DICT = "snappyHexMeshDict"; + + // GENERAL + public static final String CASTELLATED_MESH_KEY = "castellatedMesh"; + public static final String SNAP_KEY = "snap"; + public static final String ADD_LAYERS_KEY = "addLayers"; + public static final String AUTO_BLOCK_MESH_KEY = "autoBlockMesh"; + public static final String BLOCK_DATA_KEY = "blockData"; + public static final String CRACK_DETECTION_KEY = "crackDetection"; + public static final String CRACK_TOL_KEY = "crackTol"; + public static final String FINAL_DECOMPOSITION_KEY = "finalDecomposition"; + public static final String HIERARCHICAL_KEY = "hierarchical"; + public static final String PTSCOTCH_KEY = "ptscotch"; + public static final String[] DECOMPOSITION_KEYS = new String[] { PTSCOTCH_KEY, HIERARCHICAL_KEY }; + + // CASTELLATED + public static final String CASTELLATED_MESH_CONTROLS_KEY = "castellatedMeshControls"; + + public static final String LOCATION_IN_MESH = "locationInMesh"; + public static final String MAX_LOCAL_CELLS_KEY = "maxLocalCells"; + public static final String MAX_GLOBAL_CELLS_KEY = "maxGlobalCells"; + public static final String MIN_REFINEMENT_CELLS_KEY = "minRefinementCells"; + public static final String N_CELLS_BETWEEN_LEVELS_KEY = "nCellsBetweenLevels"; + public static final String RESOLVE_FEATURE_ANGLE_KEY = "resolveFeatureAngle"; + public static final String FEATURE_REFINE_ANGLE_KEY = "featureRefineAngle"; + public static final String REFINE_SURFACE_BOUNDARY_KEY = "refineSurfaceBoundary"; + public static final String MIN_BAFFLE_ANGLE_KEY = "minBaffleAngle"; + public static final String CURVATURE_REFINE_ANGLE_KEY = "curvatureRefineAngle"; + public static final String ALLOW_FREE_STANDING_ZONE_FACES_KEY = "allowFreeStandingZoneFaces"; + public static final String BALANCE_THEN_REFINE_KEY = "balanceThenRefine"; + public static final String MAX_LOAD_UNBALANCE_KEY = "maxLoadUnbalance"; + public static final String SPLIT_CELLS_KEY = "splitCells"; + public static final String MIN_ZONE_REGION_SIZE_KEY = "minZoneRegionSize"; + + // CASTELLATED-OS + public static final String PLANAR_ANGLE_KEY = "planarAngle"; + + // SNAP + public static final String SNAP_CONTROLS_KEY = "snapControls"; + + public static final String GLOBAL_FEATURE_EDGES_KEY = "globalFeatureEdges"; + public static final String N_SMOOTH_PATCH_KEY = "nSmoothPatch"; + public static final String DIRECT_FEATURE_SNAPPING_KEY = "directFeatureSnapping"; + public static final String TOLERANCE_KEY = "tolerance"; + public static final String REGION_FEATURE_LINES_KEY = "regionFeatureLines"; + public static final String N_RELAX_ITER_SNAP_KEY = "nRelaxIter"; + public static final String GLOBAL_REGION_SNAP_KEY = "globalRegionSnap"; + public static final String SNAP_SURF_BOUNDARY_KEY = "snapSurfBoundary"; + public static final String COLLAPSE_TOL_KEY = "collapseTol"; + public static final String SPLIT_DEGENERATE_CELLS_KEY = "splitDegenerateCells"; + public static final String N_PRE_FEATURE_ITER_KEY = "nPreFeatureIter"; + public static final String EXPLICIT_FEATURE_SNAP_KEY = "explicitFeatureSnap"; + public static final String IMPLICIT_FEATURE_SNAP_KEY = "implicitFeatureSnap"; + public static final String GEOMETRY_FEATURE_LINES_KEY = "geometryFeatureLines"; + public static final String ZONE_FEATURE_SNAPPING_KEY = "zoneFeatureSnapping"; + public static final String N_SOLVER_ITER_KEY = "nSolveIter"; + public static final String N_FEATURE_ITER_KEY = "nFeatureIter"; + public static final String N_OUTER_ITER_KEY = "nOuterIter"; + public static final String N_SLIVER_SMOOTHS_KEY = "nSliverSmooths"; + public static final String ENLARGE_STENCIL_KEY = "enlargeStencil"; + public static final String FEATURE_SNAP_CHECKS_KEY = "featureSnapChecks"; + public static final String SMOOTH_SNAPPED_SURFACE_KEY = "smoothSnappedSurface"; + + // SNAP-OS + public static final String MULTI_REGION_FEATURE_SNAP_KEY = "multiRegionFeatureSnap"; + public static final String N_FEATURE_SNAP_ITER_KEY = "nFeatureSnapIter"; + + // LAYERS + public static final String ADD_LAYERS_CONTROLS_KEY = "addLayersControls"; + + public static final String EXPANSION_RATIO_KEY = "expansionRatio"; + public static final String FINAL_LAYER_THICKNESS_KEY = "finalLayerThickness"; + public static final String RELATIVE_SIZES_KEY = "relativeSizes"; + public static final String MIN_THICKNESS_KEY = "minThickness"; + public static final String FEATURE_ANGLE_MERGE_KEY = "featureAngleMerge"; + public static final String FEATURE_ANGLE_TERMINATE_KEY = "featureAngleTerminate"; + public static final String N_RELAX_ITER_LAYERS_KEY = "nRelaxIter"; + public static final String N_RELAXED_ITER_KEY = "nRelaxedIter"; + public static final String MIN_MEDIAL_AXIS_ANGLE_KEY = "minMedialAxisAngle"; + public static final String NO_ERRORS_KEY = "noErrors"; + public static final String MAX_LAYER_ITER_KEY = "maxLayerIter"; + public static final String MAX_THICKNESS_TO_MEDIAL_RATIO_KEY = "maxThicknessToMedialRatio"; + public static final String MAX_FACE_THICKNESS_RATIO_KEY = "maxFaceThicknessRatio"; + public static final String WRITE_VTK_KEY = "writeVTK"; + public static final String PROJECT_GROWN_UP_KEY = "projectGrownUp"; + public static final String LAYER_RECOVERY_KEY = "layerRecovery"; + public static final String PRE_BALANCE_KEY = "preBalance"; + public static final String GROW_CONCAVE_EDGE_KEY = "growConcaveEdge"; + public static final String GROW_CONVEX_EDGE_KEY = "growConvexEdge"; + public static final String GROW_ZONE_LAYERS_KEY = "growZoneLayers"; + public static final String GROW_UP_PATCHES_KEY = "growUpPatches"; + public static final String N_SMOOTH_SURFACE_NORMALS_KEY = "nSmoothSurfaceNormals"; + public static final String N_SMOOTH_NORMALS_KEY = "nSmoothNormals"; + public static final String MAX_CELL_DISTORTION_KEY = "maxCellDistortion"; + public static final String MAX_PROJECTION_DISTANCE_KEY = "maxProjectionDistance"; + + // LAYERS-OS + public static final String N_GROW_KEY = "nGrow"; + public static final String N_LAYER_ITER_KEY = "nLayerIter"; + public static final String N_BUFFER_CELLS_NO_EXTRUDE_KEY = "nBufferCellsNoExtrude"; + public static final String N_SMOOTH_THICKNESS_KEY = "nSmoothThickness"; + public static final String SLIP_FEATURE_ANGLE_KEY = "slipFeatureAngle"; + public static final String FEATURE_ANGLE_KEY = "featureAngle"; + + // QUALITY + public static final String MESH_QUALITY_CONTROLS_KEY = "meshQualityControls"; + + public static final String N_VOL_SMOOTH_ITER_KEY = "nVolSmoothIter"; + public static final String MAX_NON_ORTHO_KEY = "maxNonOrtho"; + public static final String MAX_BOUNDARY_SKEWNESS_KEY = "maxBoundarySkewness"; + public static final String MAX_INTERNAL_SKEWNESS_KEY = "maxInternalSkewness"; + public static final String MAX_CONCAVE_KEY = "maxConcave"; + public static final String MIN_FLATNESS_KEY = "minFlatness"; + public static final String MIN_VOL_KEY = "minVol"; + public static final String MIN_TET_QUALITY_KEY = "minTetQuality"; + public static final String MIN_AREA_KEY = "minArea"; + public static final String MIN_TWIST_KEY = "minTwist"; + public static final String MIN_DETERMINANT_KEY = "minDeterminant"; + public static final String MIN_FACE_WEIGHT_KEY = "minFaceWeight"; + public static final String MIN_VOL_RATIO_KEY = "minVolRatio"; + public static final String MIN_TRIANGLE_TWIST_KEY = "minTriangleTwist"; + public static final String MIN_VOL_COLLAPSE_RATIO_KEY = "minVolCollapseRatio"; + public static final String MIN_INTERNAL_WARPAGE_KEY = "minInternalWarpage"; + public static final String MAX_BOUNDARY_WARPAGE_KEY = "maxBoundaryWarpage"; + public static final String FACE_FACE_CELLS_KEY = "faceFaceCells"; + public static final String MIN_SNAP_RELATIVE_VOLUME_KEY = "minSnapRelativeVolume"; + public static final String N_SMOOTH_SCALE_KEY = "nSmoothScale"; + public static final String SMOOTH_ALIGNED_EDGES_KEY = "smoothAlignedEdges"; + public static final String ERROR_REDUCTION_KEY = "errorReduction"; + public static final String MIN_SNAP_RELATIVE_TET_VOLUME_KEY = "minSnapRelativeTetVolume"; + public static final String MAX_GAUSS_GREEN_CENTROID_KEY = "maxGaussGreenCentroid"; + public static final String BAFFLE_ALL_POINTS_BOUNDARY_KEY = "baffleAllPointsBoundary"; + + // REPATCH + public static final String REPATCH_REGIONS_KEY = "repatchRegions"; + + public static final String LOCATION_KEY = "location"; + public static final String ZONE_KEY = "zone"; + public static final String EXCLUDE_PATCHES_KEY = "excludePatches"; + public static final String PATCH_KEY = "patch"; + + // WRAPPER + public static final String WRAPPER_KEY = "wrapper"; + + public static final String WRAP_KEY = "wrap"; + public static final String OUTLETS_KEY = "outlets"; + public static final String VOL_SOURCES_KEY = "volSources"; + public static final String VOL_DISTANCE_KEY = "volDistance"; + public static final String MESH_IN_MM_KEY = "meshInMM"; + public static final String MAX_ITER_KEY = "maxIter"; + public static final String WRITE_FIELDS_KEY = "writeFields"; + public static final String INVERT_KEY = "invert"; + public static final String SIGMA_KEY = "sigma"; + public static final String CUTOFF_KEY = "cutoff"; + public static final String EXCLUDE_POINTS_KEY = "excludePoints"; + + // MISC + public static final String DEBUG_KEY = "debug"; + public static final String MERGE_TOLERANCE_KEY = "mergeTolerance"; + + // FEATURES LINES + public static final String FILE_KEY = "file"; + public static final String FEATURES_KEY = "features"; + public static final String REFINE_FEATURE_EDGES_ONLY_KEY = "refineFeatureEdgesOnly"; + + // REFINEMENT SURFACES + REGIONS + public static final String REFINEMENTS_SURFACES_KEY = "refinementSurfaces"; + public static final String REFINEMENTS_REGIONS_KEY = "refinementRegions"; + public static final String PROXIMITY_INCREMENT_KEY = "proximityIncrement"; + + // GEOMETRY + public static final String GEOMETRY_KEY = "geometry"; + public static final String LAYERS_KEY = "layers"; + public static final String GAP_LEVEL_INCREMENT_KEY = "gapLevelIncrement"; + public static final String MAX_CELLS_ACROSS_GAP_KEY = "maxCellsAcrossGap"; + public static final String MAX_LAYER_THICKNESS_KEY = "maxLayerThickness"; + public static final String FCH_KEY = "fch"; + public static final String GROWN_UP_KEY = "grownUp"; + public static final String N_SURFACE_LAYERS_KEY = "nSurfaceLayers"; + + public static final String MODE_KEY = "mode"; + public static final String INSIDE = "inside"; + public static final String OUTSIDE_KEY = "outside"; + public static final String DISTANCE_KEY = "distance"; + public static final String NONE_KEY = "none"; + public static final String TWO_SIDED_KEY = "twoSided"; + + // ZONES + public static final String FACE_TYPE_KEY = "faceType"; + public static final String LEVEL_KEY = "level"; + public static final String LEVELS_KEY = "levels"; + public static final String REGIONS_KEY = "regions"; + public static final String CELL_ZONE_KEY = "cellZone"; + public static final String FACE_ZONE_KEY = "faceZone"; + public static final String CELL_ZONE_INSIDE = "cellZoneInside"; + public static final String IS_CELL_ZONE = "isCellZone"; + + public static final String INTERNAL_KEY = "internal"; + public static final String BOUNDARY_KEY = "boundary"; + public static final String BAFFLE_KEY = "baffle"; + + public static final String BAFFLE_CHECKS_KEY = "baffleChecks"; + + public SnappyHexMeshDict() { + super(SNAPPY_DICT); + setFoamFile(FoamFile.getDictionaryFoamFile(SystemFolder.SYSTEM, SNAPPY_DICT)); + } + + public SnappyHexMeshDict(File snappyHexMeshFile) { + super(snappyHexMeshFile); + } + + public SnappyHexMeshDict(SnappyHexMeshDict snappyHexMeshDict) { + super(snappyHexMeshDict); + } + + public void check() throws DictionaryException { + } + + public Dictionary getGeometry() { + return subDict(GEOMETRY_KEY); + } + + public boolean isAutoBlockMesh() { + return found(AUTO_BLOCK_MESH_KEY) && Boolean.parseBoolean(lookup(AUTO_BLOCK_MESH_KEY)); + } + + // protected void parseDictionary(String text) { + // Pattern pattern = Pattern.compile("features\\s+\\(([^)]*)\\s*\\)\\s*;"); + // Matcher matcher = pattern.matcher(text); + // StringBuffer result = new StringBuffer(); + // String group = null; + // if (matcher.find()) { + // if (matcher.groupCount() == 1) { + // group = matcher.group(1); + // //System.out.println("SnappyHexMeshDict.parseDictionary() "+group); + // } + // matcher.appendReplacement(result, ""); + // matcher.appendTail(result); + // + // text = result.toString(); + // } + // super.parseDictionary(text); + // + // if (group != null && found("castellatedMeshControls")) { + // subDict("castellatedMeshControls").add("features", "("+group+")"); + // } + // + // } + // +} diff --git a/src/eu/engys/core/project/system/SystemFolder.java b/src/eu/engys/core/project/system/SystemFolder.java new file mode 100644 index 0000000..0778f4e --- /dev/null +++ b/src/eu/engys/core/project/system/SystemFolder.java @@ -0,0 +1,463 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system; + +import java.io.File; +import java.util.Set; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryException; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.files.DefaultFileManager; +import eu.engys.core.project.files.FileManager; +import eu.engys.core.project.files.Folder; +import eu.engys.core.project.system.fieldmanipulationfunctionobjects.FieldManipulationFunctionObjectType; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObjectType; +import eu.engys.util.progress.ProgressMonitor; + +public class SystemFolder implements Folder { + + public static final String SYSTEM = "system"; + + //ECOMARINE + public static final String REGION_KEY = "region"; + public static final String PATCHES_KEY = "patches"; + public static final String EXTRUDE_TO_REGION_MESH_DICT = "extrudeToRegionMeshDict"; + + private BlockMeshDict blockMeshDict; + private SnappyHexMeshDict snappyHexMeshDict; + private FvSchemes fvSchemes; + private FvSolution fvSolution; + private FvOptions fvOptions; + private ControlDict controlDict; + private RunDict runDict; + private SetFieldsDict setFieldsDict; + private MapFieldsDict mapFieldsDict; + private DecomposeParDict decomposeParDict; + + private FileManager fileManager; + + private CustomNodeDict customDict; + + public SystemFolder(openFOAMProject prj) { + fileManager = new DefaultFileManager(new File(prj.getBaseDir(), SYSTEM)); + } + + public SystemFolder(File baseDir, SystemFolder systemFolder) { + fileManager = new DefaultFileManager(new File(baseDir, SYSTEM)); + setBlockMeshDict(systemFolder.getBlockMeshDict()); + setSnappyHexMeshDict(systemFolder.getSnappyHexMeshDict()); + setFvSchemes(systemFolder.getFvSchemes()); + setFvSolution(systemFolder.getFvSolution()); + setFvOptions(systemFolder.getFvOptions()); + setControlDict(systemFolder.getControlDict()); + setRunDict(systemFolder.getRunDict()); +// setSetFieldsDict(systemFolder.getSetFieldsDict()); + setMapFieldsDict(systemFolder.getMapFieldsDict()); + setDecomposeParDict(systemFolder.getDecomposeParDict()); + setCustomNodeDict(systemFolder.getCustomNodeDict()); + } + + @Override + public FileManager getFileManager() { + return fileManager; + } + + public BlockMeshDict getBlockMeshDict() { + return blockMeshDict; + } + + public void setBlockMeshDict(BlockMeshDict dict) throws DictionaryException { + if (dict != null && dict.isFromFile()) { + this.blockMeshDict = dict; + } else { + this.blockMeshDict = new BlockMeshDict(); + blockMeshDict.merge(dict); + } + } + + public SnappyHexMeshDict getSnappyHexMeshDict() { + return snappyHexMeshDict; + } + + public void setSnappyHexMeshDict(Dictionary dict) throws DictionaryException { + this.snappyHexMeshDict = new SnappyHexMeshDict(); + snappyHexMeshDict.merge(dict); + } + + public FvSchemes getFvSchemes() { + return fvSchemes; + } + + public void setFvSchemes(Dictionary dict) throws DictionaryException { + this.fvSchemes = new FvSchemes(); + fvSchemes.merge(dict); + } + + public FvSolution getFvSolution() { + return fvSolution; + } + + public void setFvSolution(Dictionary dict) throws DictionaryException { + this.fvSolution = new FvSolution(); + fvSolution.merge(dict); + fvSolution.check(); + } + + public FvOptions getFvOptions() { + return fvOptions; + } + + public void setFvOptions(Dictionary dict) { + this.fvOptions = new FvOptions(); + fvOptions.merge(dict); + fvOptions.check(); + } + + public ControlDict getControlDict() { + return controlDict; + } + + public void setControlDict(Dictionary dict) throws DictionaryException { + this.controlDict = new ControlDict(); + controlDict.merge(dict); + controlDict.check(); + } + + public RunDict getRunDict() { + return runDict; + } + + public void setRunDict(Dictionary dict) { + this.runDict = new RunDict(); + runDict.merge(dict); + runDict.check(); + } + + public SetFieldsDict getSetFieldsDict() { + return setFieldsDict; + } + + public void setSetFieldsDict(Dictionary dict) { + this.setFieldsDict = new SetFieldsDict(dict); + } + + public MapFieldsDict getMapFieldsDict() { + return mapFieldsDict; + } + + public void setMapFieldsDict(Dictionary dict) { + this.mapFieldsDict = new MapFieldsDict(); + mapFieldsDict.merge(dict); + mapFieldsDict.check(); + } + + public DecomposeParDict getDecomposeParDict() { + return decomposeParDict; + } + + public void setDecomposeParDict(Dictionary dict) throws DictionaryException { + this.decomposeParDict = new DecomposeParDict(); + decomposeParDict.merge(dict); + } + + public CustomNodeDict getCustomNodeDict() { + return customDict; + } + + public void setCustomNodeDict(Dictionary dict) { + this.customDict = new CustomNodeDict(); + customDict.merge(dict); + customDict.check(); + } + + public void write(Model model, ProgressMonitor monitor) { + File systemDir = fileManager.getFile(); + writeBlockMeshDict(monitor); + DictionaryUtils.writeDictionary(systemDir, snappyHexMeshDict, monitor); + DictionaryUtils.writeDictionary(systemDir, decomposeParDict, monitor); + writeControlDict(monitor); + DictionaryUtils.writeDictionary(systemDir, fvSolution, monitor); + DictionaryUtils.writeDictionary(systemDir, fvSchemes, monitor); + DictionaryUtils.writeDictionary(systemDir, fvOptions, monitor); + DictionaryUtils.writeDictionary(systemDir, setFieldsDict, monitor); + DictionaryUtils.writeDictionary(systemDir, runDict, monitor); + DictionaryUtils.writeDictionary(systemDir, customDict, monitor); + DictionaryUtils.writeDictionary(systemDir, mapFieldsDict, monitor); + } + + public void writeControlDict(ProgressMonitor monitor) { + DictionaryUtils.writeDictionary(fileManager.getFile(), controlDict, monitor); + } + + public void writeBlockMeshDict(ProgressMonitor monitor) { + if (!blockMeshDict.isFromFile()) { + DictionaryUtils.writeDictionary(fileManager.getFile(), blockMeshDict, monitor); + } + } + + public void read(Model model, Set ffoTypes, Set mfoTypes, ProgressMonitor monitor) { + File systemFolder = new File(model.getProject().getBaseDir(), SYSTEM); + if (systemFolder.exists() && systemFolder.isDirectory()) { + + readControlDict(model, monitor, systemFolder); + + readFvSolution(model, monitor, systemFolder); + + readFvSchemes(model, monitor, systemFolder); + + readFvOptions(model, monitor, systemFolder); + + readSnappyHexMeshDict(model, monitor, systemFolder); + + readBlockMeshDict(model, monitor, systemFolder); + + readDecomposeParDict(model, monitor, systemFolder); + + readSetFieldsDict(model, monitor, systemFolder); + + readMapFiedsDict(model, monitor, systemFolder); + + readRunDict(model, monitor, systemFolder); + + readCustomDict(model, monitor, systemFolder); + + model.getRuntimeFields().load(controlDict, monitor); + model.runtimeFieldsChanged(); + + model.getFieldManipulationFunctionObjects().load(controlDict, ffoTypes, monitor); + model.fieldManipulationFunctionObjectsChanged(); + + model.getMonitoringFunctionObjects().load(controlDict, mfoTypes, monitor); + model.monitoringFunctionObjectsChanged(); + + if (customDict != null) { + model.getCustom().read(model, customDict, monitor); + model.customChanged(); + } + } + } + + private void readControlDict(Model model, ProgressMonitor monitor, File systemFolder) { + File controlDictFile = new File(systemFolder, ControlDict.CONTROL_DICT); + if (controlDictFile.exists()) { + ControlDict controlDict = new ControlDict(controlDictFile); + try { + setControlDict(controlDict); + controlDict.check(); + monitor.info(ControlDict.CONTROL_DICT, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + getControlDict().functionObjectsToDict(); + } else { + setControlDict(model.getDefaults().getDefaultControlDict()); + monitor.warning(ControlDict.CONTROL_DICT + " not found, the default one will be used", 1); + } + } + + private void readFvSolution(Model model, ProgressMonitor monitor, File systemFolder) { + File fvSolutionFile = new File(systemFolder, FvSolution.FV_SOLUTION); + if (fvSolutionFile.exists()) { + Dictionary fvSolution = new Dictionary(fvSolutionFile); + try { + setFvSolution(fvSolution); + fvSolution.check(); + monitor.info(FvSolution.FV_SOLUTION, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + setFvSolution(model.getDefaults().getDefaultFvSolution()); + monitor.warning(FvSolution.FV_SOLUTION + " not found, the default one will be used", 1); + } + } + + private void readFvSchemes(Model model, ProgressMonitor monitor, File systemFolder) { + File fvSchemesFile = new File(systemFolder, FvSchemes.FV_SCHEMES); + if (fvSchemesFile.exists()) { + Dictionary fvSchemes = new Dictionary(fvSchemesFile); + try { + setFvSchemes(fvSchemes); + fvSchemes.check(); + monitor.info(FvSchemes.FV_SCHEMES, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + setFvSchemes(model.getDefaults().getDefaultFvSchemes()); + monitor.warning(FvSchemes.FV_SCHEMES + " not found, the default one will be used", 1); + } + } + + private void readFvOptions(Model model, ProgressMonitor monitor, File systemFolder) { + File fvOptionsFile = new File(systemFolder, FvOptions.FV_OPTIONS); + if (fvOptionsFile.exists()) { + Dictionary fvOptions = new Dictionary(fvOptionsFile); + try { + setFvOptions(fvOptions); + fvOptions.check(); + monitor.info(FvOptions.FV_OPTIONS, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + setFvOptions(new Dictionary(FvOptions.FV_OPTIONS)); + monitor.warning(FvOptions.FV_OPTIONS + " not found, the default one will be used", 1); + } + } + + private void readSnappyHexMeshDict(Model model, ProgressMonitor monitor, File systemFolder) { + File snappyHexMeshFile = new File(systemFolder, SnappyHexMeshDict.SNAPPY_DICT); + SnappyHexMeshDict snappy = model.getDefaults().getDefaultSnappyHexMeshDict(); + + if (snappyHexMeshFile.exists()) { + SnappyHexMeshDict snappyFromFile = new SnappyHexMeshDict(snappyHexMeshFile); + snappy.merge(snappyFromFile); + setSnappyHexMeshDict(snappy); + try { + snappyHexMeshDict.check(); + monitor.info(SnappyHexMeshDict.SNAPPY_DICT, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + setSnappyHexMeshDict(snappy); + monitor.warning(SnappyHexMeshDict.SNAPPY_DICT + " not found, the default one will be used", 1); + } + } + + private void readBlockMeshDict(Model model, ProgressMonitor monitor, File systemFolder) { + File blockMeshFile = new File(systemFolder, BlockMeshDict.BLOCK_DICT); + if (blockMeshFile.exists()) { + BlockMeshDict dict = null; + if (BlockMeshDict.containsFromFileLine(blockMeshFile)) { + dict = new BlockMeshDict(); + dict.setFromFile(true); + } else { + dict = new BlockMeshDict(blockMeshFile); + dict.setFromFile(false); + } + + try { + setBlockMeshDict(dict); + blockMeshDict.check(); + monitor.info(BlockMeshDict.BLOCK_DICT, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + setBlockMeshDict(model.getDefaults().getDefaultBlockMeshDict()); + monitor.warning(BlockMeshDict.BLOCK_DICT + " not found, the default one will be used", 1); + } + } + + private void readDecomposeParDict(Model model, ProgressMonitor monitor, File systemFolder) { + File decomposeParFile = new File(systemFolder, DecomposeParDict.DECOMPOSE_PAR_DICT); + if (decomposeParFile.exists()) { + Dictionary dict = new DecomposeParDict(decomposeParFile); + try { + setDecomposeParDict(dict); + decomposeParDict.check(); + monitor.info(DecomposeParDict.DECOMPOSE_PAR_DICT, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + setDecomposeParDict(model.getDefaults().getDefaultDecomposeParDict()); + monitor.warning(DecomposeParDict.DECOMPOSE_PAR_DICT+ " not found, the default one will be used", 1); + } + } + + private void readSetFieldsDict(Model model, ProgressMonitor monitor, File systemFolder) { + File setFieldsDictFile = new File(systemFolder, SetFieldsDict.SET_FIELDS_DICT); + if (setFieldsDictFile.exists()) { + Dictionary dict = new SetFieldsDict(setFieldsDictFile); + try { + setSetFieldsDict(dict); + setFieldsDict.check(); + monitor.info(SetFieldsDict.SET_FIELDS_DICT, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + monitor.warning(SetFieldsDict.SET_FIELDS_DICT + " NOT FOUND", 1); + } + } + + private void readMapFiedsDict(Model model, ProgressMonitor monitor, File systemFolder) { + File mapFieldsDictFile = new File(systemFolder, MapFieldsDict.MAP_FIELDS_DICT); + if (mapFieldsDictFile.exists()) { + Dictionary dict = new MapFieldsDict(mapFieldsDictFile); + try { + setMapFieldsDict(dict); + mapFieldsDict.check(); + monitor.info(MapFieldsDict.MAP_FIELDS_DICT, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + setMapFieldsDict(model.getDefaults().getDefaultMapFieldsDict()); + monitor.warning(MapFieldsDict.MAP_FIELDS_DICT + " not found, the default one will be used", 1); + } + } + + private void readRunDict(Model model, ProgressMonitor monitor, File systemFolder) { + File runDictFile = new File(systemFolder, RunDict.RUN_DICT); + if (runDictFile.exists()) { + RunDict dict = new RunDict(runDictFile); + try { + setRunDict(dict); + runDict.check(); + monitor.info(RunDict.RUN_DICT, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + monitor.warning(RunDict.RUN_DICT + " NOT FOUND", 1); + } + } + + private void readCustomDict(Model model, ProgressMonitor monitor, File systemFolder) { + File customNodeDictFile = new File(systemFolder, CustomNodeDict.CUSTOM_NODE_DICT); + if (customNodeDictFile.exists()) { + try { + Dictionary dict = new CustomNodeDict(customNodeDictFile); + setCustomNodeDict(dict); + customDict.check(); + monitor.info(CustomNodeDict.CUSTOM_NODE_DICT, 1); + } catch (DictionaryException e) { + monitor.warning(e.getMessage(), 1); + } + } else { + monitor.warning(CustomNodeDict.CUSTOM_NODE_DICT + " NOT FOUND", 1); + } + } + +} diff --git a/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObject.java b/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObject.java new file mode 100644 index 0000000..88c491c --- /dev/null +++ b/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObject.java @@ -0,0 +1,61 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.fieldmanipulationfunctionobjects; + +import eu.engys.core.dictionary.Dictionary; + +public class FieldManipulationFunctionObject { + + private FieldManipulationFunctionObjectType type; + private Dictionary dictionary; + + public FieldManipulationFunctionObject(FieldManipulationFunctionObjectType type, Dictionary dictionary) { + this.type = type; + this.dictionary = dictionary; + } + + public String getName() { + return dictionary.getName(); + } + + public FieldManipulationFunctionObjectType getType() { + return type; + } + + public Dictionary getDictionary() { + return dictionary; + } + + public void setDictionary(Dictionary dictionary) { + this.dictionary = dictionary; + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjectPanel.java b/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjectPanel.java new file mode 100644 index 0000000..88d7516 --- /dev/null +++ b/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjectPanel.java @@ -0,0 +1,47 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.fieldmanipulationfunctionobjects; + +import javax.swing.JComponent; + +public interface FieldManipulationFunctionObjectPanel { + + void layoutPanel(); + + void load(FieldManipulationFunctionObject... fos); + + void save(FieldManipulationFunctionObject fo); + + JComponent getPanel(); + + void update(); + + void start(); + + void stop(); + +} diff --git a/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjectType.java b/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjectType.java new file mode 100644 index 0000000..bfe6bab --- /dev/null +++ b/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjectType.java @@ -0,0 +1,40 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.system.fieldmanipulationfunctionobjects; + +import eu.engys.core.dictionary.Dictionary; + +public interface FieldManipulationFunctionObjectType { + + public abstract String getLabel(); + + public abstract String getKey(); + + public abstract Dictionary getDefaultDictionary(); + + public abstract FieldManipulationFunctionObjectPanel createPanel(); + +} diff --git a/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjects.java b/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjects.java new file mode 100644 index 0000000..02ff6bc --- /dev/null +++ b/src/eu/engys/core/project/system/fieldmanipulationfunctionobjects/FieldManipulationFunctionObjects.java @@ -0,0 +1,165 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.system.fieldmanipulationfunctionobjects; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.project.system.ControlDict.FUNCTIONS_KEY; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.ControlDict; +import eu.engys.util.progress.ProgressMonitor; + +public class FieldManipulationFunctionObjects extends ArrayList { + + private static Logger logger = LoggerFactory.getLogger(FieldManipulationFunctionObjects.class); + + public FieldManipulationFunctionObjects() { + super(); + } + + /* + * Save + */ + + public void save(Model model, Set types, ProgressMonitor monitor) { + ControlDict controlDict = model.getProject().getSystemFolder().getControlDict(); + controlDict.functionObjectsToDict(); + Dictionary newFunctions = new Dictionary(FUNCTIONS_KEY); + + if (controlDict.found(FUNCTIONS_KEY)) { + + Dictionary oldFunctions = controlDict.subDict(FUNCTIONS_KEY); + + keepOldFunctionObjects_UnknownType(types, oldFunctions, newFunctions); + + } + + for (FieldManipulationFunctionObject fo : this) { + newFunctions.add(fo.getDictionary()); + } + + addFunctionObjectLibs(model, newFunctions); + + controlDict.add(newFunctions); + controlDict.functionObjectsToList(); + } + + public void keepOldFunctionObjects_UnknownType(Set types, Dictionary oldFunctions, Dictionary newFunctions) { + for (Dictionary d : oldFunctions.getDictionaries()) { + if (d.found(TYPE)) { + String type = d.lookup(TYPE); + if (!isKnownFunctionObjectType(types, type)) { + newFunctions.add(new Dictionary(d)); + } + } + } + } + + private void addFunctionObjectLibs(Model model, Dictionary newFunctions) { + Dictionary defaultFunctions = model.getDefaults().getDefaultFunctions(); + for (Dictionary function : newFunctions.getDictionaries()) { + String type = function.lookup(TYPE); + if (defaultFunctions.found(type)) { + function.add("functionObjectLibs", defaultFunctions.subDict(type).lookup("functionObjectLibs")); + } + } + } + + /* + * LOAD + */ + + public void load(ControlDict controlDict, Set types, ProgressMonitor monitor) { + if (controlDict != null && controlDict.isDictionary(FUNCTIONS_KEY)) { + List functions = controlDict.subDict(FUNCTIONS_KEY).getDictionaries(); + for (Dictionary dictionary : functions) { + dictionaryToFunction(dictionary, types); + } + } else if (controlDict != null && controlDict.isList(FUNCTIONS_KEY)) { + List functions = controlDict.getList(FUNCTIONS_KEY).getListElements(); + for (DefaultElement el : functions) { + if (el instanceof Dictionary) { + Dictionary dictionary = (Dictionary) el; + dictionaryToFunction(dictionary, types); + } + } + } + } + + private void dictionaryToFunction(Dictionary dictionary, Set types) { + if (dictionary.found(TYPE)) { + String type = dictionary.lookup(TYPE); + if (isKnownFunctionObjectType(types, type)) { + add(createFunctionObject(dictionary, types, type)); + } else { + logger.warn("Unknown Function Object TYPE {}", type); + } + } + } + + private FieldManipulationFunctionObject createFunctionObject(Dictionary dictionary, Set types, String type) { + FieldManipulationFunctionObjectType foType = getFunctionObjectTypeByKey(types, type); + return new FieldManipulationFunctionObject(foType, dictionary); + } + + public Map toMap() { + Map map = new HashMap(); + for (FieldManipulationFunctionObject zone : this) { + map.put(zone.getName(), zone); + } + return Collections.unmodifiableMap(map); + } + + public boolean isKnownFunctionObjectType(Set types, String typeKey) { + for (FieldManipulationFunctionObjectType type : types) { + if (type.getKey().equals(typeKey)) { + return true; + } + } + return false; + } + + private FieldManipulationFunctionObjectType getFunctionObjectTypeByKey(Set types, String typeKey) { + for (FieldManipulationFunctionObjectType type : types) { + if (type.getKey().equals(typeKey)) { + return type; + } + } + return null; + } +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/FakeParser.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/FakeParser.java new file mode 100644 index 0000000..0e0ab76 --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/FakeParser.java @@ -0,0 +1,74 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import java.io.File; + +public class FakeParser implements Parser { + + @Override + public void init() { + } + + @Override + public void end() { + } + + @Override + public TimeBlocks updateParsing() throws Exception { + return null; + } + + @Override + public boolean checkTimeBlockConsistency(TimeBlocks newTimeBlocks) { + return true; + } + + @Override + public void clear() { + } + + @Override + public File getFile() { + return null; + } + + @Override + public boolean isValidTimeRow(String row) { + return false; + } + + @Override + public boolean isValidDataRow(String row) { + return false; + } + + @Override + public String getKey() { + return ""; + } +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObject.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObject.java new file mode 100644 index 0000000..5a4450e --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObject.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import eu.engys.core.dictionary.Dictionary; + +public class MonitoringFunctionObject { + + private MonitoringFunctionObjectType type; + private Dictionary dictionary; + private ParserView view; + + public MonitoringFunctionObject(MonitoringFunctionObjectType type, Dictionary dictionary) { + this.type = type; + this.dictionary = dictionary; + } + + public String getName() { + return dictionary.getName(); + } + + public MonitoringFunctionObjectType getType() { + return type; + } + + public Dictionary getDictionary() { + return dictionary; + } + + public void setDictionary(Dictionary dictionary) { + this.dictionary = dictionary; + } + + @Override + public String toString() { + return getName(); + } + + public ParserView getView() { + return view; + } + + public void setView(ParserView view) { + this.view = view; + } +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjectPanel.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjectPanel.java new file mode 100644 index 0000000..00052b9 --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjectPanel.java @@ -0,0 +1,49 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import javax.swing.JComponent; + +public interface MonitoringFunctionObjectPanel { + + void layoutPanel(); + + void load(MonitoringFunctionObject... fos); + + void save(MonitoringFunctionObject fo); + + JComponent getPanel(); + + MonitoringFunctionObjectPanel getDisabledPanel(MonitoringFunctionObject fos); + + void update(); + + void start(); + + void stop(); + +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjectType.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjectType.java new file mode 100644 index 0000000..b832921 --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjectType.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import eu.engys.core.dictionary.Dictionary; + +public interface MonitoringFunctionObjectType { + + public abstract String getLabel(); + + public abstract String getKey(); + + public abstract Dictionary getDefaultDictionary(); + + public abstract MonitoringFunctionObjectPanel createPanel(); + + public abstract ParserFactory getFactory(); + +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjects.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjects.java new file mode 100644 index 0000000..6aff8e1 --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/MonitoringFunctionObjects.java @@ -0,0 +1,198 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.project.system.ControlDict.FUNCTIONS_KEY; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.system.ControlDict; +import eu.engys.util.progress.ProgressMonitor; + +public class MonitoringFunctionObjects extends ArrayList { + + private static Logger logger = LoggerFactory.getLogger(MonitoringFunctionObjects.class); + + public MonitoringFunctionObjects() { + super(); + } + + /* + * Save + */ + + public void save(Model model, Set types, ProgressMonitor monitor) { + ControlDict controlDict = model.getProject().getSystemFolder().getControlDict(); + controlDict.functionObjectsToDict(); + Dictionary newFunctions = new Dictionary(FUNCTIONS_KEY); + + if (controlDict.found(FUNCTIONS_KEY)) { + + Dictionary oldFunctions = controlDict.subDict(FUNCTIONS_KEY); + + keepOldFunctionObjects_UnknownType(types, oldFunctions, newFunctions); + + deleteOldFunctionObjects_KnownType_Removed(model, types, oldFunctions); + } + + for (MonitoringFunctionObject fo : this) { + newFunctions.add(fo.getDictionary()); + } + + addFunctionObjectLibs(model, newFunctions); + + controlDict.add(newFunctions); + controlDict.functionObjectsToList(); + } + + public void keepOldFunctionObjects_UnknownType(Set types, Dictionary oldFunctions, Dictionary newFunctions) { + for (Dictionary d : oldFunctions.getDictionaries()) { + if (d.found(TYPE)) { + String type = d.lookup(TYPE); + if (!isKnownFunctionObjectType(types, type)) { + newFunctions.add(new Dictionary(d)); + } + } + } + } + + public void deleteOldFunctionObjects_KnownType_Removed(Model model, Set types, Dictionary oldFunctions) { + for (Dictionary d : oldFunctions.getDictionaries()) { + if (d.found(TYPE)) { + String type = d.lookup(TYPE); + if (isKnownFunctionObjectType(types, type)) { + if (!contains(d.getName())) { + File postProcFolder = new File(model.getProject().getBaseDir(), openFOAMProject.POST_PROC); + File foFolder = new File(postProcFolder, d.getName()); + if (foFolder.exists()) { + logger.warn("{} function object deleted", d.getName()); + FileUtils.deleteQuietly(foFolder); + } + } + } + } + } + } + + private boolean contains(String foName) { + for (MonitoringFunctionObject fo : this) { + if (fo.getName().equals(foName)) { + return true; + } + } + return false; + } + + private void addFunctionObjectLibs(Model model, Dictionary newFunctions) { + Dictionary defaultFunctions = model.getDefaults().getDefaultFunctions(); + for (Dictionary function : newFunctions.getDictionaries()) { + String type = function.lookup(TYPE); + if (defaultFunctions.found(type)) { + function.add("functionObjectLibs", defaultFunctions.subDict(type).lookup("functionObjectLibs")); + } + } + } + + /* + * LOAD + */ + + public void load(ControlDict controlDict, Set types, ProgressMonitor monitor) { + if (controlDict != null && controlDict.isDictionary(FUNCTIONS_KEY)) { + List functions = controlDict.subDict(FUNCTIONS_KEY).getDictionaries(); + for (Dictionary dictionary : functions) { + dictionaryToFunction(dictionary, types); + } + } else if (controlDict != null && controlDict.isList(FUNCTIONS_KEY)) { + List functions = controlDict.getList(FUNCTIONS_KEY).getListElements(); + for (DefaultElement el : functions) { + if (el instanceof Dictionary) { + Dictionary dictionary = (Dictionary) el; + dictionaryToFunction(dictionary, types); + } + } + } + } + + private void dictionaryToFunction(Dictionary dictionary, Set types) { + if (dictionary.found(TYPE)) { + String type = dictionary.lookup(TYPE); + if (isKnownFunctionObjectType(types, type)) { + add(createFunctionObject(dictionary, types, type)); + } else { + logger.warn("Unknown Function Object TYPE {}", type); + } + } + } + + private MonitoringFunctionObject createFunctionObject(Dictionary dictionary, Set types, String type) { + MonitoringFunctionObjectType foType = getFunctionObjectTypeByKey(types, type); + MonitoringFunctionObject fo = new MonitoringFunctionObject(foType, dictionary); + return fo; + } + + public Map toMap() { + Map map = new HashMap(); + for (MonitoringFunctionObject zone : this) { + map.put(zone.getName(), zone); + } + return Collections.unmodifiableMap(map); + } + + public boolean isKnownFunctionObjectType(Set types, String typeKey) { + for (MonitoringFunctionObjectType type : types) { + if (type.getKey().equals(typeKey)) { + return true; + } + } + return false; + } + + private MonitoringFunctionObjectType getFunctionObjectTypeByKey(Set types, String typeKey) { + for (MonitoringFunctionObjectType type : types) { + if (type.getKey().equals(typeKey)) { + return type; + } + } + return null; + } +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/Parser.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/Parser.java new file mode 100644 index 0000000..f84510d --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/Parser.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import java.io.File; + +public interface Parser { + + void init(); + + void end(); + + void clear(); + + File getFile(); + + TimeBlocks updateParsing() throws Exception; + + boolean isValidTimeRow(String row); + + boolean isValidDataRow(String row); + + String getKey(); + + boolean checkTimeBlockConsistency(TimeBlocks newTimeBlocks); + +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/ParserFactory.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/ParserFactory.java new file mode 100644 index 0000000..efe831a --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/ParserFactory.java @@ -0,0 +1,39 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import java.util.List; + +public interface ParserFactory { + + void deleteUselessLogFiles(MonitoringFunctionObject functionObject); + + List createParsers(MonitoringFunctionObject functionObject); + + ParserView createView(MonitoringFunctionObject functionObject); + +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/ParserView.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/ParserView.java new file mode 100644 index 0000000..53e5bfa --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/ParserView.java @@ -0,0 +1,73 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import java.util.List; + +import javax.swing.JComponent; + +import eu.engys.core.report.Exporter; + +public interface ParserView { + + public void reset(); + public void showLoading(); + public void stopLoading(); + public void handleSolverStarted(); + void clearData(); + + public void handleFunctionObjectChanged(); + + public JComponent getPanel(); + + public boolean isParsingEnabled(); + + public void setParsingEnabled(boolean parsingEnabled); + + void updateParsing(List newTimeBlocks); + + public String getKey(); + + public void stop(); + + void showLogFile(); + + void setCrosshairVisibile(boolean visible); + + void exportToExcel(); + + void exportToCSV(); + + void exportToPNG(); + + List gerReportParsersList(); + + Exporter getExporter(); + + + +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlock.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlock.java new file mode 100644 index 0000000..bbdff86 --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlock.java @@ -0,0 +1,67 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +public class TimeBlock implements Serializable { + + private Double time; + private Map unitsMap; + + public TimeBlock(Double time) { + this.time = time; + this.unitsMap = new LinkedHashMap(); + } + + public Map getUnitsMap() { + return unitsMap; + } + + public int getSize() { + return unitsMap.size(); + } + + public Double getTime() { + return time; + } + + public void setTime(Double time) { + this.time = time; + } + + @Override + public String toString() { + StringBuffer rowstring = new StringBuffer(); + for (String var : getUnitsMap().keySet()) { + rowstring.append(var + " "); + } + return "TIME BLOCK " + getTime() + " ROW KEYS: " + rowstring.toString(); + } +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlockUnit.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlockUnit.java new file mode 100644 index 0000000..d5175b3 --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlockUnit.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import java.io.Serializable; + +public abstract class TimeBlockUnit implements Serializable { + + private String varName; + + public TimeBlockUnit(String varName) { + this.varName = varName; + } + + public String getVarName() { + return varName; + } + + public void setVarName(String varName) { + this.varName = varName; + } + + @Override + public String toString() { + return "[" + getVarName() + "]"; + } + +} diff --git a/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlocks.java b/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlocks.java new file mode 100644 index 0000000..a2b84d6 --- /dev/null +++ b/src/eu/engys/core/project/system/monitoringfunctionobjects/TimeBlocks.java @@ -0,0 +1,158 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.system.monitoringfunctionobjects; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import com.google.common.collect.Lists; + +public class TimeBlocks implements Iterable, Serializable { + + private static final long serialVersionUID = 42L; + + private List list; + Object mutex; + + private String key; + + public TimeBlocks(String key) { + this.key = key; + list = new LinkedList<>(); + mutex = this; + } + + public TimeBlocks() { + this(""); + } + + public TimeBlocks(List blocks) { + this(); + if (!blocks.isEmpty()) { + for (TimeBlocks tb : blocks) { + addAll(tb); + } + this.key = blocks.get(0).getKey(); + } + } + + public void setKey(String key) { + synchronized (mutex) { + this.key = key; + } + } + + public String getKey() { + synchronized (mutex) { + return key; + } + } + + public void clear() { + synchronized (mutex) { + list.clear(); + } + } + + public String toString() { + synchronized (mutex) { + return list.toString(); + } + } + + public int size() { + synchronized (mutex) { + return list.size(); + } + } + + public boolean isEmpty() { + synchronized (mutex) { + return list.isEmpty(); + } + } + + public boolean addAll(TimeBlocks blocks) { + synchronized (mutex) { + return list.addAll(Lists.newArrayList(blocks)); + } + } + + public boolean add(TimeBlock block) { + synchronized (mutex) { + return list.add(block); + } + } + + public TimeBlock get(int index) { + synchronized (mutex) { + return list.get(index); + } + } + + public TimeBlock remove(int index) { + synchronized (mutex) { + return list.remove(index); + } + } + + public int indexOf(Object o) { + synchronized (mutex) { + return list.indexOf(o); + } + } + + public int lastIndexOf(Object o) { + synchronized (mutex) { + return list.lastIndexOf(o); + } + } + + public TimeBlock getLast() { + return get(list.size() - 1); + } + + public TimeBlock removeLast() { + return remove(list.size() - 1); + } + + public Iterator iterator() { + synchronized (mutex) { + return list.iterator(); + } + } + + // private void writeObject(java.io.ObjectOutputStream out) throws + // IOException { + // + // } + // private void readObject(java.io.ObjectInputStream in) throws IOException, + // ClassNotFoundException { + // + // } +} diff --git a/src/eu/engys/core/project/zero/MeshRegion.java b/src/eu/engys/core/project/zero/MeshRegion.java new file mode 100644 index 0000000..0357077 --- /dev/null +++ b/src/eu/engys/core/project/zero/MeshRegion.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero; + +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.patches.Patches; + +public class MeshRegion { + + private Patches patches; + private Fields fields; + + public void setPatches(Patches patches) { + this.patches = patches; + } + + public Patches getPatches() { + return patches; + } + + public void setFields(Fields fields) { + this.fields = fields; + } + + public Fields getFields() { + return fields; + } +} diff --git a/src/eu/engys/core/project/zero/ParallelZeroFileManager.java b/src/eu/engys/core/project/zero/ParallelZeroFileManager.java new file mode 100644 index 0000000..7cb2293 --- /dev/null +++ b/src/eu/engys/core/project/zero/ParallelZeroFileManager.java @@ -0,0 +1,276 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero; + +import static eu.engys.core.project.zero.ZeroFolderUtil.clearFiles; +import static eu.engys.core.project.zero.ZeroFolderUtil.delete; +import static eu.engys.core.project.zero.ZeroFolderUtil.getBoundaryFile; +import static eu.engys.core.project.zero.ZeroFolderUtil.getCellZonesFile; +import static eu.engys.core.project.zero.ZeroFolderUtil.getFaceZonesFile; +import static eu.engys.core.project.zero.ZeroFolderUtil.getPolyMeshDir; +import static eu.engys.core.project.zero.ZeroFolderUtil.getRegionDir; +import static eu.engys.core.project.zero.ZeroFolderUtil.newZeroDir; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.List; + +import eu.engys.core.project.files.DefaultFileManager; +import eu.engys.core.project.system.ControlDict; + +public class ParallelZeroFileManager extends DefaultFileManager implements ZeroFileManager { + + public ParallelZeroFileManager(File file, int nProcessors) { + super(file); + newZeroDirs(nProcessors); + } + + @Override + public void newZeroDirs(int nProcessors) { + if (nProcessors > 1) { + for (int i = 0; i < nProcessors; i++) { + File processorDir = newFile("processor" + i); + if (!processorDir.exists()) { + processorDir.mkdir(); + logger.warn("-> New Folder {}", processorDir); + } + newZeroDir(processorDir); + } + } + } + + @Override + public void clearZeroDirs(String timeStep) { + logger.debug("Clear zero folder!"); + for (File file : getZeroDirs(timeStep)) { + clearFiles(file); + } + } + + @Override + public String findTimeValue(ControlDict controlDict) { + File processor = newFile("processor0"); + if (processor.exists()) { + String zero = ZeroFolderUtil.findTimeValue(processor, controlDict); + logger.debug("Find Time Value: {}", zero); + return zero; + } else { + return "0"; + } + } + + @Override + public File[] getZeroDirs(String timeStep) { + List zeroFolders = new ArrayList(); + for (int i = 0;; i++) { + File processor = newFile("processor" + i); + if (processor.exists()) { + File zeroFolder = new File(processor, ZeroFolderUtil.getTimeStepString(timeStep)); + + if (zeroFolder.exists() && zeroFolder.isDirectory()) { + zeroFolders.add(zeroFolder); + } else { + logger.warn("Folder {} is missing", zeroFolder.getAbsolutePath()); + } + + File constantFolder = new File(processor, "constant"); + if (!constantFolder.exists()) { + constantFolder.mkdir(); + logger.warn("Folder {} is missing", constantFolder.getAbsolutePath()); + } + } else { + break; + } + } + return zeroFolders.toArray(new File[zeroFolders.size()]); + } + + @Override + public File[] getConstantDirs() { + List constantFolders = new ArrayList(); + + for (int i = 0;; i++) { + File processor = newFile("processor" + i); + if (processor.exists()) { + File constantFolder = new File(processor, "constant"); + + if (constantFolder.exists() && constantFolder.isDirectory()) { + constantFolders.add(constantFolder); + } + } else { + break; + } + } + return constantFolders.toArray(new File[constantFolders.size()]); + } + + @Override + public File[] getRegionDirs(String region, File[] zeroDir) { + File[] polyMesh = new File[zeroDir.length]; + for (int i = 0; i < polyMesh.length; i++) { + polyMesh[i] = getRegionDir(zeroDir[i], region); + } + return polyMesh; + } + + @Override + public File[] getPolyMeshDirs(File[] zeroDir) { + File[] polyMesh = new File[zeroDir.length]; + for (int i = 0; i < polyMesh.length; i++) { + polyMesh[i] = getPolyMeshDir(zeroDir[i]); + } + return polyMesh; + } + + @Override + public File[] getBoundaryFiles(File[] polyMesh) { + File[] boundary = new File[polyMesh.length]; + for (int i = 0; i < boundary.length; i++) { + boundary[i] = getBoundaryFile(polyMesh[i]); + } + return boundary; + } + + @Override + public File[] getCellZonesFiles(File[] polyMesh) { + File[] cellZones = new File[polyMesh.length]; + for (int i = 0; i < cellZones.length; i++) { + cellZones[i] = getCellZonesFile(polyMesh[i]); + } + return cellZones; + } + + @Override + public File[] getFaceZonesFiles(File[] polyMesh) { + File[] faceZones = new File[polyMesh.length]; + for (int i = 0; i < faceZones.length; i++) { + faceZones[i] = getFaceZonesFile(polyMesh[i]); + } + return faceZones; + } + + @Override + public ZeroFolderStructure checkFileSystem() { + ZeroFolderStructure check = new ZeroFolderStructure(); + + String timeStep = findTimeValue(null); + + File[] zeroDirs = getZeroDirs(timeStep); + File[] polyMeshes = getPolyMeshDirs(zeroDirs); + File[] boundaryFiles = getBoundaryFiles(polyMeshes); + + if (ZeroFolderUtil.exists(boundaryFiles)) { + check.setBoundaryFieldInZero(true); + } else { + File[] constantDirs = getConstantDirs(); + polyMeshes = getPolyMeshDirs(constantDirs); + boundaryFiles = getBoundaryFiles(polyMeshes); + + if (ZeroFolderUtil.exists(boundaryFiles)) { + check.setBoundaryFieldInConstant(true); + } + } + return check; + } + + @Override + public void deleteAll() { + removeRegionsZeroDirs(); + removeRegionsConstantDirs(); + removeZeroDirs("0"); + removeConstantDirs(); + removeNonZeroDirs("0"); + } + + private void removeRegionsZeroDirs() { + File[] zeroDirs = getZeroDirs("0"); + String[] regionNames = ZeroFolderUtil.getRegions(zeroDirs); + for (String regionName : regionNames) { + File[] regionDirs = getRegionDirs(regionName, zeroDirs); + delete(regionDirs); + } + } + + private void removeRegionsConstantDirs() { + File[] constantDirs = getConstantDirs(); + String[] regionNames = ZeroFolderUtil.getRegions(constantDirs); + for (String regionName : regionNames) { + File[] regionDirs = getRegionDirs(regionName, constantDirs); + delete(regionDirs); + } + } + + @Override + public void removeZeroDirs(String timeStep) { + File[] zeroDirs = getZeroDirs(timeStep); + delete(zeroDirs); + } + + public void removeConstantDirs() { + File[] constantDirs = getConstantDirs(); + delete(constantDirs); + } + + @Override + public void removeNonZeroDirs(String timeStep) { + File[] nonZeroDirs = getNonZeroDirs(timeStep); + delete(nonZeroDirs); + } + + @Override + public File[] getNonZeroDirs(String timeStep) { + List nonZeroFolders = new ArrayList(); + for (int i = 0;; i++) { + File processor = newFile("processor" + i); + if (processor.exists()) { + File[] foldersWithANumberName = processor.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + try { + Double.parseDouble(name); + return true; + } catch (NumberFormatException nfee) { + return false; + } + } + }); + if (foldersWithANumberName.length > 0) { + for (File folder : foldersWithANumberName) { + double folderValue = Double.parseDouble(folder.getName()); + double timeStepValue = Double.parseDouble(timeStep); + if (folderValue > timeStepValue) { + nonZeroFolders.add(folder); + } + } + } + } else { + break; + } + } + return nonZeroFolders.toArray(new File[nonZeroFolders.size()]); + } +} diff --git a/src/eu/engys/core/project/zero/SerialZeroFileManager.java b/src/eu/engys/core/project/zero/SerialZeroFileManager.java new file mode 100644 index 0000000..6e80c32 --- /dev/null +++ b/src/eu/engys/core/project/zero/SerialZeroFileManager.java @@ -0,0 +1,237 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero; + +import static eu.engys.core.project.zero.ZeroFolderUtil.clearFiles; +import static eu.engys.core.project.zero.ZeroFolderUtil.delete; +import static eu.engys.core.project.zero.ZeroFolderUtil.getBoundaryFile; +import static eu.engys.core.project.zero.ZeroFolderUtil.getCellZonesFile; +import static eu.engys.core.project.zero.ZeroFolderUtil.getConstantDir; +import static eu.engys.core.project.zero.ZeroFolderUtil.getFaceZonesFile; +import static eu.engys.core.project.zero.ZeroFolderUtil.getPolyMeshDir; +import static eu.engys.core.project.zero.ZeroFolderUtil.getRegionDir; +import static eu.engys.core.project.zero.ZeroFolderUtil.newZeroDir; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.FileUtils; + +import eu.engys.core.project.files.DefaultFileManager; +import eu.engys.core.project.system.ControlDict; + +public class SerialZeroFileManager extends DefaultFileManager implements ZeroFileManager { + + public SerialZeroFileManager(File file) { + super(file); + newZeroDirs(1); + } + + @Override + public void newZeroDirs(int nProcessors) { + if (nProcessors == 1) { + newZeroDir(getFile()); + } + } + + @Override + public void clearZeroDirs(String timeStep) { + for (File file : getZeroDirs(timeStep)) { + clearFiles(file); + } + } + + @Override + public String findTimeValue(ControlDict controlDict) { + return ZeroFolderUtil.findTimeValue(getFile(), controlDict); + } + + @Override + public File[] getZeroDirs(String timeStep) { + return arrayOf(newFile(ZeroFolderUtil.getTimeStepString(timeStep))); + } + + @Override + public File[] getConstantDirs() { + return arrayOf(getConstantDir(getFile())); + } + + @Override + public File[] getRegionDirs(String region, File[] zeroDirs) { + if (isOne(zeroDirs)) { + File zeroDir = zeroDirs[0]; + return arrayOf(getRegionDir(zeroDir, region)); + } else { + throw new RuntimeException(""); + } + } + + @Override + public File[] getPolyMeshDirs(File[] zeroDirs) { + if (isOne(zeroDirs)) { + File zeroDir = zeroDirs[0]; + return arrayOf(getPolyMeshDir(zeroDir)); + } else { + throw new RuntimeException(""); + } + } + + @Override + public File[] getBoundaryFiles(File[] polyMeshDirs) { + if (isOne(polyMeshDirs)) { + File polyMesh = polyMeshDirs[0]; + return arrayOf(getBoundaryFile(polyMesh)); + } else { + throw new RuntimeException(""); + } + } + + @Override + public File[] getCellZonesFiles(File[] polyMeshDirs) { + if (isOne(polyMeshDirs)) { + File polyMesh = polyMeshDirs[0]; + return arrayOf(getCellZonesFile(polyMesh)); + } else { + throw new RuntimeException(""); + } + } + + @Override + public File[] getFaceZonesFiles(File[] polyMeshDirs) { + if (isOne(polyMeshDirs)) { + File polyMesh = polyMeshDirs[0]; + return arrayOf(getFaceZonesFile(polyMesh)); + } else { + throw new RuntimeException(""); + } + } + + private File[] arrayOf(File file) { + return new File[] { file }; + } + + private boolean isOne(File[] files) { + return files.length == 1; + } + + @Override + public ZeroFolderStructure checkFileSystem() { + ZeroFolderStructure check = new ZeroFolderStructure(); + + String timeStep = findTimeValue(null); + + File zeroDir = getZeroDirs(timeStep)[0]; + File polyMesh = getPolyMeshDir(zeroDir); + File boundaryFile = getBoundaryFile(polyMesh); + + if (boundaryFile.exists()) { + check.setBoundaryFieldInZero(true); + } else { + File constantDir = getConstantDir(getFile()); + polyMesh = getPolyMeshDir(constantDir); + boundaryFile = getBoundaryFile(polyMesh); + + if (boundaryFile.exists()) { + check.setBoundaryFieldInConstant(true); + } + } + + return check; + } + + @Override + public void deleteAll() { + removeRegionsZeroDirs(); + removeRegionsConstantDirs(); + removeZeroDirs("0"); + removeConstantPolyMeshDirs(); + removeNonZeroDirs("0"); + } + + private void removeRegionsZeroDirs() { + File[] zeroDirs = getZeroDirs("0"); + String[] regionNames = ZeroFolderUtil.getRegions(zeroDirs); + for (String regionName : regionNames) { + File[] regionDirs = getRegionDirs(regionName, zeroDirs); + delete(regionDirs); + } + } + + private void removeRegionsConstantDirs() { + File[] constantDirs = getConstantDirs(); + String[] regionNames = ZeroFolderUtil.getRegions(constantDirs); + for (String regionName : regionNames) { + File[] regionDirs = getRegionDirs(regionName, constantDirs); + delete(regionDirs); + } + } + + @Override + public void removeZeroDirs(String timeStep) { + File zeroDir = new File(getFile(), ZeroFolderUtil.getTimeStepString(timeStep)); + FileUtils.deleteQuietly(zeroDir); + } + + @Override + public void removeNonZeroDirs(String timeStep) { + File[] nonZeroDirs = getNonZeroDirs(timeStep); + delete(nonZeroDirs); + } + + private void removeConstantPolyMeshDirs() { + File[] constantDirs = getConstantDirs(); + File[] polyMeshes = getPolyMeshDirs(constantDirs); + delete(polyMeshes); + } + + @Override + public File[] getNonZeroDirs(String timeStep) { + List nonZeroFolders = new ArrayList(); + File[] foldersWithANumberName = getFile().listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + try { + Double.parseDouble(name); + return true; + } catch (NumberFormatException nfee) { + return false; + } + } + }); + if (foldersWithANumberName.length > 0) { + for (File folder : foldersWithANumberName) { + double folderValue = Double.parseDouble(folder.getName()); + double timeStepValue = Double.parseDouble(timeStep); + if (folderValue > timeStepValue) { + nonZeroFolders.add(folder); + } + } + } + return nonZeroFolders.toArray(new File[nonZeroFolders.size()]); + } +} diff --git a/src/eu/engys/core/project/zero/ZeroFileManager.java b/src/eu/engys/core/project/zero/ZeroFileManager.java new file mode 100644 index 0000000..a3aeb79 --- /dev/null +++ b/src/eu/engys/core/project/zero/ZeroFileManager.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero; + +import java.io.File; + +import eu.engys.core.project.files.FileManager; +import eu.engys.core.project.system.ControlDict; + +public interface ZeroFileManager extends FileManager { + + File[] getZeroDirs(String timeStep); + + File[] getNonZeroDirs(String timeStep); + + File[] getPolyMeshDirs(File[] zeroDirs); + + File[] getBoundaryFiles(File[] polyMeshes); + + File[] getCellZonesFiles(File[] polyMeshes); + + File[] getFaceZonesFiles(File[] polyMeshes); + + File[] getConstantDirs(); + + File[] getRegionDirs(String region, File[] zeroDirs); + + void newZeroDirs(int nProcessors); + + void clearZeroDirs(String timeStep); + + ZeroFolderStructure checkFileSystem(); + + void removeZeroDirs(String timeStep); + + void removeNonZeroDirs(String timeStep); + + String findTimeValue(ControlDict controlDict); + +} diff --git a/src/eu/engys/core/project/zero/ZeroFolder.java b/src/eu/engys/core/project/zero/ZeroFolder.java new file mode 100644 index 0000000..9e92dd0 --- /dev/null +++ b/src/eu/engys/core/project/zero/ZeroFolder.java @@ -0,0 +1,438 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.defaults.DefaultsProvider; +import eu.engys.core.project.files.FileManager; +import eu.engys.core.project.files.Folder; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.cellzones.CellZones; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; +import eu.engys.core.project.zero.cellzones.CellZonesReader; +import eu.engys.core.project.zero.cellzones.CellZonesWriter; +import eu.engys.core.project.zero.facezones.FaceZones; +import eu.engys.core.project.zero.facezones.FaceZonesReader; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.fields.FieldsDefaults; +import eu.engys.core.project.zero.fields.FieldsReader; +import eu.engys.core.project.zero.fields.FieldsWriter; +import eu.engys.core.project.zero.fields.Initialisations; +import eu.engys.core.project.zero.patches.BoundaryConditionsDefaults; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.core.project.zero.patches.PatchesReader; +import eu.engys.core.project.zero.patches.PatchesWriter; +import eu.engys.util.progress.ConsoleMonitor; +import eu.engys.util.progress.ProgressMonitor; + +public class ZeroFolder implements Folder { + + private static final Logger logger = LoggerFactory.getLogger(ZeroFolder.class); + + private ZeroFileManager zeroFileManager; + + private Map regions = new HashMap<>(); + + private String timeValue = "0"; + + public ZeroFolder(openFOAMProject prj) { + zeroFileManager = prj.isParallel() ? new ParallelZeroFileManager(prj.getBaseDir(), prj.getProcessors()) : new SerialZeroFileManager(prj.getBaseDir()); + } + + public ZeroFolder(File baseDir, ZeroFolder zeroFolder) { + if (zeroFolder.getFileManager() instanceof ParallelZeroFileManager) { + ParallelZeroFileManager pZero = (ParallelZeroFileManager) zeroFolder.getFileManager(); + zeroFileManager = new ParallelZeroFileManager(baseDir, pZero.getZeroDirs(zeroFolder.getTimeValue()).length); + } else { + zeroFileManager = new SerialZeroFileManager(baseDir); + } + this.timeValue = zeroFolder.getTimeValue(); + } + + public void read(Model model, CellZonesBuilder builder, Set modules, Initialisations initialisations, ProgressMonitor monitor) { + try { + timeValue = zeroFileManager.findTimeValue(model.getProject().getSystemFolder().getControlDict()); + + File[] zeroDirs = zeroFileManager.getZeroDirs("0"); + File[] timeDirs = zeroFileManager.getZeroDirs(timeValue); + File[] polyMeshes = zeroFileManager.getPolyMeshDirs(zeroDirs); + File[] boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + File[] cellZonesFiles = zeroFileManager.getCellZonesFiles(polyMeshes); + File[] faceZonesFiles = zeroFileManager.getFaceZonesFiles(polyMeshes); + String[] regionNames = ZeroFolderUtil.getRegions(zeroDirs); + + if (!ZeroFolderUtil.exists(boundaryFiles)) { + File[] constantDirs = zeroFileManager.getConstantDirs(); + polyMeshes = zeroFileManager.getPolyMeshDirs(constantDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + cellZonesFiles = zeroFileManager.getCellZonesFiles(polyMeshes); + faceZonesFiles = zeroFileManager.getFaceZonesFiles(polyMeshes); + regionNames = ZeroFolderUtil.getRegions(constantDirs); + } + + monitor.setIndeterminate(false); + + model.setPatches(readPatches(monitor, boundaryFiles)); + model.setCellZones(readCellZones(model, builder, monitor, cellZonesFiles, modules)); + model.setFaceZones(readFaceZones(monitor, faceZonesFiles)); + model.setFields(readFields(null, model.getProject(), model.getState(), model.getDefaults(), model.getPatches(), modules, initialisations, monitor, timeDirs, boundaryFiles)); + + BoundaryConditionsDefaults.loadBoundaryConditionsFromFields(model.getPatches(), model.getFields()); + + regions.clear(); + if (regionNames != null && regionNames.length > 0) { + logger.info("REGIONS: found regions {}", Arrays.toString(regionNames)); + for (String regionName : regionNames) { + zeroDirs = zeroFileManager.getZeroDirs("0"); + timeDirs = zeroFileManager.getZeroDirs(timeValue); + File[] regionTimeDirs = zeroFileManager.getRegionDirs(regionName, timeDirs); + + ZeroFolderUtil.mkDirs(regionTimeDirs); + + File[] regionDirs = zeroFileManager.getRegionDirs(regionName, zeroDirs); + polyMeshes = zeroFileManager.getPolyMeshDirs(regionDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + cellZonesFiles = zeroFileManager.getCellZonesFiles(polyMeshes); + faceZonesFiles = zeroFileManager.getFaceZonesFiles(polyMeshes); + + if (!ZeroFolderUtil.exists(boundaryFiles)) { + File[] constantDirs = zeroFileManager.getConstantDirs(); + regionDirs = zeroFileManager.getRegionDirs(regionName, constantDirs); + polyMeshes = zeroFileManager.getPolyMeshDirs(regionDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + cellZonesFiles = zeroFileManager.getCellZonesFiles(polyMeshes); + faceZonesFiles = zeroFileManager.getFaceZonesFiles(polyMeshes); + } + + Patches patches = readPatches(monitor, boundaryFiles); + Fields fields = readFields(regionName, model.getProject(), model.getState(), model.getDefaults(), patches, modules, initialisations, monitor, regionTimeDirs, boundaryFiles); + MeshRegion region = new MeshRegion(); + region.setPatches(patches); + region.setFields(fields); + + BoundaryConditionsDefaults.loadBoundaryConditionsFromFields(patches, fields); + regions.put(regionName, region); + } + } + } catch (Exception e) { + logger.error("Error in load", e); + monitor.error(e.getMessage(), 1); + } + model.patchesChanged(); + model.cellZonesChanged(); + model.faceZonesChanged(); + } + + public Patches readPatches() { + File[] zeroDirs = zeroFileManager.getZeroDirs("0"); + File[] polyMeshes = zeroFileManager.getPolyMeshDirs(zeroDirs); + File[] boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + + if (!ZeroFolderUtil.exists(boundaryFiles)) { + File[] constantDirs = zeroFileManager.getConstantDirs(); + polyMeshes = zeroFileManager.getPolyMeshDirs(constantDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + } + + return readPatches(new ConsoleMonitor(), boundaryFiles); + } + + public Patches readPatches(String regionName) { + File[] zeroDirs = zeroFileManager.getZeroDirs("0"); + File[] regionDirs = zeroFileManager.getRegionDirs(regionName, zeroDirs); + File[] polyMeshes = zeroFileManager.getPolyMeshDirs(regionDirs); + File[] boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + + if (!ZeroFolderUtil.exists(boundaryFiles)) { + File[] constantDirs = zeroFileManager.getConstantDirs(); + regionDirs = zeroFileManager.getRegionDirs(regionName, constantDirs); + polyMeshes = zeroFileManager.getPolyMeshDirs(regionDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + } + + return readPatches(new ConsoleMonitor(), boundaryFiles); + } + + private Patches readPatches(ProgressMonitor monitor, File[] boundaryFiles) { + if (ZeroFolderUtil.exists(boundaryFiles)) { + monitor.setCurrent("Reading patches", 0, boundaryFiles.length, 1); + Patches patches = new PatchesReader(monitor).read(boundaryFiles); + monitor.info("Patches: " + patches.filterProcBoundary().patchesNames().toString(), 1); + return patches; + } else { + monitor.warning("Missing boundary fields", 1); + logger.warn(Arrays.toString(boundaryFiles) + " does not exist"); + return new Patches(); + } + } + + private CellZones readCellZones(Model model, CellZonesBuilder builder, ProgressMonitor monitor, File[] cellZonesFiles, Set modules) { + if (ZeroFolderUtil.exists(cellZonesFiles)) { + monitor.setCurrent("Reading cell zones", 0, cellZonesFiles.length, 1); + CellZones cellZones = new CellZonesReader(model, builder, modules, monitor).read(cellZonesFiles); + monitor.info("Cell Zones: " + cellZones.zonesNames().toString(), 1); + return cellZones; + } else { + monitor.warning("Missing cellZones file", 1); + logger.warn(Arrays.toString(cellZonesFiles) + " does not exist"); + return new CellZones(); + } + } + + private FaceZones readFaceZones(ProgressMonitor monitor, File[] faceZonesFiles) { + if (ZeroFolderUtil.exists(faceZonesFiles)) { + monitor.setCurrent("Reading face zones", 0, faceZonesFiles.length, 1); + FaceZones faceZones = new FaceZonesReader(monitor).read(faceZonesFiles); + monitor.info("Face Zones: " + faceZones.zonesNames().toString(), 1); + return faceZones; + } else { + monitor.warning("Missing faceZones file", 1); + logger.warn(Arrays.toString(faceZonesFiles) + " does not exist"); + return new FaceZones(); + } + } + + private Fields readFields(String region, openFOAMProject prj, State state, DefaultsProvider defaults, Patches patches, Set modules, Initialisations initialisations, ProgressMonitor monitor, File[] timeDirs, File[] boundaryFiles) { + if (initialisations != null && ZeroFolderUtil.exists(timeDirs) && ZeroFolderUtil.exists(boundaryFiles)) { + Fields fields = new Fields(); + if (prj.isParallel()) { + fields.newParallelFields(prj.getProcessors()); + } + logger.debug("Loading fields from defaults"); + fields.merge(FieldsDefaults.loadFieldsFromDefaults(state, defaults, patches, region)); + logger.debug("Loading fields from MODULE defaults"); + fields.merge(ModulesUtil.loadFieldsFromDefaults(modules, region)); + logger.debug("Reading field from case"); + fields.merge(new FieldsReader(initialisations, monitor).read(fields.keySet(), timeDirs)); + fields.fixPVisibility(state); + + monitor.info("Fields: " + fields.fieldNames().toString(), 1); + return fields; + } else { + monitor.warning("Missing fields", 1); + logger.warn(Arrays.toString(timeDirs) + " does not exist"); + return new Fields(); + } + } + + /* + * Write + */ + + public void write(Model model, CellZonesBuilder cellZonesBuilder, Set modules, Initialisations initialisations, ProgressMonitor monitor) { + if (avoidSave(model)) + return; + + try { + String currentTimeValue = zeroFileManager.findTimeValue(model.getProject().getSystemFolder().getControlDict()); + boolean timeStepHasChanged = !currentTimeValue.equals(timeValue); + if (timeStepHasChanged) { + logger.info("Timestep has changed {} -> {}", timeValue, currentTimeValue); + this.timeValue = currentTimeValue; + } + + File[] zeroDirs = zeroFileManager.getZeroDirs("0"); + File[] timeDirs = zeroFileManager.getZeroDirs(timeValue); + File[] polyMeshes = zeroFileManager.getPolyMeshDirs(zeroDirs); + File[] boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + File[] cellZonesFiles = zeroFileManager.getCellZonesFiles(polyMeshes); + + if (!ZeroFolderUtil.exists(boundaryFiles)) { + File[] constantDirs = zeroFileManager.getConstantDirs(); + polyMeshes = zeroFileManager.getPolyMeshDirs(constantDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + cellZonesFiles = zeroFileManager.getCellZonesFiles(polyMeshes); + } + + writePatches(model.getPatches(), model, monitor, boundaryFiles); + writeCellZones(model, cellZonesBuilder, monitor, cellZonesFiles, modules); + writeFields(model.getFields(), model.getPatches(), modules, initialisations, monitor, timeDirs, boundaryFiles, timeStepHasChanged); + + if (!regions.isEmpty()) { + for (String regionName : regions.keySet()) { + MeshRegion region = regions.get(regionName); + + zeroDirs = zeroFileManager.getZeroDirs("0"); + File[] regionTimeDirs = zeroFileManager.getRegionDirs(regionName, timeDirs); + File[] regionDirs = zeroFileManager.getRegionDirs(regionName, zeroDirs); + polyMeshes = zeroFileManager.getPolyMeshDirs(regionDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + cellZonesFiles = zeroFileManager.getCellZonesFiles(polyMeshes); + + if (!ZeroFolderUtil.exists(boundaryFiles)) { + File[] constantDirs = zeroFileManager.getConstantDirs(); + regionDirs = zeroFileManager.getRegionDirs(regionName, constantDirs); + polyMeshes = zeroFileManager.getPolyMeshDirs(regionDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + cellZonesFiles = zeroFileManager.getCellZonesFiles(polyMeshes); + } + + writePatches(region.getPatches(), model, monitor, boundaryFiles); + writeFields(region.getFields(), region.getPatches(), modules, initialisations, monitor, regionTimeDirs, boundaryFiles, timeStepHasChanged); + } + } + } catch (Exception e) { + logger.error("Error in write", e); + monitor.error("Zero folder error: " + e.getMessage(), 2); + } + } + + public void writePatches(Model model, Patches patches) { + File[] zeroDirs = zeroFileManager.getZeroDirs("0"); + File[] polyMeshes = zeroFileManager.getPolyMeshDirs(zeroDirs); + File[] boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + + if (!ZeroFolderUtil.exists(boundaryFiles)) { + File[] constantDirs = zeroFileManager.getConstantDirs(); + polyMeshes = zeroFileManager.getPolyMeshDirs(constantDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + } + + writePatches(patches, model, new ConsoleMonitor(), boundaryFiles); + } + + public void writePatches(Model model, Patches patches, String regionName) { + File[] zeroDirs = zeroFileManager.getZeroDirs("0"); + File[] regionDirs = zeroFileManager.getRegionDirs(regionName, zeroDirs); + File[] polyMeshes = zeroFileManager.getPolyMeshDirs(regionDirs); + File[] boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + + if (!ZeroFolderUtil.exists(boundaryFiles)) { + File[] constantDirs = zeroFileManager.getConstantDirs(); + regionDirs = zeroFileManager.getRegionDirs(regionName, constantDirs); + polyMeshes = zeroFileManager.getPolyMeshDirs(regionDirs); + boundaryFiles = zeroFileManager.getBoundaryFiles(polyMeshes); + } + + writePatches(patches, model, new ConsoleMonitor(), boundaryFiles); + } + + private void writePatches(Patches patches, Model model, ProgressMonitor monitor, File[] boundaryFiles) { + if (ZeroFolderUtil.exists(boundaryFiles)) { + monitor.setCurrent("Saving patches", 0, boundaryFiles.length, 1); + new PatchesWriter(model, monitor).write(patches, boundaryFiles); + } else { + monitor.warning("Missing boundary fields", 1); + logger.warn(Arrays.toString(boundaryFiles) + " does not exist"); + } + } + + private void writeCellZones(Model model, CellZonesBuilder builder, ProgressMonitor monitor, File[] cellZonesFiles, Set modules) { + CellZonesWriter cellZonesWriter = new CellZonesWriter(builder, modules, monitor); + cellZonesWriter.writeFvOptions(model); + if (ZeroFolderUtil.exists(cellZonesFiles)) { + monitor.setCurrent("Saving cell zones", 0, cellZonesFiles.length, 1); + cellZonesWriter.writeCellZoneFiles(model, cellZonesFiles); + monitor.info("Cell Zones: " + model.getCellZones().zonesNames().toString(), 1); + } else { + monitor.warning("Missing cellZones file", 1); + logger.warn(Arrays.toString(cellZonesFiles) + " does not exist"); + } + } + + private void writeFields(Fields fields, Patches patches, Set modules, Initialisations initialisations, ProgressMonitor monitor, File[] timeDirs, File[] boundaryFiles, boolean timeStepHasChanged) { + if (initialisations != null && ZeroFolderUtil.exists(timeDirs) && ZeroFolderUtil.exists(boundaryFiles)) { + if (timeStepHasChanged) { + monitor.setCurrent("Re-Reading fields", 0, timeDirs.length, 1); + fields = new FieldsReader(initialisations, monitor).read(fields.keySet(), timeDirs); + BoundaryConditionsDefaults.fieldsToBoundaryConditions(patches, fields); + } + monitor.setCurrent("Saving fields", 0, timeDirs.length, 1); + BoundaryConditionsDefaults.saveBoundaryConditionsToFields(patches, fields); + new FieldsWriter(monitor).write(fields, timeDirs); + monitor.info("Fields: " + fields.fieldNames().toString(), 1); + } else { + monitor.warning("Missing fields", 1); + logger.warn(Arrays.toString(timeDirs) + " does not exist"); + } + } + + String getTimeValue() { + return timeValue; + } + + @Override + public FileManager getFileManager() { + return zeroFileManager; + } + + public void deleteMesh() { + regions.clear(); + zeroFileManager.deleteAll(); + if (zeroFileManager instanceof ParallelZeroFileManager) { + new SerialZeroFileManager(zeroFileManager.getFile()).deleteAll(); + } + } + + protected boolean avoidSave(Model model) { + return model.getCellZones().isEmpty() && model.getPatches().isEmpty() && model.getFields().isEmpty(); + } + + public void clearFields() { + zeroFileManager.clearZeroDirs(timeValue); + } + + public void removeNonZeroTimeFolders_GreaterThanActualTimeStep() { + zeroFileManager.removeNonZeroDirs(timeValue); + } + + public boolean hasNonZeroTimeFolders() { + return zeroFileManager.getNonZeroDirs("0").length > 0; + } + + public MeshRegion getRegion(String regionName) { + return regions.get(regionName); + } + + public boolean hasRegion(String regionName) { + return regions.containsKey(regionName); + } + + // For tests purposes only!!! + public void setTimeValue(String timeValue) { + this.timeValue = timeValue; + } + + public ZeroFileManager getZeroFileManager() { + return zeroFileManager; + } + + public boolean hasRegions() { + return !regions.isEmpty(); + } +} diff --git a/src/eu/engys/core/project/zero/ZeroFolderStructure.java b/src/eu/engys/core/project/zero/ZeroFolderStructure.java new file mode 100644 index 0000000..75e7154 --- /dev/null +++ b/src/eu/engys/core/project/zero/ZeroFolderStructure.java @@ -0,0 +1,49 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero; + +public class ZeroFolderStructure { + + private boolean boundaryFieldInZero; + private boolean boundaryFieldInConstant; + + public boolean isBoundaryFieldInZero() { + return boundaryFieldInZero; + } + + public void setBoundaryFieldInZero(boolean boundaryFieldInZero) { + this.boundaryFieldInZero = boundaryFieldInZero; + } + + public boolean isBoundaryFieldInConstant() { + return boundaryFieldInConstant; + } + + public void setBoundaryFieldInConstant(boolean boundaryFieldInConstant) { + this.boundaryFieldInConstant = boundaryFieldInConstant; + } + +} diff --git a/src/eu/engys/core/project/zero/ZeroFolderUtil.java b/src/eu/engys/core/project/zero/ZeroFolderUtil.java new file mode 100644 index 0000000..fffad45 --- /dev/null +++ b/src/eu/engys/core/project/zero/ZeroFolderUtil.java @@ -0,0 +1,311 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero; + +import static eu.engys.core.project.system.ControlDict.START_FROM_KEY; +import static eu.engys.core.project.system.ControlDict.START_TIME_VALUE; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Comparator; +import java.util.zip.GZIPInputStream; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.RegexFileFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.system.ControlDict; +import eu.engys.util.RegexpUtils; + +public class ZeroFolderUtil { + + private static final Logger logger = LoggerFactory.getLogger(ZeroFolderUtil.class); + + public static final String CELL_ZONES = "cellZones"; + public static final String FACE_ZONES = "faceZones"; + public static final String BOUNDARY = "boundary"; + public static final String POLY_MESH = "polyMesh"; + public static final String CONSTANT = "constant"; + public static final String PROCESSOR = "processor"; + public static final String ZERO = "0"; + + public static String PROCESSOR(int i) { + return PROCESSOR + i; + } + + public static void clearFiles(File parent) { + if (parent.list().length != 0) { + File[] files = parent.listFiles(); + for (File file : files) { + if (file.isFile()) { + logger.debug("Deleting {}", file); + file.delete(); + } + } + } + } + + public static void newZeroDir(File parent) { + File zeroDir = getZeroDir(parent); + if (!zeroDir.exists()) { + zeroDir.mkdir(); + logger.warn("New Folder {}", zeroDir); + } + File constantDir = getConstantDir(parent); + if (!constantDir.exists()) { + constantDir.mkdir(); + logger.warn("New Folder {}", constantDir); + } + File polyMesh = getPolyMeshDir(zeroDir); + if (!polyMesh.exists()) { + polyMesh.mkdir(); + logger.warn("New Folder {}", polyMesh); + } + } + + public static File getZeroDir(File parent) { + return new File(parent, ZERO); + } + + public static File getPolyMeshDir(File zeroDir) { + return new File(zeroDir, POLY_MESH); + } + + public static File getConstantDir(File zeroDir) { + return new File(zeroDir, CONSTANT); + } + + public static File getRegionDir(File zeroDir, String region) { + return new File(zeroDir, region); + } + + public static File getBoundaryFile(File polyMesh) { + File boundary = new File(polyMesh, BOUNDARY); + File boundary_gz = new File(polyMesh, BOUNDARY + ".gz"); + if (boundary.exists() && boundary.length() > 0) { + return boundary; + } else if (boundary_gz.exists()) { + gunzip(boundary_gz, boundary); + return boundary; + } else { + return boundary; + } + } + + public static File getCellZonesFile(File polyMesh) { + File cellZones = new File(polyMesh, CELL_ZONES); + File cellZones_gz = new File(polyMesh, CELL_ZONES + ".gz"); + if (cellZones.exists() && cellZones.length() > 0) { + return cellZones; + } else if (cellZones_gz.exists()) { + gunzip(cellZones_gz, cellZones); + return cellZones; + } else { + return cellZones; + } + } + + public static File getFaceZonesFile(File polyMesh) { + File faceZones = new File(polyMesh, FACE_ZONES); + File faceZones_gz = new File(polyMesh, FACE_ZONES + ".gz"); + if (faceZones.exists() && faceZones.length() > 0) { + return faceZones; + } else if (faceZones_gz.exists()) { + gunzip(faceZones_gz, faceZones); + return faceZones; + } else { + return faceZones; + } + } + + public static String getActualTimeValue(openFOAMProject project) { + return getTimeStepString(project.getZeroFolder().getTimeValue()); + } + + public static String findTimeValue(File proc0, ControlDict controlDict) { + if (controlDict == null || !controlDict.isField(START_FROM_KEY)) { + return getFirstFolderName(proc0); + } + + String startFrom = controlDict.lookup(START_FROM_KEY); + String time = "0"; + switch (startFrom) { + case ControlDict.FIRST_TIME_VALUE: + time = getFirstFolderName(proc0); + break; + case ControlDict.LATEST_TIME_VALUE: + time = getLastFolderName(proc0); + break; + case ControlDict.START_TIME_VALUE: + time = controlDict.lookup(START_TIME_VALUE); + break; + default: + time = getFirstFolderName(proc0); + break; + } + logger.info("Start From: " + startFrom + " T: " + time); + return time; + } + + private static String getFirstFolderName(File proc0) { + String[] directories = getDirectories(proc0); + String firstFolderName = "0"; + if (directories.length > 0) { + Arrays.sort(directories, new Comparator() { + public int compare(String s1, String s2) { + return Double.valueOf(s1).compareTo(Double.valueOf(s2)); + } + }); + firstFolderName = directories[0]; + } + return firstFolderName; + } + + private static String getLastFolderName(File proc0) { + String[] directories = getDirectories(proc0); + String lastFolderName = "0"; + if (directories != null && directories.length > 0) { + Arrays.sort(directories, new Comparator() { + public int compare(String s1, String s2) { + return Double.valueOf(s1).compareTo(Double.valueOf(s2)); + } + }); + lastFolderName = directories[directories.length - 1]; + } + return lastFolderName; + } + + private static String[] getDirectories(File proc0) { + RegexFileFilter filter = new RegexFileFilter(RegexpUtils.DOUBLE); + return proc0.list(filter); + } + + // private static String getStartTimeValue(String value) { + // return Double.parseDouble(value); + // } + + public static String[] getRegions(File... zeroDirs) { + if (zeroDirs == null || zeroDirs.length == 0) { + return new String[0]; + } + File zeroDir = zeroDirs[0]; + String[] regionDirs = zeroDir.list(new IsAValidRegionFolder()); + if (regionDirs == null) { + return new String[0]; + } + return regionDirs; + } + + private static class IsAValidRegionFolder implements FilenameFilter { + @Override + public boolean accept(File dir, String name) { + if (name.equals(POLY_MESH)) { + return false; + } + + File folder = new File(dir, name); + if (folder.isDirectory()) { + File polyMesh = getPolyMeshDir(folder); + if (polyMesh.exists()) { + File boundaryFile = getBoundaryFile(polyMesh); + if (boundaryFile.exists()) { + return true; + } + } + } + + return false; + } + } + + public static boolean exists(File... boundaryFiles) { + if (boundaryFiles == null || boundaryFiles.length == 0) { + return false; + } + boolean value = true; + for (File file : boundaryFiles) { + value = value && file.exists(); + } + return value; + } + + private static void gunzip(File inputFile, File outputFile) { + try { + GZIPInputStream gzipInputStream = null; + + gzipInputStream = new GZIPInputStream(new FileInputStream(inputFile)); + + OutputStream out = new FileOutputStream(outputFile); + + byte[] buf = new byte[1024]; + int len; + + while ((len = gzipInputStream.read(buf)) > 0) { + out.write(buf, 0, len); + } + + gzipInputStream.close(); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String getTimeStepString(String timeStep) { + try { + Integer i = Integer.valueOf(timeStep); + return String.valueOf(i); + } catch (NumberFormatException e) { + return timeStep; + } + } + + public static void mkDirs(File[] dirs) { + if (dirs != null) { + for (File file : dirs) { + if (!file.exists()) { + file.mkdir(); + } + } + } + } + + public static void delete(File[] dirs) { + if (dirs != null) { + for (File file : dirs) { + logger.debug("Deleting {}", file); + FileUtils.deleteQuietly(file); + } + } + } +} diff --git a/src/eu/engys/core/project/zero/cellzones/CellZone.java b/src/eu/engys/core/project/zero/cellzones/CellZone.java new file mode 100644 index 0000000..26c6285 --- /dev/null +++ b/src/eu/engys/core/project/zero/cellzones/CellZone.java @@ -0,0 +1,137 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.cellzones; + +import java.util.HashSet; +import java.util.Set; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.ui.checkboxtree.LoadableItem; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class CellZone implements VisibleItem, LoadableItem { + + private final String originalName; + private String name; + private Set types = new HashSet<>(); + private boolean visible; + private boolean loaded; + private Dictionary dictionary; + + public CellZone(String originalName) { + this.originalName = originalName; + this.name = originalName; + } + + public String getOriginalName() { + return originalName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void setTypes(Set types) { + this.types = types; + } + + public Set getTypes() { + return types; + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public void setVisible(boolean selected) { + this.visible = selected; + } + + @Override + public boolean isLoaded() { + return loaded; + } + + @Override + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } + + public void setDictionary(String key, Dictionary d) { + if (dictionary == null) { + this.dictionary = new Dictionary(originalName); + } + this.dictionary.add(new Dictionary(key, d)); + } + + public Dictionary getDictionary(String key) { + return dictionary.subDict(key); + } + + public void removeDictionary(String key) { + if (hasDictionary(key)) { + dictionary.remove(key); + } + } + + public boolean hasDictionary(String key) { + return dictionary != null && dictionary.found(key); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(name); + sb.append(" ["); + for (String type : types) { + sb.append(type); + sb.append("\n"); + } + sb.append("] "); + sb.append(visible); + + return sb.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CellZone) { + return ((CellZone) obj).getName().equals(name); + } + return super.equals(obj); + } + + public boolean hasType(String key) { + return types.contains(key); + } +} diff --git a/src/eu/engys/core/project/zero/cellzones/CellZoneType.java b/src/eu/engys/core/project/zero/cellzones/CellZoneType.java new file mode 100644 index 0000000..f9bc96d --- /dev/null +++ b/src/eu/engys/core/project/zero/cellzones/CellZoneType.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.cellzones; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.cellzones.CellZonePanel; + +public interface CellZoneType extends Comparable { + + public static final String MRF_KEY = "mrf"; + public static final String POROUS_KEY = "porous"; + public static final String THERMAL_KEY = "thermal"; + public static final String HUMIDITY_KEY = "humidity"; + public static final String SLIDING_MESH_KEY = "sliding"; + + public abstract String getKey(); + + public abstract String getLabel(); + + public abstract Dictionary getDefaultDictionary(); + + public abstract CellZonePanel getPanel(); + + public abstract boolean isEnabled(); + + public abstract void setEnabled(boolean enabled); + + public abstract void updateStatusByState(); + +}; diff --git a/src/eu/engys/core/project/zero/cellzones/CellZones.java b/src/eu/engys/core/project/zero/cellzones/CellZones.java new file mode 100644 index 0000000..866ceef --- /dev/null +++ b/src/eu/engys/core/project/zero/cellzones/CellZones.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.cellzones; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CellZones extends ArrayList { + + public CellZones() { + super(); + } + + public List zonesNames() { + List names = new ArrayList<>(); + for (CellZone zone : this) { + names.add(zone.getName()); + } + return names; + } + + public Map toMap() { + Map zonesMap = new HashMap(); + for (CellZone zone : this) { + zonesMap.put(zone.getName(), zone); + } + return Collections.unmodifiableMap(zonesMap); + } + + public void addZones(List cellZones) { + addAll(cellZones); + } + + public boolean hasPorous() { + for (CellZone zone : this) { + if (zone.getTypes().contains(CellZoneType.POROUS_KEY)) { + return true; + } + } + return false; + } + + public boolean hasMRF() { + for (CellZone zone : this) { + if (zone.getTypes().contains(CellZoneType.MRF_KEY)) { + return true; + } + } + return false; + } + + public boolean hasSliding() { + for (CellZone zone : this) { + if (zone.getTypes().contains(CellZoneType.SLIDING_MESH_KEY)) { + return true; + } + } + return false; + } + + public boolean hasThermal() { + for (CellZone zone : this) { + if (zone.getTypes().contains(CellZoneType.THERMAL_KEY)) { + return true; + } + } + return false; + } +} diff --git a/src/eu/engys/core/project/zero/cellzones/CellZones200To210Converter.java b/src/eu/engys/core/project/zero/cellzones/CellZones200To210Converter.java new file mode 100644 index 0000000..3989549 --- /dev/null +++ b/src/eu/engys/core/project/zero/cellzones/CellZones200To210Converter.java @@ -0,0 +1,226 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.cellzones; + +import java.util.ArrayList; +import java.util.List; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.ListField; +import eu.engys.core.project.Project200To210Converter.MRFZones; +import eu.engys.core.project.Project200To210Converter.PorousZones; + +public class CellZones200To210Converter { + + public static List loadMRFDictionary(MRFZones MRFZones) { + List zones = new ArrayList<>(); + if (MRFZones != null) { + Dictionary zonesDictionary = null; + if (MRFZones.isList("")) { + ListField list = MRFZones.getListFields().get(0); + zonesDictionary = new Dictionary(""); + for (DefaultElement el : list.getListElements()) { + if (el instanceof Dictionary) { + zonesDictionary.add((Dictionary) el); + } + } + } else { + zonesDictionary = MRFZones; + } + + if (zonesDictionary != null) { + for (Dictionary d : zonesDictionary.getDictionaries()) { + String zoneName = d.getName(); + Dictionary encodedDictionary = new Dictionary(d); + encodedDictionary.add(Dictionary.TYPE, "mrf"); + + CellZone zone = new CellZone(zoneName); + zone.setName(zoneName); + zone.getTypes().add(CellZoneType.MRF_KEY); + zone.setDictionary(CellZoneType.MRF_KEY, encodedDictionary); + + zones.add(zone); + } + } + } + return zones; + } + +// public static void saveMRFDictionary(ArrayList cellZones, MRFZones MRFZones) { +// boolean asList = true; +// if (MRFZones != null) { +// MRFZones.clear(); +// for (CellZone cellZone : cellZones) { +// String zoneName = cellZone.getName(); +// +// if (cellZone.getType() == CellZoneType.MRF) { +// Dictionary encodedDictionary = cellZone.getDictionary(); +// +// Dictionary toBeDecoded = new Dictionary(zoneName); +// toBeDecoded.merge(encodedDictionary); +// toBeDecoded.remove(Dictionary.TYPE); +// +// if (asList) { +// MRFZones.addToList(toBeDecoded); +// } else { +// MRFZones.add(toBeDecoded); +// } +// } else { +// //System.err.println(zoneName + " NOT A MRF Zone"); +// } +// } +// } +// } + + public static List loadPorousDictionary(PorousZones porousZones) { + List zones = new ArrayList<>(); + if (porousZones != null) { + Dictionary zonesDictionary = null; + if (porousZones.isList("")) { + ListField list = porousZones.getListFields().get(0); + zonesDictionary = new Dictionary(""); + for (DefaultElement el : list.getListElements()) { + if (el instanceof Dictionary) { + zonesDictionary.add((Dictionary) el); + } + } + } else { + zonesDictionary = porousZones; + } + + if (zonesDictionary != null) { + + } + for (Dictionary toBeEncoded : zonesDictionary.getDictionaries()) { + String zoneName = toBeEncoded.getName(); + + Dictionary encodedDictionary = new Dictionary("porous"); + + if (toBeEncoded.found("Darcy")) { + Dictionary darcyDict = toBeEncoded.subDict("Darcy"); + //System.out.println("CellZoneBuilder.encodePorousDictionary() darcyDict: "+darcyDict); + encodedDictionary.add(darcyDict.lookupScalar("d")); + encodedDictionary.add(darcyDict.lookupScalar("f")); + encodedDictionary.add("e1", toBeEncoded.lookup("e1")); + encodedDictionary.add("e2", toBeEncoded.lookup("e2")); + encodedDictionary.add("porosity", toBeEncoded.lookup("porosity")); + encodedDictionary.add(Dictionary.TYPE, "porousDarcy"); + } else if (toBeEncoded.found("powerLaw")) { + Dictionary powerLawDict = toBeEncoded.subDict("powerLaw"); + encodedDictionary.add("C0", powerLawDict.lookup("C0")); + encodedDictionary.add("C1", powerLawDict.lookup("C1")); + encodedDictionary.add("porosity", toBeEncoded.lookup("porosity")); + encodedDictionary.add(Dictionary.TYPE, "porousPowerLaw"); + } else { + //bad + } + + CellZone zone = new CellZone(zoneName); + zone.setName(zoneName); + zone.getTypes().add(CellZoneType.POROUS_KEY); + zone.setDictionary(CellZoneType.POROUS_KEY, encodedDictionary); + + if (toBeEncoded.found("thermalModel")) { + Dictionary thermalDict = new Dictionary("thermalModel"); + + if (toBeEncoded.subDict("thermalModel").found("powerLaw")) { + Dictionary powerLaw = toBeEncoded.subDict("powerLaw"); + thermalDict.merge(powerLaw); + thermalDict.add(Dictionary.TYPE, "powerLaw"); + } else if (toBeEncoded.subDict("thermalModel").found(Dictionary.TYPE)) { + thermalDict.merge(toBeEncoded.subDict("thermalModel")); + } + + zone.getTypes().add(CellZoneType.THERMAL_KEY); + zone.setDictionary(CellZoneType.THERMAL_KEY, thermalDict); + } + + + zones.add(zone); + } + } + + return zones; + } + +// public static void savePorousDictionary(ArrayList cellZones, PorousZones porousZones) { +// boolean asList = true; +// if (porousZones != null) { +// porousZones.clear(); +// for (CellZone cellZone : cellZones) { +// String zoneName = cellZone.getName(); +// if (cellZone.getType() == CellZoneType.POROUS || cellZone.getType() == CellZoneType.THERMAL_POROUS || cellZone.getType() == CellZoneType.THERMAL) { +// Dictionary encodedDictionary = cellZone.getDictionary(); +// String typeString = encodedDictionary.lookup(Dictionary.TYPE); +// +// Dictionary toBeDecoded = new Dictionary(zoneName); +// if (typeString.equals("porousDarcy")) { +// Dictionary darcyDict = new Dictionary("Darcy"); +// darcyDict.add(encodedDictionary.lookupScalar("d")); +// darcyDict.add(encodedDictionary.lookupScalar("f")); +// +// toBeDecoded.add(darcyDict); +// toBeDecoded.add("e1", encodedDictionary.lookup("e1")); +// toBeDecoded.add("e2", encodedDictionary.lookup("e2")); +// toBeDecoded.add("porosity", encodedDictionary.lookup("porosity")); +// +// } else if (typeString.equals("porousPowerLaw")) { +// Dictionary powerLawDict = new Dictionary("powerLaw"); +// powerLawDict.add("C0", encodedDictionary.lookup("C0")); +// powerLawDict.add("C1", encodedDictionary.lookup("C1")); +// toBeDecoded.add(powerLawDict); +// toBeDecoded.add("porosity", encodedDictionary.lookup("porosity")); +// } +// toBeDecoded.remove(Dictionary.TYPE); +// +// /* in case of thermal porous zone */ +// if (encodedDictionary.found("thermalModel")) { +// Dictionary thermalDict = new Dictionary("thermalModel"); +// +// Dictionary thermalModel = encodedDictionary.subDict("thermalModel"); +// String thermalType = thermalModel.lookup(Dictionary.TYPE); +// if (thermalType.equals("powerLaw")) { +// thermalDict.merge(thermalModel); +// } else if (thermalType.equals("fixedTemperature")) { +// thermalDict.merge(thermalModel); +// } +// toBeDecoded.add(thermalDict); +// } +// +// if (asList) { +// porousZones.addToList(toBeDecoded); +// } else { +// porousZones.add(toBeDecoded); +// } +// } else { +// //System.err.println(zoneName + " NOT A Thermal Zone"); +// } +// } +// } +// } + +} diff --git a/src/eu/engys/core/project/zero/cellzones/CellZonesBuilder.java b/src/eu/engys/core/project/zero/cellzones/CellZonesBuilder.java new file mode 100644 index 0000000..206d32b --- /dev/null +++ b/src/eu/engys/core/project/zero/cellzones/CellZonesBuilder.java @@ -0,0 +1,50 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.cellzones; + +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.core.project.system.FvOptions; + +public interface CellZonesBuilder { + + public void loadMRFDictionary(Model model); + public void loadMRFDictionary(CellZones cellZones, FvOptions fvOptions); + public void saveMRFDictionary(CellZones cellZones, FvOptions fvOptions); + public void saveMRFDictionary(Model model); + + public void loadPorousDictionary(CellZones cellZones, FvOptions fvOptions); + public void loadPorousDictionary(Model model); + public void savePorousDictionary(CellZones cellZones, FvOptions fvOptions); + public void savePorousDictionary(Model model); + + + public void loadThermalDictionary(Model model); + public void loadThermalDictionary(CellZones cellZones, FvOptions fvOptions, State state); + public void saveThermalDictionary(CellZones cellZones, FvOptions fvOptions, State state); + public void saveThermalDictionary(Model model); + +} diff --git a/src/eu/engys/core/project/zero/cellzones/CellZonesReader.java b/src/eu/engys/core/project/zero/cellzones/CellZonesReader.java new file mode 100644 index 0000000..98571a2 --- /dev/null +++ b/src/eu/engys/core/project/zero/cellzones/CellZonesReader.java @@ -0,0 +1,164 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.cellzones; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.FvOptions; +import eu.engys.util.IOUtils; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; + +public class CellZonesReader { + + private static Logger logger = LoggerFactory.getLogger(CellZones.class); + private Set modules; + private ProgressMonitor monitor; + private Model model; + private CellZonesBuilder builder; + + public CellZonesReader(Model model, CellZonesBuilder builder, Set modules, ProgressMonitor monitor) { + this.model = model; + this.builder = builder; + this.modules = modules; + this.monitor = monitor; + } + + public CellZones read(File... cellZonesFiles) { + CellZones cellZones = readCellZoneFiles(cellZonesFiles); + readCellZoneTypeAndDictionary(cellZones); + return cellZones; + } + + public CellZones readCellZoneFiles(File... cellZonesFiles) { + CellZones cellZones = new CellZones(); + List zones = null; + if (cellZonesFiles.length == 1) { + zones = readCellZones(cellZonesFiles[0]); + } else { + zones = readParallelCellZones(cellZonesFiles); + } + cellZones.addAll(zones); + return cellZones; + } + + private void readCellZoneTypeAndDictionary(CellZones cellZones) { + FvOptions fvOptions = model.getProject().getSystemFolder().getFvOptions(); + builder.loadMRFDictionary(cellZones, fvOptions); + builder.loadPorousDictionary(cellZones, fvOptions); + builder.loadThermalDictionary(cellZones, fvOptions, model.getState()); + ModulesUtil.updateCellZonesFromModel(modules, cellZones); + } + + private List readParallelCellZones(File[] cellZonesFiles) { + final List zones = Collections.synchronizedList(new ArrayList()); + Runnable[] runnables = new Runnable[cellZonesFiles.length]; + for (int i = 0; i < cellZonesFiles.length; i++) { + final File cellZoneFile = cellZonesFiles[i]; + runnables[i] = new Runnable() { + @Override + public void run() { + merge(zones, readCellZones(cellZoneFile)); + } + }; + } + ExecUtil.execParallelAndWait(runnables); + return zones; + } + + private void merge(List zones, List readZones) { + for (CellZone zone : readZones) { + if (!zones.contains(zone)) { + zones.add(zone); + } + } + } + + private List readCellZones(File cellZones) throws IllegalStateException { + monitor.setCurrent(null, monitor.getCurrent() + 1, 2); + logger.info("READ: CellZones {}", cellZones.getAbsolutePath()); + List zones = new ArrayList(); + + if (cellZones.exists()) { + try { + String cellZonesString = IOUtils.readStringFromFile(cellZones); + // remove comments + cellZonesString = cellZonesString.replaceAll("/\\*(?:.|[\\n\\r])*?\\*/", ""); + + Pattern pattern = Pattern.compile("(\\d+)\\s*\\("); + Matcher matcher = pattern.matcher(cellZonesString); + + if (matcher.find()) { + + if (matcher.groupCount() == 1) { + String nZones = matcher.group(1); + + Pattern patternForType = Pattern.compile("([\\S]+)\\s*\\{\\s*type\\s*(\\w+);"); + Matcher matcherForType = patternForType.matcher(cellZonesString); + int zonesCounter = 0; + while (matcherForType.find()) { + zonesCounter++; + if (matcherForType.groupCount() == 2) { + String zoneName = matcherForType.group(1); + String zoneType = matcherForType.group(2); + + CellZone cz = new CellZone(zoneName); + cz.setName(zoneName); + cz.setVisible(true); + + zones.add(cz); + } + } + if (Integer.parseInt(nZones) != zonesCounter) { + monitor.error(String.format("Number of read patches (%d) is invalid (expected %d).", zonesCounter, nZones), 2); + } + } + } + } catch (Exception e) { + monitor.warning("Cannot read the file: " + e.getMessage(), 2); + logger.warn("Cannot read the file", e); + } + } else { + monitor.warning("File does not exist", 2); + logger.warn("CellZones file does not exist"); + } + + return zones; + } +} diff --git a/src/eu/engys/core/project/zero/cellzones/CellZonesUtils.java b/src/eu/engys/core/project/zero/cellzones/CellZonesUtils.java new file mode 100644 index 0000000..317141f --- /dev/null +++ b/src/eu/engys/core/project/zero/cellzones/CellZonesUtils.java @@ -0,0 +1,108 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.cellzones; + +public class CellZonesUtils { + + /* + * MRF + */ + public static final String MRF_SOURCE_KEY = "MRFSource"; + public static final String ORIGIN_KEY = "origin"; + public static final String OMEGA_KEY = "omega"; + public static final String AXIS_KEY = "axis"; + public static final String ATTACHED_PATCHES_KEY = "attachedPatches"; + public static final String ROTATING_PATCHES_KEY = "rotatingPatches"; + public static final String NON_ROTATING_PATCHES_KEY = "nonRotatingPatches"; + + /* + * POROUS + */ + public static final String POROUS_DARCY_KEY = "porousDarcy"; + public static final String POROUS_POWER_LAW_KEY = "porousPowerLaw"; + public static final String EXPLICIT_POROSITY_SOURCE_KEY = "explicitPorositySource"; + public static final String E1_KEY = "e1"; + public static final String E2_KEY = "e2"; + public static final String D_KEY = "d"; + public static final String F_KEY = "f"; + public static final String C0_KEY = "C0"; + public static final String C1_KEY = "C1"; + public static final String POWER_LAW_KEY = "powerLaw"; + public static final String DARCY_FORCHHEIMER_KEY = "DarcyForchheimer"; + public static final String COORDINATE_SYSTEM_KEY = "coordinateSystem"; + public static final String COORDINATE_ROTATION_KEY = "coordinateRotation"; + public static final String CARTESIAN_KEY = "cartesian"; + public static final String AXES_ROTATION_KEY = "axesRotation"; + + /* + * Thermal + */ + + public static final String THERMAL_FIXED_KEY = "thermalFixed"; + public static final String THERMAL_SCALAR_KEY = "thermalScalar"; + public static final String THERMAL_EXPONENTIAL_KEY = "thermalExponential"; + public static final String FIXED_TEMPERATURE_CONSTRAINT_KEY = "fixedTemperatureConstraint"; + public static final String EXPONENTIAL_THERMAL_SOURCE_KEY = "exponentialThermalSource"; + public static final String SCALAR_SEMI_IMPLICT_SOURCE_KEY = "scalarSemiImplicitSource"; + public static final String SCALAR_EXPLICIT_SET_VALUE_KEY = "scalarExplicitSetValue"; + public static final String TEMPERATURE_KEY = "temperature"; + public static final String CE_KEY = "Ce"; + public static final String CM_KEY = "Cm"; + public static final String T0_KEY = "T0"; + public static final String MODE_KEY = "mode"; + public static final String VOLUME_MODE_KEY = "volumeMode"; + public static final String PLACE_HOLDER_KEY = "placeHolder"; + public static final String H_KEY = "h"; + public static final String T_KEY = "T"; + public static final String INJECTION_RATE_KEY = "injectionRate"; + public static final String INJECTION_RATE_SU_SP_KEY = "injectionRateSuSp"; + public static final String SPECIFIC_KEY = "specific"; + public static final String UNIFORM_KEY = "uniform"; + + /* + * Humidity + */ + public static final String W_KEY = "w"; + + /* + * Sliding + */ + public static final String t0_KEY = "t0"; + public static final String THETA_KEY = "theta"; + public static final String PERIOD_KEY = "period"; + public static final String ABSOLUTE_KEY = "absolute"; + public static final String[] VOLUME_MODE_KEYS = new String[] { ABSOLUTE_KEY, SPECIFIC_KEY }; + + /* + * OTHER KEYS + */ + public static final String COEFFS_KEY = "Coeffs"; + public static final String ACTIVE_KEY = "active"; + public static final String SELECTION_MODE_KEY = "selectionMode"; + public static final String CELL_ZONE_KEY = "cellZone"; + + +} diff --git a/src/eu/engys/core/project/zero/cellzones/CellZonesWriter.java b/src/eu/engys/core/project/zero/cellzones/CellZonesWriter.java new file mode 100644 index 0000000..c48445d --- /dev/null +++ b/src/eu/engys/core/project/zero/cellzones/CellZonesWriter.java @@ -0,0 +1,141 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.cellzones; + +import java.io.File; +import java.io.FileWriter; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.DictionaryWriter; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.FvOptions; +import eu.engys.util.IOUtils; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; + +public class CellZonesWriter { + + private static final Logger logger = LoggerFactory.getLogger(CellZones.class); + + private ProgressMonitor monitor; + + private Set modules; + + private CellZonesBuilder builder; + + public CellZonesWriter(CellZonesBuilder builder, Set modules, ProgressMonitor monitor) { + this.builder = builder; + this.modules = modules; + this.monitor = monitor; + } + + public void writeFvOptions(Model model) { + FvOptions fvOptions = model.getProject().getSystemFolder().getFvOptions(); + if(fvOptions != null){ + fvOptions.clear(); + } + builder.saveMRFDictionary(model); + builder.savePorousDictionary(model); + builder.saveThermalDictionary(model); + ModulesUtil.updateModelFromCellZones(modules); + } + + public void writeCellZoneFiles(Model model, File... cellZonesFiles) { + final CellZones cellZones = model.getCellZones(); + Runnable[] runnables = new Runnable[cellZonesFiles.length]; + for (int i = 0; i < cellZonesFiles.length; i++) { + final File cellZoneFile = cellZonesFiles[i]; + runnables[i] = new Runnable() { + public void run() { + writeCellZones(cellZones, cellZoneFile); + } + }; + } + ExecUtil.execSerial(runnables); + } + + private void writeCellZones(CellZones cellZones, File cellZonesFile) { + monitor.setCurrent(null, monitor.getCurrent() + 1, 2); + logger.info("WRITE: CellZones {}", cellZonesFile.getAbsolutePath()); + + Map zonesOriginalNames = new HashMap(); + for (CellZone zone : cellZones) { + zonesOriginalNames.put(zone.getOriginalName(), zone.getName()); + } + + try { + String cellZonesString = IOUtils.readStringFromFile(cellZonesFile); + + StringBuffer sb = new StringBuffer(cellZonesString.length()); + + cellZonesString = cellZonesString.replaceAll("/\\*(?:.|[\\n\\r])*?\\*/", ""); + + Pattern pattern = Pattern.compile("(\\d+)\\s*?\\(((?:[\\s\\S])*?\\s*?\\})\\s*?\\)"); + Matcher matcher = pattern.matcher(cellZonesString); + + if (matcher.find()) { + if (matcher.groupCount() == 2) { + String nZones = matcher.group(1); + String zonesString = matcher.group(2); + + FoamFile foamFile = FoamFile.getDictionaryFoamFile("regIOobject", "\"0/polyMesh\"", "cellZones"); + new DictionaryWriter(foamFile).writeDictionary(sb, ""); + + sb.append(nZones + "("); + Pattern patternForType = Pattern.compile("([\\S]+)\\s*?\\{\\s*?type\\s*?(\\w+);"); + Matcher matcherForType = patternForType.matcher(zonesString); + + while (matcherForType.find()) { + String originalName = matcherForType.group(1); + String newName = zonesOriginalNames.get(originalName); + String replacement = newName + "\n {\n type cellZone;"; + matcherForType.appendReplacement(sb, replacement); + } + matcherForType.appendTail(sb); + sb.append(")"); + } + + FileWriter outStream = new FileWriter(cellZonesFile); + outStream.write(sb.toString()); + outStream.close(); + } + } catch (Exception e) { + monitor.warning("Error writing cell zones file " + e.getMessage()); + logger.warn("Error writing cell zones file {}", e.getMessage()); + } + } +} diff --git a/src/eu/engys/core/project/zero/facezones/FaceZone.java b/src/eu/engys/core/project/zero/facezones/FaceZone.java new file mode 100644 index 0000000..a26c15c --- /dev/null +++ b/src/eu/engys/core/project/zero/facezones/FaceZone.java @@ -0,0 +1,98 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.facezones; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.ui.checkboxtree.LoadableItem; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class FaceZone implements VisibleItem, LoadableItem { + + private final String originalName; + private String name; + private boolean visible; + private boolean loaded; + private Dictionary dictionary; + + public FaceZone(String originalName) { + this.originalName = originalName; + this.name = originalName; + } + + public String getOriginalName() { + return originalName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public void setVisible(boolean selected) { + this.visible = selected; + } + + @Override + public boolean isLoaded() { + return loaded; + } + + @Override + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } + + public void setDictionary(Dictionary d) { + this.dictionary = d; + } + + public Dictionary getDictionary() { + return dictionary; + } + + @Override + public String toString() { + return name + " [" + getName() + ", " + visible + "]"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof FaceZone) { + return ((FaceZone) obj).getName().equals(name); + } + return super.equals(obj); + } +} diff --git a/src/eu/engys/core/project/zero/facezones/FaceZones.java b/src/eu/engys/core/project/zero/facezones/FaceZones.java new file mode 100644 index 0000000..9807fce --- /dev/null +++ b/src/eu/engys/core/project/zero/facezones/FaceZones.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.facezones; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FaceZones extends ArrayList { + + public FaceZones() { + super(); + } + + public List zonesNames() { + List names = new ArrayList<>(); + for (FaceZone zone : this) { + names.add(zone.getName()); + } + return names; + } + + public Map toMap() { + HashMap zonesMap = new HashMap(); + for (FaceZone zone : this) { + zonesMap.put(zone.getName(), zone); + } + return Collections.unmodifiableMap(zonesMap); + } + + public void addZones(List faceZones) { + addAll(faceZones); + } +} diff --git a/src/eu/engys/core/project/zero/facezones/FaceZonesReader.java b/src/eu/engys/core/project/zero/facezones/FaceZonesReader.java new file mode 100644 index 0000000..3953e81 --- /dev/null +++ b/src/eu/engys/core/project/zero/facezones/FaceZonesReader.java @@ -0,0 +1,142 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.facezones; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.IOUtils; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; + +public class FaceZonesReader { + + private static Logger logger = LoggerFactory.getLogger(FaceZones.class); + private ProgressMonitor monitor; + + public FaceZonesReader(ProgressMonitor monitor) { + this.monitor = monitor; + } + + public FaceZones read(File... faceZonesFiles) { + FaceZones faceZones = new FaceZones(); + if (faceZonesFiles.length == 1) { + faceZones.addAll(readFaceZones(faceZonesFiles[0])); + } else { + faceZones.addAll(readParallelCellZones(faceZonesFiles)); + } + + return faceZones; + } + + private List readParallelCellZones(File[] faceZonesFiles) { + final List zones = Collections.synchronizedList(new ArrayList()); + Runnable[] readZonesRunnables = new Runnable[faceZonesFiles.length]; + for (int i = 0; i < faceZonesFiles.length; i++) { + final File faceZoneFile = faceZonesFiles[i]; + readZonesRunnables[i] = new Runnable() { + @Override + public void run() { + merge(zones, readFaceZones(faceZoneFile)); + } + }; + } + ExecUtil.execParallelAndWait(readZonesRunnables); + return zones; + } + + private void merge(Collection zones, List readZones) { + for (FaceZone zone : readZones) { + if (!zones.contains(zone)) { + zones.add(zone); + } + } + } + + private List readFaceZones(File faceZones) throws IllegalStateException { + monitor.setCurrent(null, monitor.getCurrent() + 1, 2); + logger.info("READ: FaceZones {}", faceZones.getAbsolutePath()); + List zones = new ArrayList(); + + if (faceZones.exists()) { + + try { + String cellZonesString = IOUtils.readStringFromFile(faceZones); + + cellZonesString = cellZonesString.replaceAll("/\\*(?:.|[\\n\\r])*?\\*/", "");// rimuovo + // i + // commenti + + Pattern pattern = Pattern.compile("(\\d+)\\s*\\("); + Matcher matcher = pattern.matcher(cellZonesString); + + if (matcher.find()) { + + if (matcher.groupCount() == 1) { + String nZones = matcher.group(1); + + Pattern patternForType = Pattern.compile("([\\S]+)\\s*\\{\\s*type\\s*(\\w+);"); + Matcher matcherForType = patternForType.matcher(cellZonesString); + int zonesCounter = 0; + while (matcherForType.find()) { + zonesCounter++; + if (matcherForType.groupCount() == 2) { + String zoneName = matcherForType.group(1); + String zoneType = matcherForType.group(2); + + FaceZone cz = new FaceZone(zoneName); + cz.setName(zoneName); + cz.setVisible(true); + + zones.add(cz); + } + } + if (Integer.parseInt(nZones) != zonesCounter) { + monitor.error(String.format("Number of read patches (%d) is invalid (expected %d).", zonesCounter, nZones), 2); + } + } + } + } catch (Exception e) { + monitor.warning("Cannot read the file: " + e.getMessage(), 2); + logger.warn("Cannot read the file", e); + } + } else { + monitor.warning("File does not exist", 2); + logger.warn("FaceZones file does not exist"); + } + + return zones; + } +} diff --git a/src/eu/engys/core/project/zero/fields/AbstractInitialisations.java b/src/eu/engys/core/project/zero/fields/AbstractInitialisations.java new file mode 100644 index 0000000..220374b --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/AbstractInitialisations.java @@ -0,0 +1,80 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.util.ArchiveUtils; +import eu.engys.util.progress.ProgressMonitor; + +public abstract class AbstractInitialisations implements Initialisations { + + private static Logger logger = LoggerFactory.getLogger(AbstractInitialisations.class); + + protected Map map = new HashMap<>(); + + protected final Model model; + + public AbstractInitialisations(Model model) { + this.model = model; + } + + public Dictionary getInitializationFor(String field) { + return map.get(field); + } + + protected void readFieldFromFile(Field field, File zeroDir, ProgressMonitor monitor) { + File file = new File(zeroDir, field.getName()); + if (file.exists()) { + field.read(file); + logger.info("READ: Field {}", field.getName()); + } else { + File fileGZ = new File(zeroDir, field.getName() + "." + ArchiveUtils.GZ); + if (fileGZ.exists()) { + ArchiveUtils.unGZ(fileGZ, zeroDir); + field.read(file); + logger.info("READ: Field {}", field.getName()); + } else { + monitor.warning("Missing field file " + field.getName(), 2); + logger.warn("READ: Missing field {}", field.getName()); + } + } + } + + // For test purpouse only! + public Map getMap() { + return map; + } + +} diff --git a/src/eu/engys/core/project/zero/fields/ArrayInternalField.java b/src/eu/engys/core/project/zero/fields/ArrayInternalField.java new file mode 100644 index 0000000..19fc83b --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/ArrayInternalField.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class ArrayInternalField implements InternalField { + + private String buffer; + private double[] value; + + public ArrayInternalField(double[] value) { + this.value = value; + } + + @Override + public int getSize() { + return 1; + } + + @Override + public double[][] getValue() { + return new double[][] { value }; + } + + @Override + public void write(FileWriter writer) throws IOException { + writer.write(buffer); + } + + @Override + public void buffer(File file) { + buffer = Field.INTERNAL_FIELD + " uniform (" + String.valueOf(value[0]) + " " + String.valueOf(value[1]) + " " + String.valueOf(value[2]) + ");"; + } +} diff --git a/src/eu/engys/core/project/zero/fields/Field.java b/src/eu/engys/core/project/zero/fields/Field.java new file mode 100644 index 0000000..c6fc81b --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/Field.java @@ -0,0 +1,281 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.util.Arrays; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.progress.ProgressMonitor; + +public class Field { + + public static final String FIELD_DEFINITION_KEY = "fieldDefinition"; + public static final String INITIALISATION_KEY = "initialisation"; + public static final String BOUNDARY_FIELD = "boundaryField"; + public static final String DIMENSIONS = "dimensions"; + public static final String INTERNAL_FIELD = "internalField"; + + public enum FieldType { + + SCALAR, VECTOR, POINT; + + public static FieldType getType(String string) { + switch (string) { + case "scalar": + return SCALAR; + case "vector": + return VECTOR; + case "point": + return POINT; + default: + return null; + } + } + + public boolean isScalar() { + return this == SCALAR; + } + + public boolean isVector() { + return this == VECTOR; + } + + public boolean isPoint() { + return this == POINT; + } + } + + private InternalField internalField; + private Dictionary boundaryField; + + + private FieldType fieldType; + private String[] initialisationMethods; + private Dictionary initialisation = new Dictionary(INITIALISATION_KEY); + private Dictionary definition = new Dictionary(FIELD_DEFINITION_KEY); + private String name; + private String dimensions; + private transient boolean visible; + + public Field(String name) { + this.name = name; + this.dimensions = null; + this.internalField = null; + this.boundaryField = new Dictionary(BOUNDARY_FIELD); + this.visible = true; + } + + public boolean isVisible() { + return visible; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getInitialisationType() { + return initialisation.lookup(Dictionary.TYPE); + } + + public FieldType getFieldType() { + return fieldType; + } + + public void setFieldType(FieldType fieldType) { + this.fieldType = fieldType; + } + + public Dictionary getInitialisation() { + return initialisation; + } + + public void setInitialisation(Dictionary initialisation) { + this.initialisation = initialisation; + } + + public void setInitialisationMethods(String[] initMethods) { + this.initialisationMethods = initMethods; + } + + public String[] getInitialisationMethods() { + return initialisationMethods; + } + + public Dictionary getDefinition() { + return definition; + } + + public void setDefinition(Dictionary definition) { + this.definition = definition; + } + + public Dictionary getBoundaryField() { + return boundaryField; + } + + public String getDimensions() { + return dimensions; + } + + public void read(File file) { + new FieldReader(this).read(file); + } + + public void setDimensions(String dimensions) { + this.dimensions = dimensions; + } + + public void setInternalField(String internalField) { + if (internalField != null && !internalField.isEmpty()) { + this.internalField = new FieldReader(this).readValue(internalField); + } else { + this.internalField = null; + } + } + + public void setInternalField(InternalField internalField) { + this.internalField = internalField; + } + + public void setBoundaryField(Dictionary boundaryField) { + this.boundaryField = boundaryField; + } + + public InternalField getInternalField() { + return internalField; + } + + public void write(File zeroDir, ProgressMonitor monitor) { + new FieldWriter(this, monitor).write(zeroDir); + } + + public void bufferInternalField(File zeroDir, ProgressMonitor monitor) { + new FieldWriter(this, monitor).bufferInternalField(zeroDir); + } + + public void merge(Field field) { + if (field.boundaryField != null && !field.boundaryField.isEmpty() ) { + setBoundaryField(field.boundaryField); + } + if (field.definition != null) { + if (this.definition != null) { + this.definition.merge(field.definition); + } else { + setDefinition(new Dictionary(field.definition)); + } + } + if (field.dimensions != null) { + setDimensions(field.dimensions); + } + if (field.fieldType != null) { + setFieldType(field.fieldType); + } + if (field.initialisation != null) { +// if (this.initialisation != null) { +// this.initialisation.merge(field.initialisation); +// } else { + setInitialisation(new Dictionary(field.initialisation)); +// } + } + if (field.initialisationMethods != null) { + setInitialisationMethods(field.initialisationMethods); + } + if (field.internalField != null) { + setInternalField(field.internalField); + } + + setVisible(field.visible); + + } + + @Override + public String toString() { + return name + " " + fieldType + " " + Arrays.toString(initialisationMethods) + " " + initialisation + definition; + } + + public static void main(String[] args) { + /* U */ + Field U0 = new Field("U"); + Field U1 = new Field("U"); + Field U2 = new Field("U"); + Field U3 = new Field("U"); + U0.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor0/0/U")); + U1.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor1/0/U")); + U2.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor2/0/U")); + U3.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor3/0/U")); + + /* p */ + Field p0 = new Field("p"); + Field p1 = new Field("p"); + Field p2 = new Field("p"); + Field p3 = new Field("p"); + p0.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor0/0/p")); + p1.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor1/0/p")); + p2.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor2/0/p")); + p3.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor3/0/p")); + + /* epsilon */ + Field epsilon0 = new Field("epsilon"); + Field epsilon1 = new Field("epsilon"); + Field epsilon2 = new Field("epsilon"); + Field epsilon3 = new Field("epsilon"); + epsilon0.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor0/0/epsilon")); + epsilon1.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor1/0/epsilon")); + epsilon2.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor2/0/epsilon")); + epsilon3.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor3/0/epsilon")); + + /* nut */ + Field nut0 = new Field("nut"); + Field nut1 = new Field("nut"); + Field nut2 = new Field("nut"); + Field nut3 = new Field("nut"); + nut0.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor0/0/nut")); + nut1.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor1/0/nut")); + nut2.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor2/0/nut")); + nut3.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor3/0/nut")); + + /* k */ + Field k0 = new Field("k"); + Field k1 = new Field("k"); + Field k2 = new Field("k"); + Field k3 = new Field("k"); + k0.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor0/0/k")); + k1.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor1/0/k")); + k2.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor2/0/k")); + k3.read(new File("/home/stefano/ENGYS/examples/HELYX2/DanicaRANS/processor3/0/k")); + + } +} diff --git a/src/eu/engys/core/project/zero/fields/FieldFilter.java b/src/eu/engys/core/project/zero/fields/FieldFilter.java new file mode 100644 index 0000000..e289bfd --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/FieldFilter.java @@ -0,0 +1,32 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +public interface FieldFilter { + + boolean accept(Field field); + +} diff --git a/src/eu/engys/core/project/zero/fields/FieldReader.java b/src/eu/engys/core/project/zero/fields/FieldReader.java new file mode 100644 index 0000000..a6289ee --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/FieldReader.java @@ -0,0 +1,245 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import static eu.engys.core.project.zero.fields.Fields.ALPHA; +import static eu.engys.core.project.zero.fields.Fields.U; + +import java.io.File; +import java.io.FileInputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryReader; +import eu.engys.core.dictionary.parser.DictionaryReader2; +import eu.engys.util.CompactStringBuilder; + +public class FieldReader { + + private static final String BOUNDARY_FIELD = "boundaryField"; + + private static final Logger logger = LoggerFactory.getLogger(FieldReader.class); + + private static final int SIZE = 8192; + + private static final Pattern END_PATTERN = Pattern.compile("([^#]*;\\s*}\\s*})\\s*.*"); + private static final String DOUBLE_NUMBER = "(\\s*\\-?\\d*\\.?\\d+([eE][-+]?[0-9]+)*\\s*)"; + private static final Pattern DOUBLE_NUMBER_PATTERN = Pattern.compile(DOUBLE_NUMBER); + private static final Pattern NONUNIFORM_VECTOR_PATTERN = Pattern.compile("internalField\\s+nonuniform\\s+List\\s+(\\d+)?\\s+\\(\\s+(\\([^#]*\\))\\s+\\)\\s*"); + private static final Pattern NONUNIFORM_SCALAR_PATTERN = Pattern.compile("internalField\\s+nonuniform\\s+List\\s+(\\d+)?\\s+\\(([^#]*)\\s+\\)\\s*"); + private static final Pattern UNIFORM_VECTOR_PATTERN = Pattern.compile("internalField\\s+uniform\\s+\\(([^\\)]*)\\)"); + private static final Pattern UNIFORM_SCALAR_PATTERN = Pattern.compile("internalField\\s+uniform\\s+" + DOUBLE_NUMBER); + + private Field field; + + public FieldReader(Field field) { + this.field = field; + } + + public void read(File file) { + field.setDimensions(readDimensions(file)); + field.setBoundaryField(readBoundaryField(file)); + field.setInternalField(readInternalField(file)); + // System.gc(); + // System.out.println("ReadField.read() "+MemoryStatus.getToolTipText(true)); + } + + private String readDimensions(File file) { + return extractString(file, "dimensions").toString().replace("dimensions", "").trim(); + } + + private InternalField readInternalField(File file) { + CharSequence internalField = extractString(file, "internalField"); + return readValue(internalField); + } + + InternalField readValue(CharSequence internalField) { + Matcher matrixMatcher = NONUNIFORM_VECTOR_PATTERN.matcher(internalField); + Matcher vectorMatcher = NONUNIFORM_SCALAR_PATTERN.matcher(internalField); + Matcher arrayMatcher = UNIFORM_VECTOR_PATTERN.matcher(internalField); + Matcher scalarMatcher = UNIFORM_SCALAR_PATTERN.matcher(internalField); + + if (matrixMatcher.matches()) { + logger.debug("Matrix: " + field.getName()); + String total = matrixMatcher.group(1); + return new MatrixInternalField(Integer.parseInt(total)); + } else if (vectorMatcher.matches()) { + logger.debug("Vector: " + field.getName()); + String total = vectorMatcher.group(1); + return new VectorInternalField(Integer.parseInt(total)); + } else if (arrayMatcher.matches()) { + logger.debug("Array: " + field.getName()); + double[] value = populateArray(arrayMatcher.group(1)); + return new ArrayInternalField(value); + } else if (scalarMatcher.matches()) { + logger.debug("Scalar: " + field.getName()); + double value = Double.parseDouble(scalarMatcher.group(1)); + return new ScalarInternalField(value); + } else { + logger.error("NO MATCH FOR {}, IT WILL BE READ AS A UNIFORM FIELD", field.getName()); + return readValue("internalField uniform " + (field.getName().startsWith(U) ? "(0 0 0)" : "0")); + } + } + + private double[] populateArray(String string) { + Matcher rowRegexMatcher = DOUBLE_NUMBER_PATTERN.matcher(string); + double[] value = new double[3]; + + int columnCounter = 0; + while (rowRegexMatcher.find()) { + value[columnCounter] = Double.valueOf(rowRegexMatcher.group().trim()); + if (columnCounter > 3) { + break; + } + columnCounter++; + } + + return value; + } + + private Dictionary readBoundaryField(File file) { + StringBuilder boundaryBuffer = new StringBuilder(); + + try (FileInputStream f = new FileInputStream(file)) { + + FileChannel ch = f.getChannel(); + byte[] barray = new byte[SIZE]; + ByteBuffer bb = ByteBuffer.wrap(barray); + boolean found = false; + + String previous = ""; + int read = 0; + while ((read = ch.read(bb)) != -1) { + String current = new String(barray, 0, read); + String boundaryString = ""; + + if (!found) { + if (current.contains(BOUNDARY_FIELD)) { + found = true; + boundaryString = current.substring(current.indexOf(BOUNDARY_FIELD)); + } else { + String concat = previous.concat(current); + if (concat.contains(BOUNDARY_FIELD)) { + found = true; + boundaryString = concat.substring(concat.indexOf(BOUNDARY_FIELD)); + } + } + } else { + boundaryString = current; + } + + if (found) { + Matcher endMatcher = END_PATTERN.matcher(boundaryString); + if (endMatcher.matches()) { + boundaryString = endMatcher.group(1); + boundaryBuffer.append(boundaryString); + break; + } else { + boundaryBuffer.append(boundaryString); + } + } + + bb.clear(); + previous = current; + } + } catch (Exception e) { + e.printStackTrace(); + } + String text = boundaryBuffer.toString(); + + Dictionary d = new Dictionary(""); + if (field.getName().startsWith(ALPHA)) { + new DictionaryReader2(d).read(text); + } else { + new DictionaryReader(d).read(text); + } + + if (d.found(BOUNDARY_FIELD)) { + return d.subDict(BOUNDARY_FIELD); + } else { + return new Dictionary(BOUNDARY_FIELD); + } + } + + public static CharSequence extractString(File file, String keyToExtract) { + CompactStringBuilder buffer = new CompactStringBuilder(); + + try (FileInputStream f = new FileInputStream(file)) { + FileChannel ch = f.getChannel(); + byte[] barray = new byte[SIZE]; + ByteBuffer bb = ByteBuffer.wrap(barray); + + boolean found = false; + + String previous = ""; + + while (ch.read(bb) != -1) { + String current = new String(barray); + String internalString = ""; + + if (!found) { + if (current.contains(keyToExtract)) { + found = true; + internalString = current.substring(current.indexOf(keyToExtract)); + } else { + String concat = previous.concat(current); + + if (concat.contains(keyToExtract)) { + found = true; + internalString = concat.substring(concat.indexOf(keyToExtract)); + } + } + } else { + internalString = current; + } + + if (found) { + if (internalString.contains(";")) { + internalString = internalString.substring(0, internalString.indexOf(";")); + buffer.append(internalString); + break; + } else { + buffer.append(internalString); + } + } + + bb.clear(); + + previous = current; + } + } catch (Exception e) { + e.printStackTrace(); + } + + return buffer.toCompactCharSequence(); + } +} diff --git a/src/eu/engys/core/project/zero/fields/FieldWriter.java b/src/eu/engys/core/project/zero/fields/FieldWriter.java new file mode 100644 index 0000000..ba5fa91 --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/FieldWriter.java @@ -0,0 +1,78 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.io.FileWriter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.util.progress.ProgressMonitor; + +public class FieldWriter { + + private static final Logger logger = LoggerFactory.getLogger(FieldWriter.class); + + private Field field; + + private ProgressMonitor monitor; + + public FieldWriter(Field field, ProgressMonitor monitor) { + this.field = field; + this.monitor = monitor; + } + + public void bufferInternalField(File zeroDir) { + String name = field.getName(); + InternalField internalField = field.getInternalField(); + File file = new File(zeroDir, name); + internalField.buffer(file); + } + + public void write(File zeroDir) { + String name = field.getName(); + String dimensions = field.getDimensions(); + Dictionary boundaryField = field.getBoundaryField(); + InternalField internalField = field.getInternalField(); + File file = new File(zeroDir, name); +// monitor.info(name, 2); + logger.info("WRITE : {}", file); + + try (FileWriter writer = new FileWriter(file)) { + writer.write(FoamFile.HEADER); + writer.write(FoamFile.getFieldFoamFile(name).toString()); + writer.write(Field.DIMENSIONS + " " + dimensions + ";\n"); + internalField.write(writer); + writer.write(boundaryField.toString()); + } catch (Exception e) { + monitor.error("Error writing " + file); + logger.error("Error writing " + file, e); + } + } +} diff --git a/src/eu/engys/core/project/zero/fields/Fields.java b/src/eu/engys/core/project/zero/fields/Fields.java new file mode 100644 index 0000000..0ce26f6 --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/Fields.java @@ -0,0 +1,232 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; + +import eu.engys.core.project.state.State; + +public class Fields extends LinkedHashMap { + + public static final String SMOKE = "smoke"; + public static final String DT_SMOKE = "Dtsmoke"; + public static final String CO2 = "CO2"; + public static final String DT_CO2 = "DtCO2"; + public static final String AOA = "AoA"; + public static final String DT_AOA = "DtAoA"; + public static final String W = "w"; + public static final String DT_W = "Dtw"; + public static final String T = "T"; + public static final String MU_SGS = "muSgs"; + public static final String ALPHA_1 = "alpha1"; + public static final String ALPHA_SGS = "alphaSgs"; + public static final String ALPHA_T = "alphat"; + public static final String ALPHA_S = "alphas"; + public static final String NU_TILDA = "nuTilda"; + public static final String EPSILON = "epsilon"; + public static final String OMEGA = "omega"; + public static final String K = "k"; + public static final String P_RGH = "p_rgh"; + public static final String P = "p"; + public static final String U = "U"; + public static final String IDEFAULT = "IDefault"; + public static final String NU_SGS = "nuSgs"; + public static final String NUT = "nut"; + public static final String MUT = "mut"; + public static final String RHO = "rho"; + public static final String ILAMBDA = "ILambda"; + public static final String FINAL = "Final"; + + public static final String ALPHA = "alpha"; + public static final String ETA = "eta"; + + private Fields[] parallelFields; + + public static final String EDITABLE_FIELDS[] = new String[] { U, P, P_RGH, K, OMEGA, EPSILON, NU_TILDA, T, W, AOA, CO2, SMOKE }; + private static final String PASSIVE_SCALARS[] = new String[] { W, AOA, CO2, SMOKE }; + + public List listFields(FieldFilter filter) { + List list = new LinkedList(); + for (Field field : orderedFields()) { + if (filter.accept(field)) { + list.add(field); + } + } + return list; + } + + public List orderedFieldsExcludingPassiveScalars() { + List list = new LinkedList(); + for (Field field : orderedFields()) { + if (!isPassiveScalar(field)) { + list.add(field); + } + } + return list; + } + + public List orderedFields() { + List list = new LinkedList(); + list.addAll(getMultiphaseUFields()); + for (String fieldName : EDITABLE_FIELDS) { + if (this.containsKey(fieldName)) { + Field field = this.get(fieldName); + if (field.isVisible()) { + list.add(field); + } + } + } + list.addAll(getAlphaFields()); + return list; + } + + public List orderedFieldsNames() { + List list = new LinkedList<>(); + for (Field field : orderedFields()) { + list.add(field.getName()); + } + return list; + } + + public List getMultiphaseUFields() { + List list = new LinkedList(); + for (Field field : this.values()) { + String name = field.getName(); + if (name.startsWith(U) && !name.equals(U)) { + list.add(field); + } + } + return list; + } + + public List getAlphaFields() { + List list = new LinkedList(); + for (Field field : this.values()) { + String name = field.getName(); + if (name.startsWith(ALPHA) && !name.equals(ALPHA_S) && !name.equals(ALPHA_SGS) && !name.equals(ALPHA_T)) { + list.add(field); + } + } + return list; + } + + private boolean isPassiveScalar(Field field) { + for (String s : PASSIVE_SCALARS) { + if (s.equals(field.getName())) { + return true; + } + } + return false; + } + + public List fieldNames() { + return new LinkedList<>(keySet()); + } + + public Fields[] getParallelFields() { + return parallelFields; + } + + public Fields getFieldsForProcessor(int processor) { + return parallelFields[processor]; + } + + public void setParallelFields(Fields[] parallelFields) { + this.parallelFields = parallelFields; + } + + public void newParallelFields(int processors) { + parallelFields = new Fields[processors]; + for (int i = 0; i < parallelFields.length; i++) { + parallelFields[i] = new Fields(); + } + } + + @Override + public void clear() { + super.clear(); + if (parallelFields != null) { + for (Fields pf : parallelFields) { + pf.clear(); + } + } + } + + public static String ALPHA(String phaseName) { + return ALPHA + phaseName; + } + + public static String PHASE(String fieldName) { + return fieldName.replace(ALPHA, ""); + } + + public static String PHASE_OS(String fieldName) { + return fieldName.replace(ALPHA + ".", ""); + } + + public void merge(Fields fields) { + // putAll(fields); + for (String key : fields.keySet()) { + if (containsKey(key)) { + get(key).merge(fields.get(key)); + } else { + put(key, fields.get(key)); + } + } + + if (fields.getParallelFields() != null) { + if (parallelFields == null) { + newParallelFields(fields.getParallelFields().length); + } + + Fields[] parallelFields2 = fields.getParallelFields(); + for (int i = 0; i < parallelFields.length; i++) { + if (parallelFields2.length > i) { + parallelFields[i].merge(parallelFields2[i]); + } + } + } + } + + public void fixPVisibility(State state) { + boolean stateCompressible = state.isCompressible(); + boolean stateBuoyant = state.isBuoyant(); + boolean prghPresent = containsKey(P_RGH); + boolean pPresent = containsKey(P); + + if (pPresent && prghPresent) { + if (stateCompressible && stateBuoyant) { + get(P).setVisible(false); + get(P_RGH).setVisible(true); + } else { + get(P).setVisible(true); + get(P_RGH).setVisible(false); + } + } + } +} diff --git a/src/eu/engys/core/project/zero/fields/FieldsDefaults.java b/src/eu/engys/core/project/zero/fields/FieldsDefaults.java new file mode 100644 index 0000000..477d1be --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/FieldsDefaults.java @@ -0,0 +1,247 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import static eu.engys.core.project.constant.TurbulenceProperties.FIELD_MAPS_KEY; +import static eu.engys.core.project.constant.TurbulenceProperties.LES; +import static eu.engys.core.project.constant.TurbulenceProperties.RAS; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.project.defaults.DefaultsProvider; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.fields.Field.FieldType; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.core.project.zero.patches.Patches; + +public class FieldsDefaults { + + private static final Logger logger = LoggerFactory.getLogger(FieldsDefaults.class); + private static Map oldInitialisations = new HashMap(); + + private DefaultsProvider defaults; + + private FieldsDefaults(DefaultsProvider defaults) { + this.defaults = defaults; + } + + public static void prepareFields(Fields fields) { + saveInitializations(fields); + fields.clear(); + } + + private static void saveInitializations(Fields fieldsMap) { + oldInitialisations.clear(); + + for (String key : fieldsMap.keySet()) { + oldInitialisations.put(key, fieldsMap.get(key).getInitialisation()); + } + } + + private static void applySavedInitialization(Field field) { + if (oldInitialisations.containsKey(field.getName())) { + Dictionary initialisation = oldInitialisations.get(field.getName()); + field.setInitialisation(new Dictionary(initialisation)); + } + } + + public static Fields loadFieldsFromDefaults(State state, DefaultsProvider defaults, Patches patches, String region) { + return new FieldsDefaults(defaults).loadDefaultFields(state, patches, region); + } + + public static Field loadFieldFromDefaults(String name, DefaultsProvider defaults, Patches patches) { + return new FieldsDefaults(defaults).loadDefaultField(name, name, patches); + } + + private Field loadDefaultField(String name, String value, Patches patches) { + return newFieldFromDefaults(name, value, patches); + } + + private Fields loadDefaultFields(State state, Patches patches, String region) { + Dictionary defaultFields = getDefaultFieldMaps(state, region); + + Fields fields = addNewFields(defaultFields, patches); + if (patches.getParallelPatches() != null) { + Fields[] parallelFields = new Fields[patches.getParallelPatches().length]; + for (int i = 0; i < parallelFields.length; i++) { + parallelFields[i] = addNewFields(defaultFields, patches); + } + fields.setParallelFields(parallelFields); + } + + return fields; + } + + private Dictionary getDefaultFieldMaps(State state, String region) { + Dictionary fieldMaps = new Dictionary(FIELD_MAPS_KEY); + fieldMaps.merge(getTurbulenceFieldMaps(state, defaults, region)); + fieldMaps.merge(getStateFieldMaps(state, defaults, region)); + return fieldMaps; + } + + private Dictionary getStateFieldMaps(State state, DefaultsProvider defaults, String region) { + return defaults.getDefaultsFieldMapsFor(state, region); + } + + private Dictionary getTurbulenceFieldMaps(State state, DefaultsProvider defaults, String region) { + if (state.getTurbulenceModel() != null && !state.getFlow().isNone() && !state.getMethod().isNone() && !state.getSolverType().isNone()) { + String modelName = state.getTurbulenceModel().getName(); + String compType = state.getSolverType().isCoupled() ? "coupledIncompressible" : state.isCompressible() ? "compressible" : "incompressible"; + String turbType = state.isLES() ? LES : RAS; + String modelCoeffs = modelName + "Coeffs"; + + Dictionary fieldMaps = new Dictionary(FIELD_MAPS_KEY); + + Dictionary tpp = defaults.getDefaultTurbulenceProperties(); + if (tpp != null && tpp.isDictionary(compType + turbType)) { + if (tpp.subDict(compType + turbType).isDictionary(modelCoeffs)) { + Dictionary defCoeff = tpp.subDict(compType + turbType).subDict(modelCoeffs); + if (region != null) { + if (defCoeff.found(FIELD_MAPS_KEY+"."+region)) { + fieldMaps.merge(defCoeff.subDict(FIELD_MAPS_KEY+"."+region)); + } + } else { + if (defCoeff.found(FIELD_MAPS_KEY)) { + fieldMaps.merge(defCoeff.subDict(FIELD_MAPS_KEY)); + } + } + } + } + return fieldMaps; + } + return new Dictionary(""); + } + + private Fields addNewFields(Dictionary defaultFieldsMap, Patches patches) { + Fields fields = new Fields(); + for (FieldElement element : defaultFieldsMap.getFields()) { + String name = element.getName(); + String value = element.getValue(); + + Field field = newFieldFromDefaults(name, value, patches); + + applySavedInitialization(field); + + fields.put(name, field); + } + return fields; + } + + private Field newFieldFromDefaults(String name, String value, Patches patches) { + Dictionary defaultsDictionary = getDefaultsDictionary(value); + + Field field = new Field(name); + if (defaultsDictionary.found("initialisation")) { + field.setInitialisation(new Dictionary(defaultsDictionary.subDict("initialisation"))); + } + if (defaultsDictionary.found("allowedFieldInitialisationMethods")) { + field.setInitialisationMethods(defaultsDictionary.lookupArray("allowedFieldInitialisationMethods")); + } + if (defaultsDictionary.found("fieldDefinition")) { + Dictionary definition = new Dictionary(defaultsDictionary.subDict("fieldDefinition")); + field.setDefinition(definition); + field.setFieldType(FieldType.getType(definition.lookup(Dictionary.TYPE))); + field.setDimensions(definition.lookup("dimensions")); + field.setInternalField("internalField " + definition.lookup("internalField")); + field.setBoundaryField(getBoundaryConditionsFromDefaults(field.getFieldType(), patches, definition)); + } + + return field; + } + + private Dictionary getDefaultsDictionary(String value) { + Dictionary defaultsDictionary = defaults.getDefaultFieldsData().subDict(value); + if (defaultsDictionary == null) { + logger.warn("Cannot find {} into defaults", value); + // JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Cannot find " + value + " into defaults", "Warning", JOptionPane.WARNING_MESSAGE); + return new Dictionary(""); + } + return defaultsDictionary; + } + + private Dictionary getBoundaryConditionsFromDefaults(FieldType fieldType, Patches patches, Dictionary definition) { + Dictionary regionDefaults = definition.subDict("boundaryConditions").subDict("regionDefaults"); + Dictionary boundaryField = new Dictionary("boundaryField"); + for (Patch patch : patches) { + boundaryField.add(getDefaultBoundaryCondition(fieldType, regionDefaults, patch)); + } + return boundaryField; + } + + private static Dictionary getDefaultBoundaryCondition(FieldType fieldType, Dictionary regionDefaults, Patch patch) { + String patchType = patch.getPhisicalType() == BoundaryType.OPENING ? BoundaryType.PATCH_KEY : patch.getPhisicalType().getKey(); + String patchName = patch.getName(); + + if (regionDefaults.found(patchType)) { + Dictionary defaultDictionary = regionDefaults.subDict(patchType); + Dictionary fieldPatch = new Dictionary(patchName); + fieldPatch.merge(defaultDictionary); + return fieldPatch; + } else if (patch.getPhisicalType().isCyclicAMI()) { + Dictionary fieldPatch = new Dictionary(patchName); + fieldPatch.add(Dictionary.TYPE, BoundaryType.CYCLIC_AMI_KEY); + fieldPatch.add(Dictionary.VALUE, fieldType == FieldType.SCALAR ? "uniform 0" : "uniform (0 0 0)"); + return fieldPatch; + } else { + Dictionary fieldPatch = new Dictionary(patchName); + fieldPatch.add(Dictionary.TYPE, patchType); + return fieldPatch; + } + } + + public static void setAsDefault(Field field, Patch patch) { + String patchName = patch.getName(); + String fieldName = field.getName(); + + try { + if(field.getDefinition() != null && !field.getDefinition().isEmpty()){ + Dictionary boundaryField = field.getBoundaryField(); + Dictionary regionDefaults = field.getDefinition().subDict("boundaryConditions").subDict("regionDefaults"); + + Dictionary defaultDictionary = getDefaultBoundaryCondition(field.getFieldType(), regionDefaults, patch); + if (boundaryField.found(patchName) && !fieldName.equals("U")) { + Dictionary fieldPatch = boundaryField.subDict(patchName); + fieldPatch.clear(); + fieldPatch.merge(defaultDictionary); + } else { + Dictionary fieldPatch = new Dictionary(patchName); + fieldPatch.merge(defaultDictionary); + boundaryField.add(fieldPatch); + } + } + } catch (Exception e) { + logger.error(patchName + " " + fieldName, e); + } + } + +} diff --git a/src/eu/engys/core/project/zero/fields/FieldsReader.java b/src/eu/engys/core/project/zero/fields/FieldsReader.java new file mode 100644 index 0000000..2b443b8 --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/FieldsReader.java @@ -0,0 +1,109 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.util.ArrayList; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.progress.ProgressMonitor; + +public class FieldsReader { + + private static final Logger logger = LoggerFactory.getLogger(FieldsReader.class); + + private Initialisations initialisations; + private ProgressMonitor monitor; + + public FieldsReader(Initialisations initialisations, ProgressMonitor monitor) { + this.monitor = monitor; + this.initialisations = initialisations; + } + + public Fields read(final Set fieldNames, File... zeroDirs) { + Fields fields = creteNewFields(zeroDirs); + + Fields[] parallelFields = fields.getParallelFields(); + + int total = zeroDirs.length * fieldNames.size(); + monitor.setCurrent("Reading fields", 0, total, 1); + + for (int i = 0; i < parallelFields.length; i++) { + final Fields pFields = parallelFields[i]; + final File zeroDir = zeroDirs[i]; + readFields(pFields, fieldNames, zeroDir); + } + copyFields(parallelFields[0], fields); + + return fields; + } + + private Fields creteNewFields(File... zeroDirs) { + Fields fields = new Fields(); + Fields[] parallelFields = new Fields[zeroDirs.length]; + for (int i = 0; i < parallelFields.length; i++) { + parallelFields[i] = new Fields(); + } + fields.setParallelFields(parallelFields); + + return fields; + } + + private void readFields(Fields fields, Set fieldNames, File zeroDir) { + logger.debug("----------Reading fields from {}", zeroDir); + + for (String fieldName : fieldNames) { + fields.put(fieldName, new Field(fieldName)); + } + + if (initialisations != null) { + for (int i = 0; i < fields.size(); i++) { + Field field = new ArrayList<>(fields.values()).get(i); + initialisations.readInitialisationFromFile(field); + initialisations.loadInitialisation(zeroDir, field, monitor); + monitor.setCurrent(null, monitor.getCurrent() + 1, 2); + } + } + } + + private void copyFields(Fields sources, Fields targets) { + for (Field source : sources.values()) { + Field target = new Field(source.getName()); + target.setDefinition(new Dictionary(source.getDefinition())); + target.setDimensions(source.getDimensions()); + target.setInitialisation(new Dictionary(source.getInitialisation())); + target.setInitialisationMethods(source.getInitialisationMethods()); + target.setFieldType(source.getFieldType()); + target.setInternalField(source.getInternalField()); + + targets.put(target.getName(), target); + } + } +} diff --git a/src/eu/engys/core/project/zero/fields/FieldsWriter.java b/src/eu/engys/core/project/zero/fields/FieldsWriter.java new file mode 100644 index 0000000..e8ac8c5 --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/FieldsWriter.java @@ -0,0 +1,117 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.util.ArrayList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.zero.ZeroFolderUtil; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; + +public class FieldsWriter { + + private static Logger logger = LoggerFactory.getLogger(Fields.class); + + private ProgressMonitor monitor; + + public FieldsWriter(ProgressMonitor monitor) { + this.monitor = monitor; + } + + public void write(Fields fields, File... zeroDirs) { + if (zeroDirs.length == 1) { + _write(fields, zeroDirs[0]); + } else { + writeParallel(fields, zeroDirs); + } + } + + private void writeParallel(Fields fields, File... zeroDirs) { + Runnable[] runnables = new Runnable[zeroDirs.length]; + for (int i = 0; i < zeroDirs.length; i++) { + final Fields fieldsForProc = fields.getFieldsForProcessor(i); + + if (fieldsForProc.size() != fields.size()) { + logger.warn("Fields for processor {} are {}!", i, fieldsForProc.keySet()); + } + + final File zeroDir = zeroDirs[i]; + runnables[i] = new Runnable() { + @Override + public void run() { + _write(fieldsForProc, zeroDir); + monitor.setCurrent(null, monitor.getCurrent() + 1, 2); + } + }; + } + ExecUtil.execSerial(runnables); + // ExecUtil.execInParallelAndWait(runnables); + } + + private void _write(Fields fields, final File zeroDir) { + if (fields.isEmpty()) { + logger.info("WRITE: Fields -> none", 2); + } else { + bufferInternalFields(fields, zeroDir); + ZeroFolderUtil.clearFiles(zeroDir); + writeFields(zeroDir, fields); + } + } + + private void bufferInternalFields(Fields fields, final File zeroDir) { + Runnable[] runnablesForBuffer = new Runnable[fields.size()]; + for (int i = 0; i < fields.size(); i++) { + final Field field = new ArrayList<>(fields.values()).get(i); + runnablesForBuffer[i] = new Runnable() { + @Override + public void run() { + field.bufferInternalField(zeroDir, monitor); + } + }; + } + ExecUtil.execSerial(runnablesForBuffer); + // ExecUtil.execInParallelAndWait(runnablesForBuffer); + } + + private void writeFields(final File zeroDir, Fields fields) { + Runnable[] runnablesForWrite = new Runnable[fields.size()]; + for (int i = 0; i < fields.size(); i++) { + final Field field = new ArrayList<>(fields.values()).get(i); + runnablesForWrite[i] = new Runnable() { + @Override + public void run() { + field.write(zeroDir, monitor); + } + }; + } + ExecUtil.execSerial(runnablesForWrite); + // ExecUtil.execInParallelAndWait(runnablesForWrite); + } +} diff --git a/src/eu/engys/core/project/zero/fields/Initialisations.java b/src/eu/engys/core/project/zero/fields/Initialisations.java new file mode 100644 index 0000000..dcecf17 --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/Initialisations.java @@ -0,0 +1,49 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.fields; + +import java.io.File; + +import eu.engys.util.progress.ProgressMonitor; + +public interface Initialisations { + + public static final String DEFAULT_KEY = "default"; + public static final String FIXED_VALUE_KEY = "fixedValue"; + public static final String POTENTIAL_FLOW_KEY = "potentialFlow"; + public static final String PRANDTL_KEY = "Prandtl"; + public static final String TURBULENT_IL_KEY = "turbulentIL"; + public static final String BOUNDARY_VALUE_KEY = "boundaryValue"; + public static final String CELL_SET_KEY = "cellSet"; + public static final String INITIALISE_UBCS_KEY = "initialiseUBCs"; + public static final String PATCH_KEY = "patch"; + + public void readInitialisationFromFile(Field field); + + public void loadInitialisation(File zeroDir, Field field, ProgressMonitor monitor); + +} diff --git a/src/eu/engys/core/project/zero/fields/InternalField.java b/src/eu/engys/core/project/zero/fields/InternalField.java new file mode 100644 index 0000000..59cf2db --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/InternalField.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public interface InternalField { + + int getSize(); + + double[][] getValue(); + + void write(FileWriter writer) throws IOException; + + void buffer(File file); + +} diff --git a/src/eu/engys/core/project/zero/fields/MatrixInternalField.java b/src/eu/engys/core/project/zero/fields/MatrixInternalField.java new file mode 100644 index 0000000..9cbc7b2 --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/MatrixInternalField.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class MatrixInternalField implements InternalField { + + private int size; + private CharSequence buffer; + + public MatrixInternalField(int size) { + this.size = size; + } + + @Override + public int getSize() { + return size; + } + + @Override + public double[][] getValue() { + return null; + } + + @Override + public void write(FileWriter writer) throws IOException { + int len = buffer.length(); + int BUF_LENGTH = 1024; + for (int start = 0, end = Math.min(BUF_LENGTH, len); end <= len + BUF_LENGTH; start = end, end += BUF_LENGTH) { + writer.write(buffer.subSequence(start, Math.min(end, len)).toString()); + } + + writer.write(";\n"); + buffer = null; + } + + @Override + public void buffer(File file) { + buffer = FieldReader.extractString(file, Field.INTERNAL_FIELD); + } + +} diff --git a/src/eu/engys/core/project/zero/fields/ScalarInternalField.java b/src/eu/engys/core/project/zero/fields/ScalarInternalField.java new file mode 100644 index 0000000..dcdd542 --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/ScalarInternalField.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class ScalarInternalField implements InternalField { + + private String buffer; + private double value; + + public ScalarInternalField(double value) { + this.value = value; + } + + @Override + public int getSize() { + return 1; + } + + @Override + public double[][] getValue() { + return new double[][] {{value}}; + } + + @Override + public void write(FileWriter writer) throws IOException { + writer.write(buffer); + } + + @Override + public void buffer(File file) { + buffer = Field.INTERNAL_FIELD + " uniform "+String.valueOf(value)+";"; + } +} diff --git a/src/eu/engys/core/project/zero/fields/VectorInternalField.java b/src/eu/engys/core/project/zero/fields/VectorInternalField.java new file mode 100644 index 0000000..7754523 --- /dev/null +++ b/src/eu/engys/core/project/zero/fields/VectorInternalField.java @@ -0,0 +1,67 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.fields; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class VectorInternalField implements InternalField { + + private CharSequence buffer; + private int size; + + public VectorInternalField(int size) { + this.size = size; + } + + @Override + public int getSize() { + return size; + } + + @Override + public double[][] getValue() { + return null; + } + + @Override + public void write(FileWriter writer) throws IOException { + int len = buffer.length(); + int BUF_LENGTH = 1024; + for (int start = 0, end = Math.min(BUF_LENGTH, len); end <= len + BUF_LENGTH; start = end, end += BUF_LENGTH) { + writer.write(buffer.subSequence(start, Math.min(end, len)).toString()); + } + writer.write(";\n"); + buffer = null; + } + + @Override + public void buffer(File file) { + buffer = FieldReader.extractString(file, Field.INTERNAL_FIELD); + } + +} diff --git a/src/eu/engys/core/project/zero/patches/BoundaryConditions.java b/src/eu/engys/core/project/zero/patches/BoundaryConditions.java new file mode 100644 index 0000000..13a909b --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/BoundaryConditions.java @@ -0,0 +1,357 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.patches; + +import static eu.engys.core.project.zero.fields.Fields.ALPHA; +import static eu.engys.core.project.zero.fields.Fields.ALPHA_SGS; +import static eu.engys.core.project.zero.fields.Fields.ALPHA_T; +import static eu.engys.core.project.zero.fields.Fields.AOA; +import static eu.engys.core.project.zero.fields.Fields.CO2; +import static eu.engys.core.project.zero.fields.Fields.DT_AOA; +import static eu.engys.core.project.zero.fields.Fields.DT_CO2; +import static eu.engys.core.project.zero.fields.Fields.DT_SMOKE; +import static eu.engys.core.project.zero.fields.Fields.DT_W; +import static eu.engys.core.project.zero.fields.Fields.EPSILON; +import static eu.engys.core.project.zero.fields.Fields.ETA; +import static eu.engys.core.project.zero.fields.Fields.IDEFAULT; +import static eu.engys.core.project.zero.fields.Fields.K; +import static eu.engys.core.project.zero.fields.Fields.MUT; +import static eu.engys.core.project.zero.fields.Fields.MU_SGS; +import static eu.engys.core.project.zero.fields.Fields.NUT; +import static eu.engys.core.project.zero.fields.Fields.NU_SGS; +import static eu.engys.core.project.zero.fields.Fields.NU_TILDA; +import static eu.engys.core.project.zero.fields.Fields.OMEGA; +import static eu.engys.core.project.zero.fields.Fields.P; +import static eu.engys.core.project.zero.fields.Fields.P_RGH; +import static eu.engys.core.project.zero.fields.Fields.SMOKE; +import static eu.engys.core.project.zero.fields.Fields.T; +import static eu.engys.core.project.zero.fields.Fields.U; +import static eu.engys.core.project.zero.fields.Fields.W; + +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.zero.fields.Fields; + +public class BoundaryConditions { + + private static final Logger logger = LoggerFactory.getLogger(BoundaryConditions.class); + + public static final String[] PLACE_HOLDER_KEYS = {"value", "refValue", "inletValue", "gradient"}; + + public static void replaceNonUniformVector(Dictionary d) { + for (String ph : PLACE_HOLDER_KEYS) { + if(isNonUniform(d, ph)){ + d.add(ph, "uniform (0 0 0)"); + logger.warn("Nonuniform field {} replaced with {}", ph, d.lookup(ph)); + } + } + } + public static void replaceNonUniformScalar(Dictionary d) { + for (String ph : PLACE_HOLDER_KEYS) { + if(isNonUniform(d, ph)){ + d.add(ph, "uniform 0"); + logger.warn("Nonuniform field {} replaced with {}", ph, d.lookup(ph)); + } + } + } + + public static boolean isNonUniform(Dictionary d) { + for (String ph : PLACE_HOLDER_KEYS) { + if(isNonUniform(d, ph)){ + return true; + } + } + return false; + } + + public static boolean isPlaceHolder(Dictionary d) { + for (String ph : PLACE_HOLDER_KEYS) { + if(isPlaceHolder(d, ph)){ + return true; + } + } + return false; + } + + private static boolean isPlaceHolder(Dictionary d, String key) { + return (d.isField(key) && d.lookup(key).contains("nonuniform 0()")) || (d.isList2(key) && d.getList2(key).isEmpty()); + } + + private static boolean isNonUniform(Dictionary d, String key) { + return (d.isField(key) && d.lookup(key).contains("nonuniform List")) || (d.isList2(key) && d.getList2(key).isNonuniform()); + } + + private Dictionary momentum; + private Dictionary turbulence; + private Dictionary thermal; + private Dictionary humidity; + private Dictionary radiation; + private Dictionary passiveScalars; + private Dictionary phase; + private Dictionary roughness; + + public BoundaryConditions() { + setMomentum(new Dictionary("momentum")); + setTurbulence(new Dictionary("turbulence")); + setThermal(new Dictionary("thermal")); + setHumidity(new Dictionary("humidity")); + setRadiation(new Dictionary("radiation")); + setPassiveScalars(new Dictionary("passiveScalars")); + setPhase(new Dictionary("phase")); + setRoughness(new Dictionary("roughness")); + } + + public BoundaryConditions(BoundaryConditions defaults) { + this(); + if (defaults != null) { + getMomentum().merge(defaults.getMomentum()); + getTurbulence().merge(defaults.getTurbulence()); + getThermal().merge(defaults.getThermal()); + getHumidity().merge(defaults.getHumidity()); + getRadiation().merge(defaults.getRadiation()); + getPassiveScalars().merge(defaults.getPassiveScalars()); + getPhase().merge(defaults.getPhase()); + getRoughness().merge(defaults.getRoughness()); + } + } + + public Dictionary toDictionary() { + Dictionary dict = new Dictionary("boundaryConditions"); + dict.merge(getMomentum()); + dict.merge(getTurbulence()); + dict.merge(getThermal()); + dict.merge(getHumidity()); + dict.merge(getRadiation()); + dict.merge(getPassiveScalars()); + dict.merge(getPhase()); + dict.merge(getRoughness()); + return dict; + } + + public void fromDictionary(Dictionary dictionary) { + for (Dictionary d : dictionary.getDictionaries()) { + add(d.getName(), d); + } + } + + // public void loadFromField(String name, Dictionary patchInField) { + // Dictionary dict = new Dictionary(name); + // dict.merge(patchInField); + // add(name, patchInField); + // } + + public void add(String name, Dictionary original) { + Dictionary dictionary = new Dictionary(original); + dictionary.setName(name.equals(Fields.P_RGH) ? Fields.P : name); + + if (isMomentum(name)) { + getMomentum().add(dictionary); + } else if (isTurbulence(name)) { + getTurbulence().add(dictionary); + } else if (isThermal(name)) { + getThermal().add(dictionary); + } else if (isHumidity(name)) { + getHumidity().add(dictionary); + } else if (isRadiation(name)) { + getRadiation().add(dictionary); + } else if (isPassiveScalar(name)) { + getPassiveScalars().add(dictionary); + } else if (isPhase(name)) { + getPhase().add(dictionary); + } else if (isRoughness(name)) { + getRoughness().add(dictionary); + } else { + + } + } + + private boolean isRoughness(String name) { + String[] list = new String[] { NUT, MUT, NU_SGS, MU_SGS }; + return Arrays.asList(list).contains(name); + } + + public static boolean isPassiveScalar(String name) { + String[] list = new String[] { AOA, DT_AOA, CO2, DT_CO2, SMOKE, DT_SMOKE }; + return Arrays.asList(list).contains(name); + } + + public static boolean isPhase(String name) { + return name.equals(ETA) || (name.startsWith(ALPHA) && !name.equals(ALPHA_SGS) && !name.equals(ALPHA_T)); + } + + public static boolean isRadiation(String name) { + return name.equals(IDEFAULT); + } + + public static boolean isHumidity(String name) { + return name.equals(W) || name.equals(DT_W); + } + + public static boolean isThermal(String name) { + return name.equals(T); + } + + public static boolean isTurbulence(String name) { + String[] list = new String[] { K, OMEGA, EPSILON, NU_TILDA, /*NUT, NU_SGS, MUT, MU_SGS, */ALPHA_SGS, ALPHA_T }; + return Arrays.asList(list).contains(name); + } + + public static boolean isMomentum(String name) { + return name.equals(P) || name.equals(P_RGH) || name.startsWith(U); + } + + public Dictionary getMomentum() { + return momentum; + } + + public Dictionary setMomentum(Dictionary momentum) { + this.momentum = momentum; + return momentum; + } + + public Dictionary getTurbulence() { + return turbulence; + } + + public Dictionary setTurbulence(Dictionary turbulence) { + this.turbulence = turbulence; + return turbulence; + } + + public Dictionary getThermal() { + return thermal; + } + + public Dictionary setThermal(Dictionary thermal) { + this.thermal = thermal; + return thermal; + } + + public Dictionary getHumidity() { + return humidity; + } + + public Dictionary setHumidity(Dictionary humidity) { + this.humidity = humidity; + return humidity; + } + + public Dictionary getRadiation() { + return radiation; + } + + public Dictionary setRadiation(Dictionary radiation) { + this.radiation = radiation; + return radiation; + } + + public Dictionary getPassiveScalars() { + return passiveScalars; + } + + public Dictionary setPassiveScalars(Dictionary passiveScalars) { + this.passiveScalars = passiveScalars; + return passiveScalars; + } + + public Dictionary getPhase() { + return phase; + } + + public Dictionary setPhase(Dictionary phase) { + this.phase = phase; + return phase; + } + + public Dictionary getRoughness() { + return roughness; + } + + public void setRoughness(Dictionary roughness) { + this.roughness = roughness; + } + + public static BoundaryConditions toMomentumRoughness(Dictionary dict) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setMomentum(dict); + bc.setRoughness(dict); + return bc; + } + + public static BoundaryConditions toMomentumThermal(Dictionary dict) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setMomentum(dict); + bc.setThermal(dict); + return bc; + } + + public static BoundaryConditions toTurbulence(Dictionary turbulence) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setTurbulence(turbulence); + return bc; + } + + public static BoundaryConditions toThermal(Dictionary thermal) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setThermal(thermal); + return bc; + } + + public static BoundaryConditions toRadiation(Dictionary radiation) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setRadiation(radiation); + return bc; + } + + public static BoundaryConditions toPhase(Dictionary phase) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setPhase(phase); + return bc; + } + + public static BoundaryConditions toPassiveScalars(Dictionary passiveScalars) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setPassiveScalars(passiveScalars); + return bc; + } + + public static BoundaryConditions toHumidity(Dictionary humidity) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setHumidity(humidity); + return bc; + } + + public static BoundaryConditions toMomentum(Dictionary momentum) { + BoundaryConditions bc = new BoundaryConditions(); + bc.setMomentum(momentum); + return bc; + } +} diff --git a/src/eu/engys/core/project/zero/patches/BoundaryConditionsDefaults.java b/src/eu/engys/core/project/zero/patches/BoundaryConditionsDefaults.java new file mode 100644 index 0000000..44975e5 --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/BoundaryConditionsDefaults.java @@ -0,0 +1,211 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.patches; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.fields.FieldsDefaults; + +public class BoundaryConditionsDefaults { + + private static final Logger logger = LoggerFactory.getLogger(BoundaryConditionsDefaults.class); + + private static Map defaultBoundaryConditions = new HashMap(); + + public static void updateBoundaryConditionsDefaultsByFields(Model model) { + defaultBoundaryConditions.clear(); + + Fields fields = model.getFields(); + Map typesMap = BoundaryType.getRegisteredBoundaryTypes(); + + for (String type : typesMap.keySet()) { + BoundaryConditions bc = extractDefaultBoundaryConditionsForType(fields.values(), type); + defaultBoundaryConditions.put(type, bc); + } + } + + private static BoundaryConditions extractDefaultBoundaryConditionsForType(Collection fields, String patchType) { + BoundaryConditions bc = new BoundaryConditions(); + for (Field field : fields) { + if (field.getDefinition() != null && field.getDefinition().subDict("boundaryConditions") != null) { + Dictionary regionDefaults = field.getDefinition().subDict("boundaryConditions").subDict("regionDefaults"); + String internalType = BoundaryType.isOpening(patchType) ? BoundaryType.PATCH_KEY : patchType; + if (regionDefaults.found(internalType)) { + Dictionary regionDefaultsForType = regionDefaults.subDict(internalType); + bc.add(field.getName(), regionDefaultsForType); + } else { + Dictionary fieldPatch = new Dictionary(field.getName()); + fieldPatch.add(Dictionary.TYPE, patchType); + bc.add(field.getName(), fieldPatch); + } + } else { + logger.error("No definition for field " + field.getName() + ": " + field.getDefinition()); + } + } + return bc; + } + + public static BoundaryConditions get(String key) { + return defaultBoundaryConditions.get(key); + } + + public static Dictionary getPressureFor(BoundaryType type, Dictionary def) { + BoundaryConditions boundaryConditions = BoundaryConditionsDefaults.get(type.getKey()); + if (boundaryConditions != null) { + Dictionary momentum = boundaryConditions.getMomentum(); + if (momentum != null) { + if (momentum.isDictionary(Fields.P)) { + return new Dictionary(momentum.subDict(Fields.P)); + } + } + } + return new Dictionary(def); + } + + + public static Dictionary getRoughness() { + BoundaryConditions boundaryConditions = BoundaryConditionsDefaults.get(BoundaryType.WALL_KEY); + if (boundaryConditions != null) { + Dictionary roughness = boundaryConditions.getRoughness(); + if (roughness != null) { + return new Dictionary(roughness); + } + } + return null; + } + + public static void loadBoundaryConditionsFromFields(Patches patches, Fields fields) { + patches.clearBoundaryConditions(); + + fieldsToBoundaryConditions(patches, fields); + + new MergeBoundaryConditions(patches, fields).execute(); + } + + public static void fieldsToBoundaryConditions(Patches patches, Fields fields) { + Fields[] parallelFields = fields.getParallelFields(); + Patches[] parallelPatches = patches.getParallelPatches(); + + if (parallelFields != null && parallelPatches != null) { + for (int i = 0; i < parallelFields.length; i++) { + Fields map = parallelFields[i]; + Patches patchesOfProcessor = parallelPatches[i]; + for (Field field : map.values()) { + fieldToBoundaryConditions(field, patchesOfProcessor); + } + } + } + } + + public static void fieldToBoundaryConditions(Field field, Patches patches) { + Map patchesMap = patches.toMap(); + + Dictionary boundaryField = field.getBoundaryField(); + + for (Dictionary patchInField : boundaryField.getDictionaries()) { + String patchName = patchInField.getName(); + Patch patch = patchesMap.get(patchName); + + if (patch != null) { + patch.getBoundaryConditions().add(field.getName(), patchInField); + } + } + } + + public static void saveBoundaryConditionsToFields(Patches patches, Fields fields) { + new SplitBoundaryConditions(patches, fields).execute(); + + boundaryConditionsToFields(patches, fields); + } + + public static void boundaryConditionsToFields(Patches patches, Fields fieldsMap) { + + /* questa roba serve veramente ? */ + for (Field field : fieldsMap.values()) { + boundaryConditionsToField(patches, field); + } + + Fields[] parallelFields = fieldsMap.getParallelFields(); + if (parallelFields != null) { + for (int i = 0; i < parallelFields.length; i++) { + Fields processorFields = parallelFields[i]; + for (Field field : processorFields.values()) { + boundaryConditionsToField(patches.getPatchesOfProcessor(i), field); + } + } + } + } + + public static void boundaryConditionsToField(Patches patches, Field field) { + Dictionary boundaryField = field.getBoundaryField(); + String fieldName = field.getName(); + for (Patch patch : patches) { + String patchName = patch.getName(); + if (patch.getBoundaryConditions() != null) { + Dictionary boundaryConditions = patch.getBoundaryConditions().toDictionary(); + if (boundaryConditions.found(fieldName)) { + Dictionary bcDictionary = boundaryConditions.subDict(fieldName); + if (boundaryField.found(patchName)) { + Dictionary fieldPatch = boundaryField.subDict(patchName); + fieldPatch.clear(); + fieldPatch.merge(bcDictionary); + } else { + Dictionary fieldPatch = new Dictionary(patchName); + boundaryField.add(fieldPatch); + fieldPatch.merge(bcDictionary); + } + + } else if (fieldName.equals(Fields.P_RGH) && boundaryConditions.found(Fields.P)) { + Dictionary bcDictionary = boundaryConditions.subDict(Fields.P); + if (boundaryField.found(patchName)) { + Dictionary fieldPatch = boundaryField.subDict(patchName); + fieldPatch.clear(); + fieldPatch.merge(bcDictionary); + } else { + Dictionary fieldPatch = new Dictionary(patchName); + boundaryField.add(fieldPatch); + fieldPatch.merge(bcDictionary); + } + + } else { + FieldsDefaults.setAsDefault(field, patch); + } + } else { + FieldsDefaults.setAsDefault(field, patch); + } + } + } +} diff --git a/src/eu/engys/core/project/zero/patches/BoundaryType.java b/src/eu/engys/core/project/zero/patches/BoundaryType.java new file mode 100644 index 0000000..f60f4f1 --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/BoundaryType.java @@ -0,0 +1,225 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.patches; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +public class BoundaryType { + + public static final String MAPPED_PATCH_KEY = "mappedPatch"; + public static final String MAPPED_WALL_KEY = "mappedWall"; + public static final String CYCLIC_KEY = "cyclic"; + public static final String CYCLIC_AMI_KEY = "cyclicAMI"; + public static final String EMPTY_KEY = "empty"; + public static final String INLET_KEY = "inlet"; + public static final String OPENING_KEY = "opening"; + public static final String OUTLET_KEY = "outlet"; + public static final String PATCH_KEY = "patch"; + public static final String PROCESSOR_KEY = "processor"; + public static final String PROCESSOR_CYCLIC_KEY = "processorCyclic"; + public static final String SYMMETRY_KEY = "symmetry"; + public static final String SYMMETRY_PLANE_KEY = "symmetryPlane"; + public static final String WALL_KEY = "wall"; + public static final String WEDGE_KEY = "wedge"; + public static final String FREE_SURFACE_KEY = "freeSurface"; + + public static final String CYCLIC_LABEL = "Cyclic"; + public static final String CYCLIC_AMI_LABEL = "Cyclic AMI"; + public static final String EMPTY_LABEL = "Empty"; + public static final String INLET_LABEL = "Inlet"; + public static final String OPENING_LABEL = "Opening"; + public static final String OUTLET_LABEL = "Outlet"; + public static final String PATCH_LABEL = "Patch"; + public static final String PROCESSOR_LABEL = "Processor"; + public static final String PROCESSOR_CYCLIC_LABEL = "Processor Cyclic"; + public static final String SYMMETRY_LABEL = "Symmetry"; + public static final String SYMMETRY_PLANE_LABEL = "Symmetry Plane"; + public static final String WALL_LABEL = "Wall"; + public static final String WEDGE_LABEL = "Wedge"; + public static final String FREE_SURFACE_LABEL = "Free Surface"; + + public static final BoundaryType INLET = new BoundaryType(INLET_KEY, INLET_LABEL, true); + public static final BoundaryType OUTLET = new BoundaryType(OUTLET_KEY, OUTLET_LABEL, true); + public static final BoundaryType OPENING = new BoundaryType(OPENING_KEY, OPENING_LABEL, true); + public static final BoundaryType WALL = new BoundaryType(WALL_KEY, WALL_LABEL, true); + public static final BoundaryType PATCH = new BoundaryType(PATCH_KEY, PATCH_LABEL, true); + public static final BoundaryType SYMMETRY = new BoundaryType(SYMMETRY_KEY, SYMMETRY_LABEL, false); + public static final BoundaryType SYMMETRY_PLANE = new BoundaryType(SYMMETRY_PLANE_KEY, SYMMETRY_PLANE_LABEL, false); + public static final BoundaryType CYCLIC = new BoundaryType(CYCLIC_KEY, CYCLIC_LABEL, true); + public static final BoundaryType CYCLIC_AMI = new BoundaryType(CYCLIC_AMI_KEY, CYCLIC_AMI_LABEL, true); + public static final BoundaryType EMPTY = new BoundaryType(EMPTY_KEY, EMPTY_LABEL, false); + public static final BoundaryType WEDGE = new BoundaryType(WEDGE_KEY, WEDGE_LABEL, false); + public static final BoundaryType PROCESSOR = new BoundaryType(PROCESSOR_KEY, PROCESSOR_LABEL, false); + public static final BoundaryType PROCESSOR_CYCLIC = new BoundaryType(PROCESSOR_CYCLIC_KEY, PROCESSOR_CYCLIC_LABEL, false); + public static final BoundaryType FREE_SURFACE = new BoundaryType(FREE_SURFACE_KEY, FREE_SURFACE_LABEL, true); + + private static Map registeredTypes = new LinkedHashMap<>(); + private static Map registeredTypesIcon = new LinkedHashMap<>(); + + public static void registerBoundaryType(BoundaryType type) { + registeredTypes.put(type.getKey(), type); + registeredTypesIcon.put(type.getKey(), getIcon("eu/engys/resources/images/" + type.getKey() + "16.png")); + } + + public static void unregisterBoundaryType(BoundaryType type) { + registeredTypes.remove(type.getKey()); + registeredTypesIcon.remove(type.getKey()); + } + + private static Icon getIcon(String string) { + try { + return new ImageIcon(BoundaryType.class.getClassLoader().getResource(string)); + } catch (Exception e) { + return null; + } + } + + public static Map getRegisteredBoundaryTypes() { + return Collections.unmodifiableMap(registeredTypes); + } + + public static boolean isPatch(String key) { + return key.equals(PATCH_KEY); + } + + public static boolean isWall(String key) { + return key.equals(WALL_KEY); + } + + public static boolean isMappedWall(String key) { + return key.equals(MAPPED_WALL_KEY); + } + + public static boolean isMappedPatch(String key) { + return key.equals(MAPPED_PATCH_KEY); + } + + public static boolean isOpening(String key) { + return key.equals(OPENING_KEY); + } + + public static boolean isPatchPhysicalType(String key) { + return key.equals(INLET_KEY) || key.equals(OUTLET_KEY) || key.equals(OPENING_KEY); + } + + public static boolean isWallPhysicalType(String key) { + return key.equals(FREE_SURFACE_KEY); + } + + public static boolean isCoupledSymmetryPlaneType(String patchType) { + return patchType.equals(SYMMETRY_PLANE_KEY); + } + + public static boolean isProcessor(String key) { + return key.equals(PROCESSOR_KEY); + } + + public static boolean isProcessorCyclic(String key) { + return key.equals(PROCESSOR_CYCLIC_KEY); + } + + public static boolean isCyclicAMI(String key) { + return key.equals(CYCLIC_AMI_KEY); + } + + public static boolean isInlet(Patch patch) { + return patch.getPhisicalType().getKey().equals(INLET_KEY); + } + + public static boolean isKnown(String key) { + return registeredTypes.containsKey(key); + } + + public static BoundaryType getDefaultType() { + return WALL; + } + + public static String getDefaultKey() { + return WALL_KEY; + } + + public static BoundaryType getType(String key) { + return registeredTypes.get(key); + } + + private String label; + private String key; + private boolean hasBoundaryConditions; + + private BoundaryType(String key, String label, boolean hasBoundaryConditions) { + this.key = key; + this.label = label; + this.hasBoundaryConditions = hasBoundaryConditions; + } + + public String getLabel() { + return label; + } + + public String getKey() { + return key; + } + + public boolean hasBoundaryConditions() { + return hasBoundaryConditions; + } + + public Icon getIcon() { + return registeredTypesIcon.get(key); + } + + @Override + public String toString() { + return getKey(); + } + + @Override + public boolean equals(Object obj) { + return toString().equals(obj.toString()); + } + + public boolean isProcessor() { + return this == PROCESSOR; + } + + public boolean isProcessorCyclic() { + return this == PROCESSOR_CYCLIC; + } + + public boolean isCyclicAMI() { + return this == CYCLIC_AMI; + } + + public boolean isPatch() { + return this == PATCH; + } +}; diff --git a/src/eu/engys/core/project/zero/patches/MergeBoundaryConditions.java b/src/eu/engys/core/project/zero/patches/MergeBoundaryConditions.java new file mode 100644 index 0000000..69580a8 --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/MergeBoundaryConditions.java @@ -0,0 +1,317 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.patches; + +import static eu.engys.core.project.zero.fields.Fields.ALPHA_SGS; +import static eu.engys.core.project.zero.fields.Fields.ALPHA_T; +import static eu.engys.core.project.zero.fields.Fields.AOA; +import static eu.engys.core.project.zero.fields.Fields.CO2; +import static eu.engys.core.project.zero.fields.Fields.DT_AOA; +import static eu.engys.core.project.zero.fields.Fields.DT_CO2; +import static eu.engys.core.project.zero.fields.Fields.DT_SMOKE; +import static eu.engys.core.project.zero.fields.Fields.DT_W; +import static eu.engys.core.project.zero.fields.Fields.EPSILON; +import static eu.engys.core.project.zero.fields.Fields.ETA; +import static eu.engys.core.project.zero.fields.Fields.IDEFAULT; +import static eu.engys.core.project.zero.fields.Fields.K; +import static eu.engys.core.project.zero.fields.Fields.MUT; +import static eu.engys.core.project.zero.fields.Fields.MU_SGS; +import static eu.engys.core.project.zero.fields.Fields.NUT; +import static eu.engys.core.project.zero.fields.Fields.NU_SGS; +import static eu.engys.core.project.zero.fields.Fields.NU_TILDA; +import static eu.engys.core.project.zero.fields.Fields.OMEGA; +import static eu.engys.core.project.zero.fields.Fields.P; +import static eu.engys.core.project.zero.fields.Fields.SMOKE; +import static eu.engys.core.project.zero.fields.Fields.T; +import static eu.engys.core.project.zero.fields.Fields.U; +import static eu.engys.core.project.zero.fields.Fields.W; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; + +public class MergeBoundaryConditions { + + private static final Logger logger = LoggerFactory.getLogger(MergeBoundaryConditions.class); + + private Patches patches; + private Fields fields; + + public MergeBoundaryConditions(Patches patches, Fields fields) { + this.patches = patches; + this.fields = fields; + } + + public void execute() { + for (Patch patch : patches) { + String name = patch.getName(); + logger.info("Merging boundary condition for patch {}", name); + // System.out.println("*** patch "+name+" ***"); + Patches[] parallelPatches = patches.getParallelPatches(); + if (parallelPatches != null) { + boolean emptyForAllProcessors = true; + for (int i = 0; i < parallelPatches.length; i++) { + Map patchesMap = parallelPatches[i].toMap(); + // System.out.println("\tprocessor "+i); + if (patchesMap.containsKey(name)) { + Patch parallelPatch = patchesMap.get(name); + if (parallelPatch.getBoundaryConditions() != null) { + // System.out.println("MergeBoundaryConditions.execute() merge "+name); + merge(parallelPatch.getBoundaryConditions(), patch.getBoundaryConditions()); + } + emptyForAllProcessors = emptyForAllProcessors && parallelPatch.isEmpty(); +// System.out.println("*** AFTER MERGE ***"+parallelPatch.getBoundaryConditions().toDictionary()); +// System.out.println("*** AFTER MERGE ***"+patch.getBoundaryConditions().toDictionary()); + } + } + patch.setEmpty(patch.isEmpty() || emptyForAllProcessors); + } + } + } + + private void merge(BoundaryConditions source, BoundaryConditions target) { + if (!source.getMomentum().isEmpty()) { + mergeField(source.getMomentum(), target.getMomentum(), U); + for (Field U : fields.getMultiphaseUFields()) { + mergeField(source.getMomentum(), target.getMomentum(), U.getName()); + } + mergeField(source.getMomentum(), target.getMomentum(), P); + } + if (!source.getTurbulence().isEmpty()) { + mergeField(source.getTurbulence(), target.getTurbulence(), K); + mergeField(source.getTurbulence(), target.getTurbulence(), OMEGA); + mergeField(source.getTurbulence(), target.getTurbulence(), EPSILON); + mergeField(source.getTurbulence(), target.getTurbulence(), NU_TILDA); + mergeField(source.getTurbulence(), target.getTurbulence(), NUT); + mergeField(source.getTurbulence(), target.getTurbulence(), NU_SGS); + mergeField(source.getTurbulence(), target.getTurbulence(), MUT); + mergeField(source.getTurbulence(), target.getTurbulence(), MU_SGS); + mergeField(source.getTurbulence(), target.getTurbulence(), ALPHA_T); + mergeField(source.getTurbulence(), target.getTurbulence(), ALPHA_SGS); + } + if (!source.getRoughness().isEmpty()) { + mergeField(source.getRoughness(), target.getRoughness(), NUT); + mergeField(source.getRoughness(), target.getRoughness(), NU_SGS); + mergeField(source.getRoughness(), target.getRoughness(), MUT); + mergeField(source.getRoughness(), target.getRoughness(), MU_SGS); + } + if (!source.getThermal().isEmpty()) { + mergeField(source.getThermal(), target.getThermal(), T); + } + if (!source.getHumidity().isEmpty()) { + mergeField(source.getHumidity(), target.getHumidity(), W); + mergeField(source.getHumidity(), target.getHumidity(), DT_W); + } + if (!source.getRadiation().isEmpty()) { + mergeField(source.getRadiation(), target.getRadiation(), IDEFAULT); + } + if (!source.getPassiveScalars().isEmpty()) { + mergeField(source.getPassiveScalars(), target.getPassiveScalars(), AOA); + mergeField(source.getPassiveScalars(), target.getPassiveScalars(), DT_AOA); + mergeField(source.getPassiveScalars(), target.getPassiveScalars(), CO2); + mergeField(source.getPassiveScalars(), target.getPassiveScalars(), DT_CO2); + mergeField(source.getPassiveScalars(), target.getPassiveScalars(), SMOKE); + mergeField(source.getPassiveScalars(), target.getPassiveScalars(), DT_SMOKE); + } + if (!source.getPhase().isEmpty()) { + mergeField(source.getPhase(), target.getPhase(), ETA); + for (Field af : fields.getAlphaFields()) { + mergeField(source.getPhase(), target.getPhase(), af.getName()); + } + } + } + + private void mergeField(Dictionary source, Dictionary target, String field) { + if (source.isDictionary(field) /* && target.isDictionary(field) */) { + Dictionary fieldSource = source.subDict(field); + // Dictionary fieldTarget = target.subDict(field); + + if (BoundaryConditions.isPlaceHolder(fieldSource)) { + // System.out.println("\t\t"+field+" PH"); + /* DO NOTHING */ + } else { + // System.out.println("\t\t"+field+" UN"); + target.add(new Dictionary(fieldSource)); + } + } else if (source.isDictionary(field)) { + // System.err.println("ERROR: missing TARGET "+field+" dictionary"); + } else { + // System.err.println("ERROR: missing SOURCE "+field+" dictionary"); + // System.out.println(""+source+target); + } + } + + public void mergeExcludingNonUniform(BoundaryConditions source, BoundaryConditions target) { + if (!source.getMomentum().isEmpty()) { + mergeExcludingNonUniform(source.getMomentum(), target.getMomentum(), U); + for (Field U : fields.getMultiphaseUFields()) { + mergeExcludingNonUniform(source.getMomentum(), target.getMomentum(), U.getName()); + } + mergeExcludingNonUniform(source.getMomentum(), target.getMomentum(), P); + } + if (!source.getTurbulence().isEmpty()) { + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), K); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), OMEGA); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), EPSILON); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), NU_TILDA); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), NUT); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), NU_SGS); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), MUT); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), MU_SGS); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), ALPHA_T); + mergeExcludingNonUniform(source.getTurbulence(), target.getTurbulence(), ALPHA_SGS); + } + if (!source.getRoughness().isEmpty()) { + mergeExcludingNonUniform(source.getRoughness(), target.getRoughness(), NUT); + mergeExcludingNonUniform(source.getRoughness(), target.getRoughness(), NU_SGS); + mergeExcludingNonUniform(source.getRoughness(), target.getRoughness(), MUT); + mergeExcludingNonUniform(source.getRoughness(), target.getRoughness(), MU_SGS); + } + if (!source.getThermal().isEmpty()) { + mergeExcludingNonUniform(source.getThermal(), target.getThermal(), T); + } + if (!source.getHumidity().isEmpty()) { + mergeExcludingNonUniform(source.getHumidity(), target.getHumidity(), W); + mergeExcludingNonUniform(source.getHumidity(), target.getHumidity(), DT_W); + } + if (!source.getRadiation().isEmpty()) { + mergeExcludingNonUniform(source.getRadiation(), target.getRadiation(), IDEFAULT); + } + if (!source.getPassiveScalars().isEmpty()) { + mergeExcludingNonUniform(source.getPassiveScalars(), target.getPassiveScalars(), AOA); + mergeExcludingNonUniform(source.getPassiveScalars(), target.getPassiveScalars(), DT_AOA); + mergeExcludingNonUniform(source.getPassiveScalars(), target.getPassiveScalars(), CO2); + mergeExcludingNonUniform(source.getPassiveScalars(), target.getPassiveScalars(), DT_CO2); + mergeExcludingNonUniform(source.getPassiveScalars(), target.getPassiveScalars(), SMOKE); + mergeExcludingNonUniform(source.getPassiveScalars(), target.getPassiveScalars(), DT_SMOKE); + } + if (!source.getPhase().isEmpty()) { + mergeExcludingNonUniform(source.getPhase(), target.getPhase(), ETA); + for (Field af : fields.getAlphaFields()) { + mergeExcludingNonUniform(source.getPhase(), target.getPhase(), af.getName()); + } + } + } + + private void mergeExcludingNonUniform(Dictionary source, Dictionary target, String field) { + if (source.isDictionary(field) && target.isDictionary(field)) { + Dictionary fieldSource = source.subDict(field); + Dictionary fieldTarget = target.subDict(field); + if (haveSameType(fieldSource, fieldTarget)) { + if (BoundaryConditions.isNonUniform(fieldTarget)) { + fieldTarget.merge(fieldSource); + } else { + /* DO NOTHING */ + } + } else { + /* DO NOTHING */ + } + } else if (source.isDictionary(field) && !target.isDictionary(field)) { + // System.err.println("ERROR: missing target "+field+" dictionary"); + } else if (!source.isDictionary(field) && target.isDictionary(field)) { + // System.err.println("ERROR: missing source "+field+" dictionary"); + } else { + // System.err.println("ERROR: missing both "+field+" dictionary"); + } + } + + private boolean haveSameType(Dictionary d1, Dictionary d2) { + return d1.isField(Dictionary.TYPE) && d2.isField(Dictionary.TYPE) && d1.lookup(Dictionary.TYPE).equals(d2.lookup(Dictionary.TYPE)); + } + + + public void excludeNonUniform(BoundaryConditions target) { + if (!target.getMomentum().isEmpty()) { + excludeNonUniform(target.getMomentum(), U); + for (Field U : fields.getMultiphaseUFields()) { + excludeNonUniform(target.getMomentum(), U.getName()); + } + excludeNonUniform(target.getMomentum(), P); + } + if (!target.getTurbulence().isEmpty()) { + excludeNonUniform(target.getTurbulence(), K); + excludeNonUniform(target.getTurbulence(), OMEGA); + excludeNonUniform(target.getTurbulence(), EPSILON); + excludeNonUniform(target.getTurbulence(), NU_TILDA); + excludeNonUniform(target.getTurbulence(), NUT); + excludeNonUniform(target.getTurbulence(), NU_SGS); + excludeNonUniform(target.getTurbulence(), MUT); + excludeNonUniform(target.getTurbulence(), MU_SGS); + excludeNonUniform(target.getTurbulence(), ALPHA_T); + excludeNonUniform(target.getTurbulence(), ALPHA_SGS); + } + if (!target.getRoughness().isEmpty()) { + excludeNonUniform(target.getRoughness(), NUT); + excludeNonUniform(target.getRoughness(), NU_SGS); + excludeNonUniform(target.getRoughness(), MUT); + excludeNonUniform(target.getRoughness(), MU_SGS); + } + if (!target.getThermal().isEmpty()) { + excludeNonUniform(target.getThermal(), T); + } + if (!target.getHumidity().isEmpty()) { + excludeNonUniform(target.getHumidity(), W); + excludeNonUniform(target.getHumidity(), DT_W); + } + if (!target.getRadiation().isEmpty()) { + excludeNonUniform(target.getRadiation(), IDEFAULT); + } + if (!target.getPassiveScalars().isEmpty()) { + excludeNonUniform(target.getPassiveScalars(), AOA); + excludeNonUniform(target.getPassiveScalars(), DT_AOA); + excludeNonUniform(target.getPassiveScalars(), CO2); + excludeNonUniform(target.getPassiveScalars(), DT_CO2); + excludeNonUniform(target.getPassiveScalars(), SMOKE); + excludeNonUniform(target.getPassiveScalars(), DT_SMOKE); + } + if (!target.getPhase().isEmpty()) { + excludeNonUniform(target.getPhase(), ETA); + for (Field af : fields.getAlphaFields()) { + excludeNonUniform(target.getPhase(), af.getName()); + } + } + } + + private void excludeNonUniform(Dictionary target, String field) { + if (target.isDictionary(field) && target.isDictionary(field)) { + Dictionary fieldTarget = target.subDict(field); + if (BoundaryConditions.isNonUniform(fieldTarget)) { + if (field.equals(Fields.U)) { + BoundaryConditions.replaceNonUniformVector(fieldTarget); + } else { + BoundaryConditions.replaceNonUniformScalar(fieldTarget); + } + } + } + } + +} diff --git a/src/eu/engys/core/project/zero/patches/Patch.java b/src/eu/engys/core/project/zero/patches/Patch.java new file mode 100644 index 0000000..4061310 --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/Patch.java @@ -0,0 +1,154 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.patches; + +import vtk.vtkPolyData; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.util.ui.checkboxtree.LoadableItem; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class Patch implements VisibleItem, LoadableItem { + + public static final int NONE = -1; + private final String originalName; + private String name; + private BoundaryType phisicalType; + private String type; + private boolean visible; + private boolean loaded; + private Dictionary dictionary; + private BoundaryConditions boundaryConditions; + private boolean empty; + private vtkPolyData dataSet; + + public Patch(String originalName) { + this.originalName = originalName; + } + + public Patch(Patch patch) { + this.originalName = patch.originalName; + this.name = patch.name; + this.phisicalType = patch.phisicalType; + this.type = patch.type; + this.visible = patch.visible; + this.loaded = patch.loaded; + this.boundaryConditions = new BoundaryConditions(patch.boundaryConditions); + this.dictionary = new Dictionary(patch.getDictionary()); + } + + public String getOriginalName() { + return originalName; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public BoundaryType getPhisicalType() { + return phisicalType; + } + public void setPhisicalType(BoundaryType type) { + this.phisicalType = type; + } + + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public void setVisible(boolean selected) { + this.visible = selected; + } + + @Override + public boolean isLoaded() { + return loaded; + } + + @Override + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } + + public void setBoundaryConditions(BoundaryConditions boundaryConditions) { + this.boundaryConditions = boundaryConditions; + } + + public BoundaryConditions getBoundaryConditions() { + return boundaryConditions; + } + + @Override + public String toString() { + return name + " [ type: " + phisicalType.getLabel() + ", visible: " + visible + ", loaded: " + loaded + "]"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Patch) { + return getName().equals(((Patch) obj).getName()); + } else { + return super.equals(obj); + } + } + + public void setEmpty(boolean b) { + this.empty = b; + } + + public boolean isEmpty() { + return empty; + } + + public void setDictionary(Dictionary patch) { + this.dictionary = patch; + } + + public Dictionary getDictionary() { + return dictionary; + } + + public vtkPolyData getDataSet() { + return dataSet; + } + + public void setDataSet(vtkPolyData dataSet) { + this.dataSet = dataSet; + } + +} diff --git a/src/eu/engys/core/project/zero/patches/Patches.java b/src/eu/engys/core/project/zero/patches/Patches.java new file mode 100644 index 0000000..f41a571 --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/Patches.java @@ -0,0 +1,163 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.patches; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import eu.engys.util.PrefUtil; + +public class Patches extends ArrayList { + + private Patches[] parallelPatches; + + public Patches() { + super(); + } + + public Map toMap() { + Map patchesMap = new HashMap(); + for (Patch patch : this) { + patchesMap.put(patch.getName(), patch); + } + return Collections.unmodifiableMap(patchesMap); + } + + public void print() { + for (Patch patch : this) { + System.err.println(" >>>>>>>>>> " + patch.getName()+", hash: "+patch.hashCode()); + System.err.println(patch.getBoundaryConditions().toDictionary()); + } + } + + public Patches filterProcBoundary() { + Patches nonProcPatches = new Patches(); + for (Patch p : this) { + if (!p.getPhisicalType().isProcessor() && !p.getPhisicalType().isProcessorCyclic()) { + nonProcPatches.add(p); + } + } + return nonProcPatches; + } + + public Patches patchesToDisplay() { + Patches patches = new Patches(); + for (Patch patch : this) { + Boolean hideEmptyPatches = PrefUtil.getBoolean(PrefUtil.HIDE_EMPTY_PATCHES); + if ( (patch.isEmpty() && hideEmptyPatches) || patch.getPhisicalType().isProcessor() || patch.getPhisicalType().isProcessorCyclic()) { + continue; + } + patches.add(patch); + } + return patches; + } + + public void printBoundaryConditions(int procIndex, int patchIndex) { + if (procIndex < 0) { + for (int i = 0; i < parallelPatches.length; i++) { + Patch patch = parallelPatches[i].get(patchIndex); + System.out.println("PATCHES PRINT BOUNDARY CONDITIONS processor " + i + ", patch: " + patch.getName() + " " + patch.getBoundaryConditions().toDictionary()); + } + } else { + Patch patch = parallelPatches[procIndex].get(patchIndex); + System.out.println("PATCHES PRINT BOUNDARY CONDITIONS processor " + procIndex + ", patch: " + patch.getName() + " " + patch.getBoundaryConditions().toDictionary()); + } + } + + public void setParallelPatches(Patches[] parallelPatches) { + this.parallelPatches = parallelPatches; + } + + public Patches[] getParallelPatches() { + return parallelPatches; + } + + public Patches getPatchesOfProcessor(int processor) { + return parallelPatches[processor]; + } + + public void clearBoundaryConditions() { + for (Patch patch : this) { + patch.setBoundaryConditions(new BoundaryConditions()); + } + if (parallelPatches != null) { + for (Patches patches : parallelPatches) { + patches.clearBoundaryConditions(); + } + } + } + + public boolean addPatches(Collection c) { + if (parallelPatches != null) { + for (Patches patches : parallelPatches) { + for (Patch patch : c) { + patches.add(new Patch(patch)); + } + } + } + return super.addAll(c); + } + + public void newParallelPatches(int processors) { + parallelPatches = new Patches[processors]; + for (int i = 0; i < parallelPatches.length; i++) { + parallelPatches[i] = new Patches(); + } + } + + public List patchesNames() { + List names = new ArrayList<>(); + for (Patch patch : this) { + names.add(patch.getName()); + } + return names; + } + + public List patchesNames(BoundaryType type) { + List names = new ArrayList<>(); + for (Patch patch : this) { + if (patch.getPhisicalType().equals(type)) { + names.add(patch.getName()); + } + } + return names; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for (Patch patch : this) { + sb.append(patch.getName() + " - "); + } + return sb.toString(); + } + +} diff --git a/src/eu/engys/core/project/zero/patches/PatchesReader.java b/src/eu/engys/core/project/zero/patches/PatchesReader.java new file mode 100644 index 0000000..63ac7a8 --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/PatchesReader.java @@ -0,0 +1,183 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.patches; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.util.IOUtils; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; + +public class PatchesReader { + + private static final Logger logger = LoggerFactory.getLogger(Patches.class); + private ProgressMonitor monitor; + + public PatchesReader(ProgressMonitor monitor) { + this.monitor = monitor; + } + + public Patches read(File... boundaryFiles) { + Patches patches = new Patches(); + + final Patches[] parallelPatches = new Patches[boundaryFiles.length]; + + Runnable[] runnables = new Runnable[boundaryFiles.length]; + for (int i = 0; i < boundaryFiles.length; i++) { + final File boundary = boundaryFiles[i]; + final int index = i; + runnables[i] = new Runnable() { + @Override + public void run() { + Patches readPatches = readBoundary(boundary); + parallelPatches[index] = readPatches; + } + }; + } + ExecUtil.execParallelAndWait(runnables); + + for (Patches readPatches : parallelPatches) { + merge(patches, readPatches); + } + patches.setParallelPatches(parallelPatches); + + return patches; + } + + private void merge(Patches patches, Patches readPatches) { + for (Patch patch : readPatches) { + if (!patches.contains(patch)) { + patches.add(new Patch(patch)); + } + } + } + + Patches readBoundary(File boundary) { + logger.info("READ: Patches {}", boundary.getAbsolutePath()); + Patches patches = new Patches(); + if (boundary.exists()) { + try { + String boundaryString = IOUtils.readStringFromFile(boundary); + boundaryString = boundaryString.replaceAll("/\\*(?:.|[\\n\\r])*?\\*/", ""); + + Pattern pattern = Pattern.compile("(\\d*)\\s*\\(([^#]*)\\)"); + Matcher matcher = pattern.matcher(boundaryString); + if (matcher.find()) { + if (matcher.groupCount() == 2) { + String nPatch = matcher.group(1); + String patchesString = matcher.group(2); + Dictionary dict = DictionaryUtils.readDictionary(patchesString); + List notKnownPatches = new ArrayList(); + for (Dictionary patch : dict.getDictionaries()) { + Patch bm = dictToPatch(notKnownPatches, patch); + patches.add(bm); + } + monitor.setCurrent(null, monitor.getCurrent() + 1, 2); + + if (!nPatch.isEmpty() && Integer.parseInt(nPatch) != patches.size()) { + monitor.error("Number of read patches (" + patches.size() + ") is invalid (expected " + nPatch + ").", 2); + } else if (!notKnownPatches.isEmpty()) { + StringBuilder sb = new StringBuilder(); + sb.append("Unknown patches type: \n"); + for (String string : notKnownPatches) { + sb.append("\t " + string + "\n"); + } + monitor.warning(sb.toString(), 2); + } + } + } + } catch (Exception e) { + monitor.warning("Cannot read the file: " + e.getMessage(), 2); + logger.warn("Cannot read the file", e); + } + } else { + monitor.warning("Boundary file does not exist", 2); + logger.warn("Boundary file does not exist"); + } + return patches; + } + + public static Patch dictToPatch(List notKnownPatches, Dictionary patch) { + String patchName = patch.getName(); + String patchType = patch.lookup("type"); + String physicalType = patch.lookup("physicalType"); + String nFaces = patch.lookup("nFaces"); + + Patch bm = new Patch(patchName); + bm.setDictionary(patch); + bm.setName(patchName); + bm.setVisible(true); + bm.setEmpty(nFaces != null && Integer.valueOf(nFaces) == 0); + bm.setType(patchType); + + if (BoundaryType.isPatch(patchType)) { + if (BoundaryType.isKnown(physicalType)) { + bm.setPhisicalType(BoundaryType.getType(physicalType)); + } else if (BoundaryType.isKnown(BoundaryType.OPENING_KEY)) { + bm.setPhisicalType(BoundaryType.OPENING); + } else { + bm.setPhisicalType(BoundaryType.PATCH); + } + } else if (BoundaryType.isWall(patchType)) { + if (BoundaryType.isKnown(physicalType)) { + bm.setPhisicalType(BoundaryType.getType(physicalType)); + } else { + bm.setPhisicalType(BoundaryType.WALL); + } + } else if (BoundaryType.isMappedPatch(patchType)) { + if (BoundaryType.isKnown(physicalType)) { + bm.setPhisicalType(BoundaryType.getType(physicalType)); + } else { + bm.setPhisicalType(BoundaryType.WALL); + } + } else if (BoundaryType.isMappedWall(patchType)) { + if (BoundaryType.isKnown(physicalType)) { + bm.setPhisicalType(BoundaryType.getType(physicalType)); + } else { + bm.setPhisicalType(BoundaryType.WALL); + } + } else if (BoundaryType.isKnown(patchType)) { + bm.setPhisicalType(BoundaryType.getType(patchType)); + } else if (BoundaryType.isProcessor(patchType)) { + bm.setPhisicalType(BoundaryType.PROCESSOR); + } else if (BoundaryType.isProcessorCyclic(patchType)) { + bm.setPhisicalType(BoundaryType.PROCESSOR_CYCLIC); + } else { + notKnownPatches.add(patchName + ": " + patchType); + bm.setPhisicalType(BoundaryType.getDefaultType()); + } + return bm; + } +} diff --git a/src/eu/engys/core/project/zero/patches/PatchesWriter.java b/src/eu/engys/core/project/zero/patches/PatchesWriter.java new file mode 100644 index 0000000..1437e22 --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/PatchesWriter.java @@ -0,0 +1,189 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.project.zero.patches; + +import static eu.engys.core.dictionary.Dictionary.TYPE; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.DictionaryWriter; +import eu.engys.core.dictionary.FoamFile; +import eu.engys.core.project.Model; +import eu.engys.util.IOUtils; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; + +public class PatchesWriter { + + public static final String OFFSETS_KEY = "offsets"; + public static final String TYPE_KEY = "type"; + public static final String PHYSICAL_TYPE_KEY = "physicalType"; + public static final String START_FACE_KEY = "startFace"; + public static final String N_FACES_KEY = "nFaces"; + + private static final Logger logger = LoggerFactory.getLogger(Patches.class); + + private ProgressMonitor monitor; + + private Model model; + + public PatchesWriter(Model model, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + } + + public void write(final Patches patches, File... boundaryFiles) { + Runnable[] runnables = new Runnable[boundaryFiles.length]; + for (int i = 0; i < boundaryFiles.length; i++) { + final File boundary = boundaryFiles[i]; + runnables[i] = new Runnable() { + @Override + public void run() { + writeBoundary(patches, boundary); + } + }; + } +// ExecUtil.execInParallelAndWait(runnables); + ExecUtil.execSerial(runnables); + } + + private void writeBoundary(Patches patches, File boundaryFile) { + monitor.setCurrent(null, monitor.getCurrent() + 1, 2); + logger.info("WRITE: Boundary {}", boundaryFile.getAbsolutePath()); + + Map originalNames = new HashMap(); + Map phisicalTypes = new HashMap(); + Map types = new HashMap(); + Map dictionaries = new HashMap(); + + for (Patch patch : patches) { + phisicalTypes.put(patch.getName(), patch.getPhisicalType().getKey()); + types.put(patch.getName(), patch.getType()); + originalNames.put(patch.getOriginalName(), patch.getName()); + dictionaries.put(patch.getName(), new Dictionary(patch.getDictionary())); + } + + try { + String boundaryString = IOUtils.readStringFromFile(boundaryFile); + + StringBuffer sb = new StringBuffer(boundaryString.length()); + + boundaryString = boundaryString.replaceAll("/\\*(?:.|[\\n\\r])*?\\*/", ""); + + Pattern pattern = Pattern.compile("(\\d+)\\s*\\(([^#]*)\\)"); + Matcher matcher = pattern.matcher(boundaryString); + + if (matcher.find()) { + if (matcher.groupCount() == 2) { + String nPatch = matcher.group(1); + + FoamFile foamFile = FoamFile.getDictionaryFoamFile("polyBoundaryMesh", "\"0/polyMesh\"", "boundary"); + new DictionaryWriter(foamFile).writeDictionary(sb, ""); + + sb.append(nPatch + "(\n"); + String patchesString = matcher.group(2); + + Dictionary patchesStringAsDictionary = DictionaryUtils.readDictionary(patchesString); + for (Dictionary originalPatchDict : patchesStringAsDictionary.getDictionaries()) { + String originalName = originalPatchDict.getName(); + String newName = originalNames.get(originalName); + + Dictionary patchDict = new Dictionary(newName); + patchDict.add(N_FACES_KEY, originalPatchDict.lookup(N_FACES_KEY)); + patchDict.add(START_FACE_KEY, originalPatchDict.lookup(START_FACE_KEY)); + + if (phisicalTypes.containsKey(newName)) { + String phisicalType = phisicalTypes.get(newName); + String type = types.get(newName); + + if (BoundaryType.isPatchPhysicalType(phisicalType)) { + patchDict.add(TYPE_KEY, "patch"); + patchDict.add(PHYSICAL_TYPE_KEY, phisicalType); + } else if (BoundaryType.isCoupledSymmetryPlaneType(phisicalType) && model.getState().getSolverType().isCoupled()) { + patchDict.add(TYPE_KEY, "patch"); + patchDict.add(PHYSICAL_TYPE_KEY, phisicalType); + } else if (BoundaryType.isWallPhysicalType(phisicalType)) { + patchDict.add(TYPE_KEY, type); + patchDict.add(PHYSICAL_TYPE_KEY, phisicalType); + + if (type.equals("mappedPatch") || type.equals("mappedWall")) { + patchDict.add(OFFSETS_KEY, originalPatchDict.lookup(OFFSETS_KEY)); + Dictionary dictionary = dictionaries.get(newName); + if (dictionary.found(N_FACES_KEY)) + dictionary.remove(N_FACES_KEY); + if (dictionary.found(START_FACE_KEY)) + dictionary.remove(START_FACE_KEY); + if (dictionary.found(OFFSETS_KEY)) + dictionary.remove(OFFSETS_KEY); + + patchDict.merge(dictionary); + } + } else { + patchDict.add(TYPE, phisicalType); + } + + if (phisicalType.equals("cyclic") || phisicalType.equals("cyclicAMI") || phisicalType.equals("processor")) { + Dictionary dictionary = dictionaries.get(newName); + if (dictionary.found(N_FACES_KEY)) + dictionary.remove(N_FACES_KEY); + if (dictionary.found(START_FACE_KEY)) + dictionary.remove(START_FACE_KEY); + + patchDict.merge(dictionary); + } + } else { + patchDict.add(TYPE_KEY, originalPatchDict.lookup(TYPE_KEY)); + } + + new DictionaryWriter(patchDict).writeDictionary(sb, " "); + } + + sb.append(")"); + } + } + + FileWriter outStream = new FileWriter(boundaryFile); + outStream.write(sb.toString()); + outStream.close(); + + } catch (IOException e) { + monitor.warning("Cannot read or write boundary file"); + logger.warn("Cannot read or write boundary file", e); + } + + } +} diff --git a/src/eu/engys/core/project/zero/patches/SplitBoundaryConditions.java b/src/eu/engys/core/project/zero/patches/SplitBoundaryConditions.java new file mode 100644 index 0000000..29d2f1d --- /dev/null +++ b/src/eu/engys/core/project/zero/patches/SplitBoundaryConditions.java @@ -0,0 +1,192 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.core.project.zero.patches; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; + +public class SplitBoundaryConditions { + + public static boolean VERBOSE = false; + + private static final Logger logger = LoggerFactory.getLogger(SplitBoundaryConditions.class); + + private Patches patches; + private Fields fields; + + public SplitBoundaryConditions(Patches patches, Fields fields) { + this.patches = patches; + this.fields = fields; + } + + public void execute() { + for (Patch patch : patches) { + String patchName = patch.getName(); + logger.info("Splitting boundary condition for patch {}", patchName); + // System.out.println("*** patch " + patchName + " *** " + + // patch.getBoundaryConditions().toDictionary()); + Patches[] parallelPatches = patches.getParallelPatches(); + if (parallelPatches != null) { + for (int i = 0; i < parallelPatches.length; i++) { + info("\t processor " + i); + Map patchesMap = parallelPatches[i].toMap(); + if (patchesMap.containsKey(patchName)) { + Patch parallelPatch = patchesMap.get(patchName); + parallelPatch.setPhisicalType(patch.getPhisicalType()); + if (patch.getBoundaryConditions() != null && parallelPatch.getBoundaryConditions() != null) { + // System.out.println("SplitBoundaryConditions.execute() split BEFORE "+patchName+parallelPatch.getBoundaryConditions().toDictionary()); + splitTo(patch.getBoundaryConditions(), parallelPatch.getBoundaryConditions()); + //System.out.println("SplitBoundaryConditions.execute() split AFTER "+patchName+parallelPatch.getBoundaryConditions().toDictionary()); + } else if (patch.getBoundaryConditions() == null) { + // System.out.println("SplitBoundaryConditions.execute() GUI patch "+patch.getName()+" has null BC"); + parallelPatch.setBoundaryConditions(null); + } else if (parallelPatch.getBoundaryConditions() == null) { + // System.out.println("SplitBoundaryConditions.execute() parallel patch "+patch.getName()+" has null BC"); + /* do nothing ? */ + } + } + } + } + } + } + + public void splitTo(BoundaryConditions source, BoundaryConditions target) { + if (target.getMomentum() != null) { + splitField(source.getMomentum(), target.getMomentum(), Fields.U); + for (Field U : fields.getMultiphaseUFields()) { + splitField(source.getMomentum(), target.getMomentum(), U.getName()); + } + splitField(source.getMomentum(), target.getMomentum(), Fields.P); + } + if (target.getTurbulence() != null) { + splitField(source.getTurbulence(), target.getTurbulence(), Fields.K); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.OMEGA); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.EPSILON); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.NU_TILDA); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.NUT); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.NU_SGS); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.MUT); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.MU_SGS); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.ALPHA_T); + splitField(source.getTurbulence(), target.getTurbulence(), Fields.ALPHA_SGS); + } + if (target.getRoughness() != null) { + splitField(source.getRoughness(), target.getRoughness(), Fields.NUT); + splitField(source.getRoughness(), target.getRoughness(), Fields.NU_SGS); + splitField(source.getRoughness(), target.getRoughness(), Fields.MUT); + splitField(source.getRoughness(), target.getRoughness(), Fields.MU_SGS); + } + if (target.getThermal() != null) { + splitField(source.getThermal(), target.getThermal(), Fields.T); + } + if (target.getHumidity() != null) { + splitField(source.getHumidity(), target.getHumidity(), Fields.W); + splitField(source.getHumidity(), target.getHumidity(), Fields.DT_W); + } + if (target.getRadiation() != null) { + splitField(source.getRadiation(), target.getRadiation(), Fields.IDEFAULT); + } + if (target.getPassiveScalars() != null) { + splitField(source.getPassiveScalars(), target.getPassiveScalars(), Fields.AOA); + splitField(source.getPassiveScalars(), target.getPassiveScalars(), Fields.DT_AOA); + splitField(source.getPassiveScalars(), target.getPassiveScalars(), Fields.CO2); + splitField(source.getPassiveScalars(), target.getPassiveScalars(), Fields.DT_CO2); + splitField(source.getPassiveScalars(), target.getPassiveScalars(), Fields.SMOKE); + splitField(source.getPassiveScalars(), target.getPassiveScalars(), Fields.DT_SMOKE); + } + if (target.getPhase() != null) { + splitField(source.getPhase(), target.getPhase(), Fields.ETA); + for (Field af : fields.getAlphaFields()) { + splitField(source.getPhase(), target.getPhase(), af.getName()); + } + } + } + + private void splitField(Dictionary source, Dictionary target, String field) { + if (source.isDictionary(field) && target.isDictionary(field)) { + Dictionary fieldSource = source.subDict(field); + Dictionary fieldTarget = target.subDict(field); + if (haveSameType(fieldSource, fieldTarget)) { + if (BoundaryConditions.isPlaceHolder(fieldTarget)) { + if (BoundaryConditions.isPlaceHolder(fieldSource)) { + /* DO NOTHING */ + info("\t\t "+field+" (PH + PH) DO NOTHING"); + } else { + /* DO NOTHING */ + info("\t\t "+field+" (UN + PH) SAVE EXCLUDING UNIFORM"+target); + fieldTarget.merge(fieldSource, BoundaryConditions.PLACE_HOLDER_KEYS); + } + } else { + if (BoundaryConditions.isPlaceHolder(fieldSource)) { + /* BOH? */ + info("\t\t "+field+" (PH + UN) BOH?"+fieldSource+fieldTarget); + } else { + /* SAVE */ + if (BoundaryConditions.isNonUniform(fieldSource)) { + /* DO NOTHING */ + info("\t\t "+field+" (NUN + UN) DO NOTHING"); + fieldTarget.merge(fieldSource, BoundaryConditions.PLACE_HOLDER_KEYS); + } else { + info("\t\t "+field+" (UN + UN) SAVE"); + // System.out.println("SplitBoundaryConditions.splitField() SOURCE BEFORE "+fieldSource); + // System.out.println("SplitBoundaryConditions.splitField() TARGET BEFORE "+fieldTarget); + fieldTarget.clear(); + fieldTarget.merge(fieldSource); + // System.out.println("SplitBoundaryConditions.splitField() SOURCE AFTER "+fieldSource); + // System.out.println("SplitBoundaryConditions.splitField() TARGET AFTER "+fieldTarget); + } + } + } + } else { + // System.err.println("ERROR: different type for "+field+" dictionary"); + fieldTarget.clear(); + fieldTarget.merge(fieldSource); + } + } else if (source.isDictionary(field) && !target.isDictionary(field)) { + // System.err.println("ERROR: missing target "+field+" dictionary"); + } else if (!source.isDictionary(field) && target.isDictionary(field)) { + // System.err.println("ERROR: missing source "+field+" dictionary"); + } else { + // System.err.println("ERROR: missing both "+field+" dictionary"); + } + } + + private static void info(String msg) { + if (VERBOSE) System.err.println(msg); + } + + private boolean haveSameType(Dictionary d1, Dictionary d2) { + return d1.isField("type") && d2.isField("type") && d1.lookup("type").equals(d2.lookup("type")); + } + +} diff --git a/src/eu/engys/core/report/Exporter.java b/src/eu/engys/core/report/Exporter.java new file mode 100644 index 0000000..b3b5f37 --- /dev/null +++ b/src/eu/engys/core/report/Exporter.java @@ -0,0 +1,143 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report; + +import java.io.File; +import java.util.List; + +import org.apache.poi.ss.usermodel.Workbook; + +import au.com.bytecode.opencsv.CSVWriter; +import eu.engys.core.project.system.monitoringfunctionobjects.Parser; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.core.report.excel.CSVExporter; +import eu.engys.core.report.excel.ExcelExporter; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.progress.SilentMonitor; + +public abstract class Exporter { + + protected static final String POPULATING_SHEET = "Populating sheet "; + protected static final String PARSING_LOG_FILE = "Parsing log file: "; + protected static final String DOTS = "..."; + + protected List parsers; + protected ProgressMonitor monitor; + + public Exporter(List parsers, ProgressMonitor monitor) { + this.parsers = parsers; + this.monitor = monitor; + } + + protected TimeBlocks getTimeBlocks() throws Exception { + monitor.setIndeterminate(false); + monitor.setTotal(parsers.size()); + + TimeBlocks blocks = new TimeBlocks(); + for (int i = 0; i < parsers.size(); i++) { + Parser parser = parsers.get(i); + monitor.info(PARSING_LOG_FILE + parser.getFile(), 1); + parser.init(); + blocks.addAll(parser.updateParsing()); + parser.end(); + monitor.setCurrent(null, monitor.getCurrent() + 1); + } + return blocks; + } + + /* + * Excel + */ + + public void exportToExcel(File reportFile, ProgressMonitor monitor) throws Exception { + ExcelExporter exporter = new ExcelExporter(parsers, monitor) { + @Override + protected void populate(Workbook workbook) throws Exception { + populateExcelFile(workbook); + } + }; + exporter.create(reportFile); + exporter.show(reportFile); + } + + protected abstract void populateExcelFile(Workbook workbook) throws Exception; + + /* + * CSV + */ + + public void exportToCSV(File reportFile, ProgressMonitor monitor) throws Exception { + CSVExporter exporter = new CSVExporter(parsers, monitor) { + + @Override + protected void populate(CSVWriter writer) throws Exception { + populateCSVFile(writer); + } + }; + + exporter.create(reportFile); + exporter.show(reportFile); + } + + protected void populateCSVFile(CSVWriter writer) throws Exception { + + } + + protected void addRow(CSVWriter writer, String string) { + writer.writeNext(new String[] { string }); + } + + protected void addEmptyRow(CSVWriter writer) { + writer.writeNext(new String[] { "" }); + } + + /* + * For test purposes only + */ + public void exportToExcel_TEST(File reportFile) throws Exception { + ExcelExporter exporter = new ExcelExporter(parsers, new SilentMonitor()) { + + @Override + protected void populate(Workbook workbook) throws Exception { + populateExcelFile(workbook); + } + }; + + exporter.create(reportFile); + } + + public void exportToCSV_TEST(File reportFile) throws Exception { + CSVExporter exporter = new CSVExporter(parsers, new SilentMonitor()) { + + @Override + protected void populate(CSVWriter writer) throws Exception { + populateCSVFile(writer); + } + }; + + exporter.create(reportFile); + } +} diff --git a/src/eu/engys/core/report/excel/CSVExporter.java b/src/eu/engys/core/report/excel/CSVExporter.java new file mode 100644 index 0000000..ad771a0 --- /dev/null +++ b/src/eu/engys/core/report/excel/CSVExporter.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report.excel; + +import java.io.File; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; + +import au.com.bytecode.opencsv.CSVWriter; +import eu.engys.core.executor.FileManagerSupport; +import eu.engys.core.project.system.monitoringfunctionobjects.Parser; +import eu.engys.util.progress.ProgressMonitor; + +public abstract class CSVExporter { + + protected List parsers; + protected ProgressMonitor monitor; + + public CSVExporter(List parsers, ProgressMonitor monitor) { + this.parsers = parsers; + this.monitor = monitor; + } + + public CSVExporter(Parser parser) { + List parsers = new ArrayList<>(); + parsers.add(parser); + this.parsers = parsers; + } + + public void create(File reportFile) throws Exception { + CSVWriter writer = new CSVWriter(new FileWriter(reportFile), ','); + populate(writer); + end(writer); + } + + protected abstract void populate(CSVWriter writer) throws Exception; + + private void end(CSVWriter writer) throws Exception { + writer.close(); + } + + public void show(File reportFile) { + FileManagerSupport.open(reportFile); + } + +} diff --git a/src/eu/engys/core/report/excel/ExcelExporter.java b/src/eu/engys/core/report/excel/ExcelExporter.java new file mode 100644 index 0000000..f924b85 --- /dev/null +++ b/src/eu/engys/core/report/excel/ExcelExporter.java @@ -0,0 +1,83 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report.excel; + +import static eu.engys.util.ui.FileChooserUtils.EXCEL_EXTENSION_NEW; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.FilenameUtils; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import eu.engys.core.executor.FileManagerSupport; +import eu.engys.core.project.system.monitoringfunctionobjects.Parser; +import eu.engys.util.progress.ProgressMonitor; + +public abstract class ExcelExporter { + + protected List parsers; + protected ProgressMonitor monitor; + + public ExcelExporter(List parsers, ProgressMonitor monitor) { + this.parsers = parsers; + this.monitor = monitor; + } + + public ExcelExporter(Parser parser) { + List parsers = new ArrayList<>(); + parsers.add(parser); + this.parsers = parsers; + } + + public void create(File reportFile) throws Exception { + Workbook workbook = null; + if (FilenameUtils.getExtension(reportFile.getAbsolutePath()).equals(EXCEL_EXTENSION_NEW)) { + workbook = new XSSFWorkbook(); + } else { + workbook = new HSSFWorkbook(); + } + populate(workbook); + end(workbook, reportFile); + } + + protected abstract void populate(Workbook workbook) throws Exception; + + private void end(Workbook workbook, File reportFile) throws Exception { + FileOutputStream fileOut = new FileOutputStream(reportFile); + workbook.write(fileOut); + fileOut.close(); + } + + public void show(File reportFile) { + FileManagerSupport.open(reportFile); + } + +} diff --git a/src/eu/engys/core/report/excel/ExcelUtils.java b/src/eu/engys/core/report/excel/ExcelUtils.java new file mode 100644 index 0000000..b2483af --- /dev/null +++ b/src/eu/engys/core/report/excel/ExcelUtils.java @@ -0,0 +1,84 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report.excel; + +import javax.vecmath.Point3d; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; + +public class ExcelUtils { + + public static void addHeaderCell(Workbook workbook, Row row, int col, String value) { + Cell cell = row.createCell(col); + cell.setCellValue(value); + + Font font = workbook.createFont(); + font.setBoldweight(Font.BOLDWEIGHT_BOLD); + + CellStyle cellStyle = workbook.createCellStyle(); + cellStyle.setFont(font); + cellStyle.setAlignment(CellStyle.ALIGN_CENTER); + cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + cell.setCellStyle(cellStyle); + } + + public static void addEmptyCell(Workbook workbook, Row row, int col) { + row.createCell(col).setCellValue(""); + } + + public static void addDoubleCell(Sheet sheet, int row, int col, double value) { + sheet.getRow(row + 1).createCell(col + 1).setCellValue(value); + } + + public static void addPointCells(Sheet sheet, int row, int col, Point3d point) { + sheet.getRow(row + 1).createCell(col + 1).setCellValue(point.getX()); + sheet.getRow(row + 1).createCell(col + 2).setCellValue(point.getY()); + sheet.getRow(row + 1).createCell(col + 3).setCellValue(point.getZ()); + } + + public static void mergeColumnsOnRow(Sheet sheet, int firstRow, int firstColumn, int lastColumn) { + sheet.addMergedRegion(new CellRangeAddress(firstRow, firstRow, firstColumn, lastColumn)); + } + + public static void autoSizeColumns(Sheet sheet) { + // header row + for (int i = 0; i < sheet.getRow(0).getLastCellNum(); i++) { + sheet.autoSizeColumn(i, true); + } + + // table row + for (int i = 0; i < sheet.getRow(1).getLastCellNum(); i++) { + sheet.autoSizeColumn(i, true); + } + } + +} diff --git a/src/eu/engys/core/report/pdf/PDFImage.java b/src/eu/engys/core/report/pdf/PDFImage.java new file mode 100644 index 0000000..76718ae --- /dev/null +++ b/src/eu/engys/core/report/pdf/PDFImage.java @@ -0,0 +1,46 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report.pdf; + +public class PDFImage { + + private String title; + private String name; + + public PDFImage(String name, String title) { + this.name = name; + this.title = title; + } + + public String getTitle() { + return title; + } + + public String getName() { + return name; + } + +} diff --git a/src/eu/engys/core/report/pdf/PDFPage.java b/src/eu/engys/core/report/pdf/PDFPage.java new file mode 100644 index 0000000..379888f --- /dev/null +++ b/src/eu/engys/core/report/pdf/PDFPage.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report.pdf; + +import com.lowagie.text.Element; + +public interface PDFPage { + + public abstract String getTitle(); + + public abstract Element getElement(); + +} diff --git a/src/eu/engys/core/report/pdf/PDFPageEvent.java b/src/eu/engys/core/report/pdf/PDFPageEvent.java new file mode 100644 index 0000000..6ecb85e --- /dev/null +++ b/src/eu/engys/core/report/pdf/PDFPageEvent.java @@ -0,0 +1,79 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report.pdf; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import com.lowagie.text.BadElementException; +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Image; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfPageEventHelper; +import com.lowagie.text.pdf.PdfWriter; + +public class PDFPageEvent extends PdfPageEventHelper { + + private static final int FRONT_PAGE_INDEX = 1; + private URL frontPagewatermarkImage; + private URL watermarkImage; + + public PDFPageEvent(URL frontPagewatermarkImage, URL watermarkImage) { + this.frontPagewatermarkImage = frontPagewatermarkImage; + this.watermarkImage = watermarkImage; + } + + @Override + public void onEndPage(PdfWriter writer, Document document) { + try { + _addWatermark(writer, document); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void _addWatermark(PdfWriter writer, Document document) throws BadElementException, MalformedURLException, IOException, DocumentException { + PdfContentByte canvas = writer.getDirectContentUnder(); + Image image = null; + if (document.getPageNumber() == FRONT_PAGE_INDEX) { + image = Image.getInstance(frontPagewatermarkImage); + } else { + image = Image.getInstance(watermarkImage); + } + image.setAlignment(Image.MIDDLE); + float x = (document.getPageSize().getWidth() - image.getWidth()) / 2; + float y = (document.getPageSize().getHeight() - image.getHeight()) / 2; + if (document.getPageNumber() == FRONT_PAGE_INDEX) { + image.setAbsolutePosition(x, y - 30); + } else { + image.setAbsolutePosition(x, y); + } + canvas.addImage(image); + + } +} diff --git a/src/eu/engys/core/report/pdf/PDFReport.java b/src/eu/engys/core/report/pdf/PDFReport.java new file mode 100644 index 0000000..c1112d8 --- /dev/null +++ b/src/eu/engys/core/report/pdf/PDFReport.java @@ -0,0 +1,107 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report.pdf; + +import java.io.File; +import java.io.FileOutputStream; +import java.net.URL; +import java.util.LinkedList; +import java.util.List; + +import com.lowagie.text.Document; +import com.lowagie.text.Element; +import com.lowagie.text.HeaderFooter; +import com.lowagie.text.Phrase; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PdfWriter; + +import eu.engys.core.project.Model; + +public abstract class PDFReport { + + protected Model model; + + private Document document; + private PdfWriter writer; + private File reportFile; + + private List pages = new LinkedList<>(); + + public PDFReport(Model model, File reportFile) { + this.model = model; + this.reportFile = reportFile; + } + + public void create() throws Exception { + document = new Document(); + writer = PdfWriter.getInstance(document, new FileOutputStream(reportFile)); + writer.setPageEvent(new PDFPageEvent(getFrontPageWaterMarkImage(), getWaterMarkImage())); + document.open(); + addFooter(); + populate(); + end(); + } + + private void addFooter() { + HeaderFooter headerFooter = new HeaderFooter(new Phrase(getFooter()), false); + headerFooter.setAlignment(Element.ALIGN_CENTER); + headerFooter.setBorder(Rectangle.TOP); + document.setFooter(headerFooter); + } + + protected abstract void populate() throws Exception; + + public abstract URL getWaterMarkImage(); + + public abstract URL getFrontPageWaterMarkImage(); + + public abstract String getFooter(); + + protected void addPage(PDFPage page) { + pages.add(page); + } + + private void end() throws Exception { + for (PDFPage page : pages) { + document.add(page.getElement()); + } + document.close(); + writer.close(); + } + + public Model getModel() { + return model; + } + + public PdfWriter getWriter() { + return writer; + } + + public Document getDocument() { + return document; + } + +} diff --git a/src/eu/engys/core/report/pdf/PDFUtils.java b/src/eu/engys/core/report/pdf/PDFUtils.java new file mode 100644 index 0000000..8de6769 --- /dev/null +++ b/src/eu/engys/core/report/pdf/PDFUtils.java @@ -0,0 +1,213 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.core.report.pdf; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.lowagie.text.BadElementException; +import com.lowagie.text.Document; +import com.lowagie.text.Element; +import com.lowagie.text.Font; +import com.lowagie.text.Image; +import com.lowagie.text.Paragraph; +import com.lowagie.text.Phrase; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PdfPCell; +import com.lowagie.text.pdf.PdfPTable; + +import eu.engys.core.project.Model; + +public class PDFUtils { + + private static final Logger logger = LoggerFactory.getLogger(PDFUtils.class); + + private static final int DEFAULT_FONT = Font.HELVETICA; + public static final String POSTPRO = "POSTPRO"; + + public static final int MEDIUM_FONT = 18; + public static final int BIG_FONT = 25; + + public static final int SMALL_LINE_SPACING = 10; + public static final int MEDIUM_LINE_SPACING = 20; + public static final int LARGE_LINE_SPACING = 50; + public static final int HUGE_LINE_SPACING = 100; + + public static final String NO_VALUE = "-"; + + public static Paragraph createParagraph() { + return createParagraph(MEDIUM_LINE_SPACING); + } + + public static Paragraph createParagraph(int lineSpacing) { + return createParagraph(lineSpacing, Element.ALIGN_CENTER); + } + + public static Paragraph createParagraph(int lineSpacing, int align) { + Paragraph paragraph = new Paragraph(); + paragraph.setLeading(lineSpacing); + paragraph.setAlignment(align); + paragraph.setSpacingBefore(10); + return paragraph; + } + + public static Phrase createLine(String text) { + return createLine(text, MEDIUM_FONT, false, Color.BLACK); + } + + public static Phrase createLine(String text, int fontSize) { + return createLine(text, fontSize, false, Color.BLACK); + } + + public static Phrase createLine(String text, int fontSize, boolean bold) { + return createLine(text, fontSize, bold, Color.BLACK); + } + + public static Phrase createLine(String text, int fontSize, boolean bold, Color color) { + Font font = new Font(DEFAULT_FONT, fontSize, bold ? Font.BOLD : Font.NORMAL, color); + Phrase phrase = new Phrase(text + "\n", font); + return phrase; + } + + public static PdfPTable createTableKeyValue(String[][] data) { + PdfPTable table = new PdfPTable(data[0].length); + for (String[] row : data) { + String key = row[0]; + String value = row[1]; + + Paragraph keyParagraph = new Paragraph(key); + keyParagraph.getFont().setStyle(Font.BOLD); + + PdfPCell keyCell = new PdfPCell(keyParagraph); + keyCell.setPadding(5); + keyCell.setHorizontalAlignment(PdfPCell.LEFT); + keyCell.setBorderWidth(1); + keyCell.setBorderColor(Color.GRAY); + table.addCell(keyCell); + + PdfPCell valueCell = new PdfPCell(new Paragraph(value)); + valueCell.setPadding(5); + valueCell.setHorizontalAlignment(PdfPCell.LEFT); + valueCell.setBorderWidth(1); + valueCell.setBorderColor(Color.GRAY); + table.addCell(valueCell); + + } + return table; + } + + public static PdfPTable createTable(String[][] data) { + PdfPTable table = new PdfPTable(data[0].length); + for (String[] row : data) { + for (String value : row) { + PdfPCell cell = new PdfPCell(new Paragraph(value)); + cell.setPadding(5); + cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); + cell.setBorderWidth(1); + cell.setBorderColor(Color.GRAY); + if (table.getRows().size() % 2 == 0) { + cell.setBackgroundColor(new Color(245, 245, 245)); + } else { + cell.setBackgroundColor(new Color(230, 250, 250)); + } + table.addCell(cell); + } + } + return table; + } + + public static Image createImage(Document document, URL url) throws BadElementException, MalformedURLException, IOException { + Image image = Image.getInstance(url); + image.setAlignment(Image.MIDDLE); + float ratio = image.getWidth() / (document.getPageSize().getWidth() - 100); + image.scaleAbsolute((image.getWidth() / ratio), (image.getHeight() / ratio)); + return image; + } + + public static PdfPTable createImagePage(Model model, PDFImage[] images) { + File postProFolder = new File(model.getProject().getBaseDir(), POSTPRO); + if (postProFolder.exists()) { + PdfPTable table = new PdfPTable(1); + table.getDefaultCell().setBorder(Rectangle.BOX); + + for (PDFImage image : images) { + File file = new File(postProFolder, image.getName()); + addImageToTable(table, file); + addTitleToTable(table, image.getTitle()); + addEmptyCellToTable(table); + } + table.setWidthPercentage(70); + table.setKeepTogether(true); + + return table; + } else { + return new PdfPTable(1); + } + } + + private static void addEmptyCellToTable(PdfPTable table) { + PdfPCell emptyCell = new PdfPCell(new Phrase("")); + emptyCell.setBorder(Rectangle.NO_BORDER); + table.addCell(emptyCell); + } + + private static void addTitleToTable(PdfPTable table, String title) { + if (title.isEmpty()) { + return; + } + PdfPCell textCell = new PdfPCell(new Phrase(title)); + textCell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); + table.addCell(textCell); + } + + private static void addImageToTable(PdfPTable table, File imageFile) { + try { + if (imageFile.exists()) { + Image image = Image.getInstance(imageFile.toURI().toURL()); + image.setAlignment(Image.MIDDLE); + table.addCell(image); + } else { + PdfPCell missingImageText = new PdfPCell(new Phrase("Missing Image")); + missingImageText.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); + table.addCell(missingImageText); + } + } catch (BadElementException | IOException e) { + logger.error(e.getMessage()); + } + } + + public static Paragraph createImagesBlock(Model model, PDFImage... images) { + Paragraph p = createParagraph(); + p.add(createImagePage(model, images)); + return p; + } +} diff --git a/src/eu/engys/gui/AboutWindow.java b/src/eu/engys/gui/AboutWindow.java new file mode 100644 index 0000000..79ce270 --- /dev/null +++ b/src/eu/engys/gui/AboutWindow.java @@ -0,0 +1,166 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JWindow; + +import eu.engys.util.ApplicationInfo; +import eu.engys.util.Util; +import eu.engys.util.ui.UiUtil; + +public class AboutWindow { + + private JWindow window; + private final Icon vendorIcon; + private final Icon applicationIcon; + + public AboutWindow(Icon vendorIcon, Icon applicationIcon) { + this.vendorIcon = vendorIcon; + this.applicationIcon = applicationIcon; + createWindow(); + } + + private void createWindow() { + window = new JWindow(UiUtil.getActiveWindow()); + window.getContentPane().setLayout(new BorderLayout()); + JPanel mainPanel = createMainPanel(); + window.getContentPane().add(mainPanel, BorderLayout.CENTER); + window.setSize(mainPanel.getPreferredSize().width, mainPanel.getPreferredSize().height); + window.setLocationRelativeTo(null); + window.setVisible(true); + } + + private JPanel createMainPanel() { + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.setBackground(Color.WHITE); + mainPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + mainPanel.add(createNorthPanel(), BorderLayout.NORTH); + mainPanel.add(createCenterPanel(), BorderLayout.CENTER); + mainPanel.add(createCloseButtonPanel(), BorderLayout.SOUTH); + return mainPanel; + } + + private JPanel createNorthPanel() { + JPanel panel = new JPanel(new BorderLayout()); + panel.setBackground(Color.WHITE); + panel.add(getImage(vendorIcon), BorderLayout.WEST); + panel.add(getImage(applicationIcon), BorderLayout.CENTER); + panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + return panel; + } + + private JLabel getImage(Icon imageIcon) { + JLabel label = new JLabel(imageIcon); + label.setOpaque(true); + label.setBackground(Color.WHITE); + return label; + } + + private JPanel createCloseButtonPanel() { + JPanel panel = new JPanel(new FlowLayout()); + panel.setBackground(Color.WHITE); + panel.add(new JButton(new AbstractAction("Close") { + @Override + public void actionPerformed(ActionEvent e) { + window.dispose(); + } + })); + return panel; + } + + private JPanel createCenterPanel() { + JLabel vers = center("" + ApplicationInfo.getVersion() + "", 20f, Color.BLACK); + JLabel copy = center("" + ApplicationInfo.getCopyright() + "", 10f, Color.BLACK); + + JPanel infoPanel = new JPanel(new GridBagLayout()); + infoPanel.setBackground(Color.WHITE); + infoPanel.add(vers, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(30, 10, 0, 10), 0, 0)); + infoPanel.add(copy, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 10, 30, 10), 0, 0)); + + final JButton sitebutton = createOpenSiteButton(); + JPanel siteButtonPanel = new JPanel(new GridBagLayout()); + siteButtonPanel.setBackground(Color.WHITE); + siteButtonPanel.add(sitebutton, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 10, 20, 10), 0, 0)); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(infoPanel, BorderLayout.NORTH); + // mainPanel.add(new JPanel(), BorderLayout.CENTER); + mainPanel.add(siteButtonPanel, BorderLayout.CENTER); + return mainPanel; + } + + private JButton createOpenSiteButton() { + final JButton button = new JButton(new AbstractAction(ApplicationInfo.getSite()) { + + @Override + public void actionPerformed(ActionEvent e) { + try { + Util.openWebpage(new URL(ApplicationInfo.getSite())); + } catch (MalformedURLException e1) { + e1.printStackTrace(); + } + } + }); + button.setForeground(Color.BLUE); + return button; + } + + private JLabel center(String text, float size, Color color) { + JLabel label = new JLabel(text) { + @Override + public void paintComponent(Graphics g) { + Graphics2D graphics2d = (Graphics2D) g; + graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + super.paintComponent(g); + } + }; + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + label.setHorizontalAlignment(JLabel.CENTER); + label.setFont(label.getFont().deriveFont(size)); + label.setForeground(color); + return label; + } +} diff --git a/src/eu/engys/gui/AbstractGUIPanel.java b/src/eu/engys/gui/AbstractGUIPanel.java new file mode 100644 index 0000000..6c7f402 --- /dev/null +++ b/src/eu/engys/gui/AbstractGUIPanel.java @@ -0,0 +1,235 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui; + +import java.awt.BorderLayout; +import java.awt.Font; + +import javax.inject.Inject; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSeparator; +import javax.swing.JToolBar; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.Model; +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; + +public abstract class AbstractGUIPanel extends JPanel implements GUIPanel, ModelObserver { + + private static final Logger logger = LoggerFactory.getLogger(GUIPanel.class); + + @Inject + protected ProgressMonitor monitor; + + private final String title; + protected final Model model; + + private JLabel titleLabel; + protected JToolBar titleToolbar; + + protected CanvasPanel view3D; + + public AbstractGUIPanel(String title, Model model) { + super(new BorderLayout()); + this.title = title; + this.model = model; + + setName(title); + logger.info("-> {}", title); + } + + @Override + public void install(CanvasPanel view3D) { + this.view3D = view3D; + } + + @Override + public void layoutPanel() { + JComponent titleComponent = createTitle(title); + JComponent mainComponent = layoutComponents(); + + titleComponent.setBorder(BorderFactory.createEmptyBorder(0, 0, 4, 8)); + mainComponent.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 8)); + + add(titleComponent, BorderLayout.NORTH); + add(mainComponent, BorderLayout.CENTER); + } + + protected JComponent layoutComponents() { + return new JLabel("Component"); + } + + private JComponent createTitle(String text) { + titleLabel = new JLabel(text); + Font font = titleLabel.getFont(); + titleLabel.setFont(font.deriveFont(font.getSize2D() + 2).deriveFont(Font.BOLD)); + + titleToolbar = UiUtil.getToolbar("view.gui.toolbar"); + titleToolbar.add(titleLabel); + titleToolbar.add(Box.createHorizontalGlue()); + + PanelBuilder pb = new PanelBuilder(); + pb.addComponent(titleToolbar); + pb.addComponent(new JSeparator()); + + return pb.removeMargins().getPanel(); + } + + protected void setTitle(String title) { + if (titleLabel != null) { + titleLabel.setText(title); + } + } + + @Override + public String getName() { + return title; + } + + @Override + public String getKey() { + return title; + } + + @Override + public String getTitle() { + return title; + } + + @Override + public String getVersion() { + return getClass().getPackage().getImplementationVersion(); + } + + @Override + public JComponent getPanel() { + JScrollPane scrollPane = new JScrollPane(this); + scrollPane.getVerticalScrollBar().setUnitIncrement(20); + scrollPane.setBorder(BorderFactory.createEmptyBorder()); + return scrollPane; + } + + @Override + public void load() { + } + + @Override + public void resetToDefaults() { + } + + @Override + public void save() { + requestFocusInWindow(); + } + + @Override + public void clear() { + } + + @Override + public boolean canStart() { + return true; + } + + @Override + public void start() { + } + + @Override + public boolean canStop() { + return true; + } + + @Override + public void stop() { + save(); + } + + public Model getModel() { + return model; + } + + @Override + public void fieldManipulationFunctionObjectsChanged() { + } + + @Override + public void monitoringFunctionObjectsChanged() { + } + + @Override + public void stateChanged() { + } + + @Override + public void runtimeFieldsChanged() { + } + + @Override + public void fieldsChanged() { + } + + @Override + public void solverChanged() { + } + + @Override + public void materialsChanged() { + } + + @Override + public void projectChanged() { + } + + @Override + public int getIndex() { + return -1; + } + + public ProgressMonitor getMonitor() { + return monitor; + } + + public void setMonitor(ProgressMonitor monitor) { + this.monitor = monitor; + } + + @Override + public String toString() { + return title; + } + +} diff --git a/src/eu/engys/gui/Actions.java b/src/eu/engys/gui/Actions.java new file mode 100644 index 0000000..d9c0259 --- /dev/null +++ b/src/eu/engys/gui/Actions.java @@ -0,0 +1,37 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui; + +import javax.swing.JToolBar; + +public interface Actions { + + public JToolBar toolbar(); + + public void update(); + +} diff --git a/src/eu/engys/gui/CreateCaseDialog.java b/src/eu/engys/gui/CreateCaseDialog.java new file mode 100644 index 0000000..e3b0926 --- /dev/null +++ b/src/eu/engys/gui/CreateCaseDialog.java @@ -0,0 +1,366 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui; + +import static eu.engys.util.ui.ComponentsFactory.checkField; +import static eu.engys.util.ui.ComponentsFactory.intArrayField; +import static eu.engys.util.ui.ComponentsFactory.intField; +import static eu.engys.util.ui.ComponentsFactory.labelArrayField; +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.Arrays; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import eu.engys.core.project.CaseParameters; +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.FileFieldPanel; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.IntegerField; +import eu.engys.util.ui.textfields.StringField; +import eu.engys.util.ui.textfields.verifiers.AbstractVerifier; +import eu.engys.util.ui.textfields.verifiers.AbstractVerifier.ValidationStatusListener; + +public class CreateCaseDialog extends JPanel { + + public static final String CREATE_CASE_LABEL = "Create Case"; + public static final String HIERARCHY_LABEL = "Hierarchy"; + public static final String PROCESSORS_LABEL = "Processors"; + public static final String PARALLEL_LABEL = "Parallel"; + public static final String PARENT_FOLDER_LABEL = "Parent Folder"; + public static final String CASE_NAME_LABEL = "Case Name"; + + enum Status { + OK, ERROR, CANCEL + } + + private static final int X = 0; + private static final int Y = 1; + private static final int Z = 2; + + private OkDialogAction okAction = new OkDialogAction(); + private CancelDialogAction cancelAction = new CancelDialogAction(); + + private JDialog dialog; + private FileFieldPanel fileField; + private StringField nameField; + private IntegerField nProcessorsField; + private JCheckBox isParallel; + + private File baseDir; + private IntegerField[] nHierarchyField; + private Status status = Status.ERROR; + + public CreateCaseDialog() { + super(new BorderLayout()); + layoutComponents(); + createDialog(); + setDefaultValues(); + } + + private void layoutComponents() { + fileField = ComponentsFactory.fileField(SelectionMode.DIRS_ONLY, "Select a folder where to save the case", false); + nameField = stringField(); + isParallel = checkField(); + nProcessorsField = intField(); + nHierarchyField = intArrayField(3); + + ((AbstractVerifier) nameField.getInputVerifier()).setValidationStatusListener(new ValidationStatusListener() { + + @Override + public void validatePassed() { + okAction.setEnabled(true); + } + + @Override + public void validateFailed() { + okAction.setEnabled(false); + } + }); + + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(CASE_NAME_LABEL, nameField); + builder.addComponent(PARENT_FOLDER_LABEL, fileField); + builder.addComponent(PARALLEL_LABEL, isParallel); + builder.addComponent(PROCESSORS_LABEL, nProcessorsField); + builder.addComponent(labelArrayField("x", "y", "z")); + builder.addComponent(HIERARCHY_LABEL, nHierarchyField[X], nHierarchyField[Y], nHierarchyField[Z]); + nProcessorsField.setEnabled(false); + for (IntegerField f : nHierarchyField) + f.setEnabled(false); + + isParallel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + nProcessorsField.setEnabled(isParallel.isSelected()); + nProcessorsField.setIntValue(isParallel.isSelected() ? 2 : 1); + for (IntegerField f : nHierarchyField) + f.setEnabled(isParallel.isSelected()); + } + }); + nProcessorsField.addPropertyChangeListener(new IntFieldHandler(nProcessorsField, nHierarchyField)); + nProcessorsField.setIntValue(1); + + add(builder.getPanel()); + } + + private void createDialog() { + JButton okButton = new JButton(okAction); + okButton.setName("button.ok"); + + JButton cancelButton = new JButton(cancelAction); + cancelButton.setName("button.cancel"); + + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + + dialog = new JDialog(UiUtil.getActiveWindow(), CREATE_CASE_LABEL); + dialog.setName("create.case.dialog"); + dialog.setModal(true); + dialog.setSize(350, 250); + dialog.setLocationRelativeTo(null); + dialog.getContentPane().setLayout(new BorderLayout()); + dialog.getContentPane().add(this, BorderLayout.CENTER); + dialog.getContentPane().add(buttonsPanel, BorderLayout.SOUTH); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.getRootPane().setDefaultButton(okButton); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + if (cancelAction.isEnabled()) { + cancelAction(); + } + } + }); + } + + private void setDefaultValues() { + File lastDir = PrefUtil.getWorkDir(PrefUtil.WORK_DIR); + fileField.setFile(lastDir); + + nameField.setText("newCase"); + + isParallel.setSelected(false); + isParallel.doClick(); + } + + public void showDialog() { + dialog.setVisible(true); + } + + private void closeDialog() { + dialog.setVisible(false); + dialog.dispose(); + } + + public CaseParameters getParameters() { + CaseParameters params = new CaseParameters(); + params.setBaseDir(baseDir); + params.setParallel(isParallel.isSelected()); + params.setnProcessors(nProcessorsField.getIntValue()); + params.setnHierarchy(new int[] { nHierarchyField[0].getIntValue(), nHierarchyField[1].getIntValue(), nHierarchyField[2].getIntValue() }); + return params; + } + + private void checkStatus() { + String warning = "Create Case Warning"; + String error = "Create Case Error"; + String parentPath = fileField.getFilePath(); + if (parentPath.isEmpty()) { + JOptionPane.showMessageDialog(dialog, "Empty parent folder", error, JOptionPane.ERROR_MESSAGE); + status = Status.CANCEL; + } else { + File parent = new File(parentPath); + if (parent.exists()) { + if (Util.canWrite(parent)) { + baseDir = new File(parent, nameField.getText()); + if (baseDir.exists()) { + if (baseDir.isFile()) { + JOptionPane.showMessageDialog(dialog, "File already exists", error, JOptionPane.ERROR_MESSAGE); + status = Status.CANCEL; + } else if (baseDir.isDirectory() && baseDir.list().length != 0) { + int retVal = JOptionPane.showConfirmDialog(dialog, "Folder already exists. Continue anyway?", warning, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (retVal == JOptionPane.NO_OPTION) { + status = Status.CANCEL; + } else { + status = Status.OK; + } + } else { + status = Status.OK; + } + } else { + status = Status.OK; + } + } else { + JOptionPane.showMessageDialog(dialog, "Write permission", error, JOptionPane.ERROR_MESSAGE); + status = Status.CANCEL; + } + } else { + String msg = String.format("Folder %s does not exist.\n Do you want to create it?", parent); + int retVal = JOptionPane.showConfirmDialog(dialog, msg, warning, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (retVal == JOptionPane.NO_OPTION) { + status = Status.CANCEL; + } else { + if (parent.canWrite()) { + status = Status.OK; + } else { + JOptionPane.showMessageDialog(dialog, "Write permission", error, JOptionPane.ERROR_MESSAGE); + status = Status.CANCEL; + } + } + } + } + } + + private void okAction() { + checkStatus(); + if (isOK()) { + if (isParallel.isSelected() && !productEqualsToNumberOfSubdomain()) { + JOptionPane.showMessageDialog(dialog, "Product of Hierarchical Coefficients should be equal to the Number of Processors", "Decomposition error", JOptionPane.ERROR_MESSAGE); + return; + } + } + closeDialog(); + } + + private boolean productEqualsToNumberOfSubdomain() { + int nOfSubdomains = nProcessorsField.getIntValue(); + int x = nHierarchyField[X].getIntValue(); + int y = nHierarchyField[Y].getIntValue(); + int z = nHierarchyField[Z].getIntValue(); + + return nOfSubdomains == x * y * z; + } + + private void cancelAction() { + status = Status.CANCEL; + closeDialog(); + } + + public boolean isOK() { + return status == Status.OK; + } + + public boolean isError() { + return status == Status.ERROR; + } + + public boolean isCancel() { + return status == Status.CANCEL; + } + + private final class OkDialogAction extends AbstractAction implements Runnable { + + public OkDialogAction() { + super("OK"); + } + + @Override + public void actionPerformed(ActionEvent e) { + SwingUtilities.invokeLater(OkDialogAction.this); + } + + @Override + public void run() { + okAction(); + } + } + + private final class CancelDialogAction extends AbstractAction implements Runnable { + + public CancelDialogAction() { + super("Cancel"); + } + + @Override + public void actionPerformed(ActionEvent e) { + SwingUtilities.invokeLater(CancelDialogAction.this); + } + + @Override + public void run() { + cancelAction(); + } + } + + class IntFieldHandler implements PropertyChangeListener { + private IntegerField[] nHierarchyField; + private IntegerField nProcessorsField; + + public IntFieldHandler(IntegerField nProcessorsField, IntegerField[] nHierarchyField) { + this.nProcessorsField = nProcessorsField; + this.nHierarchyField = nHierarchyField; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + int np = nProcessorsField.getIntValue(); + + int[] factors = Util.getFactorsFor(np); + nHierarchyField[X].setIntValue(factors[0]); + nHierarchyField[Y].setIntValue(factors[1]); + nHierarchyField[Z].setIntValue(factors[2]); + } + } + } + + public static void main(String[] args) { + System.out.println("12 -> " + Arrays.toString(Util.getFactorsFor(12))); + System.out.println("128 -> " + Arrays.toString(Util.getFactorsFor(128))); + System.out.println("120 -> " + Arrays.toString(Util.getFactorsFor(120))); + System.out.println("512 -> " + Arrays.toString(Util.getFactorsFor(512))); + System.out.println("2 -> " + Arrays.toString(Util.getFactorsFor(2))); + System.out.println("47 -> " + Arrays.toString(Util.getFactorsFor(47))); + System.out.println("13 -> " + Arrays.toString(Util.getFactorsFor(13))); + System.out.println("1 -> " + Arrays.toString(Util.getFactorsFor(1))); + // System.out.println("0 -> "+Arrays.toString(getFactorsFor(0))); + } + + public JDialog getDialog() { + return dialog; + } +} diff --git a/src/eu/engys/gui/DefaultGUIPanel.java b/src/eu/engys/gui/DefaultGUIPanel.java new file mode 100644 index 0000000..178649d --- /dev/null +++ b/src/eu/engys/gui/DefaultGUIPanel.java @@ -0,0 +1,47 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui; + +import eu.engys.core.project.Model; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.TreeNodeManager; + +public class DefaultGUIPanel extends AbstractGUIPanel { + + private DefaultTreeNodeManager treeNodeManager; + + public DefaultGUIPanel(String title, Model model) { + super(title, model); + this.treeNodeManager = new DefaultTreeNodeManager(model, this); + model.addObserver(treeNodeManager); + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } +} diff --git a/src/eu/engys/gui/GUIError.java b/src/eu/engys/gui/GUIError.java new file mode 100644 index 0000000..4b7d9cf --- /dev/null +++ b/src/eu/engys/gui/GUIError.java @@ -0,0 +1,35 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui; + +public class GUIError extends RuntimeException { + + public GUIError(String msg) { + super(msg); + } + +} diff --git a/src/eu/engys/gui/GUIPanel.java b/src/eu/engys/gui/GUIPanel.java new file mode 100644 index 0000000..4a68a7e --- /dev/null +++ b/src/eu/engys/gui/GUIPanel.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui; + +import javax.swing.JComponent; + +import eu.engys.core.modules.ModulePanel; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.gui.view3D.CanvasPanel; + +public interface GUIPanel extends ModulePanel { + + public void load(); + + public void save(); + + public void resetToDefaults(); + + public JComponent getPanel(); + + public TreeNodeManager getTreeNodeManager(); + + public void clear(); + + public String getName(); + + public String getVersion(); + + public boolean canStart(); + + public void start(); + + public boolean canStop(); + + public void stop(); + + public void layoutPanel(); + + public void install(CanvasPanel view3D); +} diff --git a/src/eu/engys/gui/GlassPane.java b/src/eu/engys/gui/GlassPane.java new file mode 100644 index 0000000..7841ba6 --- /dev/null +++ b/src/eu/engys/gui/GlassPane.java @@ -0,0 +1,78 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +import javax.swing.JPanel; + +public class GlassPane extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener { + + public GlassPane() { + super(null); + addMouseListener(this); + addMouseMotionListener(this); + addMouseWheelListener(this); + setOpaque(false); + } + + @Override + public void mouseDragged(MouseEvent e) { + } + + @Override + public void mouseMoved(MouseEvent e) { + } + + @Override + public void mouseClicked(MouseEvent e) { + } + + @Override + public void mousePressed(MouseEvent e) { + } + + @Override + public void mouseReleased(MouseEvent e) { + } + + @Override + public void mouseEntered(MouseEvent e) { + } + + @Override + public void mouseExited(MouseEvent e) { + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + } + +} diff --git a/src/eu/engys/gui/ListBuilderFactory.java b/src/eu/engys/gui/ListBuilderFactory.java new file mode 100644 index 0000000..77c2b5f --- /dev/null +++ b/src/eu/engys/gui/ListBuilderFactory.java @@ -0,0 +1,152 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui; + +import java.util.ArrayList; +import java.util.List; + +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.project.Model; +import eu.engys.core.project.runtimefields.RuntimeField; +import eu.engys.core.project.zero.facezones.FaceZone; +import eu.engys.core.project.zero.facezones.FaceZones; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.util.ui.ListBuilder; + +public class ListBuilderFactory { + + public static ListBuilder getPatchesListBuilder(final Model model) { + ListBuilder listBuilder = new ListBuilder() { + + @Override + public String getTitle() { + return "Select Patches"; + } + + @Override + public String[] getSourceElements() { + Patches patches = model.getPatches(); + List elements = new ArrayList<>(); + if (patches != null) { + for (Patch patch : patches.patchesToDisplay()) { + elements.add(patch.getName()); + } + } + return elements.toArray(new String[0]); + } + + @Override + public int getSelectionMode() { + return ListBuilder.MULTIPLE_SELECTION; + } + }; + return listBuilder; + } + + public static ListBuilder getFaceZonesListBuilder(final Model model) { + ListBuilder listBuilder = new ListBuilder() { + + @Override + public String getTitle() { + return "Select Face Zone"; + } + + @Override + public String[] getSourceElements() { + FaceZones faceZones = model.getFaceZones(); + List elements = new ArrayList<>(); + if (faceZones != null) { + for (FaceZone zone : faceZones) { + elements.add(zone.getName()); + } + } + return elements.toArray(new String[0]); + } + + @Override + public int getSelectionMode() { + return ListBuilder.MULTIPLE_SELECTION; + } + }; + return listBuilder; + } + + public static ListBuilder getFieldsListBuilder(final Model model) { + ListBuilder fieldsListBuilder = new ListBuilder() { + + @Override + public String getTitle() { + return "Select Fields"; + } + + @Override + public String[] getSourceElements() { + List fields = model.getFields().orderedFields(); + List runTimeFields = model.getRuntimeFields().fields(); + + List elements = new ArrayList<>(); + if (fields != null) { + for (Field f : fields) { + elements.add(f.getName()); + } + for (RuntimeField rtf : runTimeFields) { + elements.add(rtf.getName()); + } + } + return elements.toArray(new String[0]); + } + + @Override + public int getSelectionMode() { + return ListBuilder.MULTIPLE_SELECTION; + } + }; + return fieldsListBuilder; + } + + public static ListBuilder getAdvancedMeshPatchesListBuilder(final Model model, final String title) { + ListBuilder listBuilder = new ListBuilder() { + + @Override + public String getTitle() { + return title; + } + + @Override + public String[] getSourceElements() { + return new GeometryToMesh(model).listPatches(); + } + + @Override + public int getSelectionMode() { + return ListBuilder.MULTIPLE_SELECTION; + } + }; + return listBuilder; + } +} diff --git a/src/eu/engys/gui/MenuBar.java b/src/eu/engys/gui/MenuBar.java new file mode 100644 index 0000000..976a010 --- /dev/null +++ b/src/eu/engys/gui/MenuBar.java @@ -0,0 +1,167 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.comparator.NameFileComparator; +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.IOFileFilter; + +import eu.engys.core.executor.FileManagerSupport; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.gui.RecentItems.RecentItemsObserver; +import eu.engys.gui.view.View; +import eu.engys.launcher.StartUpMonitor; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; + +public class MenuBar extends JMenuBar implements RecentItemsObserver { + + public static final Icon OPEN_ICON = ResourcesUtil.getIcon("application.open.icon"); + public static final Icon FILE_ICON = ResourcesUtil.getIcon("file"); + + private JMenu fileMenu; + private JMenu editMenu; + // private JMenu dictionariesMenu; + private JMenu helpMenu; + // private JMenu viewMenu; + private JMenu recentCasesMenu; + + private View view; + + public MenuBar(View view) { + super(); + this.view = view; + StartUpMonitor.info("Loading Menu Bar"); + fileMenu = new JMenu("File"); + fileMenu.add(ActionManager.getInstance().get("application.create")); + fileMenu.add(ActionManager.getInstance().get("application.open")); + + recentCasesMenu = new JMenu("Open Recent"); + recentCasesMenu.setIcon(OPEN_ICON); + fileMenu.add(recentCasesMenu); + + fileMenu.add(ActionManager.getInstance().get("application.save")); + fileMenu.add(ActionManager.getInstance().get("application.saveAs")); + fileMenu.addSeparator(); + fileMenu.add(ActionManager.getInstance().get("application.exit")); + + editMenu = new JMenu("Edit"); + editMenu.setName("Application Edit"); + + // dictionariesMenu = new JMenu("Dictionaries"); + + helpMenu = new JMenu("Help"); + + add(fileMenu); + add(editMenu); + // add(dictionariesMenu); + add(helpMenu); + + RecentItems.getInstance().addObserver(this); + } + + public JMenu getFileMenu() { + return fileMenu; + } + + public JMenu getEditMenu() { + return editMenu; + } + + public JMenu getHelpMenu() { + return helpMenu; + } + + @Override + public void onRecentItemChange(RecentItems src) { + recentCasesMenu.removeAll(); + List items = RecentItems.getInstance().getItems(); + if (items.isEmpty()) { + JMenuItem menuItem = new JMenuItem(RecentItems.NO_ITEMS); + menuItem.setEnabled(false); + recentCasesMenu.add(menuItem); + } else { + Icon CASE_ICON = ResourcesUtil.getIcon(ApplicationInfo.getVendor().toLowerCase() + ".case"); + for (final String item : items) { + recentCasesMenu.add(new AbstractAction(item, CASE_ICON) { + @Override + public void actionPerformed(ActionEvent e) { + if (view.getController().allowActionsOnRunning(false)) { + view.getController().openCase(new File(item)); + } + } + }); + } + recentCasesMenu.addSeparator(); + recentCasesMenu.add(new AbstractAction("Clear") { + @Override + public void actionPerformed(ActionEvent e) { + RecentItems.getInstance().clear(); + } + }); + } + } + + public void updateDictionariesList(final Model model) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + // dictionariesMenu.removeAll(); + if (model.hasProject()) { + File baseDir = model.getProject().getBaseDir(); + IOFileFilter fileFilter = FileFilterUtils.or(FileFilterUtils.suffixFileFilter("Dict"), FileFilterUtils.suffixFileFilter("Properties"), FileFilterUtils.prefixFileFilter("fv")); + List files = new ArrayList(FileUtils.listFiles(baseDir, fileFilter, FileFilterUtils.directoryFileFilter())); + Collections.sort(files, NameFileComparator.NAME_INSENSITIVE_COMPARATOR); + for (final File file : files) { + JMenuItem menuItem = new JMenuItem(new AbstractAction(file.getName(), FILE_ICON) { + @Override + public void actionPerformed(ActionEvent e) { + FileManagerSupport.open(file); + } + }); + menuItem.setToolTipText(file.getAbsolutePath()); + // dictionariesMenu.add(menuItem); + } + } + } + }); + } +} diff --git a/src/eu/engys/gui/ModelObserver.java b/src/eu/engys/gui/ModelObserver.java new file mode 100644 index 0000000..284b788 --- /dev/null +++ b/src/eu/engys/gui/ModelObserver.java @@ -0,0 +1,47 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui; + +public interface ModelObserver { + + void fieldManipulationFunctionObjectsChanged(); + + void monitoringFunctionObjectsChanged(); + + void stateChanged(); + + void fieldsChanged(); + + void runtimeFieldsChanged(); + + void solverChanged(); + + void materialsChanged(); + + void projectChanged(); + + String getTitle(); +} diff --git a/src/eu/engys/gui/PreferencesDialog.java b/src/eu/engys/gui/PreferencesDialog.java new file mode 100644 index 0000000..6127ddd --- /dev/null +++ b/src/eu/engys/gui/PreferencesDialog.java @@ -0,0 +1,595 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui; + +import static eu.engys.util.ui.ComponentsFactory.checkField; +import static eu.engys.util.ui.ComponentsFactory.intField; +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import net.java.dev.designgridlayout.Componentizer; + +import org.apache.commons.io.FileUtils; + +import eu.engys.core.OpenFOAMEnvironment; +import eu.engys.core.executor.FileManagerSupport; +import eu.engys.core.project.defaults.DictDataFolder; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.FileFieldPanel; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; +import eu.engys.util.ui.textfields.StringField; + +public class PreferencesDialog { + + private static final String DEFAULT_DICTIONARIES_LABEL = "Default Dictionaries"; + public static final String ERROR_LABEL_TEXT = "* the file no longer exist"; + private static final String PREFIX_FOR_TOOLTIP = "Full Installation Path, "; + private static final String OPENFOAM_TOOLTIP_LINUX = "e.g. /%s/OpenFOAM-x.x_engysEdition-x.x"; + private static final String OPENFOAM_TOOLTIP_WINDOWS = "e.g. \\%s\\OpenFOAM-x.x_engysEdition-x.x"; + private static final String OPENFOAM_TOOLTIP_LINUX_OS = "e.g. /%s/OpenFOAM-x.x.x"; + private static final String OPENFOAM_TOOLTIP_WINDOWS_OS = "e.g. \\%s\\OpenFOAM-x.x.x"; + private static final String PARAVIEW_TOOLTIP_LINUX = "e.g. /ParaView x.x.x/bin/paraview"; + private static final String PARAVIEW_TOOLTIP_WINDOWS = "e.g. \\ParaView x.x.x\\bin\\paraview.exe"; + private static final String FIELDVIEW_TOOLTIP_LINUX = "e.g. /fv/bin/fv"; + private static final String FIELDVIEW_TOOLTIP_WINDOWS = "e.g. \\Intelligent Light\\FVWINxx\\bin\\fv.bat"; + private static final String ENSIGHT_TOOLTIP_LINUX = "e.g. /CEI/bin/ensight100"; + private static final String ENSIGHT_TOOLTIP_WINDOWS = "e.g. \\CEI\\bin\\ensight100.bat"; + + private static final String TERMINAL_TOOLTIP = "Override system terminal, e.g. 'xterm'"; + private static final String FILE_MANAGER_TOOLTIP = "Override system file manager, e.g. 'nautilus'"; + private static final String DEFAULT_HOSTFILE_TOOLTIP = "Turn on/off the default hostfile (needs restart)"; + // private static final String FILE_OPENER_TOOLTIP = + // "Override system file opener, e.g. 'gnome-open'"; + + /* + * Labels + */ + + private static final String PATHS_LABEL = "Paths"; + public static final String CORE_FOLDER_LABEL = "Core Folder"; + public static final String PARA_VIEW_EXECUTABLE_LABEL = "ParaView Executable"; + public static final String FIELD_VIEW_EXECUTABLE_LABEL = "FieldView Executable"; + public static final String EN_SIGHT_EXECUTABLE_LABEL = "EnSight Executable"; + + private static final String SERVER_LABEL = "Server"; + // public static final String OUTPUT_LOG_WAIT_TIME_LABEL = "Output Log Wait Time"; + public static final String KILL_WAIT_TIME_LABEL = "Kill Wait Time"; + public static final String OUTPUT_LOG_REFRESH_INTERVAL_LABEL = "Output Log Refresh Interval"; + public static final String RUN_WAIT_TIME_LABEL = "Run Wait time"; + // public static final String STOP_WAIT_TIME_LABEL = "Stop Wait Time"; + public static final String CONNECTION_TRIES_INTERVAL_MSEC_LABEL = "Connection Tries Interval [msec]"; + public static final String CONNECTION_TRIES_LABEL = "Connection Tries"; + + private static final String _3D_RENDERING_LABEL = "3D Rendering"; + public static final String ENABLE_LOD_THRESHOLD_KB_LABEL = "Enable LOD Threshold [KB]"; + public static final String LOCK_INTERACTIVE_RENDER_FOR_MSEC_LABEL = "Lock Interactive Render For [msec]"; + public static final String DISBLE_TRANSPARENCY_THRESHOLD_KB_LABEL = "Disable Transparency Threshold [KB]"; + + private static final String MISC_LABEL = "Misc"; + public static final String MAX_LOG_LINES_LABEL = "Max Log Lines"; + // public static final String MAX_CHART_LINES_LABEL = "Max Chart Lines"; + public static final String HIDE_EMPTY_PATCHES_LABEL = "Hide Empty Patches"; + public static final String CUSTOM_FILE_MANAGER_LABEL = "Custom File Manager"; + public static final String CUSTOM_TERMINAL_COMMAND_LABEL = "Custom Terminal Command"; + public static final String DEFAULT_HOSTFILE_NONE_LABEL = "Default Hostfile Off (needs restart)"; + + private JDialog dialog; + private FileFieldPanel fieldViewPanel; + private FileFieldPanel ensightPanel; + private FileFieldPanel paraViewPanel; + private FileFieldPanel openFoamPanel; + + private IntegerField connectionTries; + private IntegerField connectionRefresh; + private IntegerField waitForStopTime; + private IntegerField waitForRunTime; + private IntegerField scriptRefresh; + private IntegerField waiForKillTime; + private IntegerField logWaitTime; + + private IntegerField interactiveMemory; + private IntegerField interactiveTime; + private IntegerField transparencyMemory; + + private StringField defaultTerminal; + private StringField defaultFileManager; + private StringField defaultFileOpener; + private JCheckBox defaultHostFile; + + private JCheckBox hideEmptyPatches; + + private IntegerField maxChartRows; + private IntegerField maxLogRows; + + private final boolean isOS; + private final boolean paraview; + private final boolean fieldview; + private final boolean ensight; + private final boolean hasSolverPreferences; + + private JLabel errorLabel; + private JButton okButton; + private JButton openDefaults; + private DictDataFolder dictDataFolder; + + public PreferencesDialog(boolean isOS, boolean paraview, boolean fieldview, boolean ensight, boolean hasSolverPreferences, DictDataFolder dictDataFolder) { + this.isOS = isOS; + this.paraview = paraview;// HELYX-OS or Windows OS + this.fieldview = fieldview;// HELYX-SAS and HELYX + this.ensight = ensight;// HELYX + this.hasSolverPreferences = hasSolverPreferences; + this.dictDataFolder = dictDataFolder; + + initDialog(); + load(); + } + + private void initDialog() { + JScrollPane scrollPane = new JScrollPane(createCenterPanel()); + scrollPane.setBorder(BorderFactory.createEmptyBorder()); + scrollPane.getVerticalScrollBar().setUnitIncrement(20); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(scrollPane, BorderLayout.CENTER); + mainPanel.add(createButtonsPanel(), BorderLayout.SOUTH); + + dialog = new JDialog(UiUtil.getActiveWindow(), "Preferences", ModalityType.APPLICATION_MODAL); + dialog.getContentPane().setLayout(new BorderLayout()); + dialog.getContentPane().add(mainPanel); + dialog.setSize(800, 600); + dialog.setLocationRelativeTo(null); + dialog.setName("PreferencesDialog"); + dialog.getRootPane().setDefaultButton(okButton); + } + + private JPanel createButtonsPanel() { + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + okButton = new JButton(new AbstractAction("OK") { + @Override + public void actionPerformed(ActionEvent e) { + save(); + dialog.setVisible(false); + } + }); + okButton.setName("OK"); + JButton cancelButton = new JButton(new AbstractAction("Cancel") { + @Override + public void actionPerformed(ActionEvent e) { + dialog.setVisible(false); + } + }); + cancelButton.setName("Cancel"); + + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + return buttonsPanel; + } + + /* + * Load + */ + + public void load() { + loadPathProperties(); + loadBatchProperties(); + loadVTKProperties(); + loadMiscProperties(); + + } + + private void loadPathProperties() { + openFoamPanel.setFile(PrefUtil.getOpenFoamEntry()); + if (paraview) { + paraViewPanel.setFile(PrefUtil.getParaViewEntry()); + } + if (fieldview) { + fieldViewPanel.setFile(PrefUtil.getFieldViewEntry()); + } + if (ensight) { + ensightPanel.setFile(PrefUtil.getEnsightEntry()); + } + + updateErrorLabel(); + } + + private void updateErrorLabel() { + boolean coreOk = openFoamPanel.hasExistingFile(); + if (!coreOk || !isParaViewOk() || !isFieldViewOk() || !isEnsightOk()) { + errorLabel.setText(ERROR_LABEL_TEXT); + } else { + errorLabel.setText(""); + } + } + + private void loadBatchProperties() { + connectionTries.setIntValue(PrefUtil.getInt(PrefUtil.SERVER_CONNECTION_MAX_TRIES)); + connectionRefresh.setIntValue(PrefUtil.getInt(PrefUtil.SERVER_CONNECTION_REFRESH_TIME)); + waitForRunTime.setIntValue(PrefUtil.getInt(PrefUtil.SERVER_WAIT_FOR_RUN_REFRESH_TIME)); + scriptRefresh.setIntValue(PrefUtil.getInt(PrefUtil.SCRIPT_RUN_REFRESH_TIME)); + waiForKillTime.setIntValue(PrefUtil.getInt(PrefUtil.SCRIPT_WAIT_FOR_KILL_REFRESH_TIME)); + } + + private void loadVTKProperties() { + interactiveMemory.setIntValue(PrefUtil.getInt(PrefUtil._3D_LOCK_INTRACTIVE_MEMORY)); + interactiveTime.setIntValue(PrefUtil.getInt(PrefUtil._3D_LOCK_INTRACTIVE_TIME)); + transparencyMemory.setIntValue(PrefUtil.getInt(PrefUtil._3D_TRANSPARENCY_MEMORY)); + } + + private void loadMiscProperties() { + if (Util.isUnix()) { + defaultTerminal.setStringValue(PrefUtil.getString(PrefUtil.HELYX_DEFAULT_TERMINAL)); + defaultFileManager.setStringValue(PrefUtil.getString(PrefUtil.HELYX_DEFAULT_FILE_MANAGER)); + defaultHostFile.setSelected(PrefUtil.getBoolean(PrefUtil.DEFAULT_HOSTFILE_NONE)); + } + hideEmptyPatches.setSelected(PrefUtil.getBoolean(PrefUtil.HIDE_EMPTY_PATCHES)); + maxLogRows.setIntValue(PrefUtil.getInt(PrefUtil.BATCH_MONITOR_DIALOG_MAX_ROW)); + } + + /* + * Save + */ + + // public for test purposes only + public void save() { + savePathProperties(); + saveBatchProperties(); + saveVTKProperties(); + saveMiscProperties(); + } + + private void savePathProperties() { + PrefUtil.setOpenFoamEntry(openFoamPanel.getFile()); + if (paraview) { + PrefUtil.setParaViewEntry(paraViewPanel.getFile()); + } + if (fieldview) { + PrefUtil.setFieldViewEntry(fieldViewPanel.getFile()); + } + if (ensight) { + PrefUtil.setEnsightEntry(ensightPanel.getFile()); + } + } + + private void saveBatchProperties() { + PrefUtil.putInt(PrefUtil.SERVER_CONNECTION_MAX_TRIES, connectionTries.getIntValue()); + PrefUtil.putInt(PrefUtil.SERVER_CONNECTION_REFRESH_TIME, connectionRefresh.getIntValue()); + PrefUtil.putInt(PrefUtil.SERVER_WAIT_FOR_RUN_REFRESH_TIME, waitForRunTime.getIntValue()); + + PrefUtil.putInt(PrefUtil.SCRIPT_RUN_REFRESH_TIME, scriptRefresh.getIntValue()); + PrefUtil.putInt(PrefUtil.SCRIPT_WAIT_FOR_KILL_REFRESH_TIME, waiForKillTime.getIntValue()); + } + + private void saveVTKProperties() { + PrefUtil.putInt(PrefUtil._3D_LOCK_INTRACTIVE_MEMORY, interactiveMemory.getIntValue()); + PrefUtil.putInt(PrefUtil._3D_LOCK_INTRACTIVE_TIME, interactiveTime.getIntValue()); + PrefUtil.putInt(PrefUtil._3D_TRANSPARENCY_MEMORY, transparencyMemory.getIntValue()); + } + + private void saveMiscProperties() { + if (Util.isUnix()) { + PrefUtil.putString(PrefUtil.HELYX_DEFAULT_TERMINAL, defaultTerminal.getStringValue()); + PrefUtil.putString(PrefUtil.HELYX_DEFAULT_FILE_MANAGER, defaultFileManager.getStringValue()); + PrefUtil.putBoolean(PrefUtil.DEFAULT_HOSTFILE_NONE, defaultHostFile.isSelected()); + } + PrefUtil.putBoolean(PrefUtil.HIDE_EMPTY_PATCHES, hideEmptyPatches.isSelected()); + PrefUtil.putInt(PrefUtil.BATCH_MONITOR_DIALOG_MAX_ROW, maxLogRows.getIntValue()); + } + + /* + * Layout + */ + + private Component createCenterPanel() { + JPanel pathsPanel = createPathsPanel(); + JPanel batchPanel = createBatchPanel(); + JPanel vtkPanel = createVTKPanel(); + JPanel miscPanel = createMiscPanel(); + + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(pathsPanel); + if (hasSolverPreferences) { + builder.addComponent(batchPanel); + } + builder.addComponent(vtkPanel); + builder.addComponent(miscPanel); + + JPanel container = new JPanel(new BorderLayout()); + container.setOpaque(false); + container.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + container.add(builder.getPanel(), BorderLayout.CENTER); + container.add(errorLabel = new JLabel(""), BorderLayout.SOUTH); + errorLabel.setForeground(Color.RED.darker()); + errorLabel.setName("error.label"); + return container; + } + + private JPanel createPathsPanel() { + String ofPrompt = ""; + if (Util.isWindows()) { + if (isOS) { + ofPrompt = String.format(OPENFOAM_TOOLTIP_WINDOWS_OS, ApplicationInfo.getVendor()); + } else { + ofPrompt = String.format(OPENFOAM_TOOLTIP_WINDOWS, ApplicationInfo.getVendor()); + } + } else { + if (isOS) { + ofPrompt = String.format(OPENFOAM_TOOLTIP_LINUX_OS, ApplicationInfo.getVendor()); + } else { + ofPrompt = String.format(OPENFOAM_TOOLTIP_LINUX, ApplicationInfo.getVendor()); + } + } + + String ofTooltip = PREFIX_FOR_TOOLTIP + ofPrompt; + + PanelBuilder pathBuilder = new PanelBuilder(); + addResettableComponent(pathBuilder, CORE_FOLDER_LABEL, openFoamPanel = ComponentsFactory.fileField(SelectionMode.DIRS_ONLY, ofTooltip, ofPrompt, true), PrefUtil.OPENFOAM_KEY); + openFoamPanel.addPropertyChangeListener(new UpdateErrorLabelListener()); + + if (paraview) { + String pvPrompt = Util.isWindows() ? PARAVIEW_TOOLTIP_WINDOWS : PARAVIEW_TOOLTIP_LINUX; + String pvTooltip = PREFIX_FOR_TOOLTIP + pvPrompt; + + paraViewPanel = ComponentsFactory.fileField(SelectionMode.FILES_ONLY, pvTooltip, pvPrompt, true); + paraViewPanel.addPropertyChangeListener(new UpdateErrorLabelListener()); + addResettableComponent(pathBuilder, PARA_VIEW_EXECUTABLE_LABEL, paraViewPanel, PrefUtil.PARAVIEW_KEY); + } + + if (fieldview) { + String fvPrompt = Util.isWindows() ? FIELDVIEW_TOOLTIP_WINDOWS : FIELDVIEW_TOOLTIP_LINUX; + String fvTooltip = PREFIX_FOR_TOOLTIP + fvPrompt; + + fieldViewPanel = ComponentsFactory.fileField(SelectionMode.FILES_ONLY, fvTooltip, fvPrompt, true); + fieldViewPanel.addPropertyChangeListener(new UpdateErrorLabelListener()); + addResettableComponent(pathBuilder, FIELD_VIEW_EXECUTABLE_LABEL, fieldViewPanel, PrefUtil.FIELDVIEW_KEY); + } + if (ensight) { + String fvPrompt = Util.isWindows() ? ENSIGHT_TOOLTIP_WINDOWS : ENSIGHT_TOOLTIP_LINUX; + String fvTooltip = PREFIX_FOR_TOOLTIP + fvPrompt; + + ensightPanel = ComponentsFactory.fileField(SelectionMode.FILES_ONLY, fvTooltip, fvPrompt, true); + ensightPanel.addPropertyChangeListener(new UpdateErrorLabelListener()); + addResettableComponent(pathBuilder, EN_SIGHT_EXECUTABLE_LABEL, ensightPanel, PrefUtil.ENSIGHT_KEY); + } + JPanel panel = pathBuilder.getPanel(); + panel.setBorder(BorderFactory.createTitledBorder(PATHS_LABEL)); + return panel; + } + + private JPanel createBatchPanel() { + PanelBuilder batchBuilder = new PanelBuilder(); + addResettableComponent(batchBuilder, CONNECTION_TRIES_LABEL, connectionTries = intField(), PrefUtil.SERVER_CONNECTION_MAX_TRIES); + addResettableComponent(batchBuilder, CONNECTION_TRIES_INTERVAL_MSEC_LABEL, connectionRefresh = intField(), PrefUtil.SERVER_CONNECTION_REFRESH_TIME); + addResettableComponent(batchBuilder, RUN_WAIT_TIME_LABEL, waitForRunTime = intField(), PrefUtil.SERVER_WAIT_FOR_RUN_REFRESH_TIME); + addResettableComponent(batchBuilder, OUTPUT_LOG_REFRESH_INTERVAL_LABEL, scriptRefresh = intField(), PrefUtil.SCRIPT_RUN_REFRESH_TIME); + addResettableComponent(batchBuilder, KILL_WAIT_TIME_LABEL, waiForKillTime = intField(), PrefUtil.SCRIPT_WAIT_FOR_KILL_REFRESH_TIME); + batchBuilder.getPanel().setBorder(BorderFactory.createTitledBorder(SERVER_LABEL)); + return batchBuilder.getPanel(); + } + + private JPanel createVTKPanel() { + PanelBuilder vtkBuilder = new PanelBuilder(); + addResettableComponent(vtkBuilder, LOCK_INTERACTIVE_RENDER_FOR_MSEC_LABEL, interactiveTime = intField(), PrefUtil._3D_LOCK_INTRACTIVE_TIME); + addResettableComponent(vtkBuilder, ENABLE_LOD_THRESHOLD_KB_LABEL, interactiveMemory = intField(), PrefUtil._3D_LOCK_INTRACTIVE_MEMORY); + addResettableComponent(vtkBuilder, DISBLE_TRANSPARENCY_THRESHOLD_KB_LABEL, transparencyMemory = intField(), PrefUtil._3D_TRANSPARENCY_MEMORY); + vtkBuilder.getPanel().setBorder(BorderFactory.createTitledBorder(_3D_RENDERING_LABEL)); + return vtkBuilder.getPanel(); + } + + private JPanel createMiscPanel() { + PanelBuilder miscBuilder = new PanelBuilder(); + if (Util.isUnix()) { + addResettableComponent(miscBuilder, CUSTOM_TERMINAL_COMMAND_LABEL, defaultTerminal = stringField(), PrefUtil.HELYX_DEFAULT_TERMINAL); + defaultTerminal.setPrompt(TERMINAL_TOOLTIP); + + addResettableComponent(miscBuilder, CUSTOM_FILE_MANAGER_LABEL, defaultFileManager = stringField(), PrefUtil.HELYX_DEFAULT_FILE_MANAGER); + defaultFileManager.setPrompt(FILE_MANAGER_TOOLTIP); + + addResettableComponent(miscBuilder, DEFAULT_HOSTFILE_NONE_LABEL, defaultHostFile = checkField(), PrefUtil.DEFAULT_HOSTFILE_NONE); + defaultHostFile.setToolTipText(DEFAULT_HOSTFILE_TOOLTIP); + } + addResettableComponent(miscBuilder, HIDE_EMPTY_PATCHES_LABEL, hideEmptyPatches = checkField(), PrefUtil.HIDE_EMPTY_PATCHES); + addResettableComponent(miscBuilder, MAX_LOG_LINES_LABEL, maxLogRows = intField(), PrefUtil.BATCH_MONITOR_DIALOG_MAX_ROW); + + openDefaults = new JButton(new AbstractAction("Show Files") { + @Override + public void actionPerformed(ActionEvent e) { + if (dictDataFolder.toFile() != null && dictDataFolder.toFile().exists()) { + FileManagerSupport.open(dictDataFolder.toFile()); + } + } + }); + JButton resetButton = new JButton(new ViewAction("Reset", "Reset Files To Default") { + @Override + public void actionPerformed(ActionEvent e) { + try { + FileUtils.forceDeleteOnExit(new File(ApplicationInfo.getHome(), "dictData")); + } catch (IOException e1) { + } finally { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Restart " + ApplicationInfo.getName() + " to complete this action."); + } + } + }); + miscBuilder.addComponent(DEFAULT_DICTIONARIES_LABEL, Componentizer.create().minAndMore(openDefaults).minToPref(resetButton).component()); + + miscBuilder.getPanel().setBorder(BorderFactory.createTitledBorder(MISC_LABEL)); + return miscBuilder.getPanel(); + } + + private void addResettableComponent(PanelBuilder builder, String label, JComponent compToAdd, String prefKey) { + JButton resetButton = createResetButton(compToAdd, prefKey); + resetButton.setName(label + ".reset"); + compToAdd.setName(label); + builder.addComponent(label, Componentizer.create().minAndMore(compToAdd).minToPref(resetButton).component()); + } + + private JButton createResetButton(final JComponent compToAdd, final String key) { + return new JButton(new ViewAction("Reset", "Reset Preference To Default") { + + @Override + public void actionPerformed(ActionEvent e) { + Object value = PrefUtil.getDefaultValue(key); + if (compToAdd instanceof IntegerField) { + resetIntegerField(compToAdd, value); + } else if (compToAdd instanceof StringField) { + resetStringField(compToAdd, value); + } else if (compToAdd instanceof JCheckBox) { + resetBooleanField(compToAdd, value); + } else if (compToAdd instanceof DoubleField) { + resetDoubleField(compToAdd, value); + } else if (compToAdd instanceof FileFieldPanel) { + if(key.equals(PrefUtil.OPENFOAM_KEY)){ + resetOpenFoamFileField(compToAdd); + } else { + resetFileField(compToAdd); + } + } + } + + private void resetFileField(final JComponent compToAdd) { + ((FileFieldPanel) compToAdd).setFile(null); + } + + private void resetOpenFoamFileField(final JComponent compToAdd) { + File[] openFoamDir = OpenFOAMEnvironment.getOpenFoamDir(); + if (Util.isVarArgsNotNullAndOfSize(1, openFoamDir)) { + ((FileFieldPanel) compToAdd).setFile(openFoamDir[0]); + } else { + ((FileFieldPanel) compToAdd).setFile(null); + } + } + + private void resetDoubleField(final JComponent compToAdd, Object value) { + if (value == null) { + ((DoubleField) compToAdd).setDoubleValue(0); + } else { + double doubleValue = Double.parseDouble(String.valueOf(value)); + ((DoubleField) compToAdd).setDoubleValue(doubleValue); + } + } + + private void resetBooleanField(final JComponent compToAdd, Object value) { + if (value == null) { + ((JCheckBox) compToAdd).setSelected(false); + } else { + boolean booleanValue = Boolean.valueOf(String.valueOf(value)); + ((JCheckBox) compToAdd).setSelected(booleanValue); + } + } + + private void resetStringField(final JComponent compToAdd, Object value) { + if (value == null) { + ((StringField) compToAdd).setStringValue(""); + } else { + String stringValue = String.valueOf(value); + ((StringField) compToAdd).setStringValue(stringValue); + } + } + + private void resetIntegerField(final JComponent compToAdd, Object value) { + if (value == null) { + ((IntegerField) compToAdd).setIntValue(0); + } else { + int intValue = Integer.parseInt(String.valueOf(value)); + ((IntegerField) compToAdd).setIntValue(intValue); + } + } + }); + } + + /* + * Utils + */ + + private boolean isParaViewOk() { + if (paraview) { + return paraViewPanel.hasExistingFile(); + } + return true; + } + + private boolean isEnsightOk() { + if (ensight) { + return ensightPanel.hasExistingFile(); + } + return true; + } + + private boolean isFieldViewOk() { + if (fieldview) { + return fieldViewPanel.hasExistingFile(); + } + return true; + } + + public void show() { + dialog.setVisible(true); + } + + private class UpdateErrorLabelListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + updateErrorLabel(); + } + } + + } + + // For test purpose only + public JDialog getDialog() { + return dialog; + } +} diff --git a/src/eu/engys/gui/RecentItems.java b/src/eu/engys/gui/RecentItems.java new file mode 100644 index 0000000..7ff76ce --- /dev/null +++ b/src/eu/engys/gui/RecentItems.java @@ -0,0 +1,129 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ +package eu.engys.gui; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; + +import eu.engys.util.PrefUtil; + +public class RecentItems { + + public interface RecentItemsObserver { + void onRecentItemChange(RecentItems src); + } + + public final static String RECENT_ITEM_STRING = "recent.item."; + + static final int MAX_ITEMS = 5; + + public static final String NO_ITEMS = "No recent files"; + + private List items = new ArrayList<>(); + private List m_observers = new ArrayList(); + + private static RecentItems instance; + + public static RecentItems getInstance() { + if (instance == null) { + instance = new RecentItems(); + } + return instance; + } + + public RecentItems() { + loadFromPreferences(); + } + + public void push(File item) { + items.remove(item.getAbsolutePath()); + items.add(0, item.getAbsolutePath()); + + if (items.size() > MAX_ITEMS) { + items.remove(items.size() - 1); + } + + update(); + storeToPreferences(); + } + + public void remove(Object item) { + items.remove(item); + update(); + storeToPreferences(); + } + + public List getItems() { + return items; + } + + public int size() { + return items.size(); + } + + public void addObserver(RecentItemsObserver observer) { + m_observers.add(observer); + update(); + } + + public void removeObserver(RecentItemsObserver observer) { + m_observers.remove(observer); + } + + private void update() { + for (RecentItemsObserver observer : m_observers) { + observer.onRecentItemChange(this); + } + } + + void loadFromPreferences() { + // load recent files from properties + String recentItems = PrefUtil.getString(PrefUtil.RECENT_PROJECTS, ""); + for (String item : recentItems.split(File.pathSeparator)) { + File file = new File(item); + if (file.exists()) { + items.add(item); + } + } + } + + void storeToPreferences() { + List list = new ArrayList<>(); + for (int i = 0; i < MAX_ITEMS; i++) { + if (i < items.size()) { + list.add(items.get(i)); + } + } + PrefUtil.putString(PrefUtil.RECENT_PROJECTS, StringUtils.join(list, File.pathSeparator)); + } + + public void clear() { + items.clear(); + storeToPreferences(); + } +} diff --git a/src/eu/engys/gui/StandardScriptFactory.java b/src/eu/engys/gui/StandardScriptFactory.java new file mode 100644 index 0000000..75d3409 --- /dev/null +++ b/src/eu/engys/gui/StandardScriptFactory.java @@ -0,0 +1,104 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui; + +import static eu.engys.core.OpenFOAMEnvironment.loadEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.printHeader; +import static eu.engys.core.OpenFOAMEnvironment.printVariables; +import static eu.engys.util.OpenFOAMCommands.CHECK_MESH_PARALLEL; +import static eu.engys.util.OpenFOAMCommands.CHECK_MESH_SERIAL; +import static eu.engys.util.OpenFOAMCommands.SET_FIELDS_PARALLEL; +import static eu.engys.util.OpenFOAMCommands.SET_FIELDS_SERIAL; + +import java.util.List; + +import javax.inject.Inject; + +import eu.engys.core.controller.DefaultScriptFactory; +import eu.engys.core.controller.ScriptBuilder; +import eu.engys.core.project.Model; + +public class StandardScriptFactory extends DefaultScriptFactory { + + @Inject + public StandardScriptFactory(Model model) { + super(model); + } + + protected boolean performBlockMesh() { + return true; + } + + @Override + protected List getSerialCheckMeshScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, CHECK_MESH); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(CHECK_MESH_SERIAL()); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getParallelCheckMeshScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, CHECK_MESH); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(CHECK_MESH_PARALLEL()); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getSerialInitialiseScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, INITIALISE_FIELDS.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(SET_FIELDS_SERIAL()); + sb.newLine(); + return sb.getLines(); + } + + @Override + protected List getParallelInitialiseScript() { + ScriptBuilder sb = new ScriptBuilder(); + printHeader(sb, INITIALISE_FIELDS.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + sb.newLine(); + sb.append(SET_FIELDS_PARALLEL()); + sb.newLine(); + return sb.getLines(); + } + +} diff --git a/src/eu/engys/gui/StartPanel.java b/src/eu/engys/gui/StartPanel.java new file mode 100644 index 0000000..c8064fd --- /dev/null +++ b/src/eu/engys/gui/StartPanel.java @@ -0,0 +1,214 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import eu.engys.application.Application; +import eu.engys.core.presentation.ActionManager; +import eu.engys.gui.view.View; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; + +public class StartPanel extends JPanel { + + private static final String DEMO_START = "Go under Help > License Manager to provide a valid license."; + + private List actions; + private Application application; + private View view; + + public StartPanel(Application application, View view) { + super(new BorderLayout()); + this.application = application; + this.view = view; + this.actions = createActions(); + layoutComponents(); + setBorder(BorderFactory.createEmptyBorder(10, 25, 10, 25)); + } + + private List createActions() { + List actions = new ArrayList(); + + actions.add(ActionManager.getInstance().get("application.create")); + actions.add(ActionManager.getInstance().get("application.open")); + actions.add(ActionManager.getInstance().get("application.exit")); + + return actions; + } + + private void layoutComponents() { + JPanel topPanel = new JPanel(new BorderLayout()); + JPanel bottomPanel = new JPanel(new BorderLayout()); + + topPanel.add(createBannerPanel(), BorderLayout.NORTH); + topPanel.add(application.createAdPanel(), BorderLayout.CENTER); + + bottomPanel.add(createProjectActionsPanel(), BorderLayout.CENTER); + bottomPanel.add(application.createVersionPanel(), BorderLayout.SOUTH); + + add(topPanel, BorderLayout.NORTH); + add(bottomPanel, BorderLayout.CENTER); + } + + private JComponent createBannerPanel() { + JLabel banner = new JLabel(application.getBannerIcon()); + return banner; + } + + protected JPanel createProjectActionsPanel() { + final ImageIcon BG_IMAGE = (ImageIcon) application.getBgIcon(); + JPanel containerPanel = new JPanel(new BorderLayout()) { + @Override + protected void paintComponent(Graphics g) { + setOpaque(false); + g.drawImage(BG_IMAGE.getImage(), (getWidth() - BG_IMAGE.getImage().getWidth(null)) - 10, getHeight() - BG_IMAGE.getImage().getHeight(null), null); + super.paintComponent(g); + } + }; + + int width = actions.size() >= 4 ? 700 : BG_IMAGE.getImage().getWidth(null); + int height = 260 * (((actions.size() - 1) / 3) + 1); + containerPanel.setPreferredSize(new Dimension(width, height)); + + JPanel buttonsPanel = createButtonsPanel(); + + JPanel recentPanel = createRecentPanel(); + + JPanel titlePanel = new JPanel(new GridBagLayout()); + titlePanel.setBorder(BorderFactory.createTitledBorder("Select an action")); + titlePanel.setOpaque(false); + titlePanel.add(buttonsPanel, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(10, 10, 10, 10), 0, 0)); + titlePanel.add(recentPanel, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.VERTICAL, new Insets(10, 10, 10, 10), 0, 0)); + + containerPanel.add(titlePanel, BorderLayout.CENTER); + containerPanel.add(getDemoLabel(), BorderLayout.SOUTH); + return containerPanel; + } + + private JPanel createRecentPanel() { + JPanel panel = new JPanel(new BorderLayout()); + panel.setOpaque(false); + List items = RecentItems.getInstance().getItems(); + if (items.isEmpty()) { + JLabel label = new JLabel(RecentItems.NO_ITEMS); + panel.add(label); + } else { + List buttons = new ArrayList<>(); + Icon CASE_ICON = ResourcesUtil.getIcon(ApplicationInfo.getVendor().toLowerCase() + ".case"); + for (final String item : items) { + JButton button = new JButton((new AbstractAction(truncateItem(item), CASE_ICON) { + @Override + public void actionPerformed(ActionEvent e) { + if (view.getController().allowActionsOnRunning(false)) { + view.getController().openCase(new File(item)); + } + } + })); + buttons.add(button); + } + panel.add(UiUtil.getCommandColumnToolbar(buttons)); + } + + return panel; + } + + private String truncateItem(String projectName) { + int MAX_LEN = 30; + String path = projectName; + if (path.length() <= MAX_LEN) { + return path; + } else { + return "..." + path.substring(path.length() - MAX_LEN, path.length()); + } + } + + private JLabel getDemoLabel() { + String licenseErrorMessage = System.getProperty("license.error.message", null); + if (licenseErrorMessage != null && !licenseErrorMessage.isEmpty()) { + JLabel label = new JLabel("" + licenseErrorMessage + "
" + DEMO_START + ""); + label.setForeground(new Color(0xff0000)); + return label; + } else { + return new JLabel(); + } + } + + private JPanel createButtonsPanel() { + List buttons = createButtons(); + + int colNumber = 1; + int rows = ((buttons.size() - 1) / colNumber) + 1; + int cols = Math.min(buttons.size(), colNumber); + + JPanel panel = new JPanel(new GridLayout(rows, cols, 0, 10)); + panel.setOpaque(false); + + for (JButton button : buttons) { + button.setName("suite." + button.getText()); + // button.setHorizontalTextPosition(JButton.CENTER); + // button.setVerticalTextPosition(JButton.BOTTOM); + button.setFocusable(false); + panel.add(button); + } + return panel; + } + + private List createButtons() { + List buttons = new ArrayList(); + for (Action action : actions) { + final JButton button = new JButton(); + button.setAction(action); + // button.setOpaque(true); + buttons.add(button); + } + return buttons; + } + +} diff --git a/src/eu/engys/gui/casesetup/CaseSetup.java b/src/eu/engys/gui/casesetup/CaseSetup.java new file mode 100644 index 0000000..fdaf894 --- /dev/null +++ b/src/eu/engys/gui/casesetup/CaseSetup.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +public @interface CaseSetup { + +} diff --git a/src/eu/engys/gui/casesetup/CaseSetup3DElement.java b/src/eu/engys/gui/casesetup/CaseSetup3DElement.java new file mode 100644 index 0000000..5e79917 --- /dev/null +++ b/src/eu/engys/gui/casesetup/CaseSetup3DElement.java @@ -0,0 +1,50 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup; + +import java.util.Set; + +import javax.inject.Inject; + +import eu.engys.gui.GUIPanel; +import eu.engys.gui.view.AbstractView3DElement; +import eu.engys.gui.view3D.CanvasPanel; + +public class CaseSetup3DElement extends AbstractView3DElement { + + @Inject + public CaseSetup3DElement(@CaseSetup Set panels) { + super(panels); + } + + @Override + public void load(CanvasPanel view3D) { + view3D.getMeshController().newContext(getClass()); + view3D.getGeometryController().newEmptyContext(getClass()); + } + +} diff --git a/src/eu/engys/gui/casesetup/CaseSetupElement.java b/src/eu/engys/gui/casesetup/CaseSetupElement.java new file mode 100644 index 0000000..fd761d3 --- /dev/null +++ b/src/eu/engys/gui/casesetup/CaseSetupElement.java @@ -0,0 +1,118 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup; + +import java.util.HashSet; +import java.util.Set; + +import javax.inject.Inject; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulePanel; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.core.project.state.State; +import eu.engys.gui.Actions; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.view.AbstractViewElement; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElementPanel; +import eu.engys.util.plaf.ILookAndFeel; + +public class CaseSetupElement extends AbstractViewElement { + + private ViewElementPanel viewElementPanel; + + @Inject + @CaseSetup + private ProjectWriter writer; + @Inject + @CaseSetup + private ProjectReader reader; + + @Inject + public CaseSetupElement(@CaseSetup String title, @CaseSetup Set panels, Set modules, @CaseSetup View3DElement view3DElement, @CaseSetup Actions actions, ILookAndFeel lookAndFeel) { + super(title, panels, modules, view3DElement, actions, lookAndFeel); + } + + @Override + public ViewElementPanel getPanel() { + return viewElementPanel; + } + + @Override + public void layoutComponents() { + viewElementPanel = new ViewElementPanel(this); + super.layoutComponents(); + } + + @Override + protected Set getModulePanels() { + Set allPanels = new HashSet(); + for (ModulePanel panel : ModulesUtil.getCaseSetupPanels(modules)) { + allPanels.add((GUIPanel) panel); + } + return allPanels; + } + + @Override + public int getPreferredWidth() { + return 700; + } + + @Override + public void start() { + super.start(); + } + + @Override + public ProjectReader getReader() { + return reader; + } + + @Override + public ProjectWriter getWriter() { + return writer; + } + + @Override + public void load(Model model) { + super.load(model); + ModulesUtil.updateTree(modules, getPanel()); + } + + @Override + public void changeObserved(Object arg) { + if (arg instanceof State) { + ModulesUtil.updateTree(modules, getPanel()); + getActions().update(); + } + super.changeObserved(arg); + } +} diff --git a/src/eu/engys/gui/casesetup/RuntimeControlsPanel.java b/src/eu/engys/gui/casesetup/RuntimeControlsPanel.java new file mode 100644 index 0000000..a44a390 --- /dev/null +++ b/src/eu/engys/gui/casesetup/RuntimeControlsPanel.java @@ -0,0 +1,346 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup; + +import static eu.engys.core.project.system.ControlDict.ADJUSTABLE_RUN_TIME_KEY; +import static eu.engys.core.project.system.ControlDict.ADJUST_TIME_STEP_KEY; +import static eu.engys.core.project.system.ControlDict.DELTA_T_KEY; +import static eu.engys.core.project.system.ControlDict.END_TIME_KEY; +import static eu.engys.core.project.system.ControlDict.FUNCTIONS_KEY; +import static eu.engys.core.project.system.ControlDict.GRAPH_FORMAT_KEY; +import static eu.engys.core.project.system.ControlDict.GRAPH_FORMAT_VALUE; +import static eu.engys.core.project.system.ControlDict.MAX_ALPHA_CO_KEY; +import static eu.engys.core.project.system.ControlDict.MAX_CO_KEY; +import static eu.engys.core.project.system.ControlDict.MAX_DELTA_T_KEY; +import static eu.engys.core.project.system.ControlDict.PURGE_WRITE_KEY; +import static eu.engys.core.project.system.ControlDict.RUN_TIME_VALUE; +import static eu.engys.core.project.system.ControlDict.START_FROM_KEY; +import static eu.engys.core.project.system.ControlDict.START_FROM_VALUES; +import static eu.engys.core.project.system.ControlDict.START_TIME_KEY; +import static eu.engys.core.project.system.ControlDict.START_TIME_VALUE; +import static eu.engys.core.project.system.ControlDict.STOP_AT_KEY; +import static eu.engys.core.project.system.ControlDict.TIME_FORMAT_KEY; +import static eu.engys.core.project.system.ControlDict.TIME_FORMAT_VALUES; +import static eu.engys.core.project.system.ControlDict.TIME_PRECISION_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_COMPRESSION_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_COMPRESSION_VALUES; +import static eu.engys.core.project.system.ControlDict.WRITE_CONTROL_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_CONTROL_VALUES; +import static eu.engys.core.project.system.ControlDict.WRITE_FORMAT_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_FORMAT_VALUES; +import static eu.engys.core.project.system.ControlDict.WRITE_INTERVAL_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_PRECISION_KEY; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.inject.Inject; +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.Solver; +import eu.engys.core.project.state.State; +import eu.engys.core.project.system.ControlDict; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.util.Symbols; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.SelectionValueConfigurator; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; + +public class RuntimeControlsPanel extends DefaultGUIPanel { + + public static final String RUNTIME_CONTROLS = "Runtime Controls"; + + public static final String DATA_WRITING_LABEL = "Data Writing"; + public static final String TIME_SETTINGS_LABEL = "Time Settings"; + public static final String GRAPH_FORMAT_LABEL = "Graph Format"; + public static final String TIME_PRECISION_LABEL = "Time Precision"; + public static final String TIME_FORMAT_LABEL = "Time Format"; + public static final String WRITE_COMPRESSION_LABEL = "Write Compression"; + public static final String WRITE_PRECISION_LABEL = "Write Precision"; + public static final String WRITE_FORMAT_LABEL = "Write Format"; + public static final String PURGE_WRITE_LABEL = "Purge Write"; + public static final String WRITE_CONTROL_LABEL = "Write Control"; + public static final String MAX_TIME_STEP_LABEL = "Max Time Step"; + public static final String MAX_COURANT_ALPHA_LABEL = "Max Courant Alpha"; + public static final String MAX_COURANT_NUMBER_LABEL = "Max Courant Number"; + public static final String ADJUSTABLE_TIME_STEP_LABEL = "Adjustable Time Step"; + public static final String DELTA_T_LABEL = Symbols.DELTA_T + "(s)"; + public static final String END_TIME_LABEL = "End Time"; + public static final String START_FROM_LABEL = "Start From"; + + // public static final String J_PLOT_LABEL = "JPlot"; + // public static final String GRACE_XMRG_LABEL = "Grace/XMRG"; + // public static final String GNU_PLOT_LABEL = "GNUPlot"; + public static final String RAW_LABEL = "Raw"; + // public static final String SCIENTIFIC_LABEL = "Scientific"; + // public static final String FIXED_LABEL = "Fixed"; + public static final String GENERAL_LABEL = "General"; + public static final String COMPRESSED_LABEL = "Compressed"; + public static final String UNCOMPRESSED_LABEL = "Uncompressed"; + // public static final String BINARY_LABEL = "Binary"; + public static final String ASCII_LABEL = "ASCII"; + public static final String CLOCK_TIME_LABEL = "Clock Time"; + public static final String CPU_TIME_LABEL = "CPU Time"; + public static final String RUN_TIME_LABEL = "Run Time"; + public static final String TIME_STEP_LABEL = "Time Step"; + public static final String START_TIME_LABEL = "Start Time"; + public static final String LATEST_TIME_LABEL = "Latest Time"; + public static final String FIRST_TIME_LABEL = "First Time"; + public static final String[] START_FROM_LABELS = { FIRST_TIME_LABEL, LATEST_TIME_LABEL, START_TIME_LABEL }; + public static final String[] WRITE_CONTROL_LABELS = { TIME_STEP_LABEL, RUN_TIME_LABEL, CPU_TIME_LABEL, CLOCK_TIME_LABEL }; + public static final String[] WRITE_FORMAT_LABELS = { ASCII_LABEL }; + // public static final String[] WRITE_FORMAT_LABELS = { ASCII_LABEL, + // BINARY_LABEL }; + public static final String[] WRITE_COMPRESSION_LABELS = { UNCOMPRESSED_LABEL, COMPRESSED_LABEL }; + public static final String[] TIME_FORMAT_LABELS = { GENERAL_LABEL }; + // public static final String[] TIME_FORMAT_LABELS = { GENERAL_LABEL, + // FIXED_LABEL, SCIENTIFIC_LABEL }; + public static final String[] GRAPH_FORMAT_LABELS = { RAW_LABEL }; + // public static final String[] GRAPH_FORMAT_LABELS = { RAW_LABEL, + // GNU_PLOT_LABEL, GRACE_XMRG_LABEL, J_PLOT_LABEL }; + + private DictionaryModel dictionaryModel; + private JCheckBox adjustableTime; + private JComponent maxCourantNumber; + private JComponent maxAlphaCourant; + private JComponent maxTimeStep; + private DoubleField deltaT; + private Solver solver = null; + + private boolean isSaving = false; + + @Inject + public RuntimeControlsPanel(Model model) { + super(RUNTIME_CONTROLS, model); + } + + @Override + public void start() { + super.start(); + updatePanel(model.getState()); + } + + protected JComponent layoutComponents() { + dictionaryModel = new DictionaryModel(new Dictionary("")); + PanelBuilder timeBuilder = new PanelBuilder(); + + JComboBox startFrom = dictionaryModel.bindSelection(START_FROM_KEY, START_FROM_VALUES, START_FROM_LABELS); + final DoubleField startTime = dictionaryModel.bindDouble(START_TIME_KEY); + DoubleField endTime = dictionaryModel.bindDouble(END_TIME_KEY); + + timeBuilder.addComponent(START_FROM_LABEL, startFrom, startTime); + timeBuilder.addComponent(END_TIME_LABEL, endTime); + + startTime.setEnabled(false); + startFrom.addPropertyChangeListener("value", new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + startTime.setEnabled(START_TIME_VALUE.equals(evt.getNewValue())); + } + }); + + deltaT = dictionaryModel.bindDouble(DELTA_T_KEY); + timeBuilder.addComponent(DELTA_T_LABEL, deltaT); + + adjustableTime = dictionaryModel.bindBoolean(ADJUST_TIME_STEP_KEY); + maxCourantNumber = dictionaryModel.bindDouble(MAX_CO_KEY); + maxAlphaCourant = dictionaryModel.bindDouble(MAX_ALPHA_CO_KEY); + maxTimeStep = dictionaryModel.bindDouble(MAX_DELTA_T_KEY); + + timeBuilder.addComponent(ADJUSTABLE_TIME_STEP_LABEL, adjustableTime); + timeBuilder.addComponent(MAX_COURANT_NUMBER_LABEL, maxCourantNumber); + timeBuilder.addComponent(MAX_COURANT_ALPHA_LABEL, maxAlphaCourant); + timeBuilder.addComponent(MAX_TIME_STEP_LABEL, maxTimeStep); + + adjustableTime.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + maxCourantNumber.setEnabled(adjustableTime.isSelected()); + maxAlphaCourant.setEnabled(adjustableTime.isSelected() && model.getState().getMultiphaseModel().isMultiphase()); + maxTimeStep.setEnabled(adjustableTime.isSelected()); + } + }); + adjustableTime.setSelected(false); + maxCourantNumber.setEnabled(false); + maxAlphaCourant.setEnabled(false); + maxTimeStep.setEnabled(false); + + PanelBuilder dataWriteBuilder = new PanelBuilder(); + SelectionValueConfigurator conf = new SelectionValueConfigurator() { + @Override + public String write(String value) { + if (value != null && value.equals(RUN_TIME_VALUE) && adjustableTime.isSelected()) + return ADJUSTABLE_RUN_TIME_KEY; + return value; + } + + @Override + public String read(String value) { + if (value != null && value.equals(ADJUSTABLE_RUN_TIME_KEY)) + return RUN_TIME_VALUE; + return value; + } + }; + dataWriteBuilder.addComponent(WRITE_CONTROL_LABEL, dictionaryModel.bindSelection(WRITE_CONTROL_KEY, WRITE_CONTROL_VALUES, WRITE_CONTROL_LABELS, conf), dictionaryModel.bindDouble(WRITE_INTERVAL_KEY)); + dataWriteBuilder.addComponent(PURGE_WRITE_LABEL, dictionaryModel.bindIntegerPositive(PURGE_WRITE_KEY)); + + JComboBox writeFormat = dictionaryModel.bindSelection(WRITE_FORMAT_KEY, WRITE_FORMAT_VALUES, WRITE_FORMAT_LABELS); + writeFormat.setEnabled(false); + dataWriteBuilder.addComponent(WRITE_FORMAT_LABEL, writeFormat); + + dataWriteBuilder.addComponent(WRITE_PRECISION_LABEL, dictionaryModel.bindIntegerPositive(WRITE_PRECISION_KEY)); + dataWriteBuilder.addComponent(WRITE_COMPRESSION_LABEL, dictionaryModel.bindSelection(WRITE_COMPRESSION_KEY, WRITE_COMPRESSION_VALUES, WRITE_COMPRESSION_LABELS)); + + JComboBox timeFormat = dictionaryModel.bindSelection(TIME_FORMAT_KEY, TIME_FORMAT_VALUES, TIME_FORMAT_LABELS); + timeFormat.setEnabled(false); + dataWriteBuilder.addComponent(TIME_FORMAT_LABEL, timeFormat); + + dataWriteBuilder.addComponent(TIME_PRECISION_LABEL, dictionaryModel.bindIntegerPositive(TIME_PRECISION_KEY)); + + JComboBox graphFormat = dictionaryModel.bindSelection(GRAPH_FORMAT_KEY, GRAPH_FORMAT_VALUE, GRAPH_FORMAT_LABELS); + graphFormat.setEnabled(false); + dataWriteBuilder.addComponent(GRAPH_FORMAT_LABEL, graphFormat); + + JPanel timePanel = timeBuilder.margins(.5, .5, .5, .5).getPanel(); + timePanel.setBorder(BorderFactory.createTitledBorder(TIME_SETTINGS_LABEL)); + timePanel.setName(TIME_SETTINGS_LABEL); + + JPanel dataWritePanel = dataWriteBuilder.margins(.5, .5, .5, .5).getPanel(); + dataWritePanel.setBorder(BorderFactory.createTitledBorder(DATA_WRITING_LABEL)); + dataWritePanel.setName(DATA_WRITING_LABEL); + + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(timePanel); + builder.addComponent(dataWritePanel); + + return builder.removeMargins().getPanel(); + } + + @Override + public void load() { + loadControlDict(); + updatePanel(model.getState()); + } + + @Override + public void save() { + ControlDict controlDict = getModel().getProject().getSystemFolder().getControlDict(); + if (controlDict != null) { + boolean changed = hasControlDictChanged(controlDict); + controlDict.merge(dictionaryModel.getDictionary()); + controlDict.add(STOP_AT_KEY, END_TIME_KEY); + if (changed) { + isSaving = true; + model.projectChanged(); + isSaving = false; + } + } + } + + private boolean hasControlDictChanged(ControlDict controlDict) { + ControlDict d = new ControlDict(controlDict); + d.remove(ControlDict.FUNCTIONS_KEY); + return !d.toString().equals(dictionaryModel.getDictionary().toString()); + } + + @Override + public void stateChanged() { + super.stateChanged(); + State state = model.getState(); + + if (this.solver == null || !(state.getSolver().equals(this.solver))) { + this.solver = state.getSolver(); + loadControlDict(); + updatePanel(state); + } else { + /* + * Entro qua se ho cambiato solo turbulence model e quindi non serve + * svrazzare via quello che ce nella GUI Il file controlDict ora + * contiene i valori di default. Lo mergio con i valori della GUI + * per non perdere i cambiamenti fatti. Ovviamente questo significa + * che quello che ce nella GUI...rimane! + */ + Dictionary controlDict = model.getProject().getSystemFolder().getControlDict(); + if (controlDict != null) { + controlDict.merge(dictionaryModel.getDictionary()); + } + } + } + + @Override + public void projectChanged() { + if (!isSaving) { + loadControlDict(); + } + } + + private void loadControlDict() { + ControlDict controlDict = model.getProject().getSystemFolder().getControlDict(); + if (controlDict != null) { + Dictionary dictionary = new Dictionary(controlDict); + dictionary.remove(FUNCTIONS_KEY); + dictionaryModel.setDictionary(dictionary); + } + } + + private void updatePanel(final State state) { + this.solver = state.getSolver(); + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + boolean isTransient = state.isTransient(); + boolean isSteadyMultiphase = state.isSteady() && state.getMultiphaseModel().isMultiphase(); + boolean isSteadyCoupled = state.isSteady() && state.getSolverType().isCoupled(); + + if (isTransient || isSteadyMultiphase || isSteadyCoupled) { + deltaT.setEnabled(true); + } else { + deltaT.setEnabled(false); + deltaT.setDoubleValue(1); + } + + adjustableTime.setEnabled((isTransient || isSteadyMultiphase) && !isSonic(state)); + maxCourantNumber.setEnabled((isTransient || isSteadyMultiphase) && adjustableTime.isSelected()); + maxAlphaCourant.setEnabled((isTransient || isSteadyMultiphase) && adjustableTime.isSelected() && state.getMultiphaseModel().isMultiphase()); + maxTimeStep.setEnabled((isTransient || isSteadyMultiphase) && adjustableTime.isSelected()); + } + }); + } + + private boolean isSonic(State state) { + return state.isHighMach() && state.getSolverFamily().isPimple(); + } +} diff --git a/src/eu/engys/gui/casesetup/actions/DecomposeCase.java b/src/eu/engys/gui/casesetup/actions/DecomposeCase.java new file mode 100644 index 0000000..ebbab68 --- /dev/null +++ b/src/eu/engys/gui/casesetup/actions/DecomposeCase.java @@ -0,0 +1,139 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.actions; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.loadEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.printHeader; +import static eu.engys.core.OpenFOAMEnvironment.printVariables; +import static eu.engys.core.project.openFOAMProject.LOG; +import static eu.engys.util.OpenFOAMCommands.DECOMPOSE_PAR; +import static eu.engys.util.OpenFOAMCommands.DECOMPOSE_PAR_ALLREGIONS; +import static eu.engys.util.OpenFOAMCommands.DECOMPOSE_PAR_CONSTANT; +import static eu.engys.util.OpenFOAMCommands.DECOMPOSE_PAR_CONSTANT_ALLREGIONS; + +import java.io.File; +import java.nio.file.Paths; +import java.util.concurrent.Executors; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.Controller.OpenOptions; +import eu.engys.core.controller.ScriptBuilder; +import eu.engys.core.controller.actions.AbstractRunCommand; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorHook; +import eu.engys.core.executor.ExecutorListener.ExecutorState; +import eu.engys.core.executor.ExecutorMonitor; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.util.IOUtils; +import eu.engys.util.Util; + +public class DecomposeCase extends AbstractRunCommand { + + private static final String DECOMPOSE_RUN = "decomposeCase.run"; + private static final String DECOMPOSE_BAT = "decomposeCase.bat"; + + private File logFile; + private String actionName; + private String logName; + + public DecomposeCase(Model model, Controller controller, String actionName, String logName) { + super(model, controller); + this.actionName = actionName; + this.logName = logName; + this.logFile = Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, logName).toFile(); + } + + @Override + public void beforeExecute() { + IOUtils.clearFile(logFile); + } + + @Override + public void executeClient() { + File script = getScript(); + File baseDir = model.getProject().getBaseDir(); + + if (terminal == null) { + this.terminal = new TerminalExecutorMonitor(logFile); + } + if (service == null) { + this.service = Executors.newSingleThreadExecutor(); + } + + ExecutorMonitor monitor = new ExecutorMonitor(); + monitor.addHook(ExecutorState.FINISH, new FinishHook()); + + this.executor = Executor.script(script).description(actionName).inFolder(baseDir).inTerminal(terminal).withMonitors(monitor).inService(service).env(getEnvironment(model, logName)); + executor.exec(); + } + + private File getScript() { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? DECOMPOSE_BAT : DECOMPOSE_RUN); + ScriptBuilder sb = new ScriptBuilder(); + writeScript(sb); + + IOUtils.writeLinesToFile(file, sb.getLines()); + + file.setExecutable(true); + return file; + } + + private void writeScript(ScriptBuilder sb) { + printHeader(sb, actionName.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + writeCommand(sb); + } + + private void writeCommand(ScriptBuilder sb) { + if (model.getProject().isMeshOnZero() || model.getProject().isSerial()) { + if (model.getProject().getZeroFolder().hasRegions()) { + sb.append(DECOMPOSE_PAR_ALLREGIONS()); + } else { + sb.append(DECOMPOSE_PAR()); + } + } else { + if (model.getProject().getZeroFolder().hasRegions()) { + sb.append(DECOMPOSE_PAR_CONSTANT_ALLREGIONS()); + } else { + sb.append(DECOMPOSE_PAR_CONSTANT()); + } + } + } + + private class FinishHook implements ExecutorHook { + + @Override + public void run(ExecutorMonitor monitor) { + if (controller.getListener() != null) { + controller.reopenCase(OpenOptions.PARALLEL); + } + } + } + +} diff --git a/src/eu/engys/gui/casesetup/actions/DecomposeCaseAction.java b/src/eu/engys/gui/casesetup/actions/DecomposeCaseAction.java new file mode 100644 index 0000000..d0aa40c --- /dev/null +++ b/src/eu/engys/gui/casesetup/actions/DecomposeCaseAction.java @@ -0,0 +1,129 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.actions; + +import static eu.engys.core.project.openFOAMProject.LOG; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.nio.file.Paths; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.swing.Icon; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.OpenFOAMEnvironment; +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.actions.RunCommand; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.util.IOUtils; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class DecomposeCaseAction extends ViewAction { + + private static final Logger logger = LoggerFactory.getLogger(DecomposeCaseAction.class); + + private static final Icon DECOMPOSE_ICON = ResourcesUtil.getIcon("decompose.icon"); + private static final String DECOMPOSE_LABEL = ResourcesUtil.getString("casesetup.decompose.label"); + private static final String DECOMPOSE_TOOLTIP = ResourcesUtil.getString("casesetup.decompose.tooltip"); + + public static final String ACTION_NAME = "Decompose"; + public static final String LOG_NAME = "decomposeCase.log"; + + private Model model; + private Controller controller; + + private boolean shouldUseWithZeroFlag; + + public DecomposeCaseAction(Model model, Controller controller, boolean shouldUseWithZeroFlag) { + super(DECOMPOSE_LABEL, DECOMPOSE_ICON, DECOMPOSE_TOOLTIP); + this.model = model; + this.controller = controller; + this.shouldUseWithZeroFlag = shouldUseWithZeroFlag; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (controller.isDemo()) { + UiUtil.showDemoMessage(); + } else { + if (OpenFOAMEnvironment.isEnvironementLoaded()) { + _actionPerformed(); + } else { + UiUtil.showCoreEnvironmentNotLoadedWarning(); + } + } + } + + private void _actionPerformed() { + DecomposeCasePanel panel = new DecomposeCasePanel(model); + panel.showDialog(); + if (panel.getStatus().isOK()) { + controller.saveCase(model.getProject().getBaseDir()); + decompose(); + } + } + + private void decompose() { + if (model.getProject().isParallel()) { + decomposeParallelCase(); + } else { + decomposeSerialCase(); + } + } + + private void decomposeSerialCase() { + RunCommand command = new DecomposeCase(model, controller, ACTION_NAME, LOG_NAME); + command.beforeExecute(); + command.executeClient(); + } + + private void decomposeParallelCase() { + File logFile = Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, LOG_NAME).toFile(); + + IOUtils.clearFile(logFile); + + TerminalExecutorMonitor terminal = new TerminalExecutorMonitor(logFile); + ExecutorService service = Executors.newSingleThreadExecutor(); + + RunCommand reconstructCase = new ReconstructCase(model, controller, shouldUseWithZeroFlag, ACTION_NAME, LOG_NAME); + reconstructCase.inService(service); + reconstructCase.inTerminal(terminal); + reconstructCase.executeClient(); + + RunCommand decomposeCase = new DecomposeCase(model, controller, ACTION_NAME, LOG_NAME); + decomposeCase.inService(service); + decomposeCase.inTerminal(terminal); + decomposeCase.executeClient(); + } + +} diff --git a/src/eu/engys/gui/casesetup/actions/DecomposeCasePanel.java b/src/eu/engys/gui/casesetup/actions/DecomposeCasePanel.java new file mode 100644 index 0000000..3566091 --- /dev/null +++ b/src/eu/engys/gui/casesetup/actions/DecomposeCasePanel.java @@ -0,0 +1,286 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.actions; + +import static eu.engys.core.project.system.DecomposeParDict.DELTA_KEY; +import static eu.engys.core.project.system.DecomposeParDict.HIERARCHICAL_COEFFS_KEY; +import static eu.engys.core.project.system.DecomposeParDict.HIERARCHICAL_KEY; +import static eu.engys.core.project.system.DecomposeParDict.METHOD_KEY; +import static eu.engys.core.project.system.DecomposeParDict.NUMBER_OF_SUBDOMAINS_KEY; +import static eu.engys.core.project.system.DecomposeParDict.N_KEY; +import static eu.engys.core.project.system.DecomposeParDict.ORDER_KEY; +import static eu.engys.core.project.system.DecomposeParDict.SCOTCH_KEY; +import static eu.engys.core.project.system.DecomposeParDict.TYPE_KEYS; +import static eu.engys.core.project.system.DecomposeParDict.YXZ_KEY; +import static eu.engys.util.ui.ComponentsFactory.labelArrayField; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.DecomposeParDict; +import eu.engys.util.Util; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.IntegerField; + +public class DecomposeCasePanel extends JPanel { + + public static final String DECOMPOSE_CASE_LABEL = "Decompose Case"; + public static final String HIERARCHY_LABEL = "Hierarchy"; + public static final String PROCESSORS_LABEL = "Processors"; + public static final String DECOMPOSITION_TYPE_LABEL = "Decomposition Type"; + + public static final String HIERARCHICAL_LABEL = "Hierarchical"; + public static final String SCOTCH_LABEL = "Scotch"; + private static final String[] TYPE_LABELS = { HIERARCHICAL_LABEL, SCOTCH_LABEL }; + + public enum Status { + OK, CANCEL; + + public boolean isOK() { + return this == OK; + } + + public boolean isCancel() { + return this == CANCEL; + } + } + + private final int X = 1; + private final int Y = 0; + private final int Z = 2; + +// private OkDialogAction okAction = new OkDialogAction(); +// private CancelDialogAction cancelAction = new CancelDialogAction(); + + private JDialog dialog; + + private Model model; + private DictionaryModel mainModel; + private DictionaryModel hierarchicalDictionaryModel; + private IntegerField nProcessorsField; + private IntegerField[] nHierarchyField; + private JComboBox decompositionType; + private Status status = Status.CANCEL; + + public DecomposeCasePanel(Model model) { + super(new BorderLayout()); + setName("decompose.panel"); + this.model = model; + this.mainModel = new DictionaryModel(); + this.hierarchicalDictionaryModel = new DictionaryModel(); + layoutComponents(); + } + + public void load() { + DecomposeParDict decomposeParDict = model.getProject().getSystemFolder().getDecomposeParDict(); + Dictionary dictionary = new Dictionary(decomposeParDict); + dictionary.remove(HIERARCHICAL_COEFFS_KEY); + mainModel.setDictionary(dictionary); + Dictionary coeffsDict = decomposeParDict.isDictionary(HIERARCHICAL_COEFFS_KEY) ? new Dictionary(decomposeParDict.subDict(HIERARCHICAL_COEFFS_KEY)) : new Dictionary(HIERARCHICAL_COEFFS_KEY); + + hierarchicalDictionaryModel.setDictionary(coeffsDict); + recalculateFactors(); + } + + private void layoutComponents() { + PanelBuilder builder = new PanelBuilder(); + decompositionType = mainModel.bindSelection(METHOD_KEY, TYPE_KEYS, TYPE_LABELS); + nProcessorsField = mainModel.bindIntegerPositive(NUMBER_OF_SUBDOMAINS_KEY); + nHierarchyField = hierarchicalDictionaryModel.bindIntegerArray(N_KEY, 3); + + builder.addComponent(DECOMPOSITION_TYPE_LABEL, decompositionType); + builder.addComponent(PROCESSORS_LABEL, nProcessorsField); + builder.addComponent(labelArrayField("x", "y", "z")); + builder.addComponent(HIERARCHY_LABEL, nHierarchyField); + + for (IntegerField f : nHierarchyField) + f.setEnabled(false); + + decompositionType.addPropertyChangeListener("value", new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + for (IntegerField f : nHierarchyField) + f.setEnabled(HIERARCHICAL_KEY.equals(evt.getNewValue())); + + } + }); + nProcessorsField.addPropertyChangeListener(new RecalculateFactorsOnChange()); + nProcessorsField.setIntValue(1); + + add(builder.getPanel()); + } + + public void showDialog() { + createDialog(); + load(); + dialog.setVisible(true); + } + + private void createDialog() { + if (dialog == null) { + dialog = new JDialog(UiUtil.getActiveWindow(), DECOMPOSE_CASE_LABEL); + dialog.setName("create.case.dialog"); + + AbstractAction saveAndCloseDialogAction = new AbstractAction("OK") { + @Override + public void actionPerformed(ActionEvent e) { + if (TYPE_KEYS[0].equals(decompositionType.getSelectedItem()) && !productEqualsToNumberOfSubdomain()) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Product of Hierarchical Coefficients should be equal to the Number of Processors", "Decomposition Error", JOptionPane.ERROR_MESSAGE); + return; + } + save(); + status = Status.OK; + dialog.setVisible(false); + } + }; + + final AbstractAction cancelAction = new AbstractAction("Cancel") { + @Override + public void actionPerformed(ActionEvent e) { + status = Status.CANCEL; + dialog.setVisible(false); + dialog.dispose(); + dialog = null; + } + }; + + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + JButton okButton = new JButton(saveAndCloseDialogAction); + okButton.setName("OK"); + buttonsPanel.add(okButton); + + JButton cancelButton = new JButton(cancelAction); + cancelButton.setName("Cancel"); + buttonsPanel.add(cancelButton); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(this, BorderLayout.CENTER); + mainPanel.add(buttonsPanel, BorderLayout.SOUTH); + + dialog.add(mainPanel); + dialog.setSize(350, 200); + dialog.setLocationRelativeTo(null); + dialog.setModal(true); + dialog.getRootPane().setDefaultButton(okButton); + + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + cancelAction.actionPerformed(null); + } + }); + } + } + + private boolean productEqualsToNumberOfSubdomain() { + int nOfSubdomains = nProcessorsField.getIntValue(); + int x = nHierarchyField[X].getIntValue(); + int y = nHierarchyField[Y].getIntValue(); + int z = nHierarchyField[Z].getIntValue(); + + return nOfSubdomains == x * y * z; + } + + public void save() { + Dictionary d = new Dictionary(mainModel.getDictionary()); + Dictionary hierarchicalModelDictionary = new Dictionary(hierarchicalDictionaryModel.getDictionary()); +// hierarchicalModelDictionary.setName(HIERARCHICAL_COEFFS_KEY); + fixSubdomainsOrder(hierarchicalModelDictionary); + d.add(hierarchicalModelDictionary); + + DecomposeParDict decomposeParDict = model.getProject().getSystemFolder().getDecomposeParDict(); + decomposeParDict.merge(d); + + if (SCOTCH_KEY.equals(decomposeParDict.lookup(METHOD_KEY)) && decomposeParDict.found(HIERARCHICAL_COEFFS_KEY)) { + decomposeParDict.remove(HIERARCHICAL_COEFFS_KEY); + } else if (HIERARCHICAL_KEY.equals(decomposeParDict.lookup(METHOD_KEY)) && decomposeParDict.found(HIERARCHICAL_COEFFS_KEY)) { + Dictionary hCoeffs = decomposeParDict.subDict(HIERARCHICAL_COEFFS_KEY); + if (!hCoeffs.found(DELTA_KEY)) + hCoeffs.add(DELTA_KEY, "0.001"); + if (!hCoeffs.found(ORDER_KEY)) + hCoeffs.add(ORDER_KEY, YXZ_KEY); + } + } + + private void fixSubdomainsOrder(Dictionary dict) { + if (dict.found(N_KEY)) { + String subdomains = dict.lookup(N_KEY); + String noParenthesis = subdomains.replaceAll("\\(", "").replaceAll("\\)", ""); + String trimmedLine = Util.getTrimmedSingleSpaceLine(noParenthesis); + String[] values = trimmedLine.split(" "); + dict.add(N_KEY, "(" + values[1] + " " + values[0] + " " + values[2] + ")"); + } + } + + private void recalculateFactors() { + int np = nProcessorsField.getIntValue(); + + int[] factors = Util.getFactorsFor(np); + nHierarchyField[X].setIntValue(factors[0]); + nHierarchyField[Y].setIntValue(factors[1]); + nHierarchyField[Z].setIntValue(factors[2]); + } + + public Status getStatus() { + return status; + } + + class RecalculateFactorsOnChange implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + recalculateFactors(); + } + } + + } + + /* + * For tests puroposes only + */ + public JDialog getDialog() { + return dialog; + } + +} diff --git a/src/eu/engys/gui/casesetup/actions/DefaultCaseSetupActions.java b/src/eu/engys/gui/casesetup/actions/DefaultCaseSetupActions.java new file mode 100644 index 0000000..c71bb41 --- /dev/null +++ b/src/eu/engys/gui/casesetup/actions/DefaultCaseSetupActions.java @@ -0,0 +1,73 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.actions; + +import java.awt.Component; +import java.util.List; + +import javax.swing.JToolBar; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; +import eu.engys.gui.Actions; +import eu.engys.util.ui.UiUtil; + +public abstract class DefaultCaseSetupActions implements Actions { + + protected Model model; + protected Controller controller; + protected DecomposeCaseAction decomposeCaseAction; + + public DefaultCaseSetupActions(Model model, Controller controller) { + this.model = model; + this.controller = controller; + this.decomposeCaseAction = new DecomposeCaseAction(model, controller, shouldUseWithZeroFlag()); + } + + protected abstract List getToolbarComponents(); + + protected abstract boolean shouldUseWithZeroFlag(); + + @Override + public JToolBar toolbar() { + JToolBar toolbar = UiUtil.getToolbar("view.element.toolbar"); + for (Component c : getToolbarComponents()) { + if (c == null) { + toolbar.addSeparator(); + } else { + toolbar.add(c); + } + } + return toolbar; + } + + + @Override + public void update() { + decomposeCaseAction.setEnabled(!model.getPatches().isEmpty() && !model.getState().getMultiphaseModel().getKey().equals("ECOMARINE")); + } +} diff --git a/src/eu/engys/gui/casesetup/actions/ReconstructCase.java b/src/eu/engys/gui/casesetup/actions/ReconstructCase.java new file mode 100644 index 0000000..1b2f07b --- /dev/null +++ b/src/eu/engys/gui/casesetup/actions/ReconstructCase.java @@ -0,0 +1,128 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.actions; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.loadEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.printHeader; +import static eu.engys.core.OpenFOAMEnvironment.printVariables; +import static eu.engys.core.project.openFOAMProject.LOG; +import static eu.engys.util.OpenFOAMCommands.RECONSTRUCT_PAR; +import static eu.engys.util.OpenFOAMCommands.RECONSTRUCT_PAR_ALLREGIONS; +import static eu.engys.util.OpenFOAMCommands.RECONSTRUCT_PAR_MESH; +import static eu.engys.util.OpenFOAMCommands.RECONSTRUCT_PAR_MESH_ALLREGIONS; +import static eu.engys.util.OpenFOAMCommands.RECONSTRUCT_PAR_MESH_CONSTANT; +import static eu.engys.util.OpenFOAMCommands.RECONSTRUCT_PAR_MESH_CONSTANT_ALLREGIONS; + +import java.io.File; +import java.nio.file.Paths; +import java.util.concurrent.Executors; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.ScriptBuilder; +import eu.engys.core.controller.actions.AbstractRunCommand; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.util.IOUtils; +import eu.engys.util.Util; + +public class ReconstructCase extends AbstractRunCommand { + + private static final String RECONSTRUCT_CASE_RUN = "reconstructCase.run"; + private static final String RECONSTRUCT_CASE_BAT = "reconstructCase.bat"; + + private String actionName; + private String logName; + private File logFile; + private boolean shouldUseWithZeroFlag; + + public ReconstructCase(Model model, Controller controller, boolean shouldUseWithZeroFlag, String actionName, String logName) { + super(model, controller); + this.shouldUseWithZeroFlag = shouldUseWithZeroFlag; + this.actionName = actionName; + this.logName = logName; + this.logFile = Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, logName).toFile(); + } + + @Override + public void executeClient() { + File script = getScript(); + File baseDir = model.getProject().getBaseDir(); + + if (terminal == null) { + this.terminal = new TerminalExecutorMonitor(logFile); + } + if (service == null) { + this.service = Executors.newSingleThreadExecutor(); + } + + this.executor = Executor.script(script).description(actionName).inFolder(baseDir).inTerminal(terminal).inService(service).env(getEnvironment(model, logName)); + executor.exec(); + } + + private File getScript() { + File file = new File(model.getProject().getBaseDir(), Util.isWindows() ? RECONSTRUCT_CASE_BAT : RECONSTRUCT_CASE_RUN); + ScriptBuilder sb = new ScriptBuilder(); + writeScript(sb); + IOUtils.writeLinesToFile(file, sb.getLines()); + file.setExecutable(true); + return file; + } + + private void writeScript(ScriptBuilder sb) { + printHeader(sb, actionName.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + writeCommand(sb); + } + + private void writeCommand(ScriptBuilder sb) { + boolean meshOnZero = model.getProject().isMeshOnZero(); + + if (meshOnZero) { + if (model.getProject().getZeroFolder().hasRegions()) { + sb.append(RECONSTRUCT_PAR_MESH_ALLREGIONS()); + } else { + sb.append(RECONSTRUCT_PAR_MESH()); + } + } else { + if (model.getProject().getZeroFolder().hasRegions()) { + sb.append(RECONSTRUCT_PAR_MESH_CONSTANT_ALLREGIONS()); + } else { + sb.append(RECONSTRUCT_PAR_MESH_CONSTANT()); + } + } + + if (model.getProject().getZeroFolder().hasRegions()) { + sb.append(RECONSTRUCT_PAR_ALLREGIONS(shouldUseWithZeroFlag)); + } else { + sb.append(RECONSTRUCT_PAR(shouldUseWithZeroFlag)); + } + + } + +} diff --git a/src/eu/engys/gui/casesetup/actions/StandardCaseSetupActions.java b/src/eu/engys/gui/casesetup/actions/StandardCaseSetupActions.java new file mode 100644 index 0000000..15ac948 --- /dev/null +++ b/src/eu/engys/gui/casesetup/actions/StandardCaseSetupActions.java @@ -0,0 +1,58 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.actions; + +import static eu.engys.util.ui.UiUtil.createToolBarButton; + +import java.awt.Component; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; +import eu.engys.util.progress.ProgressMonitor; + +public class StandardCaseSetupActions extends DefaultCaseSetupActions { + + @Inject + public StandardCaseSetupActions(Model model, Controller controller, ProgressMonitor monitor) { + super(model, controller); + } + + @Override + protected List getToolbarComponents() { + List components = new ArrayList<>(); + components.add(createToolBarButton(decomposeCaseAction)); + return components; + } + + @Override + protected boolean shouldUseWithZeroFlag() { + return true; + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/AbstractInterpolationTable.java b/src/eu/engys/gui/casesetup/boundaryconditions/AbstractInterpolationTable.java new file mode 100644 index 0000000..00b3ac9 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/AbstractInterpolationTable.java @@ -0,0 +1,405 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.boundaryconditions; + +import static eu.engys.util.RegexpUtils.CLOSED_BRACKET; +import static eu.engys.util.RegexpUtils.DOUBLE; +import static eu.engys.util.RegexpUtils.OPEN_BRACKET; +import static eu.engys.util.RegexpUtils.POINT; +import static eu.engys.util.RegexpUtils.SPACES; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.EventObject; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.DefaultCellEditor; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; +import javax.swing.text.JTextComponent; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlock; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.gui.solver.postprocessing.data.DoubleTimeBlockUnit; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.CopyPasteSupport; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.textfields.DoubleField; + +public abstract class AbstractInterpolationTable extends JPanel { + + private static final String VALUE_VAR = "Value"; + private static final String Z_VAR = "Z"; + private static final String Y_VAR = "Y"; + private static final String X_VAR = "X"; + private static final String VECTOR_PATTERN = OPEN_BRACKET + SPACES + DOUBLE + SPACES + POINT + SPACES + CLOSED_BRACKET; + private static final String SCALAR_PATTERN = OPEN_BRACKET + SPACES + DOUBLE + SPACES + DOUBLE + SPACES + CLOSED_BRACKET; + + private JTable table; + private DefaultTableModel tableModel; + private InterpolationChartPanel chart; + protected String[] columnNames; + private JButton removeButton; + private JSplitPane splitPane; + private JPanel topPanel; + private JPanel bottomPanel; + private JDialog dialog; + private JButton okButton; + protected String[] names; + + public AbstractInterpolationTable(String[] names) { + super(new BorderLayout()); + this.names = names; + setName("interpolation.table"); + setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + setupColumnNames(); + layoutComponents(); + } + + public abstract void load(); + + public boolean isVector() { + return names.length == 3; + } + + public StringBuilder save() { + StringBuilder sb = new StringBuilder(); + sb.append("(\n"); + for (int row = 0; row < table.getRowCount(); row++) { + if (isVector()) { + Double distance = ((Double) table.getValueAt(row, 0)); + double x = ((Double) table.getValueAt(row, 1)); + double y = ((Double) table.getValueAt(row, 2)); + double z = ((Double) table.getValueAt(row, 3)); + String interpolationRow = "( " + distance + " ( " + x + " " + y + " " + z + " ) )"; + sb.append(interpolationRow + "\n"); + } else { + Double time = ((Double) table.getValueAt(row, 0)); + double value = ((Double) table.getValueAt(row, 1)); + String interpolationRow = "( " + time + " " + value + " )"; + sb.append(interpolationRow + "\n"); + } + } + sb.append(")"); + return sb; + } + + protected void loadTable(String tableData) { + if (tableData.startsWith("(") && tableData.endsWith(")")) { + tableData = tableData.substring(1, tableData.length() - 1).trim(); + try { + Pattern regex = Pattern.compile(isVector() ? VECTOR_PATTERN : SCALAR_PATTERN); + Matcher regexMatcher = regex.matcher(tableData); + while (regexMatcher.find()) { + addRow(parseRows(regexMatcher.group(0))); + } + } catch (PatternSyntaxException ex) { + ex.printStackTrace(); + } + } + } + + private Double[] parseRows(String row) { + Pattern innerRegex = Pattern.compile(DOUBLE); + Matcher innerRegexMatcher = innerRegex.matcher(row); + Double[] values = isVector() ? new Double[4] : new Double[2]; + int internalCount = 0; + while (innerRegexMatcher.find()) { + values[internalCount++] = Double.parseDouble(innerRegexMatcher.group(0)); + } + return values; + } + + /* + * GUI + */ + + protected abstract void setupColumnNames(); + + private void layoutComponents() { + createSplitPane(); + add(splitPane, BorderLayout.CENTER); + createTableButtons(); + createTable(); + createChart(); + createDialogButtons(); + createDialog(); + } + + private void createDialog() { + dialog = new JDialog(UiUtil.getActiveWindow(), "Interpolation Table", ModalityType.MODELESS); + dialog.setName("interpolation.dialog"); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + handleDialogClose_Cancel(); + } + }); + + dialog.add(this); + dialog.setSize(600, 600); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.getRootPane().setDefaultButton(okButton); + } + + public void showDialog() { + load(); + dialog.setVisible(true); + } + + private void handleDialogClose_Cancel() { + dialog.setVisible(false); + } + + private void handleDialogClose_OK() { + save(); + dialog.setVisible(false); + } + + private void createSplitPane() { + this.splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + this.splitPane.setOneTouchExpandable(false); + this.topPanel = new JPanel(new BorderLayout()); + this.bottomPanel = new JPanel(new BorderLayout()); + this.splitPane.setTopComponent(topPanel); + this.splitPane.setBottomComponent(bottomPanel); + this.splitPane.setResizeWeight(0.5); + } + + private void createTableButtons() { + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + JButton addButton = new JButton(new AbstractAction("+") { + + @Override + public void actionPerformed(ActionEvent e) { + addRow(); + } + }); + addButton.setName("add.row.button"); + buttonsPanel.add(addButton); + removeButton = new JButton(new AbstractAction("-") { + + @Override + public void actionPerformed(ActionEvent e) { + removeRows(); + } + }); + buttonsPanel.add(removeButton); + removeButton.setName("rem.row.button"); + removeButton.setEnabled(false); + + topPanel.add(buttonsPanel, BorderLayout.NORTH); + } + + private void createDialogButtons() { + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + okButton = new JButton(new AbstractAction("OK") { + + @Override + public void actionPerformed(ActionEvent e) { + handleDialogClose_OK(); + } + }); + okButton.setName("OK"); + JButton cancelButton = new JButton(new AbstractAction("Cancel") { + + @Override + public void actionPerformed(ActionEvent e) { + handleDialogClose_Cancel(); + } + }); + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + bottomPanel.add(buttonsPanel, BorderLayout.SOUTH); + } + + private void createTable() { + tableModel = new DefaultTableModel(columnNames, 0) { + @Override + public Class getColumnClass(int columnIndex) { + return Double.class; + } + }; + table = new JTable() { + public boolean editCellAt(int row, int column, EventObject e) { + boolean result = super.editCellAt(row, column, e); + final Component editor = getEditorComponent(); + if (e instanceof KeyEvent && editor instanceof JTextComponent) { + ((JTextComponent) editor).selectAll(); + } + + return result; + } + + }; + ((DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.CENTER); + table.setModel(tableModel); + tableModel.addTableModelListener(new TableModelListener() { + @Override + public void tableChanged(TableModelEvent e) { + if (e.getType() == TableModelEvent.UPDATE) { + updateChart(); + } + } + }); + table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + removeButton.setEnabled(table.getSelectedRowCount() > 0); + } + }); + setupEditors(table); + + CopyPasteSupport.addSupportTo(table); + topPanel.add(new JScrollPane(table), BorderLayout.CENTER); + } + + private void createChart() { + this.chart = new InterpolationChartPanel(getVariablesList(), columnNames[0]); + chart.layoutComponents(); + chart.initSeries(); + bottomPanel.add(chart, BorderLayout.CENTER); + } + + private List getVariablesList() { + List variables = new ArrayList<>(); + if (isVector()) { + variables.add(X_VAR); + variables.add(Y_VAR); + variables.add(Z_VAR); + } else { + variables.add(VALUE_VAR); + } + return variables; + } + + private void setupEditors(JTable table) { + final DoubleField doubleTextField = ComponentsFactory.doubleField(); + doubleTextField.setMargin(new Insets(0, 0, 0, 0)); + + DefaultCellEditor doubleEditor = new DefaultCellEditor(doubleTextField) { + @Override + public Object getCellEditorValue() { + try { + return Double.valueOf(Double.parseDouble((String) super.getCellEditorValue())); + } catch (NumberFormatException e) { + return Double.valueOf(doubleTextField.getDoubleValue()); + } + } + }; + table.setDefaultEditor(Double.class, doubleEditor); + + final TableCellRenderer r = table.getDefaultRenderer(Double.class); + table.setDefaultRenderer(Double.class, new TableCellRenderer() { + private NumberFormat formatter; + + { + formatter = NumberFormat.getInstance(); + formatter.setMaximumFractionDigits(10); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel label = (JLabel) r.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if (value instanceof Double) { + label.setText(formatter.format(value)); + } + return label; + } + }); + + } + + private void addRow() { + Object[] scalarRow = new Object[] { 0.0, 0.0 }; + Object[] vectorRow = new Object[] { 0.0, 0.0, 0.0, 0.0 }; + tableModel.addRow(isVector() ? vectorRow : scalarRow); + updateChart(); + } + + private void addRow(Object[] row) { + tableModel.addRow(row); + updateChart(); + } + + private void removeRows() { + int[] selectedRow = table.getSelectedRows(); + for (int i = selectedRow.length - 1; i >= 0; i--) { + tableModel.removeRow(selectedRow[i]); + updateChart(); + } + } + + private void updateChart() { + chart.clearData(); + TimeBlocks tbs = new TimeBlocks(); + for (int row = 0; row < table.getRowCount(); row++) { + TimeBlock timeBlock = new TimeBlock(((Double) table.getValueAt(row, 0))); + if (isVector()) { + timeBlock.getUnitsMap().put(X_VAR, new DoubleTimeBlockUnit(X_VAR, ((Double) table.getValueAt(row, 1)))); + timeBlock.getUnitsMap().put(Y_VAR, new DoubleTimeBlockUnit(Y_VAR, ((Double) table.getValueAt(row, 2)))); + timeBlock.getUnitsMap().put(Z_VAR, new DoubleTimeBlockUnit(Z_VAR, ((Double) table.getValueAt(row, 3)))); + } else { + timeBlock.getUnitsMap().put(VALUE_VAR, new DoubleTimeBlockUnit(VALUE_VAR, ((Double) table.getValueAt(row, 1)))); + } + tbs.add(timeBlock); + } + chart.addToDataSet(tbs); + } + + protected void clear() { + tableModel.setRowCount(0); + chart.clearData(); + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/BoundaryConditionsPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/BoundaryConditionsPanel.java new file mode 100644 index 0000000..c5d7408 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/BoundaryConditionsPanel.java @@ -0,0 +1,382 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions; + +import static eu.engys.util.ui.ComponentsFactory.selectField; +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; +import javax.swing.Icon; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.modules.boundaryconditions.IBoundaryConditionsPanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.core.project.zero.patches.BoundaryConditionsDefaults; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.Util; +import eu.engys.util.ui.ComponentsFactory.SelectField; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.StringField; + +public class BoundaryConditionsPanel extends AbstractGUIPanel implements IBoundaryConditionsPanel { + + public static final String BOUNDARY_CONDITIONS = "Boundary Conditions"; + public static final String PATCH_TYPE_LABEL = "Patch Type"; + public static final String PATCH_NAME_LABEL = "Patch Name"; + + private CardLayout centerPanelLayout; + private JPanel centerPanel; + + private final Set panels; + private Map panelsByType = new HashMap(); + + private StringField patchNameField; + private SelectField patchTypeField; + + private BoundaryType activeBoundaryType; + + private SelectBoundaryConditionAction selectBoundaryConditionListener; + private BoundaryConditionsTreeNodeManager treeNodeManager; + + private PropertyChangeListener listener; + + private Set modules; + + @Inject + public BoundaryConditionsPanel(Model model, Set modules, Set panels) { + super(BOUNDARY_CONDITIONS, model); + this.treeNodeManager = new BoundaryConditionsTreeNodeManager(model, this); + this.panels = panels; + this.modules = modules; + model.addObserver(treeNodeManager); + } + + protected JComponent layoutComponents() { + centerPanelLayout = new CardLayout(); + centerPanel = new JPanel(centerPanelLayout); + centerPanel.add(new JLabel(), "other"); + + PanelBuilder bcTypeBuider = new PanelBuilder(); + + // qui non usare il panel builder altrimenti il bordo del tabbedpane non + // arriva fino in fondo + JPanel panel = new JPanel(new BorderLayout()); + panel.add(bcTypeBuider.margins(0, 0, 1, 0).getPanel(), BorderLayout.NORTH); + panel.add(centerPanel, BorderLayout.CENTER); + + for (BoundaryTypePanel typePanel : panels) { + addTypePanel(typePanel); + } + + + initNameField(); + initTypeField(); + + bcTypeBuider.addComponent(PATCH_NAME_LABEL, patchNameField); + bcTypeBuider.addComponent(PATCH_TYPE_LABEL, patchTypeField); + + return panel; + } + + @Override + public void addTypePanel(BoundaryTypePanel typePanel) { + BoundaryType type = typePanel.getType(); + if (! panelsByType.containsKey(type)) { + typePanel.layoutPanel(); + panelsByType.put(type, typePanel); + centerPanel.add(typePanel.getPanel(), type.getKey()); + ModulesUtil.configureBoundaryConditionsView(modules, typePanel); + } + } + + @Override + public void removeTypePanel(BoundaryTypePanel typePanel) { + BoundaryType type = typePanel.getType(); + if (panelsByType.containsKey(type)) { + panelsByType.remove(type); + centerPanel.remove(typePanel.getPanel()); + ModulesUtil.configureBoundaryConditionsView(modules, typePanel); + } + } + + private void initTypeField() { + patchTypeField = selectField(); + patchTypeField.setSelectedIndex(-1); + patchTypeField.setEnabled(false); + selectBoundaryConditionListener = new SelectBoundaryConditionAction(patchTypeField); + patchTypeField.addActionListener(selectBoundaryConditionListener); + } + + private void initNameField() { + patchNameField = stringField(); + patchNameField.setEnabled(false); + listener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + Patch[] patches = treeNodeManager.getSelectedValues(); + if (patches.length == 1 && patches[0] != null) { + patches[0].setName(patchNameField.getText()); + treeNodeManager.refreshNode(patches[0]); + } + } + }; + patchNameField.addPropertyChangeListener(listener); + } + + class SelectBoundaryConditionAction implements ActionListener { + private JComboBox patchTypeField; + + public SelectBoundaryConditionAction(JComboBox patchTypeField) { + this.patchTypeField = patchTypeField; + } + + @Override + public void actionPerformed(ActionEvent e) { + String selectedType = (String) patchTypeField.getSelectedItem(); + BoundaryType boundaryType = BoundaryType.getType(selectedType); + BoundaryConditions defaults = BoundaryConditionsDefaults.get(boundaryType.getKey()); + Patch[] patches = treeNodeManager.getSelectedValues(); + if (patches.length > 0) { + for (Patch patch : patches) { + fixAMIPatch(patch); + patch.setBoundaryConditions(new BoundaryConditions(defaults)); + patch.setPhisicalType(boundaryType); + } + } + activateBoundaryMesh(patches); + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) patches); + } + + private void fixAMIPatch(Patch patch) { + if (patch.getPhisicalType().isCyclicAMI() && patch.getDictionary().found("neighbourPatch")) { + String neighboutPatchName = patch.getDictionary().lookup("neighbourPatch"); + for (Patch p : model.getPatches().filterProcBoundary()) { + if (p.getName().equals(neighboutPatchName)) { + p.setPhisicalType(BoundaryType.getDefaultType()); + p.setBoundaryConditions(new BoundaryConditions(BoundaryConditionsDefaults.get(BoundaryType.getDefaultKey()))); + p.setDictionary(new Dictionary("")); + } + } + } + } + } + + public void updateSelection(Patch[] currentSelection) { + updatePatchNameField(currentSelection); + updatePatchTypeField(currentSelection); + activateBoundaryMesh(currentSelection); + } + + private void updatePatchNameField(Patch[] patches) { + patchNameField.removePropertyChangeListener(listener); + if (patches.length == 1) { + patchNameField.setValue(patches[0].getName()); + } else { + StringBuilder sb = new StringBuilder(); + for (Patch patch : patches) { + sb.append(patch.getName() + " "); + } + patchNameField.setValue(sb.toString()); + } + patchNameField.addPropertyChangeListener(listener); + } + + private void updatePatchTypeField(Patch[] patches) { + patchTypeField.removeActionListener(selectBoundaryConditionListener); + if (patches.length > 0) { + patchTypeField.setEnabled(true); + if (patchesAreOfTheSameType(patches)) { + patchTypeField.setSelectedItem(patches[0].getPhisicalType().getKey()); + } else { + patchTypeField.setSelectedItem(null); + } + } else { + patchTypeField.setSelectedItem(null); + patchTypeField.setEnabled(false); + } + patchTypeField.addActionListener(selectBoundaryConditionListener); + } + + private boolean patchesAreOfTheSameType(Patch[] patches) { + BoundaryType type = null; + for (Patch patch : patches) { + if (type == null) + type = patch.getPhisicalType(); + else if (patch.getPhisicalType() != type) + return false; + + } + return true; + } + + private void activateBoundaryMesh(Patch[] patches) { + if (patches.length > 0) { + BoundaryType boundaryType = patchesAreOfTheSameType(patches) ? patches[0].getPhisicalType() : null; + + if (boundaryType != null) { + if (boundaryType.hasBoundaryConditions()) { + // System.out.println("BoundaryConditionsPanel.activateBoundaryMesh() " + // + patches[0].getBoundaryConditions().toDictionary()); + centerPanelLayout.show(centerPanel, boundaryType.getKey()); + panelsByType.get(boundaryType).loadFromPatches(patches); + } else { + centerPanelLayout.show(centerPanel, "other"); + } + } else { + centerPanelLayout.show(centerPanel, "other"); + } + setActiveBoundaryType(boundaryType); + } else { + centerPanelLayout.show(centerPanel, "other"); + setActiveBoundaryType(null); + } + } + + private void setActiveBoundaryType(BoundaryType boundaryType) { + this.activeBoundaryType = boundaryType; + } + + @Override + public void load() { + ModulesUtil.configureBoundaryConditionsView(modules, this); + loadTypeField(); + + BoundaryConditionsDefaults.updateBoundaryConditionsDefaultsByFields(model); + for (BoundaryTypePanel panel : panels) { + panel.stateChanged(); + panel.materialsChanged(); + } + } + + @Override + public void save() { + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) treeNodeManager.getSelectedValues()); + } + + @Override + public void clear() { + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) new Patch[0]); + for (BoundaryTypePanel p : panels) { + p.resetToDefault(); + } + } + + public void savePatches(Patch[] values) { + if (values.length > 0 && activeBoundaryType != null) { + for (int i = 0; i < values.length; i++) { + savePatch(values[i]); + } + } + } + + public void savePatch(Patch patch) { + patch.setPhisicalType(activeBoundaryType); + if (panelsByType.containsKey(activeBoundaryType)) { + panelsByType.get(activeBoundaryType).saveToPatch(patch); + } else { + patch.setBoundaryConditions(null); + } + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + + @Override + public void materialsChanged() { + for (BoundaryTypePanel panel : panels) { + panel.materialsChanged(); + } + } + + @Override + public void stateChanged() { + final Patch[] selectedValues = treeNodeManager.getSelectedValues(); + treeNodeManager.getSelectionHandler().clear(); + + ModulesUtil.configureBoundaryConditionsView(modules, this); + + loadTypeField(); + + BoundaryConditionsDefaults.updateBoundaryConditionsDefaultsByFields(getModel()); + + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + for (BoundaryTypePanel panel : panels) { + panel.stateChanged(); + } + + if (Util.isVarArgsNotNull(selectedValues)) { + treeNodeManager.setSelectedValues(selectedValues); + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) selectedValues); + } + } + }); + } + + private void loadTypeField() { + patchTypeField.removeActionListener(selectBoundaryConditionListener); + patchTypeField.removeAllItems(); + + Map typesMap = BoundaryType.getRegisteredBoundaryTypes(); + for (String type : typesMap.keySet()) { + BoundaryType boundaryType = typesMap.get(type); + + String key = boundaryType.getKey(); + String label = boundaryType.getLabel(); + Icon icon = boundaryType.getIcon(); + + patchTypeField.addItem(key, label, icon); + } + patchTypeField.setSelectedIndex(-1); + patchTypeField.addActionListener(selectBoundaryConditionListener); + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/BoundaryConditionsTreeNodeManager.java b/src/eu/engys/gui/casesetup/boundaryconditions/BoundaryConditionsTreeNodeManager.java new file mode 100644 index 0000000..2195174 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/BoundaryConditionsTreeNodeManager.java @@ -0,0 +1,336 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.boundaryconditions; + +import static eu.engys.core.dictionary.Dictionary.TYPE; + +import java.awt.Component; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; +import javax.swing.JPopupMenu; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreePath; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.SelectPatchesEvent; +import eu.engys.gui.tree.AbstractSelectionHandler; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.SelectionHandler; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.Util; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.checkboxtree.RootVisibleLoadableTreeNode; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class BoundaryConditionsTreeNodeManager extends DefaultTreeNodeManager { + + private static final Logger logger = LoggerFactory.getLogger(BoundaryConditionsTreeNodeManager.class); + public static final String COPY = "Copy"; + public static final String PASTE = "Paste"; + + private Map patchesMap; + private SelectionHandler selectionHandler; + + private CopyAction copyAction; + private PasteAction pasteAction; + + public BoundaryConditionsTreeNodeManager(Model model, BoundaryConditionsPanel panel) { + super(model, panel); + this.root = new RootVisibleLoadableTreeNode(panel.getTitle()); + this.selectionHandler = new BoundaryConditionsSelectionHandler(panel); + this.copyAction = new CopyAction(panel); + this.pasteAction = new PasteAction(); + this.patchesMap = new HashMap<>(); + } + + @Override + public void update(Observable o, Object arg) { + if (arg instanceof Patches) { + logger.debug("Observerd a change: arg is " + arg.getClass()); + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + selectionHandler.disable(); + loadTree(); + makeVisibleItemsChecked(); + expandTree(); + selectionHandler.enable(); + } + }); + } + } + + private void loadTree() { + logger.debug("Load 'Patches' tree"); + clear(); + for (Patch patch : model.getPatches().patchesToDisplay()) { + addPatch(root, patch); + } + treeChanged(root); + } + + private void makeVisibleItemsChecked() { + logger.debug("Make visible items checked: DO NOTHING!"); + } + + private void expandTree() { + getTree().expandNode(getRoot()); + } + + private void addPatch(DefaultMutableTreeNode parent, Patch patch) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(patch); + parent.add(node); + nodeMap.put(patch, node); + patchesMap.put(node, patch); + } + + public Patch[] getSelectedValues() { + if (getTree() != null) { + TreePath[] selectionPaths = getTree().getSelectedDescendantOf(getRoot()); + Patch[] patches = new Patch[selectionPaths.length]; + for (int i = 0; i < selectionPaths.length; i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPaths[i].getLastPathComponent(); + Patch patch = patchesMap.get(node); + patches[i] = patch; + } + return patches; + } + return new Patch[0]; + } + + public void setSelectedValues(Patch[] patches) { + if (getTree() != null) { + TreePath[] selectionPaths = new TreePath[patches.length]; + for (int i = 0; i < patches.length; i++) { + DefaultMutableTreeNode node = nodeMap.get(patches[i]); + selectionPaths[i] = new TreePath(getTree().getPathToRoot(node)); + } + getTree().setSelectionPaths(selectionPaths); + } + } + + public void clear() { + // clear node before selection handler! + clearNode(root); + selectionHandler.clear(); + nodeMap.clear(); + patchesMap.clear(); + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public Class getRendererClass() { + return Patch.class; + } + + @SuppressWarnings("serial") + public DefaultTreeCellRenderer getRenderer() { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object userObject = node.getUserObject(); + + if (userObject instanceof Patch) { + Patch renderedPatch = (Patch) userObject; + setText(renderedPatch.getName()); + setIcon(renderedPatch.getPhisicalType().getIcon()); + } else { + setIcon(null); + } + return this; + } + + }; + } + + @Override + public SelectionHandler getSelectionHandler() { + return selectionHandler; + } + + @Override + public PopUpBuilder getPopUpBuilder() { + return new PopUpBuilder() { + @Override + public void populate(JPopupMenu popUp) { + popUp.add(copyAction).setName(COPY); + popUp.add(pasteAction).setName(PASTE); + } + }; + } + + private final class CopyAction extends AbstractAction { + + private BoundaryConditionsPanel panel; + + public CopyAction(BoundaryConditionsPanel panel) { + super(COPY); + this.panel = panel; + } + + @Override + public void actionPerformed(ActionEvent e) { + Patch[] selectedValues = getSelectedValues(); + if (Util.isVarArgsNotNullAndOfSize(1, selectedValues)) { + Patch patch = selectedValues[0]; + panel.savePatch(patch); + Dictionary bc = patch.getBoundaryConditions().toDictionary(); + bc.add(TYPE, patch.getPhisicalType().getKey()); + StringSelection contents = new StringSelection(bc.toString()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, contents); + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Only Single Selection Allowed", "Copy Error", JOptionPane.ERROR_MESSAGE); + } + } + } + + private final class PasteAction extends AbstractAction { + + public PasteAction() { + super(PASTE); + } + + @Override + public void actionPerformed(ActionEvent e) { + Patch[] selectedValues = getSelectedValues(); + getTree().clearSelection(); + if (Util.isVarArgsNotNull(selectedValues)) { + Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(this); + try { + String dictionaryString = (String) contents.getTransferData(DataFlavor.stringFlavor); + if (dictionaryString.startsWith("\nboundaryConditions")) { + Dictionary dictionary = DictionaryUtils.readDictionary(dictionaryString).getDictionaries().get(0); + BoundaryType type = BoundaryType.getType(dictionary.lookup("type")); + for (Patch patch : selectedValues) { + patch.setPhisicalType(type); + patch.getBoundaryConditions().fromDictionary(dictionary); + } + setSelectedValues(selectedValues); + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Invalid Format", "Paste Error", JOptionPane.ERROR_MESSAGE); + } + } catch (Exception ee) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "An Error Occurred", "Paste Error", JOptionPane.ERROR_MESSAGE); + } + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Empty Selection", "Paste Error", JOptionPane.ERROR_MESSAGE); + } + } + } + + private final class BoundaryConditionsSelectionHandler extends AbstractSelectionHandler { + + private BoundaryConditionsPanel panel; + private Patch[] currentSelection; + + public BoundaryConditionsSelectionHandler(BoundaryConditionsPanel panel) { + this.panel = panel; + } + + @Override + public void handleSelection(boolean fire3DEvent, Object... selection) { + if (currentSelection != null && currentSelection.length > 0) { + panel.savePatches(currentSelection); + } + if (TreeUtil.isConsistent(selection, Patch.class)) { + this.currentSelection = Arrays.copyOf(selection, selection.length, Patch[].class); + } else { + this.currentSelection = new Patch[0]; + } + panel.updateSelection(currentSelection); + getTree().repaint(); + + if (fire3DEvent) { + EventManager.triggerEvent(this, new SelectPatchesEvent(currentSelection)); + } + } + + @Override + public void handleVisibility(VisibleItem item) { + } + + @Override + public void process3DSelectionEvent(Picker picker, Actor actor, boolean keep) { + if (getTree() != null && actor != null && actor.getVisibleItem() instanceof Patch) { + Patch patch = (Patch) actor.getVisibleItem(); + DefaultMutableTreeNode selectedNode = nodeMap.get(patch); + if (selectedNode != null) { + if (keep) { + getTree().addSelectedNode(selectedNode); + } else { + getTree().setSelectedNode(selectedNode); + } + } + } + } + + @Override + public void process3DVisibilityEvent(boolean selected) { + if (getTree() != null) { + for (DefaultMutableTreeNode node : nodeMap.values()) { + if (selected) { + getTree().getCheckManager().selectNode(node); + } else { + getTree().getCheckManager().deselectNode(node); + } + } + } + } + + public void clear() { + currentSelection = null; + } + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/InterpolationChartPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/InterpolationChartPanel.java new file mode 100644 index 0000000..43bab73 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/InterpolationChartPanel.java @@ -0,0 +1,100 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.boundaryconditions; + +import java.util.List; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.xy.XYSeries; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlock; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlockUnit; +import eu.engys.gui.solver.postprocessing.data.DoubleTimeBlockUnit; +import eu.engys.gui.solver.postprocessing.panels.HistoryChartPanel; +import eu.engys.util.ui.textfields.DoubleField; + +public class InterpolationChartPanel extends HistoryChartPanel { + + private static final Logger logger = LoggerFactory.getLogger(InterpolationChartPanel.class); + + public InterpolationChartPanel(List seriesNames, String domainAxisLabel) { + super("", seriesNames, domainAxisLabel, "", false); + } + + @Override + protected void createChart() { + this.chart = ChartFactory.createXYLineChart("", "", "", dataset, PlotOrientation.VERTICAL, true, true, false); + + NumberAxis domainAxis = new NumberAxis(domainAxisLabel); + domainAxis.setAutoRangeStickyZero(false); + domainAxis.setAutoRangeIncludesZero(true); + + NumberAxis rangeAxis = new NumberAxis(rangeAxisLabel); + rangeAxis.setNumberFormatOverride(DoubleField.getFormatForDISPLAY(10)); + + chart.getXYPlot().setDomainAxis(domainAxis); + chart.getXYPlot().setRangeAxis(rangeAxis); + + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) chart.getXYPlot().getRenderer(); + renderer.setDrawOutlines(true); + renderer.setUseFillPaint(true); + } + + @Override + protected void addTimeBlock(final TimeBlock block) { + for (TimeBlockUnit unit : block.getUnitsMap().values()) { + if (unit instanceof DoubleTimeBlockUnit) { + addTimeUnit(block.getTime(), unit); + } + } + } + + private void addTimeUnit(double time, TimeBlockUnit unit) { + String varName = unit.getVarName(); + if (dataset.getSeriesIndex(varName) != -1) { + XYSeries xyserie = dataset.getSeries(varName); + DoubleTimeBlockUnit doubleUnit = (DoubleTimeBlockUnit) unit; + xyserie.add(time, doubleUnit.getValue()); + } else { + logger.error("Series not found for {}", varName); + } + } + + @Override + public void initSeries() { + super.initSeries(); + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) chart.getXYPlot().getRenderer(); + for (String varName : seriesNames) { + renderer.setSeriesShapesVisible(dataset.getSeriesIndex(varName), true); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/NonUniformComboBoxController.java b/src/eu/engys/gui/casesetup/boundaryconditions/NonUniformComboBoxController.java new file mode 100644 index 0000000..264fa9f --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/NonUniformComboBoxController.java @@ -0,0 +1,71 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.boundaryconditions; + +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.DATA_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FILE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FILE_NAME_KEY; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryModel.DictionaryError; +import eu.engys.core.dictionary.model.DictionaryModel.DictionaryListener; +import eu.engys.util.ui.builder.JComboBoxController; + +public class NonUniformComboBoxController extends JComboBoxController { + private DictionaryModel model; + + public NonUniformComboBoxController(DictionaryModel model) { + super(); + this.model = model; + model.addDictionaryListener(new DictionaryListener() { + @Override + public void dictionaryChanged() throws DictionaryError { + Dictionary dict = NonUniformComboBoxController.this.model.getDictionary(); + if (dict != null && dict.found(FILE_NAME_KEY) && dict.lookup(FILE_NAME_KEY).length() > 2) { + setSelectedKey(FILE_KEY); + } else { + setSelectedKey(DATA_KEY); + } + } + }); + addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Dictionary dict = NonUniformComboBoxController.this.model.getDictionary(); + String key = getSelectedKey(); + if (key.equals(DATA_KEY) && dict.found(FILE_NAME_KEY)) { + dict.remove(FILE_NAME_KEY); + } else if (key.equals(FILE_KEY) && !dict.found(FILE_NAME_KEY)) { + dict.add(FILE_NAME_KEY, "\"\""); + } + } + }); + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/NonUniformInterpolationTable.java b/src/eu/engys/gui/casesetup/boundaryconditions/NonUniformInterpolationTable.java new file mode 100644 index 0000000..c2b9e06 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/NonUniformInterpolationTable.java @@ -0,0 +1,76 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.boundaryconditions; + +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.DATA_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FILE_NAME_KEY; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.parser.ListField2; + +public class NonUniformInterpolationTable extends AbstractInterpolationTable { + + public static final String DISTANCE_M_LABEL = "Distance [m]"; + + private DictionaryModel dictionaryModel; + + public NonUniformInterpolationTable(DictionaryModel dictionaryModel, String[] names) { + super(names); + this.dictionaryModel = dictionaryModel; + } + + @Override + protected void setupColumnNames() { + if (isVector()) { + this.columnNames = new String[] { DISTANCE_M_LABEL, names[0], names[1], names[2] }; + } else { + this.columnNames = new String[] { DISTANCE_M_LABEL, names[0] }; + } + } + + @Override + public void load() { + clear(); + Dictionary dict = dictionaryModel.getDictionary(); + if (dict.found(DATA_KEY)) { + if (dict.isList2(DATA_KEY)) { + // Fix for alpha1 which is read with DictionaryReader2 + loadTable(ListField2.convertToString(dict.getList2(DATA_KEY))); + } else { + loadTable(dict.lookup(DATA_KEY).trim()); + } + } + } + + @Override + public StringBuilder save() { + StringBuilder sb = super.save(); + dictionaryModel.getDictionary().add(DATA_KEY, sb.toString()); + dictionaryModel.getDictionary().remove(FILE_NAME_KEY); + return sb; + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/TimeVaryingComboBoxController.java b/src/eu/engys/gui/casesetup/boundaryconditions/TimeVaryingComboBoxController.java new file mode 100644 index 0000000..cd454d9 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/TimeVaryingComboBoxController.java @@ -0,0 +1,92 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.boundaryconditions; + +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.DATA_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FILE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TABLE_FILE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TABLE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.isTableFile; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryModel.DictionaryError; +import eu.engys.core.dictionary.model.DictionaryModel.DictionaryListener; +import eu.engys.util.ui.builder.JComboBoxController; + +public class TimeVaryingComboBoxController extends JComboBoxController { + private DictionaryModel model; + + public TimeVaryingComboBoxController(DictionaryModel model, final String dictionaryKey) { + super(); + this.model = model; + model.addDictionaryListener(new DictionaryListener() { + @Override + public void dictionaryChanged() throws DictionaryError { + Dictionary dict = TimeVaryingComboBoxController.this.model.getDictionary(); + if (isTableFile(dict, dictionaryKey)) { + setSelectedKey(FILE_KEY); + } else { + setSelectedKey(DATA_KEY); + } + } + }); + addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Dictionary dict = TimeVaryingComboBoxController.this.model.getDictionary(); + String key = getSelectedKey(); + if (key.equals(DATA_KEY)) { + fixData(dictionaryKey, dict); + } else if (key.equals(FILE_KEY)) { + fixFile(dictionaryKey, dict); + } + } + + private void fixData(final String dictionaryKey, Dictionary dict) { + if(dict.found(dictionaryKey)){ + dict.remove(dictionaryKey); + } + if(!dict.found(dictionaryKey + " " + TABLE_KEY)){ + dict.add(dictionaryKey + " " + TABLE_KEY, "()"); + } + } + + private void fixFile(final String dictionaryKey, Dictionary dict) { + if(dict.found(dictionaryKey + " " + TABLE_KEY)){ + dict.remove(dictionaryKey + " " + TABLE_KEY); + } + if(!dict.found(dictionaryKey)){ + dict.add(dictionaryKey, TABLE_FILE_KEY); + } + } + + }); + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/TimeVaryingInterpolationTable.java b/src/eu/engys/gui/casesetup/boundaryconditions/TimeVaryingInterpolationTable.java new file mode 100644 index 0000000..36e7f2d --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/TimeVaryingInterpolationTable.java @@ -0,0 +1,73 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.boundaryconditions; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.parser.ListField2; + +public class TimeVaryingInterpolationTable extends AbstractInterpolationTable { + + private DictionaryModel dictionaryModel; + private String dictionaryKey; + + public TimeVaryingInterpolationTable(DictionaryModel dictionaryModel, String dictionaryKey, String[] names) { + super(names); + this.dictionaryModel = dictionaryModel; + this.dictionaryKey = dictionaryKey; + } + + @Override + protected void setupColumnNames() { + if (isVector()) { + this.columnNames = new String[] { "Time Step [s]", names[0], names[1], names[2] }; + } else { + this.columnNames = new String[] { "Time Step [s]", names[0] }; + } + } + + @Override + public void load() { + clear(); + Dictionary dict = dictionaryModel.getDictionary(); + if (dict.found(dictionaryKey)) { + if (dict.isList2(dictionaryKey)) { + // Fix for alpha1 which is read with DictionaryReader2 + loadTable(ListField2.convertToString(dict.getList2(dictionaryKey))); + } else { + loadTable(dict.lookup(dictionaryKey)); + } + } + } + + @Override + public StringBuilder save() { + StringBuilder sb = super.save(); + dictionaryModel.getDictionary().add(dictionaryKey, sb.toString()); + return sb; + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/factories/CyclicFactory.java b/src/eu/engys/gui/casesetup/boundaryconditions/factories/CyclicFactory.java new file mode 100644 index 0000000..653bf10 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/factories/CyclicFactory.java @@ -0,0 +1,141 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.boundaryconditions.factories; + +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.BRIDGE_OVERLAP_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.COUPLING_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.COUPLING_LABEL; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.MATCH_TOLERANCE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.NEIGHBOUR_PATCH_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.ROTATIONAL_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.ROTATIONAL_LABEL; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.ROTATION_ANGLE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.ROTATION_AXIS_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.ROTATION_CENTRE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.SEPARATION_VECTOR_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.TRANSFORM_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.TRANSLATIONAL_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.TRANSLATIONAL_LABEL; +import static eu.engys.gui.casesetup.boundaryconditions.panels.AbstractCyclicAMISettingsPanel.WEIGHT_CORRECTION_KEY; +import eu.engys.core.dictionary.Dictionary; + +public class CyclicFactory { + + public static final String CYCLIC_AMI_KEY = "cyclicAMI"; + public static final String CYCLIC_KEY = "cyclic"; + + public static final Dictionary BOUNDARY_CONDITION = new Dictionary("patch") { + { + add(TYPE, CYCLIC_KEY); + add(VALUE, "uniform 0"); + } + }; + + public static final Dictionary BOUNDARY_CONDITION_VECTOR = new Dictionary("patch") { + { + add(TYPE, CYCLIC_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + + public static final Dictionary CYCLIC = new Dictionary("patch") { + { + add(TYPE, CYCLIC_KEY); + add(MATCH_TOLERANCE_KEY, "0.0001"); + add(NEIGHBOUR_PATCH_KEY, ""); + } + }; + + public static final Dictionary AMI_BOUNDARY_CONDITION = new Dictionary("patch") { + { + add(TYPE, CYCLIC_AMI_KEY); + add(VALUE, "uniform 0"); + } + }; + + public static final Dictionary AMI_BOUNDARY_CONDITION_VECTOR = new Dictionary("patch") { + { + add(TYPE, CYCLIC_AMI_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + + public static final Dictionary CYCLIC_AMI = new Dictionary("patch") { + { + add(TYPE, CYCLIC_AMI_KEY); + add(MATCH_TOLERANCE_KEY, "0.0001"); + add(NEIGHBOUR_PATCH_KEY, ""); + add(TRANSFORM_KEY, COUPLING_KEY); + add(BRIDGE_OVERLAP_KEY, "true"); + } + }; + + public static final Dictionary CYCLIC_AMI_OS = new Dictionary("patch") { + { + add(TYPE, CYCLIC_AMI_KEY); + add(MATCH_TOLERANCE_KEY, "0.0001"); + add(WEIGHT_CORRECTION_KEY, "0.2"); + add(NEIGHBOUR_PATCH_KEY, ""); + add(TRANSFORM_KEY, COUPLING_KEY); + add(BRIDGE_OVERLAP_KEY, "true"); + } + }; + + public static final Dictionary CYCLIC_AMI_COUPLING = new Dictionary("") { + { + add(TYPE, COUPLING_LABEL); + add(TRANSFORM_KEY, COUPLING_KEY); + } + }; + + public static final Dictionary CYCLIC_AMI_ROTATIONAL = new Dictionary("") { + { + add(TYPE, ROTATIONAL_LABEL); + add(TRANSFORM_KEY, ROTATIONAL_KEY); + add(ROTATION_AXIS_KEY, "(1 0 0)"); + add(ROTATION_CENTRE_KEY, "(0 0 0)"); + } + }; + + public static final Dictionary CYCLIC_AMI_ROTATIONAL_OS = new Dictionary("") { + { + add(TYPE, ROTATIONAL_LABEL); + add(TRANSFORM_KEY, ROTATIONAL_KEY); + add(ROTATION_AXIS_KEY, "(1 0 0)"); + add(ROTATION_CENTRE_KEY, "(0 0 0)"); + add(ROTATION_ANGLE_KEY, "30"); + } + }; + + public static final Dictionary CYCLIC_AMI_TRANSLATIONAL = new Dictionary("") { + { + add(TYPE, TRANSLATIONAL_LABEL); + add(TRANSFORM_KEY, TRANSLATIONAL_KEY); + add(SEPARATION_VECTOR_KEY, "(0 0 0)"); + } + }; + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/factories/PressureFactory.java b/src/eu/engys/gui/casesetup/boundaryconditions/factories/PressureFactory.java new file mode 100644 index 0000000..bc73fc9 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/factories/PressureFactory.java @@ -0,0 +1,135 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.factories; + +import static eu.engys.core.project.zero.fields.Fields.P; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.CLAMP_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FILE_NAME_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FIXED_FLUX_PRESSURE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FIXED_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FREESTREAM_PRESSURE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.OUT_OF_BOUNDS_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.PRESSURE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.RHO_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TABLE_FILE_COEFFS_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TABLE_FILE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TABLE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TOTAL_PRESSURE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.UNIFORM_TOTAL_PRESSURE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ZERO_GRADIENT_KEY; +import eu.engys.core.dictionary.Dictionary; + +public class PressureFactory { + + public static final Dictionary totalPressure = new Dictionary(P) { + { + add(TYPE, TOTAL_PRESSURE_KEY); + add(VALUE, "uniform 0"); + add("p0", "uniform 0"); + add("gamma", "1.4"); + } + }; + + public static final Dictionary uniformTotalPressure = new Dictionary(P) { + { + add(TYPE, UNIFORM_TOTAL_PRESSURE_KEY); + add(VALUE, "uniform 0"); + add(RHO_KEY, RHO_KEY); + add("gamma", "1.4"); + add("p0", "0"); + add(PRESSURE_KEY, TABLE_KEY + " ()"); + add(OUT_OF_BOUNDS_KEY, CLAMP_KEY); + } + }; + + public static final Dictionary fixedValuePressure_COMP = new Dictionary(P) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform 1e5"); + } + }; + + public static final Dictionary fixedValuePressure = new Dictionary(P) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform 0"); + } + }; + + public static final Dictionary staticValuePressure_COMP = new Dictionary(P) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform 1e5"); + } + }; + + public static final Dictionary staticValuePressure = new Dictionary(P) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform 0"); + } + }; + + public static final Dictionary zeroGradientPressure = new Dictionary(P) { + { + add(TYPE, ZERO_GRADIENT_KEY); + } + }; + + public static final Dictionary fixedFluxPressure = new Dictionary(P) { + { + add(TYPE, FIXED_FLUX_PRESSURE_KEY); + add(VALUE, "uniform 0"); + add(RHO_KEY, "rhok"); + } + }; + + public static final Dictionary freestreamPressure = new Dictionary(P) { + { + add(TYPE, FREESTREAM_PRESSURE_KEY); + } + }; + + // For Tests only + public static final Dictionary uniformTotalPressure_FILE = new Dictionary(P) { + { + add(TYPE, UNIFORM_TOTAL_PRESSURE_KEY); + add(VALUE, "uniform 0"); + add(RHO_KEY, RHO_KEY); + add("gamma", "1.4"); + add("p0", "0"); + add(PRESSURE_KEY, TABLE_FILE_KEY); + add(new Dictionary(TABLE_FILE_COEFFS_KEY) { + { + add(FILE_NAME_KEY, "\"\""); + add(OUT_OF_BOUNDS_KEY, CLAMP_KEY); + } + }); + } + }; + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardPhaseFactory.java b/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardPhaseFactory.java new file mode 100644 index 0000000..a5cf7ab --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardPhaseFactory.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.factories; + +import static eu.engys.core.project.zero.fields.Fields.ALPHA; +import eu.engys.core.dictionary.Dictionary; + +public class StandardPhaseFactory { + + public static final Dictionary fixedValueVelocity = new Dictionary(ALPHA) { + { + add("type", "fixedValue"); + add("value", "uniform 1"); + } + }; + + public static final Dictionary inletOutlet = new Dictionary(ALPHA) { + { + add("type", "inletOutlet"); + add("value", "uniform 0.1"); + add("inletValue", "uniform 0.1"); + } + }; + + public static final Dictionary zeroGradient = new Dictionary(ALPHA) { + { + add("type", "zeroGradient"); + } + }; + + public static final Dictionary calculated = new Dictionary(ALPHA) { + { + add("type", "calculated"); + } + }; +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardPressureFactory.java b/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardPressureFactory.java new file mode 100644 index 0000000..5ad5f1b --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardPressureFactory.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.factories; + +import eu.engys.core.dictionary.Dictionary; + +public class StandardPressureFactory extends PressureFactory { + + public static final Dictionary totalPressure = new Dictionary("p"){ + { + add("type", "totalPressure"); + add("value", "uniform 0"); + add("p0", "uniform 0"); + add("gamma", "0"); + add("rho", "rho"); + } + }; + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardVelocityFactory.java b/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardVelocityFactory.java new file mode 100644 index 0000000..ac34345 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/factories/StandardVelocityFactory.java @@ -0,0 +1,32 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.factories; + + +public class StandardVelocityFactory { + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/factories/TemperatureFactory.java b/src/eu/engys/gui/casesetup/boundaryconditions/factories/TemperatureFactory.java new file mode 100644 index 0000000..3e13d44 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/factories/TemperatureFactory.java @@ -0,0 +1,173 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.factories; + +import eu.engys.core.dictionary.Dictionary; + +public class TemperatureFactory { + + public static final Dictionary fixedValue = new Dictionary("T") { + { + add(TYPE, "fixedValue"); + add("value", "uniform 300"); + } + }; + + public static final Dictionary zeroGradient = new Dictionary("T") { + { + add(TYPE, "zeroGradient"); + } + }; + + public static final Dictionary advectiveTemperature = new Dictionary("T") { + { + add(TYPE, "advective"); + } + }; + + public static final Dictionary totalTemperature = new Dictionary("T") { + { + add(TYPE, "totalTemperature"); + add("value", "uniform 300"); + add("U", "U"); + add("phi", "phi"); + add("psi", "0"); + add("gamma", "1.4"); + add("T0", "uniform 300"); + } + + }; + + public static final Dictionary inletOutletTotalTemperature = new Dictionary("T") { + { + add(TYPE, "inletOutletTotalTemperature"); + add("value", "uniform 300"); + add("U", "U"); + add("phi", "phi"); + add("psi", "0"); + add("gamma", "1.4"); + add("T0", "uniform 300"); + } + + }; + + public static final Dictionary inletOutlet = new Dictionary("T") { + { + add(TYPE, "inletOutlet"); + add("value", "uniform 300"); + add("inletValue", "uniform 300"); + } + }; + + public static final Dictionary turbulentHeatFluxTemperature_FLUX = new Dictionary("T") { + { + add(TYPE, "incompressible::turbulentHeatFluxTemperature"); + add("value", "uniform 300"); + add("q", "uniform 10.0"); + add("heatSource", "flux"); + add("alphaEff", "kappaEff"); + add("Cp", "Cp0"); + } + }; + + public static final Dictionary turbulentHeatFluxTemperature_FLUX_COMP = new Dictionary("T") { + { + add(TYPE, "compressible::turbulentHeatFluxTemperature"); + add("value", "uniform 300"); + add("q", "uniform 10.0"); + add("heatSource", "flux"); + add("kappa", "fluidThermo"); + add("kappaName", "default"); + } + }; + + public static final Dictionary turbulentHeatFluxTemperatureOCFD_FLUX = new Dictionary("T") { + { + add(TYPE, "turbulentHeatFluxTemperature"); + add("value", "uniform 300"); + add("q", "uniform 10.0"); + add("heatSource", "flux"); + add("alphaEff", "alphaEff"); + } + }; + + public static final Dictionary turbulentHeatFluxTemperatureOCFD_FLUX_COMP = new Dictionary("T") { + { + add(TYPE, "compressible::turbulentHeatFluxTemperature"); + add("value", "uniform 300"); + add("q", "uniform 10.0"); + add("heatSource", "flux"); + add("kappa", "fluidThermo"); + add("kappaName", "default"); + add("Qr", "none"); + } + }; + + public static final Dictionary turbulentHeatFluxTemperature_POWER = new Dictionary("T") { + { + add(TYPE, "incompressible::turbulentHeatFluxTemperature"); + add("value", "uniform 300"); + add("q", "uniform 10.0"); + add("heatSource", "power"); + add("alphaEff", "kappaEff"); + add("Cp", "Cp0"); + } + }; + + public static final Dictionary turbulentHeatFluxTemperatureOCFD_POWER = new Dictionary("T") { + { + add(TYPE, "turbulentHeatFluxTemperature"); + add("value", "uniform 300"); + add("q", "uniform 10.0"); + add("heatSource", "power"); + add("alphaEff", "alphaEff"); + } + }; + + public static final Dictionary turbulentHeatFluxTemperature_POWER_COMP = new Dictionary("T") { + { + add(TYPE, "compressible::turbulentHeatFluxTemperature"); + add("value", "uniform 300"); + add("q", "uniform 10.0"); + add("heatSource", "power"); + add("kappa", "fluidThermo"); + add("kappaName", "none"); + } + }; + + public static final Dictionary turbulentHeatFluxTemperatureOCFD_POWER_COMP = new Dictionary("T") { + { + add(TYPE, "compressible::turbulentHeatFluxTemperature"); + add("value", "uniform 300"); + add("q", "uniform 10.0"); + add("heatSource", "power"); + add("kappa", "fluidThermo"); + add("kappaName", "default"); + add("Qr", "none"); + } + }; +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/factories/TurbulenceFactory.java b/src/eu/engys/gui/casesetup/boundaryconditions/factories/TurbulenceFactory.java new file mode 100644 index 0000000..123f71c --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/factories/TurbulenceFactory.java @@ -0,0 +1,303 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.factories; + +import static eu.engys.core.project.zero.fields.Fields.EPSILON; +import static eu.engys.core.project.zero.fields.Fields.K; +import static eu.engys.core.project.zero.fields.Fields.MUT; +import static eu.engys.core.project.zero.fields.Fields.MU_SGS; +import static eu.engys.core.project.zero.fields.Fields.NUT; +import static eu.engys.core.project.zero.fields.Fields.NU_SGS; +import static eu.engys.core.project.zero.fields.Fields.NU_TILDA; +import static eu.engys.core.project.zero.fields.Fields.OMEGA; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.CLAMP_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.COMPRESSIBLE_TURBULENT_MIXING_LENGTH_DISSIPATION_RATE_INLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.COMPRESSIBLE_TURBULENT_MIXING_LENGTH_FREQUENCY_INLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.CS_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FIXED_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.INLET_OUTLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.INLET_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.INTENSITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.KS_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.LENGTH_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.MIXING_LENGTH_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.MUT_K_ROUGH_WALL_FUNCTION_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.MUT_U_ROUGH_WALL_FUNCTION_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.NUT_K_ATM_ROUGH_WALL_FUNCTION_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.NUT_K_ROUGH_WALL_FUNCTION_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.NUT_TURBULENT_INTENSITY_LENGTH_SCALE_INLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.NUT_U_ROUGH_WALL_FUNCTION_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.OUT_OF_BOUNDS_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ROUGHNESS_CONSTANT_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ROUGHNESS_FACTOR_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ROUGHNESS_HEIGHT_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TABLE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TURBULENT_INTENSITY_KINETIC_ENERGY_INLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TURBULENT_MIXING_LENGTH_DISSIPATION_RATE_INLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.TURBULENT_MIXING_LENGTH_FREQUENCY_INLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.UNIFORM_FIXED_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.UNIFORM_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.Z0_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ZERO_GRADIENT_KEY; +import eu.engys.core.dictionary.Dictionary; + +public class TurbulenceFactory { + + /* + * Fixed + */ + + public static final Dictionary kFixedValue = new Dictionary(K) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform 0.01"); + } + }; + public static final Dictionary omegaFixedValue = new Dictionary(OMEGA) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform 0.01"); + } + }; + public static final Dictionary epsilonFixedValue = new Dictionary(EPSILON) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform 0.01"); + } + }; + public static final Dictionary nutildaFixedValue = new Dictionary(NU_TILDA) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform 0.01"); + } + }; + + /* + * Mixed + */ + public static final Dictionary kMixingLength = new Dictionary(K) { + { + add(TYPE, TURBULENT_INTENSITY_KINETIC_ENERGY_INLET_KEY); + add(VALUE, "uniform 0.01"); + add(INTENSITY_KEY, "0.05"); + } + }; + public static final Dictionary epsilonMixingLength = new Dictionary(EPSILON) { + { + add(TYPE, TURBULENT_MIXING_LENGTH_DISSIPATION_RATE_INLET_KEY); + add(VALUE, "uniform 0.01"); + add(MIXING_LENGTH_KEY, "0.01"); + } + }; + public static final Dictionary epsilonMixingLength_COMP = new Dictionary(EPSILON) { + { + add(TYPE, COMPRESSIBLE_TURBULENT_MIXING_LENGTH_DISSIPATION_RATE_INLET_KEY); + add(VALUE, "uniform 0.01"); + add(MIXING_LENGTH_KEY, "0.01"); + } + }; + public static final Dictionary omegaMixingLength = new Dictionary(OMEGA) { + { + add(TYPE, TURBULENT_MIXING_LENGTH_FREQUENCY_INLET_KEY); + add(VALUE, "uniform 0.01"); + add(MIXING_LENGTH_KEY, "0.01"); + } + }; + public static final Dictionary omegaMixingLength_COMP = new Dictionary(OMEGA) { + { + add(TYPE, COMPRESSIBLE_TURBULENT_MIXING_LENGTH_FREQUENCY_INLET_KEY); + add(VALUE, "uniform 0.01"); + add(MIXING_LENGTH_KEY, "0.01"); + } + }; + public static final Dictionary nuTildaMixingLength = new Dictionary(NU_TILDA) { + { + add(TYPE, NUT_TURBULENT_INTENSITY_LENGTH_SCALE_INLET_KEY); + add(VALUE, "uniform 0.01"); + add(INTENSITY_KEY, "0.05"); + add(LENGTH_KEY, "0.01"); + } + }; + + /* + * Time-varying + */ + public static final Dictionary kTimeVarying = new Dictionary(K) { + { + add(TYPE, UNIFORM_FIXED_VALUE_KEY); + add(VALUE, "uniform 0.01"); + add(UNIFORM_VALUE_KEY, TABLE_KEY + " ()"); + add(OUT_OF_BOUNDS_KEY, CLAMP_KEY); + } + }; + public static final Dictionary omegaTimeVarying = new Dictionary(OMEGA) { + { + add(TYPE, UNIFORM_FIXED_VALUE_KEY); + add(VALUE, "uniform 0.01"); + add(UNIFORM_VALUE_KEY, TABLE_KEY + " ()"); + add(OUT_OF_BOUNDS_KEY, CLAMP_KEY); + } + }; + public static final Dictionary epsilonTimeVarying = new Dictionary(EPSILON) { + { + add(TYPE, UNIFORM_FIXED_VALUE_KEY); + add(VALUE, "uniform 0.01"); + add(UNIFORM_VALUE_KEY, TABLE_KEY + " ()"); + add(OUT_OF_BOUNDS_KEY, CLAMP_KEY); + } + }; + public static final Dictionary nuTildaTimeVarying = new Dictionary(NU_TILDA) { + { + add(TYPE, UNIFORM_FIXED_VALUE_KEY); + add(VALUE, "uniform 0.01"); + add(UNIFORM_VALUE_KEY, TABLE_KEY + " ()"); + add(OUT_OF_BOUNDS_KEY, CLAMP_KEY); + } + }; + + /* + * Inlet outlet + */ + + public static final Dictionary kInletOutlet = new Dictionary(K) { + { + add(TYPE, INLET_OUTLET_KEY); + add(VALUE, "uniform 0.01"); + add(INLET_VALUE_KEY, "uniform 0.01"); + } + }; + public static final Dictionary omegaInletOutlet = new Dictionary(OMEGA) { + { + add(TYPE, INLET_OUTLET_KEY); + add(VALUE, "uniform 0.01"); + add(INLET_VALUE_KEY, "uniform 0.01"); + } + }; + public static final Dictionary epsilonInletOutlet = new Dictionary(EPSILON) { + { + add(TYPE, INLET_OUTLET_KEY); + add(VALUE, "uniform 0.01"); + add(INLET_VALUE_KEY, "uniform 0.01"); + } + }; + public static final Dictionary nuTildaInletOutlet = new Dictionary(NU_TILDA) { + { + add(TYPE, INLET_OUTLET_KEY); + add(VALUE, "uniform 0.01"); + add(INLET_VALUE_KEY, "uniform 0.01"); + } + }; + + /* + * Zero Gradient + */ + public static final Dictionary kZeroGradient = new Dictionary(K) { + { + add(TYPE, ZERO_GRADIENT_KEY); + } + }; + public static final Dictionary omegaZeroGradient = new Dictionary(OMEGA) { + { + add(TYPE, ZERO_GRADIENT_KEY); + } + }; + public static final Dictionary epsilonZeroGradient = new Dictionary(EPSILON) { + { + add(TYPE, ZERO_GRADIENT_KEY); + } + }; + public static final Dictionary nuTildaZeroGradient = new Dictionary(NU_TILDA) { + { + add(TYPE, ZERO_GRADIENT_KEY); + } + }; + + /* + * Wall + */ + public static final Dictionary nutkRoughWallFunction = new Dictionary(NUT) { + { + add(TYPE, NUT_K_ROUGH_WALL_FUNCTION_KEY); + add(VALUE, "uniform 0"); + add(KS_KEY, "uniform 0"); + add(CS_KEY, "uniform 0.5"); + } + }; + public static final Dictionary nutkAtmRoughWallFunction = new Dictionary(NUT) { + { + add(TYPE, NUT_K_ATM_ROUGH_WALL_FUNCTION_KEY); + add(VALUE, "uniform 0"); + add(Z0_KEY, "uniform 0"); + } + }; + public static final Dictionary nutURoughWallFunction = new Dictionary(NUT) { + { + add(TYPE, NUT_U_ROUGH_WALL_FUNCTION_KEY); + add(VALUE, "uniform 0"); + add(ROUGHNESS_HEIGHT_KEY, "1e-5"); + add(ROUGHNESS_CONSTANT_KEY, "0.5"); + add(ROUGHNESS_FACTOR_KEY, "1"); + } + }; + public static final Dictionary nuSgsURoughWallFunction = new Dictionary(NU_SGS) { + { + add(TYPE, NUT_U_ROUGH_WALL_FUNCTION_KEY); + add(VALUE, "uniform 0"); + add(ROUGHNESS_HEIGHT_KEY, "1e-5"); + add(ROUGHNESS_CONSTANT_KEY, "0.5"); + add(ROUGHNESS_FACTOR_KEY, "1"); + } + }; + + public static final Dictionary mutKRoughWallFunction = new Dictionary(MUT) { + { + add(TYPE, MUT_K_ROUGH_WALL_FUNCTION_KEY); + add(VALUE, "uniform 0"); + add(KS_KEY, "uniform 0"); + add(CS_KEY, "uniform 0.5"); + } + }; + public static final Dictionary mutURoughWallFunction = new Dictionary(MUT) { + { + add(TYPE, MUT_U_ROUGH_WALL_FUNCTION_KEY); + add(VALUE, "uniform 0"); + add(ROUGHNESS_HEIGHT_KEY, "1e-5"); + add(ROUGHNESS_CONSTANT_KEY, "0.5"); + add(ROUGHNESS_FACTOR_KEY, "1"); + } + }; + public static final Dictionary muSgsURoughWallFunction = new Dictionary(MU_SGS) { + { + add(TYPE, MUT_U_ROUGH_WALL_FUNCTION_KEY); + add(VALUE, "uniform 0"); + add(ROUGHNESS_HEIGHT_KEY, "1e-5"); + add(ROUGHNESS_CONSTANT_KEY, "0.5"); + add(ROUGHNESS_FACTOR_KEY, "1"); + } + }; + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/factories/VelocityFactory.java b/src/eu/engys/gui/casesetup/boundaryconditions/factories/VelocityFactory.java new file mode 100644 index 0000000..2f03cca --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/factories/VelocityFactory.java @@ -0,0 +1,245 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.factories; + +import static eu.engys.core.project.zero.fields.Fields.U; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ACCOMMODATION_COEFFICIENT_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ADVECTIVE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ALPHA_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.AXIS_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.CYLINDRICAL_INLET_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FIXED_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FLOW_RATE_INLET_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FLOW_RATE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FLUX_CORRECTED_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FREESTREAM_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.FREESTREAM_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.INLET_DIRECTION_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.INLET_OUTLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.INLET_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.MASS_FLOW_RATE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.MAXWELL_SLIP_U_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.MOVING_WALL_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.NO_SLIP_WALL_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.PHI_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.PRESSURE_DIRECT_INLET_OUTLET_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.PRESSURE_DIRECT_INLET_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.PRESSURE_INLET_OUTLET_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.PRESSURE_INLET_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.REF_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.RHO_INLET_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.RHO_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ROTATING_WALL_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.SLIP_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.SLIP_WALL_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.SURFACE_NORMAL_FIXED_VALUE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.UWALL; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.VARIABLE_HEIGHT_FLOW_RATE_INLET_VELOCITY_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.VOLUMETRIC_FLOW_RATE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.ZERO_GRADIENT_KEY; +import eu.engys.core.dictionary.Dictionary; + +public class VelocityFactory { + + public static final Dictionary fixedValueVelocity = new Dictionary(U) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + public static final Dictionary movingWallVelocity = new Dictionary(U) { + { + add(TYPE, MOVING_WALL_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + public static final Dictionary zeroGradientVelocity = new Dictionary(U) { + { + add(TYPE, ZERO_GRADIENT_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + public static final Dictionary advectiveVelocity = new Dictionary(U) { + { + add(TYPE, ADVECTIVE_KEY); + } + }; + public static final Dictionary inletOutletVelocity = new Dictionary(U) { + { + add(TYPE, INLET_OUTLET_KEY); + add(VALUE, "uniform (0 0 0)"); + add(INLET_VALUE_KEY, "uniform (0 0 0)"); + } + }; + public static final Dictionary cylindricalInletVelocity = new Dictionary(U) { + { + add(TYPE, CYLINDRICAL_INLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + add(AXIS_KEY, "(0 0 1)"); + add("centre", "(0 0 0)"); + add("axialVelocity", "30"); + add("rpm", "100"); + add("radialVelocity", "-10"); + } + }; + public static final Dictionary surfaceNormalFixedValue = new Dictionary(U) { + { + add(TYPE, SURFACE_NORMAL_FIXED_VALUE_KEY); + add(VALUE, "uniform (0 0 0)"); + add(REF_VALUE_KEY, "uniform -1.5"); + } + }; + + public static final Dictionary volumetricFlowRateInletVelocity = new Dictionary(U) { + { + add(TYPE, FLOW_RATE_INLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + add(VOLUMETRIC_FLOW_RATE_KEY, "0.1"); + } + }; + + public static final Dictionary massFlowRateInletVelocity = new Dictionary(U) { + { + add(TYPE, FLOW_RATE_INLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + add(MASS_FLOW_RATE_KEY, "0.1"); + add(RHO_KEY, "rho"); + } + }; + + public static final Dictionary massFlowRateInletVelocity_INCOMPRESSIBLE = new Dictionary(U) { + { + add(TYPE, FLOW_RATE_INLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + add(MASS_FLOW_RATE_KEY, "0.1"); + add(RHO_KEY, "rho"); + add(RHO_INLET_KEY, "1.0"); + } + }; + + public static final Dictionary variableHeightFlowRateInletVelocity = new Dictionary(U) { + { + add(TYPE, VARIABLE_HEIGHT_FLOW_RATE_INLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + add(FLOW_RATE_KEY, "0.2"); + add(ALPHA_KEY, "alpha.water"); + } + }; + + public static final Dictionary pressureInletVelocity = new Dictionary(U) { + { + add(TYPE, PRESSURE_INLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + + public static final Dictionary fluxCorrectedVelocity = new Dictionary(U) { + { + add(TYPE, FLUX_CORRECTED_VELOCITY_KEY); + } + }; + + public static final Dictionary pressureDirectedInletVelocity = new Dictionary(U) { + { + add(TYPE, PRESSURE_DIRECT_INLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + add(INLET_DIRECTION_KEY, "(1 0 0)"); + } + }; + + public static final Dictionary pressureInletOutletVelocity = new Dictionary(U) { + { + add(TYPE, PRESSURE_INLET_OUTLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + + public static final Dictionary pressureDirectedInletOutletVelocity = new Dictionary(U) { + { + add(TYPE, PRESSURE_DIRECT_INLET_OUTLET_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + add(INLET_DIRECTION_KEY, "(1 0 0)"); + } + }; + + public static final Dictionary freestreamVelocity = new Dictionary(U) { + { + add(TYPE, FREESTREAM_KEY); + add(VALUE, "uniform (0 0 0)"); + add(PHI_KEY, PHI_KEY); + add(FREESTREAM_VALUE_KEY, "uniform (0 0 0)"); + } + }; + + public static final Dictionary slipWall = new Dictionary(U) { + { + add(TYPE, SLIP_KEY); + } + }; + + public static final Dictionary slipWallCoupled = new Dictionary(U) { + { + add(TYPE, SLIP_WALL_KEY); + } + }; + + public static final Dictionary maxwellSlipWall = new Dictionary(U) { + { + add(TYPE, MAXWELL_SLIP_U_KEY); + add(VALUE, "uniform (0 0 0)"); + add(ACCOMMODATION_COEFFICIENT_KEY, "0.85"); + add("thermalCreep", "on"); + add("curvature", "on"); + add(UWALL, "uniform (0 0 0)"); + } + }; + + public static final Dictionary noSlipWall = new Dictionary(U) { + { + add(TYPE, FIXED_VALUE_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + + public static final Dictionary noSlipWallCoupled = new Dictionary(U) { + { + add(TYPE, NO_SLIP_WALL_KEY); + add(VALUE, "uniform (0 0 0)"); + } + }; + + public static final Dictionary standardRotatingWallVelocity = new Dictionary(U) { + { + add(TYPE, ROTATING_WALL_VELOCITY_KEY); + add(VALUE, "uniform (0 0 0)"); + add("origin", "(0 0 0)"); + add("axis", "(1 0 0)"); + add("omega", "5"); + } + }; + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractBoundaryTypePanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractBoundaryTypePanel.java new file mode 100644 index 0000000..781b6fb --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractBoundaryTypePanel.java @@ -0,0 +1,341 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.modules.boundaryconditions.ParametersPanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.core.project.zero.patches.Patch; + +public abstract class AbstractBoundaryTypePanel extends JPanel implements BoundaryTypePanel { + + private static final Logger logger = LoggerFactory.getLogger(BoundaryTypePanel.class); + + private ParametersPanel momentumPanel; + private ParametersPanel turbulencePanel; + private ParametersPanel thermalPanel; + private ParametersPanel pScalarsPanel; + private ParametersPanel phasePanel; + + private Map indexes = new HashMap<>(); + private Map components = new HashMap<>(); + private Map parametersPanels = new HashMap<>(); + + private JTabbedPane tabPanel; + + protected final Model model; + + public AbstractBoundaryTypePanel(Model model) { + super(new BorderLayout()); + this.model = model; + } + + @Override + public void layoutPanel() { + tabPanel = new JTabbedPane(); + tabPanel.setName("boundary.conditions.tab"); + tabPanel.putClientProperty("Synthetica.tabbedPane.tabIndex", 0); + tabPanel.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + tabChanged(); + } + }); + add(tabPanel, BorderLayout.CENTER); + setName(getClass().getSimpleName()); + } + + @Override + public void addMomentumPanel(ParametersPanel momentumPanel) { + if (tabPanel.indexOfTab(MOMENTUM) < 0) { + this.momentumPanel = momentumPanel; + components.put(MOMENTUM, momentumPanel.getComponent()); + } + } + + @Override + public void addTurbulencePanel(ParametersPanel turbulencePanel) { + if (tabPanel.indexOfTab(TURBULENCE) < 0) { + this.turbulencePanel = turbulencePanel; + components.put(TURBULENCE, turbulencePanel.getComponent()); + } + } + + @Override + public void addThermalPanel(ParametersPanel thermalPanel) { + if (tabPanel.indexOfTab(THERMAL) < 0) { + this.thermalPanel = thermalPanel; + components.put(THERMAL, thermalPanel.getComponent()); + } + } + + protected void addPScalarsPanel(ParametersPanel pScalarsPanel) { + if (tabPanel.indexOfTab(PASSIVE_SCALARS) < 0) { + this.pScalarsPanel = pScalarsPanel; + components.put(PASSIVE_SCALARS, pScalarsPanel.getComponent()); + } + } + + protected void addPhasePanel(ParametersPanel phasePanel) { + if (tabPanel.indexOfTab(PHASE_FRACTION) < 0) { + this.phasePanel = phasePanel; + components.put(PHASE_FRACTION, phasePanel.getComponent()); + } + } + + @Override + public void addPanel(String name, ParametersPanel pPanel, int index) { + if (tabPanel.indexOfTab(name) < 0) { + components.put(name, pPanel.getComponent()); + if (index >= 0) + indexes.put(name, index); + parametersPanels.put(name, pPanel); + } + } + + @Override + public void addPanel(String name, ParametersPanel pPanel) { + addPanel(name, pPanel, -1); + } + + + private void tabChanged() { + int selectedIndex = tabPanel.getSelectedIndex(); + if (selectedIndex < 0) { + return; + } + String title = tabPanel.getTitleAt(selectedIndex); + if (model == null || model.getState() == null) { + return; + } + if (title.equals(MOMENTUM)) { + momentumPanel.tabChanged(model); + } else if (title.equals(THERMAL)) { + thermalPanel.tabChanged(model); + } else if (title.equals(TURBULENCE)) { + turbulencePanel.tabChanged(model); + } else if (title.equals(PASSIVE_SCALARS)) { + pScalarsPanel.tabChanged(model); + } else if (title.equals(PHASE_FRACTION)) { + phasePanel.tabChanged(model); + } else { + if (parametersPanels.containsKey(title)) { + parametersPanels.get(title).tabChanged(model); + } + } + } + + @Override + public void stateChanged() { + State state = model.getState(); + setEnabledAt(MOMENTUM, !state.getMultiphaseModel().isMultiphase()); + setEnabledAt(TURBULENCE, (state.getTurbulenceModel() != null && !state.getTurbulenceModel().getType().isLaminar())); + setEnabledAt(THERMAL, state.isEnergy()); + setEnabledAt(PHASE_FRACTION, state.getMultiphaseModel().isMultiphase()); + + for (String title : parametersPanels.keySet()) { + setEnabledAt(title, parametersPanels.get(title).isEnabled(model)); + } + + if (isEnabledAt(MOMENTUM)) + momentumPanel.stateChanged(model); + if (isEnabledAt(THERMAL)) + thermalPanel.stateChanged(model); + if (isEnabledAt(TURBULENCE)) + turbulencePanel.stateChanged(model); + if (isEnabledAt(PASSIVE_SCALARS)) + pScalarsPanel.stateChanged(model); + if (isEnabledAt(PHASE_FRACTION)) + phasePanel.stateChanged(model); + + for (String title : parametersPanels.keySet()) { + if (isEnabledAt(title)) + parametersPanels.get(title).stateChanged(model); + } + } + + @Override + public void resetToDefault() { + if (isEnabledAt(MOMENTUM)) + momentumPanel.resetToDefault(model); + if (isEnabledAt(THERMAL)) + thermalPanel.resetToDefault(model); + if (isEnabledAt(TURBULENCE)) + turbulencePanel.resetToDefault(model); + if (isEnabledAt(PASSIVE_SCALARS)) + pScalarsPanel.resetToDefault(model); + if (isEnabledAt(PHASE_FRACTION)) + phasePanel.resetToDefault(model); + + for (String title : parametersPanels.keySet()) { + if (isEnabledAt(title)) + parametersPanels.get(title).resetToDefault(model); + } + } + + @Override + public void materialsChanged() { + if (isEnabledAt(MOMENTUM)) + momentumPanel.materialsChanged(model); + if (isEnabledAt(PHASE_FRACTION)) + phasePanel.materialsChanged(model); + + for (String title : parametersPanels.keySet()) { + if (isEnabledAt(title)) { + parametersPanels.get(title).materialsChanged(model); + } + } + } + + private void setEnabledAt(String name, boolean enable) { + // System.out.println("AbstractBoundaryTypePanel.setEnabledAt() "+name+" is "+ + // (enable? "ENABLED" : "DISABLED")); + int index = tabPanel.indexOfTab(name); + if (enable && index < 0 && components.containsKey(name)) { + if (indexes.containsKey(name)) { + tabPanel.insertTab(name, null, components.get(name), null, indexes.get(name)); + } else { + tabPanel.addTab(name, components.get(name)); + } + } else if (!enable && index >= 0) { + tabPanel.removeTabAt(index); + } + } + + private boolean isEnabledAt(String name) { + int index = tabPanel.indexOfTab(name); + return index >= 0; + } + + @Override + public void loadFromPatches(Patch... patches) { + BoundaryConditions bc = patches[0].getBoundaryConditions(); + String patchName = patches[0].getName(); + if (bc != null) { + boolean multipleSelection = patches.length > 1; + // System.out.println("AbstractBoundaryTypePanel.loadFromPatches() multipleSelection: "+multipleSelection); + if (momentumPanel != null && isEnabledAt(MOMENTUM)) { + momentumPanel.setMultipleEditing(multipleSelection); + momentumPanel.loadFromBoundaryConditions(patchName, bc); + } + if (turbulencePanel != null && isEnabledAt(TURBULENCE)) { + turbulencePanel.setMultipleEditing(multipleSelection); + turbulencePanel.loadFromBoundaryConditions(patchName, bc); + } + if (thermalPanel != null && isEnabledAt(THERMAL)) { + thermalPanel.setMultipleEditing(multipleSelection); + thermalPanel.loadFromBoundaryConditions(patchName, bc); + } + if (pScalarsPanel != null && isEnabledAt(PASSIVE_SCALARS)) { + pScalarsPanel.setMultipleEditing(multipleSelection); + pScalarsPanel.loadFromBoundaryConditions(patchName, bc); + } + if (phasePanel != null && isEnabledAt(PHASE_FRACTION)) { + phasePanel.setMultipleEditing(multipleSelection); + phasePanel.loadFromBoundaryConditions(patchName, bc); + } + for (String title : parametersPanels.keySet()) { + if (isEnabledAt(title)) { + ParametersPanel parametersPanel = parametersPanels.get(title); + parametersPanel.setMultipleEditing(multipleSelection); + parametersPanel.loadFromBoundaryConditions(patchName, bc); + } + } + } else { + logger.warn("BoundaryConditions are null"); + } + } + + @Override + public void saveToPatch(Patch patch) { + if (patch.getBoundaryConditions() == null) { + patch.setBoundaryConditions(new BoundaryConditions()); + } + BoundaryConditions bc = patch.getBoundaryConditions(); + String patchName = patch.getName(); + if (momentumPanel != null && isEnabledAt(MOMENTUM) && momentumPanel.canEdit()) + momentumPanel.saveToBoundaryConditions(patchName, bc); + if (turbulencePanel != null && isEnabledAt(TURBULENCE) && turbulencePanel.canEdit()) + turbulencePanel.saveToBoundaryConditions(patchName, bc); + if (thermalPanel != null && isEnabledAt(THERMAL) && thermalPanel.canEdit()) + thermalPanel.saveToBoundaryConditions(patchName, bc); + if (pScalarsPanel != null && isEnabledAt(PASSIVE_SCALARS) && pScalarsPanel.canEdit()) + pScalarsPanel.saveToBoundaryConditions(patchName, bc); + if (phasePanel != null && isEnabledAt(PHASE_FRACTION) && phasePanel.canEdit()) + phasePanel.saveToBoundaryConditions(patchName, bc); + for (String title : parametersPanels.keySet()) { + if (isEnabledAt(title)) { + parametersPanels.get(title).saveToBoundaryConditions(patchName, bc); + } + } + } + + @Override + public Component getPanel() { + return this; + } + + @Override + public ParametersPanel getMomentumPanel() { + return momentumPanel; + } + + @Override + public ParametersPanel getTurbulencePanel() { + return turbulencePanel; + } + + @Override + public ParametersPanel getThermalPanel() { + return thermalPanel; + } + + @Override + public ParametersPanel getPanel(String name) { + return parametersPanels.get(name); + } + + public ParametersPanel getPhasePanel() { + return phasePanel; + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractCyclicAMISettingsPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractCyclicAMISettingsPanel.java new file mode 100644 index 0000000..33656ad --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractCyclicAMISettingsPanel.java @@ -0,0 +1,333 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.AMI_BOUNDARY_CONDITION; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.AMI_BOUNDARY_CONDITION_VECTOR; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.CYCLIC_AMI_COUPLING; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.CYCLIC_AMI_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.CYCLIC_AMI_TRANSLATIONAL; + +import java.awt.BorderLayout; +import java.awt.Component; + +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.modules.boundaryconditions.ParametersPanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Field.FieldType; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.core.project.zero.patches.BoundaryConditionsDefaults; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; + +public abstract class AbstractCyclicAMISettingsPanel extends JPanel implements BoundaryTypePanel { + + public static final String MATCH_TOLERANCE_KEY = "matchTolerance"; + public static final String NEIGHBOUR_PATCH_KEY = "neighbourPatch"; + public static final String SEPARATION_VECTOR_LABEL = "Separation Vector"; + public static final String SEPARATION_VECTOR_KEY = "separationVector"; + public static final String ROTATION_CENTRE_KEY = "rotationCentre"; + public static final String ROTATION_AXIS_KEY = "rotationAxis"; + public static final String TRANSFORM_KEY = "transform"; + public static final String COUPLING_KEY = "noOrdering"; + public static final String TRANSLATIONAL_KEY = "translational"; + public static final String ROTATIONAL_KEY = "rotational"; + public static final String ROTATION_ANGLE_KEY = "rotationAngle"; + public static final String WEIGHT_CORRECTION_KEY = "lowWeightCorrection"; + public static final String BRIDGE_OVERLAP_KEY = "bridgeOverlap"; + + public static final String ROTATION_ANGLE_LABEL = "Rotation [deg]"; + public static final String WEIGHT_CORRECTION_LABEL = "Weight Correction"; + public static final String TRANSFORM_LABEL = "Transform"; + public static final String COUPLING_LABEL = "Coupling"; + public static final String TRANSLATIONAL_LABEL = "Translational"; + public static final String ROTATIONAL_LABEL = "Rotational"; + public static final String CENTRE_LABEL = "Centre"; + public static final String AXIS_LABEL = "Axis"; + public static final String NEIGHBOUR_PATCH_LABEL = "Neighbour Patch"; + public static final String MATCH_TOLERANCE_LABEL = "Match Tolerance"; + + protected DictionaryModel cyclicModel; + protected DictionaryModel rotationalModel; + protected DictionaryModel couplingModel; + private DictionaryModel translationalModel; + + protected Model model; + + protected DictionaryPanelBuilder transformBuilder; + + public AbstractCyclicAMISettingsPanel(Model model) { + super(new BorderLayout()); + this.model = model; + this.cyclicModel = new DictionaryModel(); + this.couplingModel = new DictionaryModel(); + this.rotationalModel = new DictionaryModel(); + this.translationalModel = new DictionaryModel(); + } + + @Override + public void resetToDefault() { + this.couplingModel.setDictionary(new Dictionary(CYCLIC_AMI_COUPLING)); + this.translationalModel.setDictionary(new Dictionary(CYCLIC_AMI_TRANSLATIONAL)); + } + + @Override + public void layoutPanel() { + resetToDefault(); + + PanelBuilder builder = new PanelBuilder(); + + bindAmiParameters(builder); + + transformBuilder = new DictionaryPanelBuilder(); + transformBuilder.startChoice(TRANSFORM_LABEL); + + bindCouplingParameters(); + + bindRotationalParameters(); + + bindTranslationalParameters(); + + transformBuilder.endChoice(); + transformBuilder.selectDictionary(couplingModel.getDictionary()); + + builder.addFill(transformBuilder.removeMargins().getPanel()); + + add(builder.getPanel()); + } + + protected abstract void bindAmiParameters(PanelBuilder builder); + + private void bindCouplingParameters() { + transformBuilder.startDictionary(COUPLING_LABEL, couplingModel); + transformBuilder.endDictionary(); + } + + protected abstract void bindRotationalParameters(); + + private void bindTranslationalParameters() { + transformBuilder.startDictionary(TRANSLATIONAL_LABEL, translationalModel); + transformBuilder.addComponent(SEPARATION_VECTOR_LABEL, translationalModel.bindPoint(SEPARATION_VECTOR_KEY)); + transformBuilder.endDictionary(); + } + + @Override + public BoundaryType getType() { + return BoundaryType.CYCLIC_AMI; + } + + @Override + public Component getPanel() { + return this; + } + + @Override + public void saveToPatch(Patch patch) { + Dictionary cyclicDict = new Dictionary(cyclicModel.getDictionary()); + Dictionary transformDict = new Dictionary(transformBuilder.getSelectedModel().getDictionary()); + transformDict.remove(TYPE); + cyclicDict.merge(transformDict); + + patch.setBoundaryConditions(getAMIBoundaryConditions()); + Dictionary oldPatchDict = new Dictionary(patch.getDictionary()); + Dictionary oldPatchCyclicDict = extractCyclicDict(oldPatchDict); + oldPatchCyclicDict.merge(cyclicDict); + patch.setDictionary(oldPatchCyclicDict); + + updateNeighbourPatchDictionary(patch.getName(), oldPatchDict, cyclicDict); + } + + protected Dictionary extractCyclicDict(Dictionary dictionary) { + Dictionary cyclicDict = new Dictionary(dictionary); + cyclicDict.remove(TRANSFORM_KEY); + cyclicDict.remove(SEPARATION_VECTOR_KEY); + cyclicDict.remove(ROTATION_AXIS_KEY); + cyclicDict.remove(ROTATION_CENTRE_KEY); + return cyclicDict; + } + + protected Dictionary extractTransformDict(Dictionary dictionary) { + Dictionary transformDict = new Dictionary(""); + if (dictionary.found(TRANSFORM_KEY)) { + transformDict.add(TRANSFORM_KEY, dictionary.lookup(TRANSFORM_KEY)); + } + if (dictionary.found(SEPARATION_VECTOR_KEY)) { + transformDict.add(SEPARATION_VECTOR_KEY, dictionary.lookup(SEPARATION_VECTOR_KEY)); + } + if (dictionary.found(ROTATION_AXIS_KEY)) { + transformDict.add(ROTATION_AXIS_KEY, dictionary.lookup(ROTATION_AXIS_KEY)); + } + if (dictionary.found(ROTATION_CENTRE_KEY)) { + transformDict.add(ROTATION_CENTRE_KEY, dictionary.lookup(ROTATION_CENTRE_KEY)); + } + switch (dictionary.lookup(TRANSFORM_KEY)) { + case COUPLING_KEY: + transformDict.add(TYPE, COUPLING_LABEL); + break; + case ROTATIONAL_KEY: + transformDict.add(TYPE, ROTATIONAL_LABEL); + break; + case TRANSLATIONAL_KEY: + transformDict.add(TYPE, TRANSLATIONAL_LABEL); + break; + default: + transformDict.add(TYPE, COUPLING_LABEL); + break; + } + return transformDict; + } + + private BoundaryConditions getAMIBoundaryConditions() { + BoundaryConditions boundaryConditions = new BoundaryConditions(); + for (Field field : model.getFields().values()) { + if (field.getFieldType() == FieldType.SCALAR) { + boundaryConditions.add(field.getName(), new Dictionary(AMI_BOUNDARY_CONDITION)); + } else { + boundaryConditions.add(field.getName(), new Dictionary(AMI_BOUNDARY_CONDITION_VECTOR)); + } + } + return boundaryConditions; + } + + private void updateNeighbourPatchDictionary(String patchName, Dictionary oldDict, Dictionary newDict) { + Patch neighbourPatch = model.getPatches().patchesToDisplay().toMap().get(newDict.lookup(NEIGHBOUR_PATCH_KEY)); + if (neighbourPatch != null) { + fixPreviousRelatedNeighbourPatches(patchName, neighbourPatch.getName()); + setNeighbourPatchToAMI(patchName, newDict, neighbourPatch); + } else if (isAlreadyCyclicAMIWithoutNeighbour(oldDict)) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No Neighbour Patch selected!\n", "Cyclic AMI Warning", JOptionPane.WARNING_MESSAGE); + } + } + + private void fixPreviousRelatedNeighbourPatches(String patchName, String neighbourPatchName) { + for (Patch p : model.getPatches().patchesToDisplay()) { + if (isRelatedPatch(p, patchName, neighbourPatchName)) { + setToDefaultType(p); + } + } + } + + private void setToDefaultType(Patch p) { + p.setPhisicalType(BoundaryType.getDefaultType()); + p.setBoundaryConditions(new BoundaryConditions(BoundaryConditionsDefaults.get(BoundaryType.getDefaultKey()))); + p.setDictionary(new Dictionary("")); + } + + private void setNeighbourPatchToAMI(String patchName, Dictionary newDict, Patch neighbourPatch) { + neighbourPatch.setBoundaryConditions(getAMIBoundaryConditions()); + neighbourPatch.setPhisicalType(BoundaryType.CYCLIC_AMI); + if (newDict.found(SEPARATION_VECTOR_KEY)) { + invertSeparationVector(newDict); + } + neighbourPatch.getDictionary().merge(newDict); + neighbourPatch.getDictionary().add(NEIGHBOUR_PATCH_KEY, patchName); + } + + private boolean isAlreadyCyclicAMIWithoutNeighbour(Dictionary dict) { + boolean notNull = dict != null; + boolean isCyclicAMI = dict.found(TYPE) && dict.lookup(TYPE).equals(CYCLIC_AMI_KEY); + boolean withoutNeighbour = dict.found(NEIGHBOUR_PATCH_KEY) && dict.lookup(NEIGHBOUR_PATCH_KEY).equals(""); + return notNull && isCyclicAMI && withoutNeighbour; + } + + private boolean isRelatedPatch(Patch p, String patchName, String neighbourPatchName) { + boolean isNotCurrentOrNeighbourPatch = !p.getName().equals(patchName) && !p.getName().equals(neighbourPatchName); + boolean isAMI = p.getPhisicalType().isCyclicAMI(); + boolean hasNeighbour = p.getDictionary() != null && p.getDictionary().found(NEIGHBOUR_PATCH_KEY); + if (hasNeighbour) { + boolean neighbourEqualsCurrentPatch = p.getDictionary().lookup(NEIGHBOUR_PATCH_KEY).equals(patchName); + boolean neighbourEqualsNeighbourPatch = p.getDictionary().lookup(NEIGHBOUR_PATCH_KEY).equals(neighbourPatchName); + return (isNotCurrentOrNeighbourPatch && isAMI && hasNeighbour && (neighbourEqualsCurrentPatch || neighbourEqualsNeighbourPatch)); + } + return false; + } + + private void invertSeparationVector(Dictionary d) { + String[] sepVector = d.lookupArray(SEPARATION_VECTOR_KEY); + StringBuilder sb = new StringBuilder("("); + for (String value : sepVector) { + double doubleValue = Double.parseDouble(value); + sb.append(-doubleValue + " "); + } + sb.append(")"); + d.add(SEPARATION_VECTOR_KEY, sb.toString()); + } + + @Override + public void stateChanged() { + } + + @Override + public void addMomentumPanel(ParametersPanel momentumPanel) { + } + + @Override + public void addTurbulencePanel(ParametersPanel momentumPanel) { + } + + @Override + public void addThermalPanel(ParametersPanel momentumPanel) { + } + + @Override + public void addPanel(String name, ParametersPanel pPanel) { + } + + @Override + public void addPanel(String name, ParametersPanel pPanel, int index) { + } + + @Override + public ParametersPanel getMomentumPanel() { + return null; + } + + @Override + public ParametersPanel getTurbulencePanel() { + return null; + } + + @Override + public ParametersPanel getThermalPanel() { + return null; + } + + @Override + public ParametersPanel getPanel(String name) { + return null; + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractParametersPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractParametersPanel.java new file mode 100644 index 0000000..69e87ac --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/AbstractParametersPanel.java @@ -0,0 +1,162 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.JCheckBox; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.modules.boundaryconditions.ParametersPanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryConditions; + +public abstract class AbstractParametersPanel extends JPanel implements ParametersPanel { + + private final JCheckBox allowEditing; + + protected final DictionaryPanelBuilder builder; + + private BoundaryTypePanel parentPanel; + + public AbstractParametersPanel(BoundaryTypePanel parent) { + super(new BorderLayout()); + this.parentPanel = parent; + + setName(getClass().getSimpleName()); + setOpaque(false); + + allowEditing = new JCheckBox(new AbstractAction("Allow Multiple Patches Editing") { + @Override + public void actionPerformed(ActionEvent e) { + builder.setEnabled(allowEditing.isSelected()); + canEdit = allowEditing.isSelected(); + } + }); + allowEditing.setFont(allowEditing.getFont().deriveFont(allowEditing.getFont().getSize2D() - 2)); + allowEditing.setOpaque(false); + + builder = new DictionaryPanelBuilder(); + + add(allowEditing, BorderLayout.NORTH); + add(builder.removeMargins().getPanel(), BorderLayout.CENTER); + init(); + populatePanel(); + } + + protected abstract void init(); + + protected abstract void populatePanel(); + + @Override + public JPanel getComponent() { + return this; + } + + public BoundaryTypePanel getParentPanel() { + return parentPanel; + } + + @Override + public void stateChanged(Model model) { + } + + @Override + public void materialsChanged(Model model) { + } + + @Override + public void tabChanged(Model model) { + } + + public void loadFromDictionary(Dictionary dictionary) { + } + + public void saveToDictionary(Dictionary dictionary) { + saveToDictionary(dictionary, builder); + } + + public static final void saveToDictionary(Dictionary dictionary, DictionaryPanelBuilder builder) { + DictionaryModel model = builder.getSelectedModel(); + if (model != null) { + Dictionary selected = new Dictionary(model.getDictionary()); +// System.out.println("AbstractParametersPanel.saveToDictionary() ---------"+selected.getName()+"--------- "); +// System.out.println("AbstractParametersPanel.saveToDictionary() ---------"+selected+"--------- "); + dictionary.add(selected); + for (DictionaryModel companion : model.getCompanions()) { + // System.out.println("AbstractParametersPanel.saveToDictionary() companion is "+companion.getDictionary().getName()); + dictionary.add(new Dictionary(companion.getDictionary())); + } + } + } + + public abstract void saveToBoundaryConditions(String patchName, BoundaryConditions bc); + + public abstract void loadFromBoundaryConditions(String patchName, BoundaryConditions bc); + + private boolean canEdit = false; + + @Override + public void setMultipleEditing(boolean multipleSelection) { + builder.setEnabled(!multipleSelection); + allowEditing.setVisible(multipleSelection); + allowEditing.setSelected(false); + canEdit = !multipleSelection; + } + + @Override + public boolean canEdit() { + return canEdit; + } + + @Override + public DictionaryModel getDictionaryModel() { + return builder.getSelectedModel(); + } + +// @Override +// public void selectDictionary(Dictionary dictionary) { +// builder.selectDictionary(dictionary); +// } +// +// @Override +// public void selectDictionaryByModel(DictionaryModel model, Dictionary dict) { +// builder.selectDictionaryByKey(model.getKey(), dict); +// } +// +// @Override +// public void selectDictionaries(Dictionary dictionary, Dictionary companion) { +// builder.selectDictionaries(dictionary, companion); +// } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/CyclicSettingsPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/CyclicSettingsPanel.java new file mode 100644 index 0000000..a816212 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/CyclicSettingsPanel.java @@ -0,0 +1,168 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.BOUNDARY_CONDITION; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.BOUNDARY_CONDITION_VECTOR; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.CYCLIC; + +import java.awt.BorderLayout; +import java.awt.Component; + +import javax.inject.Inject; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.modules.boundaryconditions.ParametersPanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Field.FieldType; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.ListBuilderFactory; +import eu.engys.util.ui.builder.PanelBuilder; + +public class CyclicSettingsPanel extends JPanel implements BoundaryTypePanel { + + private DictionaryModel cyclicModel; + + private Model model; + + @Inject + public CyclicSettingsPanel(Model model) { + super(new BorderLayout()); + this.model = model; + this.cyclicModel = new DictionaryModel(); + } + + @Override + public void resetToDefault() { + cyclicModel.setDictionary(new Dictionary(CYCLIC)); + } + + @Override + public void layoutPanel() { + PanelBuilder builder = new PanelBuilder(); + cyclicModel.setDictionary(new Dictionary(CYCLIC)); + builder.addComponent("Match Tolerance", cyclicModel.bindDouble("matchTolerance")); + builder.addComponent("Neighbour Patch", cyclicModel.bindSelection("neighbourPatch", ListBuilderFactory.getPatchesListBuilder(model))); + add(builder.getPanel()); + } + + @Override + public BoundaryType getType() { + return BoundaryType.CYCLIC; + } + + @Override + public Component getPanel() { + return this; + } + + @Override + public void loadFromPatches(Patch... patches) { + if (patches.length == 1) { + Dictionary dictionary = patches[0].getDictionary(); + if (dictionary.found(Dictionary.TYPE) && dictionary.lookup(Dictionary.TYPE).equals("cyclic")) { + cyclicModel.setDictionary(dictionary); + } else { + cyclicModel.setDictionary(new Dictionary(CYCLIC)); + } + } + } + + @Override + public void saveToPatch(Patch patch) { + Dictionary newDict = cyclicModel.getDictionary(); + + patch.setBoundaryConditions(getBoundaryConditions()); + patch.getDictionary().merge(newDict); + } + + private BoundaryConditions getBoundaryConditions() { + BoundaryConditions boundaryConditions = new BoundaryConditions(); + for (Field field : model.getFields().values()) { + if (field.getFieldType() == FieldType.SCALAR) { + boundaryConditions.add(field.getName(), new Dictionary(BOUNDARY_CONDITION)); + } else { + boundaryConditions.add(field.getName(), new Dictionary(BOUNDARY_CONDITION_VECTOR)); + } + } + return boundaryConditions; + } + + @Override + public void stateChanged() { + } + + @Override + public void materialsChanged() { + } + + @Override + public void addMomentumPanel(ParametersPanel momentumPanel) { + } + + @Override + public void addTurbulencePanel(ParametersPanel momentumPanel) { + } + + @Override + public void addThermalPanel(ParametersPanel momentumPanel) { + } + + @Override + public ParametersPanel getMomentumPanel() { + return null; + } + + @Override + public ParametersPanel getTurbulencePanel() { + return null; + } + + @Override + public ParametersPanel getThermalPanel() { + return null; + } + + @Override + public ParametersPanel getPanel(String name) { + return null; + } + + @Override + public void addPanel(String name, ParametersPanel pPanel) { + } + + @Override + public void addPanel(String name, ParametersPanel pPanel, int index) { + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/MomentumParametersPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/MomentumParametersPanel.java new file mode 100644 index 0000000..cb2a1d7 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/MomentumParametersPanel.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryConditions; + +public abstract class MomentumParametersPanel extends AbstractParametersPanel { + + public MomentumParametersPanel(BoundaryTypePanel parent) { + super(parent); + } + + @Override + public String getTitle() { + return "Momentum"; + } + + public boolean isEnabled(Model model) { + return true; + } + + @Override + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getMomentum(); + loadFromDictionary(dictionary); + } + + @Override + public void saveToBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getMomentum(); + saveToDictionary(dictionary); + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/PhaseParametersPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/PhaseParametersPanel.java new file mode 100644 index 0000000..75a7320 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/PhaseParametersPanel.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.patches.BoundaryConditions; + +public abstract class PhaseParametersPanel extends AbstractParametersPanel { + + public PhaseParametersPanel(BoundaryTypePanel parent) { + super(parent); + } + + @Override + public String getTitle() { + return AbstractBoundaryTypePanel.PHASE_FRACTION; + } + + public boolean isEnabled(Model model) { + State state = model.getState(); + return state.getMultiphaseModel().isMultiphase(); + } + + @Override + public void saveToBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getPhase(); + saveToDictionary(dictionary); + } + + @Override + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getPhase(); + loadFromDictionary(dictionary); + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/StandardCyclicAMISettingsPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/StandardCyclicAMISettingsPanel.java new file mode 100644 index 0000000..139ee3f --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/StandardCyclicAMISettingsPanel.java @@ -0,0 +1,108 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.CYCLIC_AMI_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.CYCLIC_AMI_OS; +import static eu.engys.gui.casesetup.boundaryconditions.factories.CyclicFactory.CYCLIC_AMI_ROTATIONAL_OS; + +import javax.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.ListBuilderFactory; +import eu.engys.util.ui.builder.PanelBuilder; + +public class StandardCyclicAMISettingsPanel extends AbstractCyclicAMISettingsPanel { + + @Inject + public StandardCyclicAMISettingsPanel(Model model) { + super(model); + } + + @Override + public void resetToDefault() { + super.resetToDefault(); + this.cyclicModel.setDictionary(new Dictionary(CYCLIC_AMI_OS)); + this.rotationalModel.setDictionary(new Dictionary(CYCLIC_AMI_ROTATIONAL_OS)); + } + + @Override + protected void bindAmiParameters(PanelBuilder builder) { + builder.addComponent(MATCH_TOLERANCE_LABEL, cyclicModel.bindDouble(MATCH_TOLERANCE_KEY)); + builder.addComponent(WEIGHT_CORRECTION_LABEL, cyclicModel.bindDouble(WEIGHT_CORRECTION_KEY)); + builder.addComponent(NEIGHBOUR_PATCH_LABEL, cyclicModel.bindSelection(NEIGHBOUR_PATCH_KEY, ListBuilderFactory.getPatchesListBuilder(model))); + } + + @Override + protected void bindRotationalParameters() { + transformBuilder.startDictionary(ROTATIONAL_LABEL, rotationalModel); + transformBuilder.addComponent(AXIS_LABEL, rotationalModel.bindPoint(ROTATION_AXIS_KEY)); + transformBuilder.addComponent(CENTRE_LABEL, rotationalModel.bindPoint(ROTATION_CENTRE_KEY)); + transformBuilder.addComponent(ROTATION_ANGLE_LABEL, rotationalModel.bindDoubleAngle_360(ROTATION_ANGLE_KEY)); + transformBuilder.endDictionary(); + } + + @Override + public void loadFromPatches(Patch... patches) { + if (patches.length == 1) { + Dictionary dictionary = patches[0].getDictionary(); + if (dictionary.found(TYPE) && dictionary.lookup(TYPE).equals(CYCLIC_AMI_KEY)) { + Dictionary cyclicDict = extractCyclicDict(dictionary); + Dictionary transformDict = extractTransformDict(dictionary); + cyclicModel.setDictionary(cyclicDict); + transformBuilder.selectDictionary(transformDict); + } else { + cyclicModel.setDictionary(new Dictionary(CYCLIC_AMI_OS)); + transformBuilder.selectDictionary(couplingModel.getDictionary()); + } + } + } + + @Override + protected Dictionary extractCyclicDict(Dictionary dictionary) { + Dictionary cyclicDict = super.extractCyclicDict(dictionary); + cyclicDict.remove(ROTATION_ANGLE_KEY); + return cyclicDict; + } + + @Override + protected Dictionary extractTransformDict(Dictionary dictionary) { + Dictionary transformDict = super.extractTransformDict(dictionary); + if (dictionary.found(ROTATION_ANGLE_KEY)) { + transformDict.add(ROTATION_ANGLE_KEY, dictionary.lookup(ROTATION_ANGLE_KEY)); + } + return transformDict; + } + + @Override + public void materialsChanged() { + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/ThermalParametersPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/ThermalParametersPanel.java new file mode 100644 index 0000000..3df271f --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/ThermalParametersPanel.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.patches.BoundaryConditions; + +public abstract class ThermalParametersPanel extends AbstractParametersPanel { + + public ThermalParametersPanel(BoundaryTypePanel parent) { + super(parent); + } + + @Override + public String getTitle() { + return "Thermal"; + } + + public boolean isEnabled(Model model) { + State state = model.getState(); + return state.isEnergy(); + } + + @Override + public void saveToBoundaryConditions(String patchName, BoundaryConditions bc) { + saveToDictionary(bc.getThermal()); + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/TurbulenceParametersPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/TurbulenceParametersPanel.java new file mode 100644 index 0000000..2b011e4 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/TurbulenceParametersPanel.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels; + +import static eu.engys.gui.casesetup.boundaryconditions.utils.TurbulenceUtils.setKEpsilon; +import static eu.engys.gui.casesetup.boundaryconditions.utils.TurbulenceUtils.setKEquationEddy; +import static eu.engys.gui.casesetup.boundaryconditions.utils.TurbulenceUtils.setKOmega; +import static eu.engys.gui.casesetup.boundaryconditions.utils.TurbulenceUtils.setSpalartAllmaras; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.TurbulenceModelType; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.patches.BoundaryConditions; + +public abstract class TurbulenceParametersPanel extends AbstractParametersPanel { + + public static final String TURBULENCE = "Turbulence"; + private TurbulenceModelType type; + + public TurbulenceParametersPanel(BoundaryTypePanel parent) { + super(parent); + } + + @Override + public String getTitle() { + return TURBULENCE; + } + + public boolean isEnabled(Model model) { + State state = model.getState(); + return (state.getTurbulenceModel() != null && state.getTurbulenceModel().getType() != TurbulenceModelType.LAMINAR); + } + + @Override + public void stateChanged(Model model) { + TurbulenceModelType type = model.getState().getTurbulenceModel().getType(); + if (this.type == null || this.type != type) { + this.type = type; + if (type.isKepsilon()) { + setKEpsilon(builder); + } else if (type.isKomega()) { + setKOmega(builder); + } else if (type.isSpalartAllmaras()) { + setSpalartAllmaras(builder); + } else if (type.isKEquationeddy()) { + setKEquationEddy(builder); + } + } + } + + @Override + public void saveToBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getTurbulence(); + saveToDictionary(dictionary); + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/MomentumPatch.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/MomentumPatch.java new file mode 100644 index 0000000..99c9a18 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/MomentumPatch.java @@ -0,0 +1,421 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels.patch; + +import static eu.engys.core.project.zero.fields.Fields.P; +import static eu.engys.core.project.zero.fields.Fields.U; +import static eu.engys.gui.casesetup.boundaryconditions.factories.PressureFactory.fixedFluxPressure; +import static eu.engys.gui.casesetup.boundaryconditions.factories.PressureFactory.fixedValuePressure; +import static eu.engys.gui.casesetup.boundaryconditions.factories.PressureFactory.fixedValuePressure_COMP; +import static eu.engys.gui.casesetup.boundaryconditions.factories.PressureFactory.freestreamPressure; +import static eu.engys.gui.casesetup.boundaryconditions.factories.PressureFactory.zeroGradientPressure; +import static eu.engys.gui.casesetup.boundaryconditions.factories.StandardPressureFactory.totalPressure; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.cylindricalInletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.fixedValueVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.freestreamVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.inletOutletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.massFlowRateInletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.pressureDirectedInletOutletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.pressureDirectedInletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.pressureInletOutletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.pressureInletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.surfaceNormalFixedValue; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.variableHeightFlowRateInletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.volumetricFlowRateInletVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.zeroGradientVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.MASS_FLOW_RATE_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.VOLUMETRIC_FLOW_RATE_KEY; +import static eu.engys.util.Symbols.CUBE; +import static eu.engys.util.Symbols.M2_S2; +import static eu.engys.util.Symbols.PASCAL; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.gui.casesetup.boundaryconditions.panels.MomentumParametersPanel; +import eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils; +import eu.engys.util.Symbols; +import eu.engys.util.ui.builder.JComboBoxController; +import eu.engys.util.ui.textfields.DoubleField; + +public class MomentumPatch extends MomentumParametersPanel { + + public static final String TOTAL_PRESSURE_LABEL = "Total Pressure"; + public static final String INLET_OUTLET_VELOCITY_LABEL = "Inlet Outlet Velocity"; + public static final String FREESTREAM_LABEL = "Freestream"; + public static final String PRESSURE_DIRECTED_INLET_OUTLET_VELOCITY_LABEL = "Pressure Directed Inlet Outlet Velocity"; + public static final String PRESSURE_INLET_OUTLET_VELOCITY_LABEL = "Pressure Inlet Outlet Velocity"; + public static final String PRESSURE_DIRECTED_INLET_VELOCITY_LABEL = "Pressure Directed Inlet Velocity"; + public static final String PRESSURE_INLET_VELOCITY_LABEL = "Pressure Inlet Velocity"; + public static final String VOLUMETRIC_FLOW_RATE_INLET_LABEL = "Volumetric Flow Rate Inlet"; + public static final String VARIABLE_HEIGHT_FLOW_RATE_INLET_LABEL = "Variable Height Flow Rate Inlet"; + public static final String MASS_FLOW_RATE_INLET_LABEL = "Mass Flow Rate Inlet"; + public static final String SURFACE_NORMAL_FIXED_VALUE_LABEL = "Surface Normal Fixed Value"; + public static final String CYLINDRICAL_INLET_VELOCITY_LABEL = "Cylindrical Inlet Velocity"; + public static final String FIXED_VALUE_LABEL = "Fixed Value"; + public static final String ZERO_GRADIENT_LABEL = "Zero Gradient"; + public static final String FREESTREAM_PRESSURE_LABEL = "Freestream Pressure"; + public static final String FIXED_FLUX_PRESSURE_LABEL = "Fixed Flux Pressure"; + public static final String PRESSURE_COMP = "Pressure " + PASCAL; + public static final String PRESSURE_INCOMP = "Pressure " + M2_S2; + + private DictionaryPanelBuilder velocityBuilder; + private JComboBoxController velocityTypeChoice; + + private DictionaryPanelBuilder pressureBuilder; + private JComboBoxController pressureChoice; + + private JLabel totalPressureLabel; + private JLabel fixedPressureLabel; + + private DoubleField fixedPressureField; + private DoubleField totalPressureField; + + private DictionaryModel fixedValueVelocityModel; + private DictionaryModel cylindricalInletVelocityModel; + private DictionaryModel surfaceNormalFixedValuemodel; + private DictionaryModel massFlowRateModel; + private DictionaryModel variableHeightFlowRateModel; + private DictionaryModel volumetricFlowRateModel; + private DictionaryModel pressureInletVelocityModel; + private DictionaryModel pressureDirectedInletVelocityModel; + private DictionaryModel pressureInletOutletVelocityModel; + private DictionaryModel pressureDirectedInletOutletVelocityModel; + private DictionaryModel freeStreamVelocityModel; + private DictionaryModel inletOutletVelocityModel; + private DictionaryModel zeroGradientVelocityModel; + + private DictionaryModel fixedValuePressureModel; + private DictionaryModel fixedFluxPressureModel; + private DictionaryModel freestreamPressureModel; + private DictionaryModel totalPressureModel; + private DictionaryModel zeroGradientPressureModel; + + public MomentumPatch(BoundaryTypePanel parent) { + super(parent); + } + + @Override + protected void init() { + // Velocity + fixedValueVelocityModel = new DictionaryModel(); + cylindricalInletVelocityModel = new DictionaryModel(); + surfaceNormalFixedValuemodel = new DictionaryModel(); + massFlowRateModel = new DictionaryModel(); + volumetricFlowRateModel = new DictionaryModel(); + variableHeightFlowRateModel = new DictionaryModel(); + pressureInletVelocityModel = new DictionaryModel(); + pressureDirectedInletVelocityModel = new DictionaryModel(); + pressureInletOutletVelocityModel = new DictionaryModel(); + pressureDirectedInletOutletVelocityModel = new DictionaryModel(); + freeStreamVelocityModel = new DictionaryModel(); + inletOutletVelocityModel = new DictionaryModel(); + zeroGradientVelocityModel = new DictionaryModel(); + + // Pressure + fixedValuePressureModel = new DictionaryModel(); + fixedFluxPressureModel = new DictionaryModel(); + freestreamPressureModel = new DictionaryModel(); + totalPressureModel = new DictionaryModel(); + zeroGradientPressureModel = new DictionaryModel(); + } + + @Override + public void resetToDefault(Model model) { + // Velocity + fixedValueVelocityModel.setDictionary(new Dictionary(fixedValueVelocity)); + cylindricalInletVelocityModel.setDictionary(new Dictionary(cylindricalInletVelocity)); + surfaceNormalFixedValuemodel.setDictionary(new Dictionary(surfaceNormalFixedValue)); + variableHeightFlowRateModel.setDictionary(new Dictionary(variableHeightFlowRateInletVelocity)); + massFlowRateModel.setDictionary(new Dictionary(massFlowRateInletVelocity)); + volumetricFlowRateModel.setDictionary(new Dictionary(volumetricFlowRateInletVelocity)); + pressureInletVelocityModel.setDictionary(new Dictionary(pressureInletVelocity)); + pressureDirectedInletVelocityModel.setDictionary(new Dictionary(pressureDirectedInletVelocity)); + pressureInletOutletVelocityModel.setDictionary(new Dictionary(pressureInletOutletVelocity)); + pressureDirectedInletOutletVelocityModel.setDictionary(new Dictionary(pressureDirectedInletOutletVelocity)); + freeStreamVelocityModel.setDictionary(new Dictionary(freestreamVelocity)); + inletOutletVelocityModel.setDictionary(new Dictionary(inletOutletVelocity)); + zeroGradientVelocityModel.setDictionary(new Dictionary(zeroGradientVelocity)); + + // Pressure + updateFixedValuePressureModel(model); + totalPressureModel.setDictionary(new Dictionary(totalPressure)); + freestreamPressureModel.setDictionary(new Dictionary(freestreamPressure)); + fixedFluxPressureModel.setDictionary(new Dictionary(fixedFluxPressure)); + zeroGradientPressureModel.setDictionary(new Dictionary(zeroGradientPressure)); + + } + + @Override + public DictionaryModel getDictionaryModel() { + DictionaryModel velocityModel = velocityBuilder.getSelectedModel(); + velocityModel.setCompanion(pressureBuilder.getSelectedModel()); + return velocityModel; + } + + @Override + public void populatePanel() { + resetToDefault(null); + /* VELOCITY */ + velocityBuilder = new DictionaryPanelBuilder(); + velocityTypeChoice = (JComboBoxController) velocityBuilder.startChoice("Velocity Type"); + + buildFixedValueVelocity(); + buildCylindricalInletVelocity(); + buildSurfaceNormalFixedValue(); + buildMassFlowRate(); + buildVolumetricFlowRate(); + buildVariableHeightFlowRate(); + buildPressureInletVelocity(); + buildPressureDirectedInletVelocity(); + buildPressureInletOutletVelocity(); + buildPressureDirectedInletOutletVelocity(); + buildFreestream(); + buildInletOutlet(); + buildZeroGradientVelocity(); + velocityBuilder.endChoice(); + + /* PRESSURE */ + pressureBuilder = new DictionaryPanelBuilder(); + pressureChoice = (JComboBoxController) pressureBuilder.startChoice("Pressure Type"); + buildFixedValuePressure(); + buildTotalPressure(); + buildFreestreamPressure(); + buildBuoyantPressure(); + buildZeroGradientPressure(); + pressureBuilder.endChoice(); + + /* ---- */ + JPanel velocityPanel = velocityBuilder.getPanel(); + JPanel pressurePanel = pressureBuilder.getPanel(); + velocityPanel.setBorder(BorderFactory.createTitledBorder("Velocity")); + pressurePanel.setBorder(BorderFactory.createTitledBorder("Pressure")); + builder.addComponent(velocityPanel); + builder.addComponent(pressurePanel); + } + + /** + * VELOCITY + */ + private void buildFixedValueVelocity() { + velocityBuilder.startDictionary(FIXED_VALUE_LABEL, fixedValueVelocityModel); + BoundaryConditionsUtils.buildSimpleFixedVelocityPanel(velocityBuilder, fixedValueVelocityModel); + velocityBuilder.endDictionary(); + } + + private void buildCylindricalInletVelocity() { + velocityBuilder.startDictionary(CYLINDRICAL_INLET_VELOCITY_LABEL, cylindricalInletVelocityModel); + BoundaryConditionsUtils.buildFixedCylindricalVelocityPanel(velocityBuilder, cylindricalInletVelocityModel); + velocityBuilder.endDictionary(); + } + + private void buildSurfaceNormalFixedValue() { + velocityBuilder.startDictionary(SURFACE_NORMAL_FIXED_VALUE_LABEL, surfaceNormalFixedValuemodel); + velocityBuilder.addComponent("Velocity Magnitude " + Symbols.M_S, surfaceNormalFixedValuemodel.bindUniformDouble("refValue", -Double.MAX_VALUE, 0, 0)); + velocityBuilder.endDictionary(); + } + + private void buildMassFlowRate() { + velocityBuilder.startDictionary(MASS_FLOW_RATE_INLET_LABEL, massFlowRateModel); + velocityBuilder.addComponent("Mass Flow Rate [kg/s]", massFlowRateModel.bindConstantDouble("massFlowRate")); + velocityBuilder.endDictionary(); + } + + private void buildVolumetricFlowRate() { + velocityBuilder.startDictionary(VOLUMETRIC_FLOW_RATE_INLET_LABEL, volumetricFlowRateModel); + velocityBuilder.addComponent("Volumetric Flow Rate [m" + CUBE + "/s]", volumetricFlowRateModel.bindConstantDouble("volumetricFlowRate")); + velocityBuilder.endDictionary(); + } + + private void buildVariableHeightFlowRate() { + velocityBuilder.startDictionary(VARIABLE_HEIGHT_FLOW_RATE_INLET_LABEL, variableHeightFlowRateModel); + velocityBuilder.addComponent("Volumetric Flow Rate [m" + CUBE + "/s]", variableHeightFlowRateModel.bindDouble("flowRate")); + velocityBuilder.endDictionary(); + } + + public void buildPressureInletVelocity() { + velocityBuilder.startDictionary(PRESSURE_INLET_VELOCITY_LABEL, pressureInletVelocityModel); + velocityBuilder.endDictionary(); + } + + public void buildPressureDirectedInletVelocity() { + velocityBuilder.startDictionary(PRESSURE_DIRECTED_INLET_VELOCITY_LABEL, pressureDirectedInletVelocityModel); + velocityBuilder.addComponent("Inlet Direction", pressureDirectedInletVelocityModel.bindPoint("inletDirection")); + velocityBuilder.endDictionary(); + } + + public void buildPressureInletOutletVelocity() { + velocityBuilder.startDictionary(PRESSURE_INLET_OUTLET_VELOCITY_LABEL, pressureInletOutletVelocityModel); + velocityBuilder.endDictionary(); + } + + public void buildPressureDirectedInletOutletVelocity() { + velocityBuilder.startDictionary(PRESSURE_DIRECTED_INLET_OUTLET_VELOCITY_LABEL, pressureDirectedInletOutletVelocityModel); + velocityBuilder.addComponent("Inlet Direction", pressureDirectedInletOutletVelocityModel.bindPoint("inletDirection")); + velocityBuilder.endDictionary(); + } + + private void buildFreestream() { + velocityBuilder.startDictionary(FREESTREAM_LABEL, freeStreamVelocityModel); + BoundaryConditionsUtils.buildFreestreamVelocityPanel(velocityBuilder, freeStreamVelocityModel); + velocityBuilder.endDictionary(); + } + + public void buildInletOutlet() { + velocityBuilder.startDictionary(INLET_OUTLET_VELOCITY_LABEL, inletOutletVelocityModel); + velocityBuilder.addComponent("Inlet Value", inletOutletVelocityModel.bindUniformPoint("inletValue")); + velocityBuilder.endDictionary(); + } + + private void buildZeroGradientVelocity() { + velocityBuilder.startDictionary(ZERO_GRADIENT_LABEL, zeroGradientVelocityModel); + velocityBuilder.endDictionary(); + } + + /** + * PRESSURE + */ + private void buildFixedValuePressure() { + fixedPressureLabel = new JLabel(PRESSURE_INCOMP); + fixedPressureField = fixedValuePressureModel.bindUniformDouble("value"); + pressureBuilder.startDictionary(FIXED_VALUE_LABEL, fixedValuePressureModel); + pressureBuilder.addComponent(fixedPressureLabel, fixedPressureField); + pressureBuilder.endDictionary(); + } + + private void buildTotalPressure() { + totalPressureLabel = new JLabel(PRESSURE_INCOMP); + pressureBuilder.startDictionary(TOTAL_PRESSURE_LABEL, totalPressureModel); + totalPressureField = totalPressureModel.bindUniformDouble("p0"); + pressureBuilder.addComponent(totalPressureLabel, totalPressureField); + pressureBuilder.endDictionary(); + } + + private void buildFreestreamPressure() { + pressureBuilder.startDictionary(FREESTREAM_PRESSURE_LABEL, freestreamPressureModel); + pressureBuilder.endDictionary(); + } + + private void buildBuoyantPressure() { + pressureBuilder.startDictionary(FIXED_FLUX_PRESSURE_LABEL, fixedFluxPressureModel); + pressureBuilder.endDictionary(); + } + + private void buildZeroGradientPressure() { + pressureBuilder.startDictionary(ZERO_GRADIENT_LABEL, zeroGradientPressureModel); + pressureBuilder.endDictionary(); + } + + /** + * END + */ + + @Override + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getMomentum(); + + if (dictionary.subDict(U) != null) { + Dictionary uDict = new Dictionary(dictionary.subDict(U)); + if (uDict.found(MASS_FLOW_RATE_KEY)) { + velocityBuilder.selectDictionaryByKey(massFlowRateModel.getKey(), uDict); + } else if (uDict.found(VOLUMETRIC_FLOW_RATE_KEY)) { + velocityBuilder.selectDictionaryByKey(volumetricFlowRateModel.getKey(), uDict); + } else { + velocityBuilder.selectDictionary(uDict); + } + } else { + velocityBuilder.selectDictionary(null); + } + + Dictionary p = dictionary.subDict(P); + if (p != null) { + pressureBuilder.selectDictionary(new Dictionary(p)); + } else { + pressureBuilder.selectDictionary(null); + } + } + + @Override + public void saveToBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary momentum = bc.getMomentum(); + DictionaryModel velocityModel = velocityBuilder.getSelectedModel(); + DictionaryModel pressureModel = pressureBuilder.getSelectedModel(); + + momentum.add(new Dictionary(velocityModel.getDictionary())); + momentum.add(new Dictionary(pressureModel.getDictionary())); + } + + @Override + public void stateChanged(Model model) { + updateGUI(model); + updateFixedValuePressureModel(model); + } + + private void updateGUI(Model model) { + pressureChoice.clearDisabledIndexes(); + velocityTypeChoice.clearDisabledIndexes(); + + if (model.getState() != null && model.getState().isCompressible()) { + fixedPressureLabel.setText(PRESSURE_COMP); + totalPressureLabel.setText(PRESSURE_COMP); + + fixedPressureField.setName(PRESSURE_COMP); + totalPressureField.setName(PRESSURE_COMP); + + velocityTypeChoice.clearDisabledIndexes(); + + velocityTypeChoice.addDisabledItem(VOLUMETRIC_FLOW_RATE_INLET_LABEL); + } else { + fixedPressureLabel.setText(PRESSURE_INCOMP); + totalPressureLabel.setText(PRESSURE_INCOMP); + + fixedPressureField.setName(PRESSURE_INCOMP); + totalPressureField.setName(PRESSURE_INCOMP); + + velocityTypeChoice.addDisabledItem(MASS_FLOW_RATE_INLET_LABEL); + } + + if (!model.getState().getMultiphaseModel().isMultiphase()) { + velocityTypeChoice.addDisabledItem(VARIABLE_HEIGHT_FLOW_RATE_INLET_LABEL); + } + } + + private void updateFixedValuePressureModel(Model model) { + if (model != null && model.getState() != null && model.getState().isCompressible()) { + fixedValuePressureModel.setDictionary(new Dictionary(fixedValuePressure_COMP)); + } else { + fixedValuePressureModel.setDictionary(new Dictionary(fixedValuePressure)); + } + } +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/PatchSettingsPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/PatchSettingsPanel.java new file mode 100644 index 0000000..92699b0 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/PatchSettingsPanel.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels.patch; + +import javax.inject.Inject; + +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.gui.casesetup.boundaryconditions.panels.AbstractBoundaryTypePanel; + +public class PatchSettingsPanel extends AbstractBoundaryTypePanel { + + @Inject + public PatchSettingsPanel(Model model) { + super(model); + setName("Turbulence"); + } + + @Override + public void layoutPanel() { + super.layoutPanel(); + MomentumPatch momentum = new MomentumPatch(this); + TurbulencePatch turbulence = new TurbulencePatch(this); + ThermalPatch thermal = new ThermalPatch(this); + PhasePatch phase = new PhasePatch(model, this); + + addMomentumPanel(momentum); + addTurbulencePanel(turbulence); + addThermalPanel(thermal); + addPhasePanel(phase); + } + + @Override + public BoundaryType getType() { + return BoundaryType.PATCH; + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/PhasePatch.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/PhasePatch.java new file mode 100644 index 0000000..a7fc777 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/PhasePatch.java @@ -0,0 +1,140 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels.patch; + +import static eu.engys.gui.casesetup.boundaryconditions.factories.StandardPhaseFactory.calculated; +import static eu.engys.gui.casesetup.boundaryconditions.factories.StandardPhaseFactory.fixedValueVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.StandardPhaseFactory.inletOutlet; +import static eu.engys.gui.casesetup.boundaryconditions.factories.StandardPhaseFactory.zeroGradient; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.materials.Materials; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.gui.casesetup.boundaryconditions.panels.PhaseParametersPanel; + +public class PhasePatch extends PhaseParametersPanel { + + public static final String FIXED_VALUE_LABEL = "Fixed Value"; + public static final String ZERO_GRADIENT_LABEL = "Zero Gradient"; + public static final String INLET_OUTLET_LABEL = "Inlet Outlet"; + public static final String CALCULATED_LABEL = "Calculated"; + + private DictionaryModel fixedModel; + private DictionaryModel inletOutletModel; + private DictionaryModel zeroGradientModel; + private DictionaryModel calculatedModel; + private Model model; + + public PhasePatch(Model model, BoundaryTypePanel parent) { + super(parent); + this.model = model; + } + + @Override + protected void init() { + fixedModel = new DictionaryModel(); + inletOutletModel = new DictionaryModel(); + zeroGradientModel = new DictionaryModel(); + calculatedModel = new DictionaryModel(); + } + + @Override + public void stateChanged(Model model) { + resetToDefault(model); + } + + @Override + public void materialsChanged(Model model) { + resetToDefault(model); + } + + @Override + public void resetToDefault(Model model) { + String alphaFieldName = ""; + if (model != null) { + Materials materials = model.getMaterials(); + String mat1Name = (materials != null && materials.size() > 0) ? materials.get(0).getName() : ""; + alphaFieldName = Fields.ALPHA + "." + mat1Name; + } else { + alphaFieldName = Fields.ALPHA; + } + + fixedModel.setDictionary(new Dictionary(alphaFieldName, fixedValueVelocity)); + inletOutletModel.setDictionary(new Dictionary(alphaFieldName, inletOutlet)); + zeroGradientModel.setDictionary(new Dictionary(alphaFieldName, zeroGradient)); + calculatedModel.setDictionary(new Dictionary(alphaFieldName, calculated)); + } + + @Override + public void populatePanel() { + resetToDefault(null); + builder.startChoice("Type"); + buildFixedValues(); + buildInletOutlet(); + buildZeroGradient(); + buildCalculated(); + builder.endChoice(); + } + + private void buildFixedValues() { + builder.startDictionary(FIXED_VALUE_LABEL, fixedModel); + builder.addComponent("Value", fixedModel.bindUniformDouble("value", 0.0, 1.0)); + builder.endDictionary(); + } + + private void buildInletOutlet() { + builder.startDictionary(INLET_OUTLET_LABEL, inletOutletModel); + builder.addComponent("Inlet Value", inletOutletModel.bindUniformDouble("inletValue", 0.0, 1.0)); + builder.endDictionary(); + } + + private void buildZeroGradient() { + builder.startDictionary(ZERO_GRADIENT_LABEL, zeroGradientModel); + builder.endDictionary(); + } + + private void buildCalculated() { + builder.startDictionary(CALCULATED_LABEL, calculatedModel); + builder.endDictionary(); + } + + @Override + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getPhase(); + if (model.getState().getMultiphaseModel().isMultiphase()) { + String alphaField = Fields.ALPHA + "." + model.getMaterials().getFirstMaterialName(); + Dictionary alphaDict = dictionary.subDict(alphaField); + if (alphaDict != null) { + builder.selectDictionary(alphaDict); + } + } + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/ThermalPatch.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/ThermalPatch.java new file mode 100644 index 0000000..27d0ec3 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/ThermalPatch.java @@ -0,0 +1,124 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels.patch; + +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.fixedValue; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.inletOutlet; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.inletOutletTotalTemperature; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.totalTemperature; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.zeroGradient; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.gui.casesetup.boundaryconditions.panels.ThermalParametersPanel; + +public class ThermalPatch extends ThermalParametersPanel { + + private DictionaryModel fixedTemperatureModel; + private DictionaryModel totalTemperatureModel; + private DictionaryModel inletOutletModel; + private DictionaryModel zeroGradientModel; + private DictionaryModel inletOutletTotalTemperatureModel; + + public ThermalPatch(BoundaryTypePanel parent) { + super(parent); + } + + @Override + protected void init() { + fixedTemperatureModel = new DictionaryModel(); + totalTemperatureModel = new DictionaryModel(); + inletOutletModel = new DictionaryModel(); + zeroGradientModel = new DictionaryModel(); + inletOutletTotalTemperatureModel = new DictionaryModel(); + } + + @Override + public void resetToDefault(Model model) { + fixedTemperatureModel.setDictionary(new Dictionary(fixedValue)); + totalTemperatureModel.setDictionary(new Dictionary(totalTemperature)); + inletOutletModel.setDictionary(new Dictionary(inletOutlet)); + zeroGradientModel.setDictionary(new Dictionary(zeroGradient)); + inletOutletTotalTemperatureModel.setDictionary(new Dictionary(inletOutletTotalTemperature)); + } + + @Override + public void populatePanel() { + resetToDefault(null); + + builder.startChoice("Type"); + buildFixedTemperaturePanel(); + buildTotalTemperaturePanel(); + buildInletOutlet(); + buildZeroGradient(); + buildInletOutletTotalTemperature(); + builder.endChoice(); + } + + private void buildFixedTemperaturePanel() { + builder.startDictionary("Fixed Temperature", fixedTemperatureModel); + builder.addComponent("Temperature Value [K]", fixedTemperatureModel.bindUniformDouble("value")); + builder.endDictionary(); + } + + private void buildTotalTemperaturePanel() { + builder.startDictionary("Total Temperature", totalTemperatureModel); + builder.addComponent("Compressibility", totalTemperatureModel.bindDouble("psi")); + builder.addComponent("Ratio Of Specific Heats", totalTemperatureModel.bindDouble("gamma")); + builder.addComponent("Temperature Value [K]", totalTemperatureModel.bindUniformDouble("T0")); + builder.endDictionary(); + } + + private void buildInletOutlet() { + builder.startDictionary("Inlet Outlet", inletOutletModel); + builder.addComponent("Temperature Value [K]", inletOutletModel.bindUniformDouble("value", "inletValue")); + builder.endDictionary(); + } + + private void buildZeroGradient() { + builder.startDictionary("Zero Gradient", zeroGradientModel); + builder.endDictionary(); + } + + private void buildInletOutletTotalTemperature() { + builder.startDictionary("Inlet Outlet Total Temperature", inletOutletTotalTemperatureModel); + builder.addComponent("Compressibility", inletOutletTotalTemperatureModel.bindDouble("psi")); + builder.addComponent("Ratio Of Specific Heats", inletOutletTotalTemperatureModel.bindDouble("gamma")); + builder.addComponent("Temperature Value [K]", inletOutletTotalTemperatureModel.bindUniformDouble("T0")); + builder.endDictionary(); + } + + @Override + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getThermal(); + Dictionary T = dictionary.subDict("T"); + builder.selectDictionary(T); + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/TurbulencePatch.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/TurbulencePatch.java new file mode 100644 index 0000000..d1c2e8e --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/patch/TurbulencePatch.java @@ -0,0 +1,197 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels.patch; + +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.epsilonFixedValue; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.epsilonInletOutlet; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.epsilonMixingLength; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.epsilonMixingLength_COMP; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.epsilonZeroGradient; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.kFixedValue; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.kInletOutlet; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.kMixingLength; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.kZeroGradient; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.nuTildaInletOutlet; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.nuTildaZeroGradient; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.nutildaFixedValue; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.omegaFixedValue; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.omegaInletOutlet; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.omegaMixingLength; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.omegaMixingLength_COMP; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TurbulenceFactory.omegaZeroGradient; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.gui.casesetup.boundaryconditions.panels.TurbulenceParametersPanel; +import eu.engys.gui.casesetup.boundaryconditions.utils.TurbulenceUtils; +import eu.engys.util.ui.builder.JComboBoxController; + +public class TurbulencePatch extends TurbulenceParametersPanel { + + private JComboBoxController typeChoice; + + private DictionaryModel dictKFixedModel; + private DictionaryModel dictOmegaFixedModel; + private DictionaryModel dictEpsilonFixedModel; + private DictionaryModel dictNuTildaFixedModel; + private DictionaryModel dictKInletOutletModel; + private DictionaryModel dictOmegaInletOutletModel; + private DictionaryModel dictEpsilonInletOutletModel; + private DictionaryModel dictNuTildaInletOutletModel; + private DictionaryModel dictKZeroGradientModel; + private DictionaryModel dictOmegaZeroGradientModel; + private DictionaryModel dictEpsilonZeroGradientModel; + private DictionaryModel dictNuTildaZeroGradientModel; + private DictionaryModel dictKTurbulentIntensityModel; + private DictionaryModel dictOmegaTurbulentIntensityModel; + private DictionaryModel dictEpsilonTurbulentIntensityModel; + + public TurbulencePatch(BoundaryTypePanel parent) { + super(parent); + } + + @Override + protected void init() { + dictKFixedModel = new DictionaryModel(); + dictOmegaFixedModel = new DictionaryModel(); + dictEpsilonFixedModel = new DictionaryModel(); + dictNuTildaFixedModel = new DictionaryModel(); + + dictKInletOutletModel = new DictionaryModel(); + dictOmegaInletOutletModel = new DictionaryModel(); + dictEpsilonInletOutletModel = new DictionaryModel(); + dictNuTildaInletOutletModel = new DictionaryModel(); + + dictKZeroGradientModel = new DictionaryModel(); + dictOmegaZeroGradientModel = new DictionaryModel(); + dictEpsilonZeroGradientModel = new DictionaryModel(); + dictNuTildaZeroGradientModel = new DictionaryModel(); + + dictKTurbulentIntensityModel = new DictionaryModel(); + dictOmegaTurbulentIntensityModel = new DictionaryModel(); + dictEpsilonTurbulentIntensityModel = new DictionaryModel(); + } + + @Override + public void resetToDefault(Model model) { + dictKFixedModel.setDictionary(new Dictionary(kFixedValue)); + dictOmegaFixedModel.setDictionary(new Dictionary(omegaFixedValue)); + dictEpsilonFixedModel.setDictionary(new Dictionary(epsilonFixedValue)); + dictNuTildaFixedModel.setDictionary(new Dictionary(nutildaFixedValue)); + + dictKInletOutletModel.setDictionary(new Dictionary(kInletOutlet)); + dictOmegaInletOutletModel.setDictionary(new Dictionary(omegaInletOutlet)); + dictEpsilonInletOutletModel.setDictionary(new Dictionary(epsilonInletOutlet)); + dictNuTildaInletOutletModel.setDictionary(new Dictionary(nuTildaInletOutlet)); + + dictKZeroGradientModel.setDictionary(new Dictionary(kZeroGradient)); + dictOmegaZeroGradientModel.setDictionary(new Dictionary(omegaZeroGradient)); + dictEpsilonZeroGradientModel.setDictionary(new Dictionary(epsilonZeroGradient)); + dictNuTildaZeroGradientModel.setDictionary(new Dictionary(nuTildaZeroGradient)); + + dictKTurbulentIntensityModel.setDictionary(new Dictionary(kMixingLength)); + + if (model != null && model.getState() != null && model.getState().isCompressible()) { + dictOmegaTurbulentIntensityModel.setDictionary(new Dictionary(omegaMixingLength_COMP)); + dictEpsilonTurbulentIntensityModel.setDictionary(new Dictionary(epsilonMixingLength_COMP)); + } else { + dictOmegaTurbulentIntensityModel.setDictionary(new Dictionary(omegaMixingLength)); + dictEpsilonTurbulentIntensityModel.setDictionary(new Dictionary(epsilonMixingLength)); + } + } + + @Override + public void populatePanel() { + resetToDefault(null); + typeChoice = (JComboBoxController) builder.startChoice("Type"); + TurbulenceUtils.buildFixedKnownValuesPanel(builder, dictKFixedModel, dictOmegaFixedModel, dictEpsilonFixedModel, dictNuTildaFixedModel); + TurbulenceUtils.buildInletOutletPanel(builder, dictKInletOutletModel, dictOmegaInletOutletModel, dictEpsilonInletOutletModel, dictNuTildaInletOutletModel); + TurbulenceUtils.buildTurbulentIntensityAndMixingLengthPanel(builder, dictKTurbulentIntensityModel, dictOmegaTurbulentIntensityModel, dictEpsilonTurbulentIntensityModel, null); + TurbulenceUtils.buildZeroGradientPanel(builder, dictKZeroGradientModel, dictOmegaZeroGradientModel, dictEpsilonZeroGradientModel, dictNuTildaZeroGradientModel); + builder.endChoice(); + } + + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getTurbulence(); + Dictionary k = dictionary.subDict(Fields.K); + Dictionary omega = dictionary.subDict(Fields.OMEGA); + Dictionary epsilon = dictionary.subDict(Fields.EPSILON); + Dictionary nutilda = dictionary.subDict(Fields.NU_TILDA); + + if (nutilda != null) { + builder.selectDictionary(nutilda); + } else if (k != null) { + if (omega != null) { + builder.selectDictionaries(omega, k); + } else if (epsilon != null) { + builder.selectDictionaries(epsilon, k); + } else { + builder.selectDictionary(k); + } + } + } + + @Override + public void tabChanged(Model model) { + super.tabChanged(model); + + fixIntensityAndMixingVisibility(model); + } + + @Override + public void stateChanged(Model model) { + super.stateChanged(model); + fixIntensityAndMixingVisibility(model); + + State state = model.getState(); + if (state.isCompressible()) { + dictEpsilonTurbulentIntensityModel.setDictionary(new Dictionary(epsilonMixingLength_COMP)); + dictOmegaTurbulentIntensityModel.setDictionary(new Dictionary(omegaMixingLength_COMP)); + } else if (state.isIncompressible()) { + dictEpsilonTurbulentIntensityModel.setDictionary(new Dictionary(epsilonMixingLength)); + dictOmegaTurbulentIntensityModel.setDictionary(new Dictionary(omegaMixingLength)); + } + + } + + private void fixIntensityAndMixingVisibility(Model model) { + State state = model.getState(); + typeChoice.clearDisabledIndexes(); + if (state.getTurbulenceModel().getType().isSpalartAllmaras()) { + typeChoice.addDisabledItem(TurbulenceUtils.BY_TURB_INTENSITY_AND_MIXING_LENGTH_LABEL); + } + + if (state.getTurbulenceModel().getType().isKEquationeddy()) { + typeChoice.addDisabledItem(TurbulenceUtils.BY_TURB_INTENSITY_AND_MIXING_LENGTH_LABEL); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardMomentumWall.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardMomentumWall.java new file mode 100644 index 0000000..f543a22 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardMomentumWall.java @@ -0,0 +1,151 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels.wall; + +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.fixedValueVelocity; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.noSlipWall; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.slipWall; +import static eu.engys.gui.casesetup.boundaryconditions.factories.VelocityFactory.standardRotatingWallVelocity; + +import java.util.Arrays; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.gui.casesetup.boundaryconditions.panels.MomentumParametersPanel; +import eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils; + +public class StandardMomentumWall extends MomentumParametersPanel { + + private static final String MOVING_WALL = "Moving Wall"; + private static final String FIXED_WALL = "Fixed Wall"; + public static final String[] TYPE_KEYS = { "noslip", "slip" }; + public static final String[] TYPE_LABELS = { "No-slip", "Slip" }; + + private DictionaryModel noSlipModel; + private DictionaryModel slipModel; + private DictionaryModel fixedVelocityModel; + private DictionaryModel rotatingWallModel; + + public StandardMomentumWall(BoundaryTypePanel parent) { + super(parent); + } + + @Override + protected void init() { + noSlipModel = new DictionaryModel(); + slipModel = new DictionaryModel(); + fixedVelocityModel = new DictionaryModel(); + rotatingWallModel = new DictionaryModel(); + } + + @Override + public void resetToDefault(Model model) { + noSlipModel.setDictionary(new Dictionary(noSlipWall)); + slipModel.setDictionary(new Dictionary(slipWall)); + fixedVelocityModel.setDictionary(new Dictionary(fixedValueVelocity)); + rotatingWallModel.setDictionary(new Dictionary(standardRotatingWallVelocity)); + } + + @Override + public void populatePanel() { + resetToDefault(null); + builder.startChoice("Type"); + fixedWallPanel(builder); + movingWallPanel(builder); + builder.endChoice(); + } + + public void fixedWallPanel(DictionaryPanelBuilder builder) { + builder.startGroup(FIXED_WALL); + builder.startChoice("Wall Type"); + + builder.startDictionary("No-slip", noSlipModel); + builder.endDictionary(); + + builder.startDictionary("Slip", slipModel); + builder.endDictionary(); + + builder.endChoice(); + builder.endGroup(); + } + + public void movingWallPanel(DictionaryPanelBuilder builder) { + builder.startGroup(MOVING_WALL); + builder.startChoice("Velocity Type"); + + buildFixedVelocityPanel(builder); + buildRotatingWallPanel(builder); + + builder.endChoice(); + builder.endGroup(); + } + + private void buildFixedVelocityPanel(DictionaryPanelBuilder builder) { + builder.startDictionary("Fixed Velocity", fixedVelocityModel); + BoundaryConditionsUtils.buildSimpleFixedVelocityPanel(builder, fixedVelocityModel); + builder.endDictionary(); + } + + private void buildRotatingWallPanel(DictionaryPanelBuilder builder) { + builder.startDictionary("Rotating Wall", rotatingWallModel); + builder.addComponent("Origin", rotatingWallModel.bindPoint("origin")); + builder.addComponent("Axis", rotatingWallModel.bindPoint("axis")); + builder.addComponent("Omega [rad/s]", rotatingWallModel.bindDouble("omega")); + builder.endDictionary(); + } + + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getMomentum(); + Dictionary U = dictionary.subDict("U"); + Dictionary p = dictionary.subDict("p"); + if (U != null) { + String U_type = U.lookup("type"); + if (U_type.contains("slip")) { + builder.selectDictionary(U); + } else if (U_type.equals("fixedValue")) { + if (U.found("value")) { + double[] value = U.lookupDoubleArray("value"); + double[] zeros = new double[] { 0, 0, 0 }; + if (Arrays.equals(value, zeros)) { + builder.selectDictionaryByModel(noSlipModel, U); + } else { + builder.selectDictionaryByModel(fixedVelocityModel, U); + } + } else { + + } + } else if (U_type.equals("tangentialVelocity") || U_type.equals("timeVaryingUniformFixedValue") || U_type.equals("rotatingWallVelocity") || U_type.equals("wheelVelocity")) { + builder.selectDictionary(U); + } + } + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardThermalWall.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardThermalWall.java new file mode 100644 index 0000000..4a51b31 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardThermalWall.java @@ -0,0 +1,140 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels.wall; + +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.fixedValue; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.turbulentHeatFluxTemperatureOCFD_FLUX; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.turbulentHeatFluxTemperatureOCFD_FLUX_COMP; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.turbulentHeatFluxTemperatureOCFD_POWER; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.turbulentHeatFluxTemperatureOCFD_POWER_COMP; +import static eu.engys.gui.casesetup.boundaryconditions.factories.TemperatureFactory.zeroGradient; +import static eu.engys.util.Symbols.SQUARE; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.patches.BoundaryConditions; +import eu.engys.gui.casesetup.boundaryconditions.panels.ThermalParametersPanel; + +public class StandardThermalWall extends ThermalParametersPanel { + + private DictionaryModel heatPowerModel; + private DictionaryModel heatFluxModel; + private DictionaryModel fixedTemperatureModel; + private DictionaryModel zeroGradientModel; + + public StandardThermalWall(BoundaryTypePanel parent) { + super(parent); + } + + @Override + protected void init() { + fixedTemperatureModel = new DictionaryModel(); + heatFluxModel = new DictionaryModel(); + heatPowerModel = new DictionaryModel(); + zeroGradientModel = new DictionaryModel(); + } + + @Override + public void resetToDefault(Model model) { + fixedTemperatureModel.setDictionary(new Dictionary(fixedValue)); + if (model != null && model.getState() != null && model.getState().isCompressible()) { + heatFluxModel.setDictionary(new Dictionary(turbulentHeatFluxTemperatureOCFD_FLUX_COMP)); + heatPowerModel.setDictionary(new Dictionary(turbulentHeatFluxTemperatureOCFD_POWER_COMP)); + } else { + heatFluxModel.setDictionary(new Dictionary(turbulentHeatFluxTemperatureOCFD_FLUX)); + heatPowerModel.setDictionary(new Dictionary(turbulentHeatFluxTemperatureOCFD_POWER)); + } + zeroGradientModel.setDictionary(new Dictionary(zeroGradient)); + } + + @Override + public void populatePanel() { + resetToDefault(null); + builder.startChoice("Type"); + buildFixedTemperaturePanel(); + buildHeatFluxPanel(); + buildTotalHeatPanel(); + buildZeroGradientPanel(); + builder.endChoice(); + } + + private void buildFixedTemperaturePanel() { + builder.startDictionary("Fixed Temperature", fixedTemperatureModel); + builder.addComponent("Temperature Value [K]", fixedTemperatureModel.bindUniformDouble("value")); + builder.endDictionary(); + } + + private void buildHeatFluxPanel() { + builder.startDictionary("Heat Flux", heatFluxModel); + builder.addComponent("Wall Heat Flux [W/m"+SQUARE+"]", heatFluxModel.bindUniformDouble("q")); + builder.endDictionary(); + } + + private void buildTotalHeatPanel() { + builder.startDictionary("Total Heat Load", heatPowerModel); + builder.addComponent("Total Heat Load At Wall [W]", heatPowerModel.bindUniformDouble("q")); + builder.endDictionary(); + } + + private void buildZeroGradientPanel() { + builder.startDictionary("Zero Gradient", zeroGradientModel); + builder.endDictionary(); + } + + @Override + public void stateChanged(Model model) { + State state = model.getState(); + if (state.isCompressible()) { + heatFluxModel.setDictionary(new Dictionary(turbulentHeatFluxTemperatureOCFD_FLUX_COMP)); + heatPowerModel.setDictionary(new Dictionary(turbulentHeatFluxTemperatureOCFD_POWER_COMP)); + } else if (state.isIncompressible()) { + heatFluxModel.setDictionary(new Dictionary(turbulentHeatFluxTemperatureOCFD_FLUX)); + heatPowerModel.setDictionary(new Dictionary(turbulentHeatFluxTemperatureOCFD_POWER)); + } + } + + @Override + public void loadFromBoundaryConditions(String patchName, BoundaryConditions bc) { + Dictionary dictionary = bc.getThermal(); + Dictionary T = dictionary.subDict("T"); + if (T != null) { + if (T.found("heatSource")) { + String source = T.lookup("heatSource"); + if (source.equals("power")) { + builder.selectDictionaryByModel(heatPowerModel, T); + } else if (source.equals("flux")) { + builder.selectDictionaryByModel(heatFluxModel, T); + } + } else { + builder.selectDictionary(T); + } + } + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardWallSettingsPanel.java b/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardWallSettingsPanel.java new file mode 100644 index 0000000..8ea8fd3 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/panels/wall/StandardWallSettingsPanel.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.panels.wall; + +import javax.inject.Inject; + +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.gui.casesetup.boundaryconditions.panels.AbstractBoundaryTypePanel; + +public class StandardWallSettingsPanel extends AbstractBoundaryTypePanel { + + @Inject + public StandardWallSettingsPanel(Model model) { + super(model); + } + + @Override + public void layoutPanel() { + super.layoutPanel(); + StandardMomentumWall momentum = new StandardMomentumWall(this); + StandardThermalWall thermal = new StandardThermalWall(this); + addMomentumPanel(momentum); + addThermalPanel(thermal); + } + + @Override + public BoundaryType getType() { + return BoundaryType.WALL; + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/utils/BoundaryConditionsUtils.java b/src/eu/engys/gui/casesetup/boundaryconditions/utils/BoundaryConditionsUtils.java new file mode 100644 index 0000000..5a83ec0 --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/utils/BoundaryConditionsUtils.java @@ -0,0 +1,350 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.utils; + +import static eu.engys.core.dictionary.Dictionary.TYPE; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.JButton; + +import net.java.dev.designgridlayout.Componentizer; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.gui.casesetup.boundaryconditions.TimeVaryingComboBoxController; +import eu.engys.gui.casesetup.boundaryconditions.TimeVaryingInterpolationTable; +import eu.engys.util.Symbols; + +public class BoundaryConditionsUtils { + + /* + * TYPES + */ + public static final String ADVECTIVE_KEY = "advective"; + public static final String ALPHA_CONTACT_ANGLE_KEY = "alphaContactAngle"; + public static final String CYLINDRICAL_INLET_VELOCITY_KEY = "cylindricalInletVelocity"; + public static final String COMPRESSIBLE_TURBULENT_MIXING_LENGTH_DISSIPATION_RATE_INLET_KEY = "compressible::turbulentMixingLengthDissipationRateInlet"; + public static final String COMPRESSIBLE_TURBULENT_MIXING_LENGTH_FREQUENCY_INLET_KEY = "compressible::turbulentMixingLengthFrequencyInlet"; + public static final String CONSTANT_ALPHA_CONTACT_ANGLE_KEY = "constantAlphaContactAngle"; + + public static final String COUPLED_TOTAL_VELOCITY_KEY = "coupledTotalVelocity"; + public static final String COUPLED_TOTAL_PRESSURE_KEY = "coupledTotalPressure"; + + public static final String DYNAMIC_ALPHA_CONTACT_ANGLE_KEY = "dynamicAlphaContactAngle"; + public static final String FIXED_FLUX_PRESSURE_KEY = "fixedFluxPressure"; + public static final String FIXED_MEAN_VALUE_KEY = "fixedMeanValue"; + public static final String FIXED_VALUE_KEY = "fixedValue"; + public static final String FLOW_RATE_INLET_VELOCITY_KEY = "flowRateInletVelocity"; + public static final String FLOW_RATE_OUTLET_VELOCITY_KEY = "flowRateOutletVelocity"; + public static final String FLUX_CORRECTED_VELOCITY_KEY = "fluxCorrectedVelocity"; + public static final String FREESTREAM_PRESSURE_KEY = "freestreamPressure"; + public static final String FREESTREAM_KEY = "freestream"; + public static final String INLET_OUTLET_KEY = "inletOutlet"; + public static final String INTERPOLATED_CYLINDRICAL_VELOCITY_KEY = "interpolatedCylindricalVelocity"; + public static final String INTERPOLATED_FIXED_VALUE_KEY = "interpolatedFixedValue"; + public static final String INTERPOLATED_INLET_OUTLET_KEY = "interpolatedInletOutlet"; + public static final String MAXWELL_SLIP_U_KEY = "maxwellSlipU"; + public static final String MOVING_WALL_VELOCITY_KEY = "movingWallVelocity"; + public static final String MOVING_WALL_COUPLED_VELOCITY_KEY = "movingNoSlipWall"; + public static final String MUT_K_ROUGH_WALL_FUNCTION_KEY = "mutKRoughWallFunction"; + public static final String MUT_U_ROUGH_WALL_FUNCTION_KEY = "mutURoughWallFunction"; + public static final String NUT_K_ROUGH_WALL_FUNCTION_KEY = "nutkRoughWallFunction"; + public static final String NUT_K_ATM_ROUGH_WALL_FUNCTION_KEY = "nutkAtmRoughWallFunction"; + public static final String NUT_U_ROUGH_WALL_FUNCTION_KEY = "nutURoughWallFunction"; + public static final String NUT_TURBULENT_INTENSITY_LENGTH_SCALE_INLET_KEY = "nutTurbulentIntensityLengthScaleInlet"; + public static final String PRESSURE_DIRECT_INLET_VELOCITY_KEY = "pressureDirectedInletVelocity"; + public static final String PRESSURE_DIRECT_INLET_OUTLET_VELOCITY_KEY = "pressureDirectedInletOutletVelocity"; + public static final String PRESSURE_INLET_OUTLET_VELOCITY_KEY = "pressureInletOutletVelocity"; + public static final String PRESSURE_INLET_VELOCITY_KEY = "pressureInletVelocity"; + public static final String RESISTIVE_PRESSURE_KEY = "resistivePressure"; + public static final String RESISTIVE_VELOCITY_KEY = "resistiveVelocity"; + public static final String ROTATING_WALL_VELOCITY_KEY = "rotatingWallVelocity"; + public static final String ROTATING_WALL_COUPLED_VELOCITY_KEY = "rotatingNoSlipWall"; + public static final String SLIP_KEY = "slip"; + public static final String SLIP_WALL_KEY = "slipWall"; + public static final String NO_SLIP_WALL_KEY = "noSlipWall"; + public static final String SUPERSONIC_FREESTREAM_KEY = "supersonicFreestream"; + public static final String SURFACE_NORMAL_FIXED_VALUE_KEY = "surfaceNormalFixedValue"; + public static final String TANGENTIAL_VELOCITY_KEY = "tangentialVelocity"; + public static final String TOTAL_PRESSURE_KEY = "totalPressure"; + public static final String TURBULENT_INTENSITY_KINETIC_ENERGY_INLET_KEY = "turbulentIntensityKineticEnergyInlet"; + public static final String TURBULENT_MIXING_LENGTH_DISSIPATION_RATE_INLET_KEY = "turbulentMixingLengthDissipationRateInlet"; + public static final String TURBULENT_MIXING_LENGTH_FREQUENCY_INLET_KEY = "turbulentMixingLengthFrequencyInlet"; + public static final String UNIFORM_FIXED_VALUE_KEY = "uniformFixedValue"; + public static final String UNIFORM_TOTAL_PRESSURE_KEY = "uniformTotalPressure"; + public static final String VARIABLE_HEIGHT_FLOW_RATE_INLET_VELOCITY_KEY = "variableHeightFlowRateInletVelocity"; + public static final String VELOCITY_GRADIENT_DISSIPATION_INLET_OUTLET_KEY = "velocityGradientDissipationInletOutlet"; + public static final String WAVE_TRANSMISSIVE_KEY = "waveTransmissive"; + public static final String WHEEL_VELOCITY_KEY = "wheelVelocity"; + public static final String WIND_PROFILE_DIRECTION_VELOCITY_KEY = "windProfileDirectionVelocity"; + public static final String ZERO_GRADIENT_KEY = "zeroGradient"; + + /* + * OTHER KEYS + */ + public static final String ACCOMMODATION_COEFFICIENT_KEY = "accommodationCoeff"; + public static final String ALPHA_KEY = "alpha"; + public static final String AXIS_KEY = "axis"; + public static final String CENTRE_KEY = "centre"; + public static final String CLAMP_KEY = "clamp"; + public static final String CS_KEY = "Cs"; + public static final String DATA_KEY = "data"; + public static final String DIRECTION_KEY = "direction"; + public static final String DISTANCE_ALONG_VECTOR_KEY = "distanceAlongVector"; + public static final String DISTANCE_TYPE_KEY = "distanceType"; + public static final String FIELD_KEY = "field"; + public static final String FILE_KEY = "file"; + public static final String FILE_NAME_KEY = "fileName"; + public static final String FLOW_RATE_KEY = "flowRate"; + public static final String FREESTREAM_VALUE_KEY = "freestreamValue"; + public static final String GAMMA_KEY = "gamma"; + public static final String GRADIENT_KEY = "gradient"; + public static final String INLET_VALUE_KEY = "inletValue"; + public static final String INLET_DIRECTION_KEY = "inletDirection"; + public static final String INTENSITY_KEY = "intensity"; + public static final String KS_KEY = "Ks"; + public static final String LENGTH_KEY = "length"; + public static final String LIMIT_KEY = "limit"; + public static final String MASS_FLOW_RATE_KEY = "massFlowRate"; + public static final String MEAN_VALUE_KEY = "meanValue"; + public static final String MIXING_LENGTH_KEY = "mixingLength"; + public static final String NONE_KEY = "none"; + public static final String NORMAL_KEY = "normal"; + public static final String OMEGA_KEY = "omega"; + public static final String ORIGIN_KEY = "origin"; + public static final String OUT_OF_BOUNDS_KEY = "outOfBounds"; + public static final String P0_KEY = "p0"; + public static final String PHASE_KEY = "phase"; + public static final String PHI_KEY = "phi"; + public static final String POINT_KEY = "point"; + public static final String POINT_DISTANCE_KEY = "pointDistance"; + public static final String PRESSURE_KEY = "pressure"; + public static final String RHO_KEY = "rho"; + public static final String RHO_INLET_KEY = "rhoInlet"; + public static final String REF_VALUE_KEY = "refValue"; + public static final String ROUGHNESS_CONSTANT_KEY = "roughnessConstant"; + public static final String ROUGHNESS_HEIGHT_KEY = "roughnessHeight"; + public static final String ROUGHNESS_FACTOR_KEY = "roughnessFactor"; + public static final String TABLE_KEY = "table"; + public static final String TABLE_FILE_KEY = "tableFile"; + public static final String THETA_0_KEY = "theta0"; + public static final String THETA_A_KEY = "thetaA"; + public static final String THETA_PROPERTIES_KEY = "thetaProperties"; + public static final String THETA_R_KEY = "thetaR"; + public static final String U_THETA_KEY = "uTheta"; + public static final String UNIFORM_VALUE_KEY = "uniformValue"; + public static final String UNIFORM_KEY = "uniform"; + public static final String USE_WALL_DISTANCE_KEY = "useWallDistance"; + public static final String UWALL = "Uwall"; + public static final String VOLUMETRIC_FLOW_RATE_KEY = "volumetricFlowRate"; + public static final String VALUE_KEY = "value"; + public static final String WALL_DISTANCE_KEY = "wallDistance"; + public static final String WIND_DIRECTION_KEY = "windDirection"; + public static final String X_KEY = "x"; + public static final String XOFFSET_KEY = "xoffset"; + public static final String XSCALE_KEY = "xscale"; + public static final String YOFFSET_KEY = "yoffset"; + public static final String Y_KEY = "y"; + public static final String YSCALE_KEY = "yscale"; + public static final String Z_KEY = "z"; + public static final String Z0_KEY = "z0"; + + /* + * LISTS + */ + public static final String[] LIMIT_KEYS = { NONE_KEY, GRADIENT_KEY, "zeroGradient", ALPHA_KEY }; + + // TO ORDER + + public static final String[] INTERP_ALGO_TYPE_KEYS = { "repeat", "clamp", "warn", "error" }; + public static final String TABLE_FILE_COEFFS_KEY = "tableFileCoeffs"; + + public static final String[] INTERP_ALGO_TYPE_LABELS = { "Repeat", "Clamp", "Warn", "Error" }; + + public static final String ZERO_GRADIENT_LABEL = "Zero Gradient"; + public static final String FIXED_VALUE_LABEL = "Fixed Value"; + + public static final String NON_UNIFORM_TEMPERATURE_LABEL = "Non-uniform Temperature"; + public static final String NON_UNIFORM_TURBULENCE_LABEL = "Non-uniform Turbulence"; + public static final String NON_UNIFORM_PHASE_FRACTION_LABEL = "Non-uniform Phase Fraction"; + + public static final String TIME_VARYING_LABEL = "Time-varying"; + public static final String TIME_VARYING_VELOCITY_LABEL = "Time-varying Velocity"; + public static final String TIME_VARYING_FLOW_RATE_LABEL = "Time-varying Flow Rate"; + public static final String TIME_VARYING_TEMPERATURE_LABEL = "Time-varying Temperature"; + public static final String TIME_VARYING_TURBULENCE_LABEL = "Time-varying Turbulence"; + public static final String TIME_VARYING_PHASE_FRACTION_LABEL = "Time-varying Phase Fraction"; + + public static final String TABLE_DATA_LABEL = "Table Data"; + public static final String INTERPOLATION_PROFILE_LABEL = "Interpolation Profile"; + public static final String FROM_FILE_LABEL = "From File"; + + public static final String INTERPOLATION_ALGORITHM_LABEL = "Interpolation Algorithm"; + + public static final String VELOCITY_LABEL = "Velocity " + Symbols.M_S; + + public static void buildSimpleFixedVelocityPanel(DictionaryPanelBuilder builder, DictionaryModel model) { + builder.addComponent(VELOCITY_LABEL, model.bindUniformPoint("value")); + } + + public static void buildFreestreamVelocityPanel(DictionaryPanelBuilder builder, DictionaryModel model) { + builder.addComponent(VELOCITY_LABEL, model.bindUniformPoint("value", "freestreamValue")); + } + + public static void buildFixedCylindricalVelocityPanel(DictionaryPanelBuilder builder, DictionaryModel model) { + builder.addComponent("Axis", model.bindPoint("axis")); + builder.addComponent("Centre", model.bindPoint("centre")); + builder.addComponent("Axial Velocity", model.bindDouble("axialVelocity")); + builder.addComponent("RPM", model.bindDouble("rpm")); + builder.addComponent("Radial Velocity", model.bindDouble("radialVelocity")); + } + + public static void buildTimeVaryingScalarPanel(DictionaryPanelBuilder builder, DictionaryModel model, String dictionaryKey, String name) { + buildTimeVaryingInterpolationTablePanel(builder, model, dictionaryKey, new String[]{name}); + } + + public static void buildTimeVaryingVectorPanel(DictionaryPanelBuilder builder, DictionaryModel model, String dictionaryKey, String X, String Y, String Z) { + buildTimeVaryingInterpolationTablePanel(builder, model, dictionaryKey, new String[]{X,Y,Z}); + } + + /* + * Utils + */ + + private static void buildTimeVaryingInterpolationTablePanel(DictionaryPanelBuilder builder, final DictionaryModel model, final String dictionaryKey, final String[] names) { + builder.startChoice(INTERPOLATION_PROFILE_LABEL, new TimeVaryingComboBoxController(model, dictionaryKey)); + + builder.startGroup(DATA_KEY, TABLE_DATA_LABEL); + JButton editButton = new JButton(new AbstractAction("Edit") { + @Override + public void actionPerformed(ActionEvent e) { + new TimeVaryingInterpolationTable(model, dictionaryKey + " " + TABLE_KEY, names).showDialog(); + } + }); + editButton.setName("Edit"); + builder.addComponent("", Componentizer.create().minToPref(editButton).component()); + builder.endGroup(); + + builder.startGroup(FILE_KEY, FROM_FILE_LABEL); + builder.addComponent("", model.bindFile(FILE_NAME_KEY)); + builder.endGroup(); + + builder.endChoice(); + + builder.addComponent(INTERPOLATION_ALGORITHM_LABEL, model.bindSelection(OUT_OF_BOUNDS_KEY, INTERP_ALGO_TYPE_KEYS, INTERP_ALGO_TYPE_LABELS)); + } + + /* + * Time varying fix + */ + + public static void fixTimeVaryingLoad(Dictionary dict, String dictionaryKey) { + String type = dict.lookup(TYPE); + if (type.equals(UNIFORM_FIXED_VALUE_KEY) || type.equals(ROTATING_WALL_VELOCITY_KEY) || type.equals(FLOW_RATE_INLET_VELOCITY_KEY) || type.equals(UNIFORM_TOTAL_PRESSURE_KEY)) { + if (isTableFile(dict, dictionaryKey)) { + if (dict.found(TABLE_FILE_COEFFS_KEY)) { + Dictionary tableFileCoeffs = dict.subDict(TABLE_FILE_COEFFS_KEY); + dict.add(OUT_OF_BOUNDS_KEY, tableFileCoeffs.lookup(OUT_OF_BOUNDS_KEY)); + dict.add(FILE_NAME_KEY, tableFileCoeffs.lookup(FILE_NAME_KEY)); + dict.remove(TABLE_FILE_COEFFS_KEY); + } + } + } + } + + public static void fixTimeVaryingSave(Dictionary dict, String dictionaryKey) { + String type = dict.lookup(TYPE); + if (type.equals(UNIFORM_FIXED_VALUE_KEY) || type.equals(ROTATING_WALL_VELOCITY_KEY) || type.equals(FLOW_RATE_INLET_VELOCITY_KEY) || type.equals(UNIFORM_TOTAL_PRESSURE_KEY)) { + if (isTableFile(dict, dictionaryKey)) { + Dictionary tableFileCoeffs = new Dictionary(TABLE_FILE_COEFFS_KEY); + tableFileCoeffs.add(OUT_OF_BOUNDS_KEY, dict.lookup(OUT_OF_BOUNDS_KEY)); + tableFileCoeffs.add(FILE_NAME_KEY, dict.lookup(FILE_NAME_KEY)); + dict.remove(OUT_OF_BOUNDS_KEY); + dict.remove(FILE_NAME_KEY); + dict.add(tableFileCoeffs); + } else { + dict.remove(FILE_NAME_KEY); + } + } + } + + public static boolean isTableFile(Dictionary dict, String dictionaryKey) { + if (dict == null) { + return false; + } + if (!dict.found(dictionaryKey)) { + return false; + } + if (!dict.isField(dictionaryKey)) { + return false; + } + return dict.lookup(dictionaryKey).equals(TABLE_FILE_KEY); + } + + public static void loadFlowRate(Dictionary U, DictionaryPanelBuilder builder) { + if (U.found(MASS_FLOW_RATE_KEY)) { + if (U.lookup(MASS_FLOW_RATE_KEY).startsWith(TABLE_KEY)) { + fixTimeVaryingLoad(U, MASS_FLOW_RATE_KEY); + builder.selectDictionaryByKey(BoundaryConditionsUtils.getTimeVaryingMassFlowRate(), U); + } else { + builder.selectDictionaryByKey(BoundaryConditionsUtils.getMassFlowRate(), U); + } + } else if (U.found(VOLUMETRIC_FLOW_RATE_KEY)) { + if (U.lookup(VOLUMETRIC_FLOW_RATE_KEY).startsWith(TABLE_KEY)) { + fixTimeVaryingLoad(U, VOLUMETRIC_FLOW_RATE_KEY); + builder.selectDictionaryByKey(BoundaryConditionsUtils.getTimeVaryingVolumetricFlowRate(), U); + } else { + builder.selectDictionaryByKey(BoundaryConditionsUtils.getVolumetricFlowRate(), U); + } + } else if (U.found(FLOW_RATE_KEY)) { + builder.selectDictionaryByKey(BoundaryConditionsUtils.getVariableHeightFlowRate(), U); + } + } + + public static String getMassFlowRate() { + return "massFlowRate"; + } + + public static String getTimeVaryingMassFlowRate() { + return "timeVaryingMassFlowRate"; + } + + public static String getTimeVaryingVolumetricFlowRate() { + return "timeVaryingVolumetricFlowRate"; + } + + public static String getVolumetricFlowRate() { + return "volumetricFlowRate"; + } + + public static String getVariableHeightFlowRate() { + return "variableHeightFlowRate"; + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/utils/ThermalUtils.java b/src/eu/engys/gui/casesetup/boundaryconditions/utils/ThermalUtils.java new file mode 100644 index 0000000..1f33b4d --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/utils/ThermalUtils.java @@ -0,0 +1,64 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.utils; + +import static eu.engys.core.dictionary.Dictionary.VALUE; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; + +public class ThermalUtils extends BoundaryConditionsUtils { + + public static final String INLET_VALUE_KEY = "inletValue"; + public static final String GAMMA_KEY = "gamma"; + public static final String T0_KEY = "T0"; + + public static final String RATIO_OF_SPECIFIC_HEATS_LABEL = "Ratio Of Specific Heats"; + public static final String TOTAL_TEMPERATURE_LABEL = "Total Temperature"; + public static final String TEMPERATURE_VALUE_K_LABEL = "Temperature Value [K]"; + public static final String FIXED_TEMPERATURE_LABEL = "Fixed Temperature"; + + public static void buildFixedTemperaturePanel(DictionaryPanelBuilder builder, DictionaryModel model) { + builder.startDictionary(FIXED_TEMPERATURE_LABEL, model); + builder.addComponent(TEMPERATURE_VALUE_K_LABEL, model.bindUniformDouble(VALUE)); + builder.endDictionary(); + model.setDictionary(model.getDictionary()); + } + + public static void buildInletOutletTemperaturePanel(DictionaryPanelBuilder builder, DictionaryModel model) { + builder.startDictionary(FIXED_TEMPERATURE_LABEL, model); + builder.addComponent(TEMPERATURE_VALUE_K_LABEL, model.bindUniformDouble(INLET_VALUE_KEY)); + builder.endDictionary(); + } + + public static void buildTotalTemperaturePanel(DictionaryPanelBuilder builder, DictionaryModel dict) { + builder.startDictionary(TOTAL_TEMPERATURE_LABEL, dict); + builder.addComponent(RATIO_OF_SPECIFIC_HEATS_LABEL, dict.bindDouble(GAMMA_KEY)); + builder.addComponent(TEMPERATURE_VALUE_K_LABEL, dict.bindUniformDouble(T0_KEY)); + builder.endDictionary(); + } + +} diff --git a/src/eu/engys/gui/casesetup/boundaryconditions/utils/TurbulenceUtils.java b/src/eu/engys/gui/casesetup/boundaryconditions/utils/TurbulenceUtils.java new file mode 100644 index 0000000..600dacd --- /dev/null +++ b/src/eu/engys/gui/casesetup/boundaryconditions/utils/TurbulenceUtils.java @@ -0,0 +1,222 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.boundaryconditions.utils; + +import static eu.engys.util.Symbols.EPSILON_SYMBOL; +import static eu.engys.util.Symbols.K_SYMBOL; +import static eu.engys.util.Symbols.M2_S; +import static eu.engys.util.Symbols.OMEGA_SYMBOL; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; + +public class TurbulenceUtils extends BoundaryConditionsUtils { + + public static final String FIXED_VALUES_LABEL = "Fixed Values"; + public static final String INFLOW_FIXED_VALUES_LABEL = "Inflow Fixed Values"; + public static final String INLET_OUTLET_LABEL = "Inlet Outlet"; + public static final String ZERO_GRADIENT_LABEL = "Zero Gradient"; + public static final String BY_TURB_INTENSITY_AND_MIXING_LENGTH_LABEL = "By Turb. Intensity And Mixing Length"; + + public static final String K_LABEL = "k " + K_SYMBOL;// "Turbulent Kinetik Energy"; + public static final String NU_TILDA_LABEL = "NuTilda " + M2_S; + public static final String EPSILON_LABEL = "Epsilon " + EPSILON_SYMBOL; + public static final String OMEGA_LABEL = "Omega " + OMEGA_SYMBOL; + public static final String KEQUATION_LABEL = K_LABEL; + + private static final String TIMEVARYING_KEY = "timevarying"; + private static final String NONUNIFROM_KEY = "nonunifrom"; + private static final String FIXED_KEY = "fixed"; + private static final String ZERO_KEY = "zero"; + private static final String INOUT_KEY = "inout"; + private static final String MIXING_KEY = "mixing"; + + public static final String TURBULENCE_INTENSITY = "Turbulence Intensity"; + + public static void buildFixedKnownValuesPanel(DictionaryPanelBuilder builder, DictionaryModel dictK, DictionaryModel dictOmega, DictionaryModel dictEpsilon, DictionaryModel dictNutilda) { + builder.startGroup(FIXED_VALUES_LABEL); + builder.startHidable(FIXED_KEY); + + dictOmega.setCompanion(dictK); + builder.startDictionary(OMEGA_LABEL, dictOmega); + builder.addComponent(K_LABEL, dictK.bindUniformDouble("value")); + builder.addComponent(OMEGA_LABEL, dictOmega.bindUniformDouble("value")); + builder.endDictionary(); + + dictEpsilon.setCompanion(dictK); + builder.startDictionary(EPSILON_LABEL, dictEpsilon); + builder.addComponent(K_LABEL, dictK.bindUniformDouble("value")); + builder.addComponent(EPSILON_LABEL, dictEpsilon.bindUniformDouble("value")); + builder.endDictionary(); + + builder.startDictionary(NU_TILDA_LABEL, dictNutilda); + builder.addComponent(NU_TILDA_LABEL, dictNutilda.bindUniformDouble("value")); + builder.endDictionary(); + + builder.startDictionary(KEQUATION_LABEL, dictK); + builder.addComponent(K_LABEL, dictK.bindUniformDouble("value")); + builder.endDictionary(); + + builder.endHidable(); + builder.endGroup(); + } + + public static void buildInletOutletPanel(DictionaryPanelBuilder builder, DictionaryModel dictK, DictionaryModel dictOmega, DictionaryModel dictEpsilon, DictionaryModel dictNutilda) { + builder.startGroup(INFLOW_FIXED_VALUES_LABEL); + builder.startHidable(INOUT_KEY); + + dictOmega.setCompanion(dictK); + builder.startDictionary(OMEGA_LABEL, dictOmega); + builder.addComponent(K_LABEL, dictK.bindUniformDouble("inletValue")); + builder.addComponent(OMEGA_LABEL, dictOmega.bindUniformDouble("inletValue")); + builder.endDictionary(); + + dictEpsilon.setCompanion(dictK); + builder.startDictionary(EPSILON_LABEL, dictEpsilon); + builder.addComponent(K_LABEL, dictK.bindUniformDouble("inletValue")); + builder.addComponent(EPSILON_LABEL, dictEpsilon.bindUniformDouble("inletValue")); + builder.endDictionary(); + + builder.startDictionary(NU_TILDA_LABEL, dictNutilda); + builder.addComponent(NU_TILDA_LABEL, dictNutilda.bindUniformDouble("inletValue")); + builder.endDictionary(); + + builder.startDictionary(KEQUATION_LABEL, dictK); + builder.addComponent(K_LABEL, dictK.bindUniformDouble("inletValue")); + builder.endDictionary(); + + builder.endHidable(); + builder.endGroup(); + } + + public static void buildZeroGradientPanel(DictionaryPanelBuilder builder, DictionaryModel dictK, DictionaryModel dictOmega, DictionaryModel dictEpsilon, DictionaryModel dictNutilda) { + builder.startGroup(ZERO_GRADIENT_LABEL); + builder.startHidable(ZERO_KEY); + + dictOmega.setCompanion(dictK); + builder.startDictionary(OMEGA_LABEL, dictOmega); + builder.endDictionary(); + + dictEpsilon.setCompanion(dictK); + builder.startDictionary(EPSILON_LABEL, dictEpsilon); + builder.endDictionary(); + + builder.startDictionary(NU_TILDA_LABEL, dictNutilda); + builder.endDictionary(); + + builder.startDictionary(KEQUATION_LABEL, dictK); + builder.endDictionary(); + + builder.endHidable(); + builder.endGroup(); + } + + public static void buildTurbulentIntensityAndMixingLengthPanel(DictionaryPanelBuilder builder, DictionaryModel dictK, DictionaryModel dictOmega, DictionaryModel dictEpsilon, DictionaryModel dictNuTilda) { + builder.startGroup(BY_TURB_INTENSITY_AND_MIXING_LENGTH_LABEL); + builder.startHidable(MIXING_KEY); + + dictOmega.setCompanion(dictK); + builder.startDictionary(OMEGA_LABEL, dictOmega); +// builder.addComponent(new JLabel(OMEGA_LABEL), new JLabel("")); + builder.addComponent(TURBULENCE_INTENSITY, dictK.bindDouble("intensity")); + builder.addComponent("Mixing Length [m]", dictOmega.bindDouble("mixingLength")); + builder.endDictionary(); + + dictEpsilon.setCompanion(dictK); + builder.startDictionary(EPSILON_LABEL, dictEpsilon); +// builder.addComponent(new JLabel(EPSILON_LABEL), new JLabel("")); + builder.addComponent(TURBULENCE_INTENSITY, dictK.bindDouble("intensity")); + builder.addComponent("Mixing Length [m]", dictEpsilon.bindDouble("mixingLength")); + builder.endDictionary(); + + if (dictNuTilda != null) { + builder.startDictionary(NU_TILDA_LABEL, dictNuTilda); +// builder.addComponent(new JLabel(NU_TILDA_LABEL), new JLabel("")); + builder.addComponent(TURBULENCE_INTENSITY, dictNuTilda.bindDouble("intensity")); + builder.addComponent("Mixing Length [m]", dictNuTilda.bindDouble("length")); + builder.endDictionary(); + } + + builder.startDictionary(KEQUATION_LABEL, dictK); + builder.endDictionary(); + builder.endHidable(); + builder.endGroup(); + } + + public static void setSpalartAllmaras(DictionaryPanelBuilder builder) { + // Dictionary selectedDict = builder.getSelectedModel().getDictionary(); + builder.setShowing(FIXED_KEY, NU_TILDA_LABEL); + // builder.setShowing(MIXING_KEY, NU_TILDA_LABEL); + builder.setShowing(NONUNIFROM_KEY, NU_TILDA_LABEL); + builder.setShowing(TIMEVARYING_KEY, NU_TILDA_LABEL); + builder.setShowing(INOUT_KEY, NU_TILDA_LABEL); + builder.setShowing(ZERO_KEY, NU_TILDA_LABEL); + + // builder.selectDictionary(selectedDict); + } + + public static void setKEquationEddy(DictionaryPanelBuilder builder) { + // Dictionary selectedDict = builder.getSelectedModel().getDictionary(); + builder.setShowing(FIXED_KEY, KEQUATION_LABEL); + // builder.setShowing(MIXING_KEY, KEQUATION_LABEL); + builder.setShowing(NONUNIFROM_KEY, KEQUATION_LABEL); + builder.setShowing(TIMEVARYING_KEY, KEQUATION_LABEL); + builder.setShowing(INOUT_KEY, KEQUATION_LABEL); + builder.setShowing(ZERO_KEY, KEQUATION_LABEL); + + // builder.selectDictionary(selectedDict); + } + + public static void setKOmega(DictionaryPanelBuilder builder) { + // Dictionary selectedDict = builder.getSelectedModel().getDictionary(); + // Dictionary selectedCompanion = + // builder.getSelectedModel().getCompanion().getDictionary(); + + builder.setShowing(FIXED_KEY, OMEGA_LABEL); + builder.setShowing(MIXING_KEY, OMEGA_LABEL); + builder.setShowing(NONUNIFROM_KEY, OMEGA_LABEL); + builder.setShowing(TIMEVARYING_KEY, OMEGA_LABEL); + builder.setShowing(INOUT_KEY, OMEGA_LABEL); + builder.setShowing(ZERO_KEY, OMEGA_LABEL); + + // builder.selectDictionaries(selectedDict, selectedCompanion); + } + + public static void setKEpsilon(DictionaryPanelBuilder builder) { + // Dictionary selectedDict = builder.getSelectedModel().getDictionary(); + // Dictionary selectedCompanion = + // builder.getSelectedModel().getCompanion().getDictionary(); + + builder.setShowing(FIXED_KEY, EPSILON_LABEL); + builder.setShowing(MIXING_KEY, EPSILON_LABEL); + builder.setShowing(NONUNIFROM_KEY, EPSILON_LABEL); + builder.setShowing(TIMEVARYING_KEY, EPSILON_LABEL); + builder.setShowing(INOUT_KEY, EPSILON_LABEL); + builder.setShowing(ZERO_KEY, EPSILON_LABEL); + + // builder.selectDictionaries(selectedDict, selectedCompanion); + } +} diff --git a/src/eu/engys/gui/casesetup/cellzones/CellZoneComparator.java b/src/eu/engys/gui/casesetup/cellzones/CellZoneComparator.java new file mode 100644 index 0000000..9a2d7a1 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/CellZoneComparator.java @@ -0,0 +1,50 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones; + +import static eu.engys.core.project.zero.cellzones.CellZoneType.HUMIDITY_KEY; +import static eu.engys.core.project.zero.cellzones.CellZoneType.MRF_KEY; +import static eu.engys.core.project.zero.cellzones.CellZoneType.POROUS_KEY; +import static eu.engys.core.project.zero.cellzones.CellZoneType.SLIDING_MESH_KEY; +import static eu.engys.core.project.zero.cellzones.CellZoneType.THERMAL_KEY; + +import java.util.Arrays; +import java.util.Comparator; + +import eu.engys.core.project.zero.cellzones.CellZoneType; + +public class CellZoneComparator implements Comparator { + + public static final String[] ORDERED_KEYS = new String[] { POROUS_KEY, MRF_KEY, SLIDING_MESH_KEY, THERMAL_KEY, HUMIDITY_KEY }; + + @Override + public int compare(CellZoneType type1, CellZoneType type2) { + int indexType1 = Arrays.asList(ORDERED_KEYS).indexOf(type1.getKey()); + int indexType2 = Arrays.asList(ORDERED_KEYS).indexOf(type2.getKey()); + return Integer.compare(indexType1, indexType2); + } + +} diff --git a/src/eu/engys/gui/casesetup/cellzones/CellZonesFactory.java b/src/eu/engys/gui/casesetup/cellzones/CellZonesFactory.java new file mode 100644 index 0000000..e5e3fb6 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/CellZonesFactory.java @@ -0,0 +1,188 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones; + +import static eu.engys.core.project.zero.cellzones.CellZoneType.HUMIDITY_KEY; +import static eu.engys.core.project.zero.cellzones.CellZoneType.MRF_KEY; +import static eu.engys.core.project.zero.cellzones.CellZoneType.POROUS_KEY; +import static eu.engys.core.project.zero.cellzones.CellZoneType.SLIDING_MESH_KEY; +import static eu.engys.core.project.zero.cellzones.CellZoneType.THERMAL_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.ABSOLUTE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.ATTACHED_PATCHES_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.AXIS_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.C0_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.C1_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.CE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.CM_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.D_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.E1_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.E2_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.F_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.NON_ROTATING_PATCHES_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.OMEGA_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.ORIGIN_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.PERIOD_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.PLACE_HOLDER_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.POROUS_DARCY_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.POROUS_POWER_LAW_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.SPECIFIC_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.T0_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.TEMPERATURE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.THERMAL_EXPONENTIAL_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.THERMAL_FIXED_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.THERMAL_SCALAR_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.THETA_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.T_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.VOLUME_MODE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.W_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.t0_KEY; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DimensionedScalar; +import eu.engys.util.DimensionalUnits; + +public class CellZonesFactory { + + /* + * MRF + */ + public static Dictionary mrf = new Dictionary(MRF_KEY) { + { + add(TYPE, MRF_KEY); + add(ORIGIN_KEY, "(0 0 0)"); + add(AXIS_KEY, "(0 0 1)"); + add(OMEGA_KEY, "constant 104.72"); + add(NON_ROTATING_PATCHES_KEY, "()"); + add(ATTACHED_PATCHES_KEY, "()"); + } + }; + + /* + * Porous + */ + public static Dictionary porousDarcyForchheimer = new Dictionary(POROUS_KEY) { + { + add(TYPE, POROUS_DARCY_KEY); + add(E1_KEY, "(1 0 0)"); + add(E2_KEY, "(0 1 0)"); + add(new DimensionedScalar(D_KEY, "(100 1000 1000)", DimensionalUnits._M2)); + add(new DimensionedScalar(F_KEY, "(100 1000 1000)", DimensionalUnits._M)); + } + }; + + public static Dictionary porousPowerLaw = new Dictionary(POROUS_KEY) { + { + add(TYPE, POROUS_POWER_LAW_KEY); + add(C0_KEY, "1e-14"); + add(C1_KEY, "1"); + } + }; + + /* + * Thermal + */ + public static Dictionary thermalFixedTemperature = new Dictionary(THERMAL_KEY) { + { + add(TYPE, THERMAL_FIXED_KEY); + add(TEMPERATURE_KEY, "constant 350"); + } + }; + + public static Dictionary thermalFixedTemperature_OS = new Dictionary(THERMAL_KEY) { + { + add(TYPE, THERMAL_FIXED_KEY); + add(T_KEY, "350"); + } + }; + + public static Dictionary thermalExponential = new Dictionary(THERMAL_KEY) { + { + add(TYPE, THERMAL_EXPONENTIAL_KEY); + add(CM_KEY, "0.291"); + add(CE_KEY, "1.369"); + add(T0_KEY, "350"); + } + }; + + public static Dictionary thermalScalarSemiImplicit = new Dictionary(THERMAL_KEY) { + { + add(TYPE, THERMAL_SCALAR_KEY); + add(VOLUME_MODE_KEY, ABSOLUTE_KEY); + add(PLACE_HOLDER_KEY, "(65 0)"); + } + }; + + /* + * Humidity + */ + + public static Dictionary humidity = new Dictionary(HUMIDITY_KEY) { + { + add(TYPE, HUMIDITY_KEY); + add(VOLUME_MODE_KEY, ABSOLUTE_KEY); + add(W_KEY, "(100 0)"); + } + }; + + /* + * Rotating + */ + public static Dictionary slidingMesh = new Dictionary(SLIDING_MESH_KEY) { + { + add(ORIGIN_KEY, "(0 0 0)"); + add(AXIS_KEY, "(0 0 1)"); + add(OMEGA_KEY, "1"); + + } + }; + + public static Dictionary coupledSlidingMesh_steady = new Dictionary(SLIDING_MESH_KEY) { + { + add(ORIGIN_KEY, "(0 0 0)"); + add(AXIS_KEY, "(0 0 1)"); + add(THETA_KEY, "60"); + add(PERIOD_KEY, "150"); + } + }; + + public static Dictionary coupledSlidingMesh_transient = new Dictionary(SLIDING_MESH_KEY) { + { + add(ORIGIN_KEY, "(0 0 0)"); + add(AXIS_KEY, "(0 0 1)"); + add(OMEGA_KEY, "-308.92"); + add(t0_KEY, "2"); + } + }; + + // For tests purposes only + public static Dictionary thermalScalarSemiImplicit_Specific = new Dictionary(THERMAL_KEY) { + { + add(TYPE, THERMAL_SCALAR_KEY); + add(VOLUME_MODE_KEY, SPECIFIC_KEY); + add(PLACE_HOLDER_KEY, "(1 2)"); + } + }; + +} diff --git a/src/eu/engys/gui/casesetup/cellzones/CellZonesPanel.java b/src/eu/engys/gui/casesetup/cellzones/CellZonesPanel.java new file mode 100644 index 0000000..d182ca2 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/CellZonesPanel.java @@ -0,0 +1,224 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones; + +import static eu.engys.gui.casesetup.cellzones.SourceTypeSelectionPanel.UPDATE_SELECTION; +import static eu.engys.gui.casesetup.cellzones.SourceTypeSelectionPanel.ZONE_TYPE_ACTIVE; +import static eu.engys.gui.casesetup.cellzones.SourceTypeSelectionPanel.ZONE_TYPE_INACTIVE; +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; +import javax.swing.JComponent; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.Util; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.StringField; + +public class CellZonesPanel extends AbstractGUIPanel { + + public static final String CELL_ZONES = "Cell Zones"; + public static final String CELL_ZONE_NAME_LABEL = "CellZone Name"; + public static final String CELL_ZONE_TYPE_LABEL = "CellZone Type"; + + private CellZonesTreeNodeManager treeNodeManager; + private List types; + + private StringField zoneNameField; + private SourcePanelContainer centerPanel; + private SourceTypeSelectionPanel zoneTypePanel; + +// private PropertyChangeListener zoneNameListener; + + @Inject + public CellZonesPanel(Model model, Set cellZoneTypes, Set modules) { + super(CELL_ZONES, model); + this.treeNodeManager = new CellZonesTreeNodeManager(model, this); + this.types = new LinkedList<>(); + types.addAll(cellZoneTypes); + types.addAll(ModulesUtil.getCellZoneTypes(modules)); + Collections.sort(types, new CellZoneComparator()); + model.addObserver(treeNodeManager); + } + + protected JComponent layoutComponents() { + centerPanel = new SourcePanelContainer(types); + + PanelBuilder typeBuilder = new PanelBuilder(); + this.zoneNameField = initNameField(); + this.zoneTypePanel = initTypePanel(); + typeBuilder.addComponent(CELL_ZONE_NAME_LABEL, zoneNameField); + typeBuilder.addComponent(CELL_ZONE_TYPE_LABEL, zoneTypePanel); + + PanelBuilder panelBuilder = new PanelBuilder(); + panelBuilder.addComponent(typeBuilder.removeMargins().getPanel()); + panelBuilder.addComponent(centerPanel); + + return panelBuilder.removeMargins().getPanel(); + } + + private StringField initNameField() { + final StringField zoneNameField = stringField(); +// zoneNameListener = new PropertyChangeListener() { +// @Override +// public void propertyChange(PropertyChangeEvent evt) { +// CellZone[] cellzones = treeNodeManager.getSelectedValues(); +// if (cellzones.length == 1 && cellzones[0] != null) { +// cellzones[0].setName(zoneNameField.getText()); +// treeNodeManager.refreshNode(cellzones[0]); +// } +// } +// }; +// zoneNameField.addPropertyChangeListener(zoneNameListener); + zoneNameField.setEnabled(false); + return zoneNameField; + } + + private SourceTypeSelectionPanel initTypePanel() { + SourceTypeSelectionPanel panel = new SourceTypeSelectionPanel(model, types); + panel.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(ZONE_TYPE_ACTIVE)) { + CellZone[] selection = treeNodeManager.getSelectedValues(); + CellZoneType type = (CellZoneType) evt.getNewValue(); + if (Util.isVarArgsNotNullAndOfSize(1, selection)) { + showPanel(type, selection[0]); + } + } else if (evt.getPropertyName().equals(ZONE_TYPE_INACTIVE)) { + CellZone[] selection = treeNodeManager.getSelectedValues(); + CellZoneType type = (CellZoneType) evt.getNewValue(); + if (Util.isVarArgsNotNullAndOfSize(1, selection)) { + hidePanel(type, selection[0]); + } + } else if (evt.getPropertyName().equals(UPDATE_SELECTION)) { + updateSelection(treeNodeManager.getSelectedValues()); + } + } + + private void showPanel(CellZoneType type, CellZone cellZone) { + String typeKey = type.getKey(); + cellZone.getTypes().add(typeKey); + if (!cellZone.hasDictionary(typeKey)) { + cellZone.setDictionary(typeKey, type.getDefaultDictionary()); + } + centerPanel.showPanel(type, cellZone.getDictionary(typeKey)); + } + + private void hidePanel(CellZoneType type, CellZone cellZone) { + cellZone.getTypes().remove(type.getKey()); + centerPanel.hidePanel(type); + } + + }); + return panel; + } + + public void updateSelection(CellZone[] selection) { +// zoneNameField.removePropertyChangeListener(zoneNameListener); + if (Util.isVarArgsNotNullAndOfSize(1, selection)) { + zoneNameField.setValue(selection[0].getName()); + zoneNameField.setEnabled(false); + zoneTypePanel.handleSelectionOnTree(selection[0]); + centerPanel.handleSelectionOnTree(selection[0]); + } else { + StringBuilder sb = new StringBuilder(); + for (CellZone cellZone : selection) { + sb.append(cellZone.getName() + " "); + } + zoneNameField.setValue(sb.toString()); + zoneNameField.setEnabled(false); + zoneTypePanel.handleSelectionOnTree(null); + centerPanel.handleSelectionOnTree(null); + } +// zoneNameField.addPropertyChangeListener(zoneNameListener); + } + + @Override + public void load() { + for (CellZoneType type : types) { + type.updateStatusByState(); + } + } + + @Override + public void stateChanged() { + for (CellZoneType type : types) { + type.updateStatusByState(); + } + fixCellZonesTypes(); + } + + private void fixCellZonesTypes() { + for (CellZone zone : model.getCellZones()) { + for (CellZoneType type : types) { + if (!type.isEnabled()) { + zone.getTypes().remove(type.getKey()); + } + } + centerPanel.saveDictionaryToCellZone(zone); + } + } + + // When change selection + public void saveCellZones(CellZone[] values) { + if (Util.isVarArgsNotNull(values)) { + for (CellZone zone : values) { + zoneTypePanel.saveTypesToCellZone(zone); + centerPanel.saveDictionaryToCellZone(zone); + } + } + } + + @Override + public void clear() { + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) new CellZone[0]); + } + + @Override + public void save() { + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) treeNodeManager.getSelectedValues()); + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + +} diff --git a/src/eu/engys/gui/casesetup/cellzones/CellZonesTreeNodeManager.java b/src/eu/engys/gui/casesetup/cellzones/CellZonesTreeNodeManager.java new file mode 100644 index 0000000..195a9b4 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/CellZonesTreeNodeManager.java @@ -0,0 +1,270 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones; + +import java.awt.Component; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreePath; + +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.cellzones.CellZones; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.SelectCellZonesEvent; +import eu.engys.gui.tree.AbstractSelectionHandler; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.SelectionHandler; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class CellZonesTreeNodeManager extends DefaultTreeNodeManager { + + private Map zonesMap; + private SelectionHandler selectionHandler; + + public CellZonesTreeNodeManager(Model model, CellZonesPanel cellZonesPanel) { + super(model, cellZonesPanel); + this.selectionHandler = new CellZonesSelectionHandler(cellZonesPanel); + this.zonesMap = new HashMap<>(); + } + + @Override + public void update(Observable o, final Object arg) { + if (arg instanceof CellZones) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + selectionHandler.disable(); + loadTree(); + selectVisibleItems(); + expandTree(); + selectionHandler.enable(); + } + }); + } + } + + private void loadTree() { + clear(); + for (CellZone zone : model.getCellZones()) { + addCellZone(root, zone); + } + treeChanged(root); + } + + private void selectVisibleItems() { + // for(DefaultMutableTreeNode node : nodeMap.values()) + // getTree().getCheckManager().selectNode(node); + } + + private void expandTree() { + getTree().expandNode(getRoot()); + } + + private void addCellZone(DefaultMutableTreeNode parent, CellZone cellZone) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(cellZone); + parent.add(node); + nodeMap.put(cellZone, node); + zonesMap.put(node, cellZone); + } + + public CellZone[] getSelectedValues() { + if (getTree() != null) { + TreePath[] selectionPaths = getTree().getSelectedDescendantOf(getRoot()); + CellZone[] cellzones = new CellZone[selectionPaths.length]; + for (int i = 0; i < selectionPaths.length; i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPaths[i].getLastPathComponent(); + CellZone zone = zonesMap.get(node); + cellzones[i] = zone; + } + return cellzones; + } + return new CellZone[0]; + } + + // public void setSelectedValue(String name) { + // System.out.println("CellZonesTreeNodeManager.setSelectedValue() name: "+name); + // DefaultMutableTreeNode selectedNode = nodeMap.get(name); + // if (getTree() != null) { + // TreePath treePath; + // if (name != null && selectedNode != null) { + // treePath = new TreePath(getModel().getPathToRoot(selectedNode)); + // } else { + // treePath = new TreePath(getModel().getPathToRoot(getRoot())); + // } + // getTree().getSelectionModel().setSelectionPath(treePath); + // getTree().clearSelection(); + // } + // } + + public void clear() { + // clear node before selection handler! + clearNode(root); + selectionHandler.clear(); + nodeMap.clear(); + zonesMap.clear(); + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public Class getRendererClass() { + return CellZone.class; + } + + public DefaultTreeCellRenderer getRenderer() { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object userObject = node.getUserObject(); + + if (userObject instanceof CellZone) { + CellZone patch = (CellZone) userObject; + setText(patch.getName()); + } + setIcon(null); + return this; + } + }; + } + + @Override + public SelectionHandler getSelectionHandler() { + return selectionHandler; + } + + private final class CellZonesSelectionHandler extends AbstractSelectionHandler { + + private CellZonesPanel panel; + private CellZone[] currentSelection; + + public CellZonesSelectionHandler(CellZonesPanel panel) { + this.panel = panel; + } + + @Override + public void handleSelection(boolean fire3DEvent, Object... selection) { + if (currentSelection != null && currentSelection.length > 0) { + panel.saveCellZones(currentSelection); + } + if (TreeUtil.isConsistent(selection, CellZone.class)) { + this.currentSelection = Arrays.copyOf(selection, selection.length, CellZone[].class); + } else { + this.currentSelection = new CellZone[0]; + } + panel.updateSelection(currentSelection); + if (fire3DEvent) { + EventManager.triggerEvent(this, new SelectCellZonesEvent(currentSelection)); + } + } + + @Override + public void handleVisibility(VisibleItem item) { + } + + @Override + public void process3DSelectionEvent(Picker picker, Actor actor, boolean keep) { + if (getTree() != null && actor.getVisibleItem() instanceof VisibleItem) { + DefaultMutableTreeNode selectedNode = nodeMap.get(actor.getVisibleItem()); + if (selectedNode != null) { + getTree().setSelectedNode(selectedNode); + } + } + } + + @Override + public void process3DVisibilityEvent(boolean selected) { + if (getTree() != null) { + for (DefaultMutableTreeNode node : nodeMap.values()) { + // if (selected) { + // getTree().getCheckManager().selectNode(node); + // } else { + getTree().getCheckManager().deselectNode(node); + // } + } + } + } + + @Override + public void clear() { + currentSelection = null; + } + } + + // private final class PopUpMenuListener extends MouseAdapter { + // private JPopupMenu popUp; + // private RemoveSurfaceAction removeAction; + // + // public PopUpMenuListener() { + // // removeAction = new RemoveSurfaceAction(); + // + // popUp = new JPopupMenu(); + // // popUp.add(removeAction); + // } + // + // @Override + // public void mouseReleased(MouseEvent e) { + // // Surface[] selectedValues = treeNodeManager.getSelectedValues(); + // // if (SwingUtilities.isRightMouseButton(e) && selectedValues.length + // // > 0) { + // // removeAction.setEnabled(selectedValues[0].getType() != + // // Type.REGION); + // // popUp.show(treeNodeManager, e.getX(), e.getY()); + // // } + // } + // } + + // private final class VisibilityListener implements TableModelListener { + // @Override + // public void tableChanged(TableModelEvent e) { + // if (e.getType() == TableModelEvent.UPDATE && e.getColumn() == 0) { + // if (e.getSource() instanceof AbstractTableModel) { + // AbstractTableModel tm = (AbstractTableModel) e.getSource(); + // int row = e.getFirstRow(); + // boolean b = Boolean.parseBoolean(tm.getValueAt(row, + // GeometryTreePanel.VISIBLE_INDEX).toString()); + // Surface surface = (Surface) tm.getValueAt(row, + // GeometryTreePanel.SURFACE_INDEX); + // EventManager.triggerEvent(this, new VisibleSurfaceEvent(surface, b)); + // } + // } + // } + // } +} diff --git a/src/eu/engys/gui/casesetup/cellzones/SourcePanelContainer.java b/src/eu/engys/gui/casesetup/cellzones/SourcePanelContainer.java new file mode 100644 index 0000000..8cbb55c --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/SourcePanelContainer.java @@ -0,0 +1,114 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones; + +import java.awt.BorderLayout; +import java.util.List; + +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.cellzones.CellZonePanel; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.util.ui.builder.PanelBuilder; + +public class SourcePanelContainer extends JPanel { + + private PanelBuilder builder; + private List types; + + public SourcePanelContainer(List types) { + super(new BorderLayout()); + this.types = types; + this.builder = new PanelBuilder(); + layoutComponents(); + } + + private void layoutComponents() { + for (CellZoneType type : types) { + CellZonePanel typePanel = type.getPanel(); + typePanel.layoutPanel(); + + builder.startHidable(type.getKey()); + + builder.startGroup("empty"); + builder.endGroup(); + + builder.startGroup(type.getLabel()); + builder.addComponent(typePanel.getPanel()); + builder.endGroup(); + + builder.endHidable(); + } + add(builder.removeMargins().getPanel()); + } + + public void handleSelectionOnTree(CellZone cellZone) { + if (cellZone != null) { + for (CellZoneType type : types) { + if (cellZone.hasType(type.getKey()) && type.isEnabled()) { + showPanel(type, cellZone.getDictionary(type.getKey())); + } else { + hidePanel(type); + } + } + } else { + hideAllPanels(); + } + } + + public void showPanel(CellZoneType type, Dictionary cellZoneDictionary) { + type.getPanel().loadFromDictionary(cellZoneDictionary); + builder.setShowing(type.getKey(), type.getLabel()); + } + + public void hidePanel(CellZoneType type) { + builder.setShowing(type.getKey(), "empty"); + } + + private void hideAllPanels() { + for (CellZoneType type : types) { + hidePanel(type); + } + } + + public void saveDictionaryToCellZone(CellZone zone) { + for (CellZoneType type : types) { + String typeKey = type.getKey(); + if (type.isEnabled()) { + if (zone.getTypes().contains(typeKey)) { + Dictionary dict = type.getPanel().saveToDictionary(); + zone.setDictionary(typeKey, dict); + } else { + zone.removeDictionary(typeKey); + } + } else { + zone.removeDictionary(typeKey); + } + } + } +} diff --git a/src/eu/engys/gui/casesetup/cellzones/SourceTypeSelectionPanel.java b/src/eu/engys/gui/casesetup/cellzones/SourceTypeSelectionPanel.java new file mode 100644 index 0000000..dc01682 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/SourceTypeSelectionPanel.java @@ -0,0 +1,135 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JCheckBox; +import javax.swing.JPanel; + +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.builder.PanelBuilder; + +public class SourceTypeSelectionPanel extends JPanel { + + public static final String ZONE_TYPE_ACTIVE = "zoneTypeActive"; + public static final String ZONE_TYPE_INACTIVE = "zoneTypeInactive"; + public static final String UPDATE_SELECTION = "updateSelection"; + + private Map checkBoxMap = new HashMap<>(); + private PanelBuilder builder; + private ActionListener checkBoxListener; + + public SourceTypeSelectionPanel(Model m, List types) { + super(new BorderLayout()); + + builder = new PanelBuilder(); + + checkBoxListener = new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + JCheckBox checkBox = (JCheckBox) e.getSource(); + boolean selected = checkBox.isSelected(); + CellZoneType type = (CellZoneType) checkBox.getClientProperty("type"); + firePropertyChange(selected ? ZONE_TYPE_ACTIVE : ZONE_TYPE_INACTIVE, null, type); + } + }; + + for (CellZoneType zoneType : types) { + JCheckBox checkBox = ComponentsFactory.checkField(zoneType.getLabel()); + checkBox.putClientProperty("type", zoneType); + checkBox.addActionListener(checkBoxListener); + + checkBox.setEnabled(false); + checkBox.setName(zoneType.getLabel()); + checkBoxMap.put(zoneType, checkBox); + builder.addComponent(checkBox); + } + add(builder.removeMargins().getPanel()); + } + + public void handleSelectionOnTree(CellZone cellZone) { + removeListeners(); + if (cellZone != null) { + selectCheckBoxes(cellZone); + } else { + unselectAndDisableCheckBoxes(); + } + addListeners(); + } + + public void saveTypesToCellZone(CellZone zone) { + for (CellZoneType type : checkBoxMap.keySet()) { + JCheckBox checkBox = checkBoxMap.get(type); + if (checkBox.isSelected()) { + zone.getTypes().add(type.getKey()); + } else { + zone.getTypes().remove(type.getKey()); + } + } + } + + private void selectCheckBoxes(CellZone cellZone) { + for (CellZoneType type : checkBoxMap.keySet()) { + JCheckBox checkBox = checkBoxMap.get(type); + checkBox.setEnabled(type.isEnabled()); + if (cellZone.getTypes().contains(type.getKey()) && type.isEnabled()) { + checkBox.setSelected(true); + } else { + checkBox.setSelected(false); + } + } + } + + private void unselectAndDisableCheckBoxes() { + for (CellZoneType type : checkBoxMap.keySet()) { + JCheckBox checkBox = checkBoxMap.get(type); + checkBox.setSelected(false); + checkBox.setEnabled(false); + } + } + + private void addListeners() { + for (JCheckBox check : checkBoxMap.values()) { + check.addActionListener(checkBoxListener); + } + } + + private void removeListeners() { + for (JCheckBox check : checkBoxMap.values()) { + check.removeActionListener(checkBoxListener); + } + } +} diff --git a/src/eu/engys/gui/casesetup/cellzones/StandardCellZonesBuilder.java b/src/eu/engys/gui/casesetup/cellzones/StandardCellZonesBuilder.java new file mode 100644 index 0000000..dfb7017 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/StandardCellZonesBuilder.java @@ -0,0 +1,328 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.project.system.SnappyHexMeshDict.CELL_ZONE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.ABSOLUTE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.ACTIVE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.AXES_ROTATION_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.AXIS_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.C0_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.C1_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.CARTESIAN_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.COEFFS_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.COORDINATE_ROTATION_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.COORDINATE_SYSTEM_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.DARCY_FORCHHEIMER_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.D_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.E1_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.E2_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.EXPLICIT_POROSITY_SOURCE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.F_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.INJECTION_RATE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.MRF_SOURCE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.OMEGA_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.ORIGIN_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.POROUS_DARCY_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.POROUS_POWER_LAW_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.POWER_LAW_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.SCALAR_EXPLICIT_SET_VALUE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.SELECTION_MODE_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.THERMAL_FIXED_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.T_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.VOLUME_MODE_KEY; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.core.project.system.FvOptions; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.core.project.zero.cellzones.CellZones; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; + +public class StandardCellZonesBuilder implements CellZonesBuilder { + + private static final Logger logger = LoggerFactory.getLogger(StandardCellZonesBuilder.class); + + @Override + public void loadMRFDictionary(Model model) { + loadMRFDictionary(model.getCellZones(), model.getProject().getSystemFolder().getFvOptions()); + } + + @Override + public void loadMRFDictionary(CellZones cellZones, FvOptions fvOptions) { + if (fvOptions != null) { + for (CellZone cellZone : cellZones) { + String zoneName = cellZone.getName(); + List zonesDict = fvOptions.getDictionaries(); + for (Dictionary zoneDict : zonesDict) { + if (zoneDict.found(CELL_ZONE_KEY) && zoneDict.lookup(CELL_ZONE_KEY).equals(zoneName)) { + if (zoneDict.found(TYPE) && zoneDict.lookup(TYPE).equals(MRF_SOURCE_KEY)) { + Dictionary encodedDictionary = new Dictionary(""); + encodedDictionary.add(TYPE, CellZoneType.MRF_KEY); + if (zoneDict.isDictionary(MRF_SOURCE_KEY + COEFFS_KEY)) { + Dictionary coeffs = zoneDict.subDict(MRF_SOURCE_KEY + COEFFS_KEY); + encodedDictionary.add(ORIGIN_KEY, coeffs.lookup(ORIGIN_KEY)); + encodedDictionary.add(AXIS_KEY, coeffs.lookup(AXIS_KEY)); + encodedDictionary.add(OMEGA_KEY, coeffs.lookup(OMEGA_KEY)); + } + + cellZone.setDictionary(CellZoneType.MRF_KEY, encodedDictionary); + cellZone.getTypes().add(CellZoneType.MRF_KEY); + } + } + } + } + } + } + + @Override + public void saveMRFDictionary(Model model) { + saveMRFDictionary(model.getCellZones(), model.getProject().getSystemFolder().getFvOptions()); + } + + @Override + public void saveMRFDictionary(CellZones cellZones, FvOptions fvOptions) { + if (fvOptions != null) { + for (CellZone cellZone : cellZones) { + String zoneName = cellZone.getName(); + + if (cellZone.hasType(CellZoneType.MRF_KEY)) { + Dictionary encodedDictionary = cellZone.getDictionary(CellZoneType.MRF_KEY); + + Dictionary toBeDecoded = new Dictionary(zoneName + "_" + CellZoneType.MRF_KEY); + toBeDecoded.add(TYPE, MRF_SOURCE_KEY); + toBeDecoded.add(ACTIVE_KEY, "true"); + toBeDecoded.add(SELECTION_MODE_KEY, CELL_ZONE_KEY); + toBeDecoded.add(CELL_ZONE_KEY, zoneName); + + Dictionary MRFSourceCoeffs = new Dictionary(MRF_SOURCE_KEY + COEFFS_KEY); + MRFSourceCoeffs.add(ORIGIN_KEY, encodedDictionary.lookup(ORIGIN_KEY)); + MRFSourceCoeffs.add(AXIS_KEY, encodedDictionary.lookup(AXIS_KEY)); + MRFSourceCoeffs.add(OMEGA_KEY, encodedDictionary.lookup(OMEGA_KEY)); + + toBeDecoded.add(MRFSourceCoeffs); + + fvOptions.add(toBeDecoded); + } else { + logger.debug(zoneName + " NOT A MRF Zone " + cellZone.getTypes()); + } + } + } + } + + @Override + public void loadPorousDictionary(Model model) { + loadPorousDictionary(model.getCellZones(), model.getProject().getSystemFolder().getFvOptions()); + } + + @Override + public void loadPorousDictionary(CellZones cellZones, FvOptions fvOptions) { + if (fvOptions != null) { + for (CellZone cellZone : cellZones) { + String zoneName = cellZone.getName(); + List zonesDict = fvOptions.getDictionaries(); + for (Dictionary zoneDict : zonesDict) { + if (zoneDict.found(CELL_ZONE_KEY) && zoneDict.lookup(CELL_ZONE_KEY).equals(zoneName)) { + if (zoneDict.lookup(TYPE).equals(EXPLICIT_POROSITY_SOURCE_KEY)) { + Dictionary encodedDictionary = new Dictionary(""); + if (zoneDict.isDictionary(EXPLICIT_POROSITY_SOURCE_KEY + COEFFS_KEY)) { + Dictionary coeffDict = zoneDict.subDict(EXPLICIT_POROSITY_SOURCE_KEY + COEFFS_KEY); + String type = coeffDict.lookup(TYPE); + + if (type.equals(DARCY_FORCHHEIMER_KEY)) { + encodedDictionary.add(TYPE, POROUS_DARCY_KEY); + + Dictionary darcyDict = coeffDict.subDict(DARCY_FORCHHEIMER_KEY + COEFFS_KEY); + encodedDictionary.add(darcyDict.lookupScalar(D_KEY)); + encodedDictionary.add(darcyDict.lookupScalar(F_KEY)); + if (darcyDict.isDictionary(COORDINATE_SYSTEM_KEY)) { + Dictionary coordSys = darcyDict.subDict(COORDINATE_SYSTEM_KEY); + if (coordSys.isDictionary(COORDINATE_ROTATION_KEY)) { + Dictionary rotation = coordSys.subDict(COORDINATE_ROTATION_KEY); + encodedDictionary.add(E1_KEY, rotation.lookup(E1_KEY)); + encodedDictionary.add(E2_KEY, rotation.lookup(E2_KEY)); + } + } + } else if (type.equals(POWER_LAW_KEY)) { + encodedDictionary.add(TYPE, POROUS_POWER_LAW_KEY); + Dictionary powerLawDict = coeffDict.subDict(POWER_LAW_KEY + COEFFS_KEY); + encodedDictionary.add(C0_KEY, powerLawDict.lookup(C0_KEY)); + encodedDictionary.add(C1_KEY, powerLawDict.lookup(C1_KEY)); + } else { + System.err.println("Unknown type"); + } + } + + cellZone.getTypes().add(CellZoneType.POROUS_KEY); + cellZone.setDictionary(CellZoneType.POROUS_KEY, encodedDictionary); + } + } + } + } + } + } + + @Override + public void savePorousDictionary(Model model) { + savePorousDictionary(model.getCellZones(), model.getProject().getSystemFolder().getFvOptions()); + } + + @Override + public void savePorousDictionary(CellZones cellZones, FvOptions fvOptions) { + if (fvOptions != null) { + for (CellZone cellZone : cellZones) { + String zoneName = cellZone.getName(); + if (cellZone.hasType(CellZoneType.POROUS_KEY)) { + Dictionary encodedDictionary = cellZone.getDictionary(CellZoneType.POROUS_KEY); + String typeString = encodedDictionary.lookup(TYPE); + + Dictionary toBeDecoded = new Dictionary(zoneName + "_" + CellZoneType.POROUS_KEY); + toBeDecoded.add(TYPE, EXPLICIT_POROSITY_SOURCE_KEY); + toBeDecoded.add(ACTIVE_KEY, "true"); + toBeDecoded.add(SELECTION_MODE_KEY, CELL_ZONE_KEY); + toBeDecoded.add(CELL_ZONE_KEY, zoneName); + + Dictionary porousCoeffs = new Dictionary(EXPLICIT_POROSITY_SOURCE_KEY + COEFFS_KEY); + toBeDecoded.add(porousCoeffs); + + if (typeString != null && typeString.equals(POROUS_DARCY_KEY)) { + porousCoeffs.add(TYPE, DARCY_FORCHHEIMER_KEY); + + Dictionary darcyDict = new Dictionary(DARCY_FORCHHEIMER_KEY + COEFFS_KEY); + if (encodedDictionary.found(D_KEY)) + darcyDict.add(encodedDictionary.lookupScalar(D_KEY)); + if (encodedDictionary.found(F_KEY)) + darcyDict.add(encodedDictionary.lookupScalar(F_KEY)); + + Dictionary coordSys = new Dictionary(COORDINATE_SYSTEM_KEY); + coordSys.add(TYPE, CARTESIAN_KEY); + coordSys.add(ORIGIN_KEY, "(0 0 0)"); + + Dictionary rotation = new Dictionary(COORDINATE_ROTATION_KEY); + rotation.add(TYPE, AXES_ROTATION_KEY); + rotation.add(E1_KEY, encodedDictionary.lookup(E1_KEY)); + rotation.add(E2_KEY, encodedDictionary.lookup(E2_KEY)); + coordSys.add(rotation); + + darcyDict.add(coordSys); + + porousCoeffs.add(darcyDict); + } else if (typeString != null && typeString.equals(POROUS_POWER_LAW_KEY)) { + porousCoeffs.add(TYPE, POWER_LAW_KEY); + + Dictionary powerLawDict = new Dictionary(POWER_LAW_KEY + COEFFS_KEY); + powerLawDict.add(C0_KEY, encodedDictionary.lookup(C0_KEY)); + powerLawDict.add(C1_KEY, encodedDictionary.lookup(C1_KEY)); + porousCoeffs.add(powerLawDict); + } + + fvOptions.add(toBeDecoded); + } else { + logger.debug(zoneName + " NOT A Porous Zone " + cellZone.getTypes()); + } + } + } + } + + @Override + public void loadThermalDictionary(Model model) { + loadThermalDictionary(model.getCellZones(), model.getProject().getSystemFolder().getFvOptions(), model.getState()); + } + + @Override + public void loadThermalDictionary(CellZones cellZones, FvOptions fvOptions, State state) { + if (fvOptions != null) { + for (CellZone cellZone : cellZones) { + String zoneName = cellZone.getName(); + List zonesDict = fvOptions.getDictionaries(); + for (Dictionary zoneDict : zonesDict) { + if (zoneDict.found(CELL_ZONE_KEY) && zoneDict.lookup(CELL_ZONE_KEY).equals(zoneName)) { + String type = zoneDict.lookup(TYPE); + if (type != null && (type.equals(SCALAR_EXPLICIT_SET_VALUE_KEY))) { + Dictionary encodedDictionary = new Dictionary(""); + if (type.equals(SCALAR_EXPLICIT_SET_VALUE_KEY)) { + if (zoneDict.isDictionary(SCALAR_EXPLICIT_SET_VALUE_KEY + COEFFS_KEY)) { + Dictionary coeffDict = zoneDict.subDict(SCALAR_EXPLICIT_SET_VALUE_KEY + COEFFS_KEY); + Dictionary injectionDict = coeffDict.subDict(INJECTION_RATE_KEY); + + encodedDictionary.add(TYPE, THERMAL_FIXED_KEY); + encodedDictionary.add(T_KEY, injectionDict.lookup(T_KEY)); + } + } + cellZone.getTypes().add(CellZoneType.THERMAL_KEY); + cellZone.setDictionary(CellZoneType.THERMAL_KEY, encodedDictionary); + } + } + } + } + } + } + + @Override + public void saveThermalDictionary(Model model) { + saveThermalDictionary(model.getCellZones(), model.getProject().getSystemFolder().getFvOptions(), model.getState()); + } + + @Override + public void saveThermalDictionary(CellZones cellZones, FvOptions fvOptions, State state) { + if (fvOptions != null) { + for (CellZone cellZone : cellZones) { + String zoneName = cellZone.getName(); + if (cellZone.hasType(CellZoneType.THERMAL_KEY)) { + Dictionary encodedDictionary = cellZone.getDictionary(CellZoneType.THERMAL_KEY); + + Dictionary toBeDecoded = new Dictionary(zoneName + "_" + CellZoneType.THERMAL_KEY); + toBeDecoded.add(TYPE, SCALAR_EXPLICIT_SET_VALUE_KEY); + toBeDecoded.add(ACTIVE_KEY, "true"); + toBeDecoded.add(SELECTION_MODE_KEY, CELL_ZONE_KEY); + toBeDecoded.add(CELL_ZONE_KEY, zoneName); + + Dictionary coeffsDict = new Dictionary(SCALAR_EXPLICIT_SET_VALUE_KEY + COEFFS_KEY); + coeffsDict.add(VOLUME_MODE_KEY, ABSOLUTE_KEY); + + Dictionary injectionDict = new Dictionary(INJECTION_RATE_KEY); + injectionDict.add(T_KEY, encodedDictionary.lookup(T_KEY)); + coeffsDict.add(injectionDict); + + toBeDecoded.add(coeffsDict); + + fvOptions.add(toBeDecoded); + } else { + logger.debug(zoneName + " NOT A Thermal Zone " + cellZone.getTypes()); + } + } + } + } + +} diff --git a/src/eu/engys/gui/casesetup/cellzones/mrf/StandardCellZoneMRFPanel.java b/src/eu/engys/gui/casesetup/cellzones/mrf/StandardCellZoneMRFPanel.java new file mode 100644 index 0000000..45b2e77 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/mrf/StandardCellZoneMRFPanel.java @@ -0,0 +1,90 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.cellzones.mrf; + +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.AXIS_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.OMEGA_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.ORIGIN_KEY; +import static eu.engys.gui.casesetup.cellzones.CellZonesFactory.mrf; +import static eu.engys.gui.casesetup.cellzones.mrf.StandardMRF.MRF_LABEL; + +import javax.inject.Inject; +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.modules.cellzones.CellZonePanel; +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.util.ui.builder.PanelBuilder; + +public class StandardCellZoneMRFPanel implements CellZonePanel { + + private PanelBuilder builder = new PanelBuilder(); + private DictionaryModel mrfModel; + + @Inject + public StandardCellZoneMRFPanel() { + } + + @Override + public void layoutPanel() { + mrfModel = new DictionaryModel(new Dictionary(mrf)); + builder.addComponent(ORIGIN_LABEL, mrfModel.bindPoint(ORIGIN_KEY)); + builder.addComponent(AXIS_LABEL, mrfModel.bindPoint(AXIS_KEY)); + builder.addComponent(OMEGA_RAD_S_LABEL, mrfModel.bindConstantDouble(OMEGA_KEY)); + mrfModel.refresh(); + + } + + @Override + public JComponent getPanel() { + JPanel panel = builder.getPanel(); + panel.setBorder(BorderFactory.createTitledBorder(MRF_LABEL)); + panel.setName(MRF_LABEL); + return panel; + } + + @Override + public void stateChanged() { + } + + @Override + public void loadFromDictionary(Dictionary cellZoneDictionary) { + Dictionary d = new Dictionary(CellZoneType.MRF_KEY); + d.merge(cellZoneDictionary); + mrfModel.setDictionary(cellZoneDictionary); + + } + + @Override + public Dictionary saveToDictionary() { + return mrfModel.getDictionary(); + } + +} diff --git a/src/eu/engys/gui/casesetup/cellzones/mrf/StandardMRF.java b/src/eu/engys/gui/casesetup/cellzones/mrf/StandardMRF.java new file mode 100644 index 0000000..8d30d67 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/mrf/StandardMRF.java @@ -0,0 +1,92 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones.mrf; + +import static eu.engys.gui.casesetup.cellzones.CellZonesFactory.mrf; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.cellzones.CellZonePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZoneType; + +public class StandardMRF implements CellZoneType { + + public static final String MRF_LABEL = "MRF"; + + private CellZonePanel panel; + + @Inject + public StandardMRF(Model model) { + this.panel = new StandardCellZoneMRFPanel(); + } + + @Override + public String getKey() { + return CellZoneType.MRF_KEY; + } + + @Override + public String getLabel() { + return MRF_LABEL; + } + + @Override + public void updateStatusByState() { + panel.stateChanged(); + } + + @Override + public Dictionary getDefaultDictionary() { + return new Dictionary(mrf); + } + + @Override + public CellZonePanel getPanel() { + return panel; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public void setEnabled(boolean enabled) { + } + + @Override + public String toString() { + return getKey(); + } + + @Override + public int compareTo(CellZoneType type) { + return getLabel().compareTo(type.getLabel()); + } + +} diff --git a/src/eu/engys/gui/casesetup/cellzones/porous/StandardCellZonePorousPanel.java b/src/eu/engys/gui/casesetup/cellzones/porous/StandardCellZonePorousPanel.java new file mode 100644 index 0000000..be500d9 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/porous/StandardCellZonePorousPanel.java @@ -0,0 +1,105 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones.porous; + +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.C0_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.C1_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.D_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.E1_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.E2_KEY; +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.F_KEY; +import static eu.engys.gui.casesetup.cellzones.CellZonesFactory.porousDarcyForchheimer; +import static eu.engys.gui.casesetup.cellzones.CellZonesFactory.porousPowerLaw; +import static eu.engys.gui.casesetup.cellzones.porous.StandardPorous.POROUS_LABEL; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPanel; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.modules.cellzones.CellZonePanel; +import eu.engys.core.project.zero.cellzones.CellZoneType; +import eu.engys.util.DimensionalUnits; + +public class StandardCellZonePorousPanel implements CellZonePanel { + + private DictionaryPanelBuilder builder; + + @Inject + public StandardCellZonePorousPanel() { + } + + @Override + public void layoutPanel() { + DictionaryModel porousDarcyModel = new DictionaryModel(new Dictionary(porousDarcyForchheimer)); + DictionaryModel porousPowerLawModel = new DictionaryModel(new Dictionary(porousPowerLaw)); + + builder = new DictionaryPanelBuilder(); + builder.startChoice(MODEL_LABEL); + + builder.startDictionary(DARCY_FORCHHEIMER, porousDarcyModel); + builder.addComponent(E1_LABEL, porousDarcyModel.bindPoint(E1_KEY)); + builder.addComponent(E2_LABEL, porousDarcyModel.bindPoint(E2_KEY)); + builder.addComponent(VISCOUS_LOSS_LABEL, porousDarcyModel.bindDimensionedPoint(D_KEY, DimensionalUnits._M2)); + builder.addComponent(INERTIAL_LOSS_LABEL, porousDarcyModel.bindDimensionedPoint(F_KEY, DimensionalUnits._M)); + builder.endDictionary(); + + builder.startDictionary(POWER_LAW, porousPowerLawModel); + builder.addComponent(C0_LABEL, porousPowerLawModel.bindDouble(C0_KEY)); + builder.addComponent(C1_LABEL, porousPowerLawModel.bindDouble(C1_KEY)); + builder.endDictionary(); + + builder.endChoice(); + } + + @Override + public JComponent getPanel() { + JPanel panel = builder.getPanel(); + panel.setBorder(BorderFactory.createTitledBorder(POROUS_LABEL)); + panel.setName(POROUS_LABEL); + return panel; + } + + @Override + public void stateChanged() { + } + + @Override + public void loadFromDictionary(Dictionary cellZoneDictionary) { + Dictionary d = new Dictionary(CellZoneType.POROUS_KEY); + d.merge(cellZoneDictionary); + builder.selectDictionary(d); + } + + @Override + public Dictionary saveToDictionary() { + return builder.getSelectedModel().getDictionary(); + } +} diff --git a/src/eu/engys/gui/casesetup/cellzones/porous/StandardPorous.java b/src/eu/engys/gui/casesetup/cellzones/porous/StandardPorous.java new file mode 100644 index 0000000..2b72676 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/porous/StandardPorous.java @@ -0,0 +1,92 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones.porous; + +import static eu.engys.gui.casesetup.cellzones.CellZonesFactory.porousDarcyForchheimer; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.cellzones.CellZonePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZoneType; + +public class StandardPorous implements CellZoneType { + + public static final String POROUS_LABEL = "Porous Medium"; + + private CellZonePanel panel; + + @Inject + public StandardPorous(Model model) { + this.panel = new StandardCellZonePorousPanel(); + } + + @Override + public String getKey() { + return CellZoneType.POROUS_KEY; + } + + @Override + public String getLabel() { + return POROUS_LABEL; + } + + @Override + public void updateStatusByState() { + panel.stateChanged(); + } + + @Override + public Dictionary getDefaultDictionary() { + return new Dictionary(porousDarcyForchheimer); + } + + @Override + public CellZonePanel getPanel() { + return panel; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public void setEnabled(boolean enabled) { + } + + @Override + public String toString() { + return getKey(); + } + + @Override + public int compareTo(CellZoneType type) { + return getLabel().compareTo(type.getLabel()); + } + +} diff --git a/src/eu/engys/gui/casesetup/cellzones/thermal/StandardCellZoneThermalPanel.java b/src/eu/engys/gui/casesetup/cellzones/thermal/StandardCellZoneThermalPanel.java new file mode 100644 index 0000000..3e490c9 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/thermal/StandardCellZoneThermalPanel.java @@ -0,0 +1,92 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones.thermal; + +import static eu.engys.core.project.zero.cellzones.CellZonesUtils.T_KEY; +import static eu.engys.gui.casesetup.cellzones.CellZonesFactory.thermalFixedTemperature_OS; +import static eu.engys.gui.casesetup.cellzones.thermal.StandardThermal.THERMAL_LABEL; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPanel; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.modules.cellzones.CellZonePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZoneType; + +public class StandardCellZoneThermalPanel implements CellZonePanel { + + private DictionaryPanelBuilder builder; + + @Inject + public StandardCellZoneThermalPanel(Model model) { + } + + @Override + public void layoutPanel() { + DictionaryModel fixedModel = new DictionaryModel(new Dictionary(thermalFixedTemperature_OS)); + + builder = new DictionaryPanelBuilder(); + builder.startChoice(MODEL_LABEL); + + builder.startDictionary(FIXED_TEMPERATURE_LABEL, fixedModel); + builder.addComponent(FIXED_TEMPERATURE_K_LABEL, fixedModel.bindConstantDouble(T_KEY)); + builder.endDictionary(); + + builder.endChoice(); + + } + + @Override + public JComponent getPanel() { + JPanel panel = builder.getPanel(); + panel.setBorder(BorderFactory.createTitledBorder(THERMAL_LABEL)); + panel.setName(THERMAL_LABEL); + return panel; + } + + @Override + public void stateChanged() { + } + + @Override + public void loadFromDictionary(Dictionary cellZoneDictionary) { + Dictionary d = new Dictionary(CellZoneType.THERMAL_KEY); + d.merge(cellZoneDictionary); + builder.selectDictionary(d); + } + + @Override + public Dictionary saveToDictionary() { + return builder.getSelectedModel().getDictionary(); + } + +} diff --git a/src/eu/engys/gui/casesetup/cellzones/thermal/StandardThermal.java b/src/eu/engys/gui/casesetup/cellzones/thermal/StandardThermal.java new file mode 100644 index 0000000..8e67353 --- /dev/null +++ b/src/eu/engys/gui/casesetup/cellzones/thermal/StandardThermal.java @@ -0,0 +1,100 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.cellzones.thermal; + +import static eu.engys.gui.casesetup.cellzones.CellZonesFactory.thermalFixedTemperature_OS; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.cellzones.CellZonePanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZoneType; + +public class StandardThermal implements CellZoneType { + + public static final String THERMAL_LABEL = "Thermal Source"; + + private Model model; + private boolean enabled; + + private CellZonePanel panel; + + @Inject + public StandardThermal(Model model) { + this.model = model; + this.panel = new StandardCellZoneThermalPanel(model); + this.enabled = false; + } + + @Override + public String getKey() { + return CellZoneType.THERMAL_KEY; + } + + @Override + public String getLabel() { + return THERMAL_LABEL; + } + + @Override + public void updateStatusByState() { + boolean isEnergy = model.getState().isEnergy(); + setEnabled(isEnergy); + panel.stateChanged(); + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public Dictionary getDefaultDictionary() { + return new Dictionary(thermalFixedTemperature_OS); + } + + @Override + public CellZonePanel getPanel() { + return panel; + } + + @Override + public String toString() { + return getKey(); + } + + @Override + public int compareTo(CellZoneType type) { + return getLabel().compareTo(type.getLabel()); + } + +} diff --git a/src/eu/engys/gui/casesetup/fields/AbstractFieldsInitialisationPanel.java b/src/eu/engys/gui/casesetup/fields/AbstractFieldsInitialisationPanel.java new file mode 100644 index 0000000..26e8a66 --- /dev/null +++ b/src/eu/engys/gui/casesetup/fields/AbstractFieldsInitialisationPanel.java @@ -0,0 +1,365 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.fields; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.dictionary.Dictionary.VALUE; +import static eu.engys.core.project.zero.fields.Fields.ALPHA_1; +import static eu.engys.core.project.zero.fields.Fields.AOA; +import static eu.engys.core.project.zero.fields.Fields.CO2; +import static eu.engys.core.project.zero.fields.Fields.EPSILON; +import static eu.engys.core.project.zero.fields.Fields.K; +import static eu.engys.core.project.zero.fields.Fields.MU_SGS; +import static eu.engys.core.project.zero.fields.Fields.NU_TILDA; +import static eu.engys.core.project.zero.fields.Fields.OMEGA; +import static eu.engys.core.project.zero.fields.Fields.P; +import static eu.engys.core.project.zero.fields.Fields.P_RGH; +import static eu.engys.core.project.zero.fields.Fields.SMOKE; +import static eu.engys.core.project.zero.fields.Fields.T; +import static eu.engys.core.project.zero.fields.Fields.U; +import static eu.engys.core.project.zero.fields.Fields.W; +import static eu.engys.core.project.zero.fields.Initialisations.CELL_SET_KEY; +import static eu.engys.core.project.zero.fields.Initialisations.DEFAULT_KEY; +import static eu.engys.core.project.zero.fields.Initialisations.FIXED_VALUE_KEY; +import static eu.engys.util.Symbols.EPSILON_SYMBOL; +import static eu.engys.util.Symbols.K_SYMBOL; +import static eu.engys.util.Symbols.M2_S; +import static eu.engys.util.Symbols.M2_S2; +import static eu.engys.util.Symbols.MU_MEASURE; +import static eu.engys.util.Symbols.M_S; +import static eu.engys.util.Symbols.OMEGA_SYMBOL; +import static eu.engys.util.Symbols.PASCAL; + +import java.awt.event.ActionEvent; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryBuilder; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.builder.JComboBoxController; +import eu.engys.util.ui.builder.PanelBuilder; + +public abstract class AbstractFieldsInitialisationPanel extends DefaultGUIPanel { + + public static final String FIELDS_INITIALISATION = "Fields Initialisation"; + + public static final String DEFAULT_LABEL = "Default"; + public static final String FIXED_VALUE_LABEL = "Fixed Value"; + public static final String CELL_SET_LABEL = "CellSet"; + public static final String EDIT_LABEL = "Edit"; + + private Map unityMeasures = new HashMap<>(); + protected Map fieldBuilderMap = new HashMap<>(); + protected Map builders = new HashMap<>(); + + private PanelBuilder mainBuilder; + + public AbstractFieldsInitialisationPanel(Model model) { + super(FIELDS_INITIALISATION, model); + } + + @Override + protected JComponent layoutComponents() { + mainBuilder = new PanelBuilder(); + + JScrollPane mainScrollPane = new JScrollPane(mainBuilder.removeMargins().getPanel()); + mainScrollPane.setBorder(BorderFactory.createEmptyBorder()); + + builders.put(DEFAULT_KEY, defaultBuilder); + builders.put(FIXED_VALUE_KEY, fixedValueBuilder); + builders.put(CELL_SET_KEY, cellSetBuilder); + + return mainScrollPane; + } + + public interface Builder { + void build(DictionaryPanelBuilder builder, Field field); + } + + private final Builder defaultBuilder = new Builder() { + @Override + public void build(DictionaryPanelBuilder builder, Field field) { + DictionaryModel dictModel = new DictionaryModel(DictionaryBuilder.newDictionary("initialisation").field(TYPE, DEFAULT_KEY).done()) { + public String getKey() { + return DEFAULT_KEY; + } + }; + builder.startDictionary(DEFAULT_LABEL, dictModel); + builder.endGroup(); + } + }; + + private final Builder fixedValueBuilder = new Builder() { + @Override + public void build(DictionaryPanelBuilder builder, Field field) { + if (field.getFieldType().isScalar()) { + DictionaryModel dictScalarModel = new DictionaryModel(DictionaryBuilder.newDictionary("initialisation").field(TYPE, FIXED_VALUE_KEY).field(VALUE, "uniform 0").done()) { + public String getKey() { + return FIXED_VALUE_KEY; + } + }; + builder.startDictionary(FIXED_VALUE_LABEL, dictScalarModel); + builder.addComponent("Value", dictScalarModel.bindUniformDouble(VALUE)); + builder.endDictionary(); + } else { + DictionaryModel dictVectorModel = new DictionaryModel(DictionaryBuilder.newDictionary("initialisation").field(TYPE, FIXED_VALUE_KEY).field(VALUE, "uniform (0 0 0)").done()) { + public String getKey() { + return FIXED_VALUE_KEY; + } + }; + builder.startDictionary(FIXED_VALUE_LABEL, dictVectorModel); + builder.addComponent("Value", dictVectorModel.bindUniformPoint(VALUE)); + builder.endDictionary(); + } + } + }; + + private final Builder cellSetBuilder = new Builder() { + @Override + public void build(DictionaryPanelBuilder builder, final Field field) { + final DictionaryModel dictModel = new DictionaryModel(getCellSetDefaultDict()) { + public String getKey() { + return CELL_SET_KEY; + } + }; + + builder.startDictionary(CELL_SET_LABEL, dictModel); + builder.addComponent("Default Value", dictModel.bindUniformDouble("defaultValue")); + + JButton editButton = getEditButton(field, dictModel); + builder.addRight(editButton); + builder.endDictionary(); + } + + private JButton getEditButton(final Field field, final DictionaryModel dictModel) { + final CellSetDialog cellSetDialog = new CellSetDialog(model, dictModel, field.getName(), "setSources", AbstractFieldsInitialisationPanel.this); + final Action action = new AbstractAction(EDIT_LABEL, EDIT_ICON) { + @Override + public void actionPerformed(ActionEvent e) { + cellSetDialog.showDialog(); + } + }; + + cellSetDialog.getDialog().addComponentListener(new ComponentAdapter() { + + @Override + public void componentShown(ComponentEvent e) { + super.componentShown(e); + action.setEnabled(false); + } + + @Override + public void componentHidden(ComponentEvent e) { + super.componentHidden(e); + action.setEnabled(true); + } + }); + + JButton editButton = new JButton(action); + editButton.setName(EDIT_LABEL); + return editButton; + } + + private Dictionary getCellSetDefaultDict() { + DictionaryBuilder boxBuilder = DictionaryBuilder.newDictionary("boxToCell"); + boxBuilder.field("box", "(0 0 0) (2.0 2.0 1.0 )"); + boxBuilder.field("value", "0.0"); + + DictionaryBuilder builder = DictionaryBuilder.newDictionary("initialisation"); + builder.field(TYPE, CELL_SET_KEY); + builder.field("defaultValue", "uniform 0.0"); + builder.list("setSources", boxBuilder.done()); + + return builder.done(); + } + + }; + + @Override + public void load() { + rebuildPanel(); + } + + @Override + public void save() { + for (Field f : fieldBuilderMap.keySet()) { + DictionaryPanelBuilder b = fieldBuilderMap.get(f); + Dictionary dictionary = b.getSelectedModel().getDictionary(); + f.setInitialisation(dictionary); + } + } + + @Override + public void stateChanged() { + rebuildLater(); + } + + @Override + public void materialsChanged() { + rebuildLater(); + } + + @Override + public void fieldsChanged() { + rebuildLater(); + } + + private void rebuildLater() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + rebuildPanel(); + } + }); + } + + protected void rebuildPanel() { + fieldBuilderMap.clear(); + mainBuilder.clear(); + + JButton initialiseButton = new JButton(ActionManager.getInstance().get("initialise.fields")); + initialiseButton.setName("fields.initialise.button"); + mainBuilder.addRight(initialiseButton); + + Fields fields = model.getFields(); + unityMeasures(fields, model.getState().isCompressible()); + + for (Field field : fields.orderedFields()) { + buildFieldPanel(field); + } + initialiseButton.setEnabled(fields.size() > 0); + + revalidate(); + repaint(); + } + + protected JComboBoxController buildFieldPanel(Field field) { + String name = field.getName(); + String labelText = unityMeasure(name); + DictionaryPanelBuilder builder = new DictionaryPanelBuilder(); + builder.addSeparator(labelText); + builder.indent(); + builder.prefix(name + "."); + JComboBoxController combo = (JComboBoxController) builder.startChoice("Type"); + String[] initialisationMethods = field.getInitialisationMethods(); + + for (String method : initialisationMethods) { + if (builders.containsKey(method)) { + builders.get(method).build(builder, field); + } + } + + builder.endChoice(); + builder.addSeparator(""); + builder.outdent(); + builder.prefix(""); + + builder.selectDictionary(field.getInitialisation()); + + JPanel builderPanel = builder.getPanel(); + builderPanel.setName(name); + builderPanel.setBorder(BorderFactory.createTitledBorder("")); + + mainBuilder.addComponent(builderPanel); + + fieldBuilderMap.put(field, builder); + + return combo; + } + + private String unityMeasure(String name) { + return name + (unityMeasures.containsKey(name) ? " " + unityMeasures.get(name) : ""); + } + + private void unityMeasures(Fields fields, boolean compressible) { + unityMeasures = new HashMap(); + if (fields.containsKey(U)) + unityMeasures.put(U, M_S); + if (fields.containsKey(P)) + unityMeasures.put(P, compressible ? PASCAL : M2_S2); + if (fields.containsKey(P_RGH)) + unityMeasures.put(P_RGH, compressible ? PASCAL : M2_S2); + if (fields.containsKey(K)) + unityMeasures.put(K, K_SYMBOL); + if (fields.containsKey(OMEGA)) + unityMeasures.put(OMEGA, OMEGA_SYMBOL); + if (fields.containsKey(EPSILON)) + unityMeasures.put(EPSILON, EPSILON_SYMBOL); + if (fields.containsKey(NU_TILDA)) + unityMeasures.put(NU_TILDA, M2_S); + + // if (fields.containsKey("nut")) unityMeasures.put(get("nut")); + // if (fields.containsKey("mut")) unityMeasures.put(get("mut")); + // if (fields.containsKey("nuSgs")) unityMeasures.put(get("nuSgs")); + if (fields.containsKey(MU_SGS)) + unityMeasures.put(MU_SGS, MU_MEASURE); + // if (fields.containsKey("D")) unityMeasures.put(get("D")); + + if (fields.containsKey(T)) + unityMeasures.put(T, "[K]"); + if (fields.containsKey(W)) + unityMeasures.put(W, ""); + if (fields.containsKey(ALPHA_1)) + unityMeasures.put(ALPHA_1, "[phase 1]"); + if (fields.containsKey(AOA)) + unityMeasures.put(AOA, ""); + if (fields.containsKey(CO2)) + unityMeasures.put(CO2, ""); + if (fields.containsKey(SMOKE)) + unityMeasures.put(SMOKE, ""); + // if (fields.containsKey("rho")) unityMeasures.put(get("rho")); + // if (fields.containsKey("alphat")) unityMeasures.put(get("alphat")); + if (fields.containsKey("Intensity")) + unityMeasures.put("Intensity", ""); + } + + /** + * Resources + */ + + protected static final Icon EDIT_ICON = ResourcesUtil.getIcon("script.edit.icon"); + +} diff --git a/src/eu/engys/gui/casesetup/fields/CellSetDialog.java b/src/eu/engys/gui/casesetup/fields/CellSetDialog.java new file mode 100644 index 0000000..ff9b862 --- /dev/null +++ b/src/eu/engys/gui/casesetup/fields/CellSetDialog.java @@ -0,0 +1,259 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.fields; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.ListField; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.AddSurfaceEvent; +import eu.engys.gui.events.view3D.RemoveSurfaceEvent; +import eu.engys.util.ui.UiUtil; + +public class CellSetDialog extends JPanel { + + public static final String CELLSET_PANEL_NAME = "cellset.panel"; + public static final String CELLSET_REM_NAME = "cellset.rem"; + public static final String CELLSET_ADD_NAME = "cellset.add"; + + private Map rowsMap = new HashMap<>(); + private JDialog dialog; + private JPanel rowsPanel; + private JScrollPane scrollPane; + private DictionaryModel dictionaryModel; + private final String fieldName; + private final Model model; + private final String listName; + private Component parentComponent; + private JButton okButton; + + public CellSetDialog(Model model, DictionaryModel dictionaryModel, String fieldName, String listName, Component parentComponent) { + super(new BorderLayout()); + this.dictionaryModel = dictionaryModel; + this.fieldName = fieldName; + this.model = model; + this.parentComponent = parentComponent; + this.listName = listName; + setName(CELLSET_PANEL_NAME); + layoutComponents(); + } + + private void layoutComponents() { + JPanel addRemovePanel = new JPanel(new FlowLayout()); + addRemovePanel.setOpaque(false); + JButton addButton = new JButton(new AddRowAction()); + addButton.setName(CELLSET_ADD_NAME); + JButton remButton = new JButton(new RemRowAction()); + remButton.setName(CELLSET_REM_NAME); + addRemovePanel.add(addButton); + addRemovePanel.add(remButton); + + JPanel okPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + okButton = new JButton(new AbstractAction("OK") { + @Override + public void actionPerformed(ActionEvent e) { + handleDialogClose(); + } + + }); + okButton.setName("OK"); + okPanel.add(okButton); + + rowsPanel = new JPanel(new GridBagLayout()); + JPanel centerPanel = new JPanel(new BorderLayout()); + centerPanel.add(rowsPanel, BorderLayout.NORTH); + centerPanel.add(new JLabel(), BorderLayout.CENTER); + + add(addRemovePanel, BorderLayout.NORTH); + scrollPane = new JScrollPane(centerPanel); + scrollPane.setBorder(BorderFactory.createEmptyBorder()); + add(scrollPane, BorderLayout.CENTER); + add(okPanel, BorderLayout.SOUTH); + layoutDialog(); + } + + public JDialog getDialog() { + return dialog; + } + + private void layoutDialog() { + Window parent = parentComponent == null ? UiUtil.getActiveWindow() : SwingUtilities.getWindowAncestor(parentComponent); + String title = fieldName.equals(Fields.ALPHA_1) ? fieldName + " [phase 1]" : fieldName; + dialog = new JDialog(parent, title, ModalityType.MODELESS); + dialog.setName("cellset.dialog"); + dialog.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + handleDialogClose(); + } + }); + + dialog.add(this); + dialog.setSize(600, 400); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.getRootPane().setDefaultButton(okButton); + } + + public void showDialog() { + load(); + dialog.setVisible(true); + } + + public void load() { + Dictionary initialisation = dictionaryModel.getDictionary(); + if (initialisation != null && initialisation.isList(listName)) { + ListField sources = initialisation.getList(listName); + for (int i = 0; i < sources.getListElements().size(); i++) { + Dictionary source = (Dictionary) sources.getListElements().get(i); + addRow(new CellSetRow(model, fieldName, source, i)); + } + } + } + + private void addRow(CellSetRow row) { + Integer index = rowsMap.size(); + rowsMap.put(index, row); + rowsPanel.add(row, new GridBagConstraints(0, index, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 10, 5, 10), 0, 0)); + rowsPanel.revalidate(); + EventManager.triggerEvent(this, new AddSurfaceEvent(row.getSurface())); + } + + private void handleDialogClose() { + save(); + clear(); + dialog.setVisible(false); + } + + public void save() { + ListField regions = new ListField(listName); + for (Dictionary dict : getDictionaries()) { + regions.add(dict); + } + Dictionary initialisation = dictionaryModel.getDictionary(); + initialisation.remove(listName); + initialisation.add(new ListField(regions)); + } + + public void clear() { + for (CellSetRow row : rowsMap.values()) { + row.clear(); + } + EventManager.triggerEvent(this, new RemoveSurfaceEvent(getSurfaces().toArray(new Surface[0]))); + rowsPanel.removeAll(); + rowsMap.clear(); + } + + private List getSurfaces() { + List surfaces = new ArrayList<>(); + for (CellSetRow row : rowsMap.values()) { + surfaces.add(row.getSurface()); + } + return surfaces; + } + + private List getDictionaries() { + List dicts = new ArrayList<>(); + for (CellSetRow row : rowsMap.values()) { + dicts.add(row.getDictionary()); + } + return dicts; + } + + private void removeRow() { + CellSetRow row = rowsMap.get(rowsMap.size() - 1); + rowsPanel.remove(row); + rowsPanel.revalidate(); + rowsMap.remove(rowsMap.size() - 1); + EventManager.triggerEvent(this, new RemoveSurfaceEvent(row.getSurface())); + } + + private class AddRowAction extends AbstractAction { + + public AddRowAction() { + super("+"); + } + + @Override + public void actionPerformed(ActionEvent e) { + addRow(new CellSetRow(model, fieldName, new Dictionary("boxToCell"), rowsMap.size())); + } + + } + + private class RemRowAction extends AbstractAction { + + public RemRowAction() { + super("-"); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (rowsMap.size() > 1) { + removeRow(); + } + } + } + + // Test purpose only + public void setInitialisation(Dictionary initialisation) { + this.dictionaryModel = new DictionaryModel(initialisation); + } + + // Test purpose only + public Dictionary getInitialisation() { + return dictionaryModel.getDictionary(); + } +} diff --git a/src/eu/engys/gui/casesetup/fields/CellSetRow.java b/src/eu/engys/gui/casesetup/fields/CellSetRow.java new file mode 100644 index 0000000..c96448e --- /dev/null +++ b/src/eu/engys/gui/casesetup/fields/CellSetRow.java @@ -0,0 +1,515 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.fields; + +import static eu.engys.core.project.geometry.Surface.CENTRE_KEY; +import static eu.engys.core.project.geometry.Surface.INNER_RADIUS_KEY; +import static eu.engys.core.project.geometry.Surface.MAX_KEY; +import static eu.engys.core.project.geometry.Surface.MIN_KEY; +import static eu.engys.core.project.geometry.Surface.OUTER_RADIUS_KEY; +import static eu.engys.core.project.geometry.Surface.POINT1_KEY; +import static eu.engys.core.project.geometry.Surface.POINT2_KEY; +import static eu.engys.core.project.geometry.Surface.RADIUS_KEY; +import static eu.engys.core.project.system.SetFieldsDict.BOX_TO_CELL_KEY; +import static eu.engys.core.project.system.SetFieldsDict.CYLINDER_TO_CELL_KEY; +import static eu.engys.core.project.system.SetFieldsDict.RING_TO_CELL_KEY; +import static eu.engys.core.project.system.SetFieldsDict.SPHERE_TO_CELL_KEY; +import static eu.engys.gui.casesetup.boundaryconditions.utils.BoundaryConditionsUtils.VALUE_KEY; +import static eu.engys.gui.mesh.panels.GeometriesPanelBuilder.CENTRE_LABEL; +import static eu.engys.gui.mesh.panels.GeometriesPanelBuilder.INNER_RADIUS_LABEL; +import static eu.engys.gui.mesh.panels.GeometriesPanelBuilder.MAX_LABEL; +import static eu.engys.gui.mesh.panels.GeometriesPanelBuilder.MIN_LABEL; +import static eu.engys.gui.mesh.panels.GeometriesPanelBuilder.OUTER_RADIUS_LABEL; +import static eu.engys.gui.mesh.panels.GeometriesPanelBuilder.POINT_1_LABEL; +import static eu.engys.gui.mesh.panels.GeometriesPanelBuilder.POINT_2_LABEL; +import static eu.engys.gui.mesh.panels.GeometriesPanelBuilder.RADIUS_LABEL; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldChangeListener; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.Box; +import eu.engys.core.project.geometry.surface.Cylinder; +import eu.engys.core.project.geometry.surface.Ring; +import eu.engys.core.project.geometry.surface.Sphere; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.AddSurfaceEvent; +import eu.engys.gui.events.view3D.ChangeSurfaceEvent; +import eu.engys.gui.events.view3D.RemoveSurfaceEvent; +import eu.engys.gui.view3D.BoxEventButton; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; + +public class CellSetRow extends JPanel { + + private static final Logger logger = LoggerFactory.getLogger(CellSetRow.class); + + public static final String BOX = "Box"; + public static final String SPHERE = "Sphere"; + public static final String CYLINDER = "Cylinder"; + public static final String RING = "Ring"; + + public static final String CELLSET_NAME = "cellset"; + public static final String CELLSET_ROW_NAME = "cellset.row"; + public static final String CELLSET_VALUE_NAME = "cellset.value"; + public static final String CELLSET_SLIDER_NAME = "cellset.slider"; + + private DictionaryModel boxModel = new DictionaryModel(getDefaultBoxModelDictionary()); + private DictionaryModel sphereModel = new DictionaryModel(getDefaultSphereModelDictionary()); + private DictionaryModel cylinderModel = new DictionaryModel(getDefaultCylinderModelDictionary()); + private DictionaryModel ringModel = new DictionaryModel(getDefaultRingModelDictionary()); + private FieldChangeListener listener; + private JPanel coordinatesPanel; + private Dictionary loadedDictionary; + private Surface surface; + private Integer index; + private JComboBox choice; + private DoubleField valueField; + private SliderChangeListener valueSliderListener; + private TextFieldChangeListener valueFieldListener; + + private BoxEventButton showBoxButton; + + private Model model; + private String fieldName; + + public CellSetRow(Model model, String fieldName, Dictionary dictionary, Integer index) { + super(new BorderLayout()); + this.model = model; + this.fieldName = fieldName; + this.loadedDictionary = dictionary; + this.index = index; + this.listener = new ValueFieldChangeListener(); + setName(CELLSET_ROW_NAME + "." + index); + layoutComponents(); + load(); + } + + private void layoutComponents() { + setBorder(BorderFactory.createTitledBorder(BOX)); + setOpaque(false); + coordinatesPanel = createCoordinatersPanel(); + choice = create3DCombo(); + JPanel valuePanel = createValuePanel(); + + add(choice, BorderLayout.NORTH); + add(coordinatesPanel, BorderLayout.CENTER); + add(valuePanel, BorderLayout.SOUTH); + } + + private JPanel createValuePanel() { + valueField = ComponentsFactory.doubleField(0.0, 0.0, 1.0); + valueField.setName(CELLSET_VALUE_NAME + "." + index); + JSlider valueSlider = createSlider(); + valueSlider.addChangeListener(valueSliderListener = new SliderChangeListener(valueField)); + valueField.addPropertyChangeListener(valueFieldListener = new TextFieldChangeListener(valueSlider)); + + JPanel valuePanel = new JPanel(new GridBagLayout()); + valuePanel.setOpaque(false); + valuePanel.add(valueSlider, new GridBagConstraints(0, 0, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + valuePanel.add(valueField, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(12, 5, 0, 0), 0, 0)); + + valuePanel.add(label(getLeftLabel()), new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); + valuePanel.add(label(getRightLabel()), new GridBagConstraints(1, 1, 1, 1, 1.0, 1.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); + valuePanel.add(label(""), new GridBagConstraints(2, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + return valuePanel; + } + + private void load() { + if (!loadedDictionary.isEmpty()) { + Dictionary newDict = new Dictionary(""); + if (loadedDictionary.found("box")) { + String boxValue = loadedDictionary.lookup("box"); + String min = boxValue.substring(0, boxValue.indexOf(")") + 1).trim(); + String max = boxValue.replace(min, "").trim(); + newDict.add(MIN_KEY, min); + newDict.add(MAX_KEY, max); + choice.setSelectedItem(BOX); + boxModel.setDictionary(newDict); + surface.setGeometryDictionary(boxModel.getDictionary()); + } else if (loadedDictionary.found(CENTRE_KEY) && loadedDictionary.found(RADIUS_KEY)) {// sphere + newDict.add(CENTRE_KEY, loadedDictionary.lookup(CENTRE_KEY)); + newDict.add(RADIUS_KEY, loadedDictionary.lookup(RADIUS_KEY)); + choice.setSelectedItem(SPHERE); + sphereModel.setDictionary(newDict); + surface.setGeometryDictionary(sphereModel.getDictionary()); + } else if (loadedDictionary.found(POINT1_KEY) && loadedDictionary.found(RADIUS_KEY)) {// cylinder + newDict.add(RADIUS_KEY, loadedDictionary.lookup(RADIUS_KEY)); + newDict.add(POINT1_KEY, loadedDictionary.lookup(POINT1_KEY)); + newDict.add(POINT2_KEY, loadedDictionary.lookup(POINT2_KEY)); + choice.setSelectedItem(CYLINDER); + cylinderModel.setDictionary(newDict); + surface.setGeometryDictionary(cylinderModel.getDictionary()); + } else if (loadedDictionary.found(INNER_RADIUS_KEY) && loadedDictionary.found(OUTER_RADIUS_KEY)) {// ring + newDict.add(POINT1_KEY, loadedDictionary.lookup(POINT1_KEY)); + newDict.add(POINT2_KEY, loadedDictionary.lookup(POINT2_KEY)); + newDict.add(INNER_RADIUS_KEY, loadedDictionary.lookup(INNER_RADIUS_KEY)); + newDict.add(OUTER_RADIUS_KEY, loadedDictionary.lookup(OUTER_RADIUS_KEY)); + choice.setSelectedItem(RING); + ringModel.setDictionary(newDict); + surface.setGeometryDictionary(ringModel.getDictionary()); + } + + if (loadedDictionary.found(VALUE_KEY)) { + String value = loadedDictionary.lookup(VALUE_KEY); + valueField.setDoubleValue(Double.parseDouble(value)); + } + } else { + addNewBox(); + } + } + + private void addNewBox() { + surface = model.getGeometry().getFactory().newSurface(Box.class, "Box_" + index); + boxModel.setDictionary(surface.getGeometryDictionary()); + } + + private JSlider createSlider() { + JSlider valueSlider = new JSlider(JSlider.HORIZONTAL, 0, fieldName.equals(Fields.ALPHA_1) ? 1 : 100, 0); + valueSlider.setName(CELLSET_SLIDER_NAME + "." + index); + valueSlider.setMajorTickSpacing(10); + valueSlider.setPaintTicks(true); + valueSlider.setPaintTrack(true); + valueSlider.setPaintLabels(false); + return valueSlider; + } + + private JComboBox create3DCombo() { + choice = new JComboBox(new String[] { BOX, SPHERE, CYLINDER, RING }); + choice.setName(CELLSET_NAME + "." + index); + choice.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + CardLayout layout = (CardLayout) coordinatesPanel.getLayout(); + Surface existingSurface = surface; + if (existingSurface != null) { + EventManager.triggerEvent(this, new RemoveSurfaceEvent(surface)); + } + if (choice.getSelectedIndex() == 0) { + layout.show(coordinatesPanel, BOX); + setBorder(BorderFactory.createTitledBorder(BOX)); + surface = model.getGeometry().getFactory().newSurface(Box.class, BOX + "_" + index); + boxModel.setDictionary(surface.getGeometryDictionary()); + } else if (choice.getSelectedIndex() == 1) { + layout.show(coordinatesPanel, SPHERE); + setBorder(BorderFactory.createTitledBorder(SPHERE)); + surface = model.getGeometry().getFactory().newSurface(Sphere.class, SPHERE + "_" + index); + sphereModel.setDictionary(surface.getGeometryDictionary()); + } else if (choice.getSelectedIndex() == 2) { + layout.show(coordinatesPanel, CYLINDER); + setBorder(BorderFactory.createTitledBorder(CYLINDER)); + surface = model.getGeometry().getFactory().newSurface(Cylinder.class, CYLINDER + "_" + index); + cylinderModel.setDictionary(surface.getGeometryDictionary()); + } else if (choice.getSelectedIndex() == 3) { + layout.show(coordinatesPanel, RING); + setBorder(BorderFactory.createTitledBorder(RING)); + surface = model.getGeometry().getFactory().newSurface(Ring.class, RING + "_" + index); + ringModel.setDictionary(surface.getGeometryDictionary()); + } + if (existingSurface != null) { + EventManager.triggerEvent(this, new AddSurfaceEvent(surface)); + } + } + }); + return choice; + } + + private JPanel createCoordinatersPanel() { + CardLayout c = new CardLayout(); + JPanel p = new JPanel(c); + p.setOpaque(false); + p.add(getBoxPanel(), BOX); + p.add(getSpherePanel(), SPHERE); + p.add(getCylinderPanel(), CYLINDER); + p.add(getRingPanel(), RING); + c.show(p, BOX); + return p; + } + + private JPanel getBoxPanel() { + PanelBuilder boxBuilder = new PanelBuilder(); + DoubleField[] boxMin = boxModel.bindPoint(MIN_KEY, listener); + DoubleField[] boxMax = boxModel.bindPoint(MAX_KEY, listener); + + showBoxButton = new BoxEventButton(boxMin, boxMax); + + boxBuilder.addComponent(MIN_LABEL, boxMin[0], boxMin[1], boxMin[2], showBoxButton); + boxBuilder.addComponentAndSpan(MAX_LABEL, boxMax); + + return boxBuilder.getPanel(); + } + + private JPanel getSpherePanel() { + PanelBuilder sphereBuilder = new PanelBuilder(); + sphereBuilder.addComponent(CENTRE_LABEL, sphereModel.bindPoint(CENTRE_KEY, listener)); + sphereBuilder.addComponent(RADIUS_LABEL, sphereModel.bindDouble(RADIUS_KEY, listener)); + return sphereBuilder.getPanel(); + + } + + private JPanel getCylinderPanel() { + PanelBuilder cylinderBuilder = new PanelBuilder(); + cylinderBuilder.addComponent(POINT_1_LABEL, cylinderModel.bindPoint(POINT1_KEY, listener)); + cylinderBuilder.addComponent(POINT_2_LABEL, cylinderModel.bindPoint(POINT2_KEY, listener)); + cylinderBuilder.addComponent(RADIUS_LABEL, cylinderModel.bindDouble(RADIUS_KEY, listener)); + return cylinderBuilder.getPanel(); + } + + private JPanel getRingPanel() { + PanelBuilder ringBuilder = new PanelBuilder(); + ringBuilder.addComponent(POINT_1_LABEL, ringModel.bindPoint(POINT1_KEY, listener)); + ringBuilder.addComponent(POINT_2_LABEL, ringModel.bindPoint(POINT2_KEY, listener)); + ringBuilder.addComponent(INNER_RADIUS_LABEL, ringModel.bindDouble(INNER_RADIUS_KEY, listener)); + ringBuilder.addComponent(OUTER_RADIUS_LABEL, ringModel.bindDouble(OUTER_RADIUS_KEY, listener)); + return ringBuilder.getPanel(); + } + + public Surface getSurface() { + return surface; + } + + public Dictionary getDictionary() { + switch (choice.getItemAt(choice.getSelectedIndex())) { + case BOX: { + Dictionary boxToCell = new Dictionary(BOX_TO_CELL_KEY); + String min = boxModel.getDictionary().lookup(MIN_KEY); + String max = boxModel.getDictionary().lookup(MAX_KEY); + boxToCell.add("box", min + " " + max); + boxToCell.add(VALUE_KEY, String.valueOf(valueField.getDoubleValue())); + return boxToCell; + } + case SPHERE: { + Dictionary sphereToCell = new Dictionary(SPHERE_TO_CELL_KEY); + String centre = sphereModel.getDictionary().lookup(CENTRE_KEY); + String radius = sphereModel.getDictionary().lookup(RADIUS_KEY); + sphereToCell.add(CENTRE_KEY, centre); + sphereToCell.add(RADIUS_KEY, radius); + sphereToCell.add(VALUE_KEY, String.valueOf(valueField.getDoubleValue())); + return sphereToCell; + } + case CYLINDER: { + Dictionary cylinderToCell = new Dictionary(CYLINDER_TO_CELL_KEY); + String p1 = cylinderModel.getDictionary().lookup(POINT1_KEY); + String p2 = cylinderModel.getDictionary().lookup(POINT2_KEY); + String radius = cylinderModel.getDictionary().lookup(RADIUS_KEY); + cylinderToCell.add(POINT1_KEY, p1); + cylinderToCell.add(POINT2_KEY, p2); + cylinderToCell.add(RADIUS_KEY, radius); + cylinderToCell.add(VALUE_KEY, String.valueOf(valueField.getDoubleValue())); + return cylinderToCell; + } + case RING: { + Dictionary ringToCell = new Dictionary(RING_TO_CELL_KEY); + String p1 = ringModel.getDictionary().lookup(POINT1_KEY); + String p2 = ringModel.getDictionary().lookup(POINT2_KEY); + String iRadius = ringModel.getDictionary().lookup(INNER_RADIUS_KEY); + String oRadius = ringModel.getDictionary().lookup(OUTER_RADIUS_KEY); + ringToCell.add(POINT1_KEY, p1); + ringToCell.add(POINT2_KEY, p2); + ringToCell.add(INNER_RADIUS_KEY, iRadius); + ringToCell.add(OUTER_RADIUS_KEY, oRadius); + ringToCell.add(VALUE_KEY, String.valueOf(valueField.getDoubleValue())); + return ringToCell; + } + default: + return null; + } + } + + private class TextFieldChangeListener implements PropertyChangeListener { + + private JSlider slider; + + public TextFieldChangeListener(JSlider slider) { + this.slider = slider; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + slider.removeChangeListener(valueSliderListener); + DoubleField field = (DoubleField) evt.getSource(); + slider.setValue((int) (field.getDoubleValue() * 100)); + slider.addChangeListener(valueSliderListener); + } + } + }; + + private class SliderChangeListener implements ChangeListener { + + private DoubleField field; + + public SliderChangeListener(DoubleField field) { + this.field = field; + } + + @Override + public void stateChanged(ChangeEvent e) { + field.removePropertyChangeListener(valueFieldListener); + JSlider slider = (JSlider) e.getSource(); + double value = slider.getValue(); + field.setDoubleValue(value / slider.getMaximum()); + field.addPropertyChangeListener(valueFieldListener); + } + }; + + private class ValueFieldChangeListener implements FieldChangeListener { + + boolean adjusting = false; + + @Override + public void actionPerformed(ActionEvent e) { + } + + @Override + public void setAdjusting(boolean b) { + this.adjusting = b; + } + + @Override + public boolean isAdjusting() { + return adjusting; + } + + @Override + public void fieldChanged() { + if (!isAdjusting()) { + if (surface.getType().isBox()) + surface.setGeometryDictionary(boxModel.getDictionary()); + else if (surface.getType().isSphere()) + surface.setGeometryDictionary(sphereModel.getDictionary()); + else if (surface.getType().isCylinder()) + surface.setGeometryDictionary(cylinderModel.getDictionary()); + else if (surface.getType().isRing()) + surface.setGeometryDictionary(ringModel.getDictionary()); + else + logger.error("Unknow surface type"); + + EventManager.triggerEvent(this, new ChangeSurfaceEvent(surface, false)); + } + } + }; + + private Dictionary getDefaultBoxModelDictionary() { + Dictionary dictionary = new Dictionary(BOX_TO_CELL_KEY); + dictionary.add(MIN_KEY, "(0.0 0.0 0.0)"); + dictionary.add(MAX_KEY, "(2.0 2.0 1.0)"); + return dictionary; + } + + private Dictionary getDefaultSphereModelDictionary() { + Dictionary dictionary = new Dictionary(SPHERE_TO_CELL_KEY); + dictionary.add(CENTRE_KEY, "(0.0 0.0 0.0 )"); + dictionary.add(RADIUS_KEY, "2.0"); + return dictionary; + } + + private Dictionary getDefaultCylinderModelDictionary() { + Dictionary dictionary = new Dictionary(CYLINDER_TO_CELL_KEY); + dictionary.add(POINT1_KEY, "(0.0 0.0 -1.5 )"); + dictionary.add(POINT2_KEY, "(0.0 0.0 1.5 )"); + dictionary.add(RADIUS_KEY, "2.0"); + return dictionary; + } + + private Dictionary getDefaultRingModelDictionary() { + Dictionary dictionary = new Dictionary(RING_TO_CELL_KEY); + dictionary.add(POINT1_KEY, "(0.0 0.0 0 )"); + dictionary.add(POINT2_KEY, "(0.05 0.0 0 )"); + dictionary.add(INNER_RADIUS_KEY, "0.2"); + dictionary.add(OUTER_RADIUS_KEY, "0.5"); + return dictionary; + } + + private String getLeftLabel() { + String label; + if (model.getState().getMultiphaseModel().isMultiphase()) { + if (fieldName.equals(Fields.ALPHA_1)) { + label = model.getMaterials().get(1).getName(); + } else if (fieldName.startsWith(Fields.ALPHA + ".")) { + label = "No " + Fields.PHASE_OS(fieldName); + } else if (fieldName.startsWith(Fields.ALPHA)) { + label = "No " + Fields.PHASE(fieldName); + } else { + label = "No " + fieldName; + } + } else { + label = "No " + fieldName; + } + return label; + } + + private String getRightLabel() { + String label; + if (model.getState().getMultiphaseModel().isMultiphase()) { + if (fieldName.equals(Fields.ALPHA_1)) { + label = model.getMaterials().get(0).getName(); + } else if (fieldName.startsWith(Fields.ALPHA)) { + label = Fields.PHASE(fieldName); + } else { + label = fieldName; + } + } else { + label = fieldName; + } + return label; + } + + private JLabel label(String name) { + return new JLabel(name); + } + + public void clear() { + if (showBoxButton.isSelected()) { + showBoxButton.doClick(); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/fields/SetFieldsDictConverter.java b/src/eu/engys/gui/casesetup/fields/SetFieldsDictConverter.java new file mode 100644 index 0000000..306b6b1 --- /dev/null +++ b/src/eu/engys/gui/casesetup/fields/SetFieldsDictConverter.java @@ -0,0 +1,123 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.fields; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.dictionary.Dictionary.VALUE; +import static eu.engys.core.project.system.SetFieldsDict.CELL_SET_KEY; +import static eu.engys.core.project.system.SetFieldsDict.DEFAULT_FIELD_VALUES_KEY; +import static eu.engys.core.project.system.SetFieldsDict.DEFAULT_VALUE_KEY; +import static eu.engys.core.project.system.SetFieldsDict.FIELD_VALUES_KEY; +import static eu.engys.core.project.system.SetFieldsDict.REGIONS_KEY; +import static eu.engys.core.project.system.SetFieldsDict.SET_SOURCES_KEY; +import static eu.engys.core.project.system.SetFieldsDict.VOL_SCALAR_FIELD_VALUE_KEY; +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.system.SetFieldsDict; +import eu.engys.core.project.zero.fields.Field; + +public class SetFieldsDictConverter { + + private Field field; + + public SetFieldsDictConverter(Field field) { + this.field = field; + } + + public Dictionary convertForRead(SetFieldsDict dictToFix) { + Dictionary fixedDict = new Dictionary(dictToFix); + fixHeaderForRead(fixedDict); + fixRegionsForRead(fixedDict); + fixedDict.setName("initialisation"); + return fixedDict; + } + + public SetFieldsDict convertForWrite(Dictionary dictToFix) { + SetFieldsDict fixedDict = new SetFieldsDict(dictToFix); + fixHeaderForWrite(fixedDict); + fixRegionsForWrite(fixedDict); + fixedDict.setName(SetFieldsDict.SET_FIELDS_DICT); + return fixedDict; + } + + private void fixHeaderForRead(Dictionary dictionary) { + if (!dictionary.found(TYPE)) { + dictionary.add(TYPE, CELL_SET_KEY); + } + if (!dictionary.found(DEFAULT_VALUE_KEY) && dictionary.found(DEFAULT_FIELD_VALUES_KEY)) { + String fixedValue = dictionary.lookup(DEFAULT_FIELD_VALUES_KEY).replace("(", "").replace(")", "").replace(VOL_SCALAR_FIELD_VALUE_KEY, "").replace(field.getName(), "").trim(); + dictionary.add(DEFAULT_VALUE_KEY, "uniform " + fixedValue); + dictionary.remove(DEFAULT_FIELD_VALUES_KEY); + } + } + + private void fixRegionsForRead(Dictionary dictionary) { + if (!dictionary.found(SET_SOURCES_KEY) && dictionary.found(REGIONS_KEY)) { + for (DefaultElement element : dictionary.getList(REGIONS_KEY).getListElements()) { + if (element instanceof Dictionary) { + Dictionary dict = (Dictionary) element; + if (!dict.found(VALUE) && dict.found(FIELD_VALUES_KEY)) { + String fixedValue = dict.lookup(FIELD_VALUES_KEY).replace("(", "").replace(")", "").replace(VOL_SCALAR_FIELD_VALUE_KEY, "").replace(field.getName(), "").trim(); + dict.add(VALUE, fixedValue); + dict.remove(FIELD_VALUES_KEY); + } + dictionary.addToList(SET_SOURCES_KEY, dict); + } + } + dictionary.remove(REGIONS_KEY); + } + } + + private void fixHeaderForWrite(Dictionary dictionary) { + if (dictionary.found(TYPE)) { + dictionary.remove(TYPE); + } + if (dictionary.found(DEFAULT_VALUE_KEY)) { + String fixedValue = "( " + VOL_SCALAR_FIELD_VALUE_KEY + " " + field.getName() + " " + dictionary.lookup(DEFAULT_VALUE_KEY).replace("uniform", "").trim() + " )"; + dictionary.add(DEFAULT_FIELD_VALUES_KEY, fixedValue); + dictionary.remove(DEFAULT_VALUE_KEY); + } + } + + private void fixRegionsForWrite(Dictionary dictionary) { + if (dictionary.found(SET_SOURCES_KEY)) { + for (DefaultElement element : dictionary.getList(SET_SOURCES_KEY).getListElements()) { + if (element instanceof Dictionary) { + Dictionary dict = (Dictionary) element; + if (dict.found(VALUE)) { + String value = dict.lookup(VALUE); + dict.add(FIELD_VALUES_KEY, "( " + VOL_SCALAR_FIELD_VALUE_KEY + " " + field.getName() + " " + value + " )"); + dict.remove(VALUE); + } + dictionary.addToList(REGIONS_KEY, dict); + } + } + dictionary.remove(SET_SOURCES_KEY); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/fields/StandardFieldsInitialisationPanel.java b/src/eu/engys/gui/casesetup/fields/StandardFieldsInitialisationPanel.java new file mode 100644 index 0000000..68f0bff --- /dev/null +++ b/src/eu/engys/gui/casesetup/fields/StandardFieldsInitialisationPanel.java @@ -0,0 +1,75 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.fields; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.project.zero.fields.Initialisations.CELL_SET_KEY; + +import javax.inject.Inject; + +import eu.engys.core.controller.Controller; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.SetFieldsDict; +import eu.engys.core.project.system.SystemFolder; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; + +public class StandardFieldsInitialisationPanel extends AbstractFieldsInitialisationPanel { + + @Inject + public StandardFieldsInitialisationPanel(Model model, Controller controller) { + super(model); + } + + @Override + public void save() { + for (Field f : fieldBuilderMap.keySet()) { + DictionaryPanelBuilder builder = fieldBuilderMap.get(f); + Dictionary dictionary = builder.getSelectedModel().getDictionary(); + + if (model.getState().getMultiphaseModel().isMultiphase() && f.getName().equals(Fields.ALPHA + "." + model.getMaterials().getFirstMaterialName())) { + if (dictionary.found(TYPE) && dictionary.lookup(TYPE).equals(CELL_SET_KEY)) { + writeSetFieldsDict(dictionary, f); + } else { + writeSetFieldsDict(new SetFieldsDict(), f); + } + } + f.setInitialisation(dictionary); + } + } + + private void writeSetFieldsDict(Dictionary dictionary, Field field) { + SetFieldsDict fixedSetFieldsDict = new SetFieldsDictConverter(field).convertForWrite(dictionary); + SystemFolder systemFolder = model.getProject().getSystemFolder(); + systemFolder.setSetFieldsDict(fixedSetFieldsDict); + DictionaryUtils.writeDictionary(systemFolder.getFileManager().getFile(), fixedSetFieldsDict, monitor); + } + +} diff --git a/src/eu/engys/gui/casesetup/fields/StandardInitialisations.java b/src/eu/engys/gui/casesetup/fields/StandardInitialisations.java new file mode 100644 index 0000000..fe37c98 --- /dev/null +++ b/src/eu/engys/gui/casesetup/fields/StandardInitialisations.java @@ -0,0 +1,162 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.fields; + +import static eu.engys.core.dictionary.Dictionary.TYPE; +import static eu.engys.core.dictionary.Dictionary.VALUE; + +import java.io.File; +import java.util.Set; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryBuilder; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.SetFieldsDict; +import eu.engys.core.project.zero.cellzones.CellZonesBuilder; +import eu.engys.core.project.zero.fields.AbstractInitialisations; +import eu.engys.core.project.zero.fields.ArrayInternalField; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.fields.ScalarInternalField; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.progress.SilentMonitor; + +public class StandardInitialisations extends AbstractInitialisations { + + private static final Logger logger = LoggerFactory.getLogger(StandardInitialisations.class); + private Set modules; + private CellZonesBuilder cellZonesBuilder; + + @Inject + public StandardInitialisations(Model model, CellZonesBuilder cellZonesBuilder, Set modules) { + super(model); + this.cellZonesBuilder = cellZonesBuilder; + this.modules = modules; + } + + @Override + public void loadInitialisation(File zeroDir, Field field, ProgressMonitor monitor) { + readFieldFromFile(field, zeroDir, monitor); + loadInitialisations(field); + } + + // Public for test purpouse only + public void loadInitialisations(Field field) { + if (map.containsKey(field.getName())) { + field.setInitialisation(map.get(field.getName())); + } else { + boolean isScalar = field.getInternalField() instanceof ScalarInternalField; + boolean isArray = field.getInternalField() instanceof ArrayInternalField; + if (isScalar) { + ScalarInternalField internalField = (ScalarInternalField) field.getInternalField(); + double value = internalField.getValue()[0][0]; + field.setInitialisation(DictionaryBuilder.newDictionary("initialisation").field(TYPE, "fixedValue").field(VALUE, String.valueOf(value)).done()); + } else if (isArray) { + ArrayInternalField internalField = (ArrayInternalField) field.getInternalField(); + double valueX = internalField.getValue()[0][0]; + double valueY = internalField.getValue()[0][1]; + double valueZ = internalField.getValue()[0][2]; + String value = "(" + valueX + " " + valueY + " " + valueZ + ")"; + field.setInitialisation(DictionaryBuilder.newDictionary("initialisation").field(TYPE, "fixedValue").field(VALUE, value).done()); + } else { + field.setInitialisation(DictionaryBuilder.newDictionary("initialisation").field(TYPE, "default").done()); + } + } + logger.info("{} initialised to {}", field.getName(), field.getInitialisationType()); + } + + @Override + public void readInitialisationFromFile(Field field) { + if (field.getName().startsWith(Fields.ALPHA)) { + SetFieldsDict setFieldsDict = model.getProject().getSystemFolder().getSetFieldsDict(); + if (setFieldsDict != null && !setFieldsDict.isEmpty()) { + readInitialisationFromSetFieldsDict(setFieldsDict, field); + map.put(field.getName(), field.getInitialisation()); + } + } + } + + private void readInitialisationFromSetFieldsDict(SetFieldsDict setFieldsDict, Field field) { + Dictionary convertedInitialisation = new SetFieldsDictConverter(field).convertForRead(setFieldsDict); + field.setInitialisation(convertedInitialisation); + } + + public void initializeFields() { + for (Field field : model.getFields().values()) { + initializeField(field); + } + model.getProject().getZeroFolder().write(model, cellZonesBuilder, modules, this, new SilentMonitor()); + } + + private void initializeField(Field field) { + String fieldName = field.getName(); + String initMethod = field.getInitialisationType(); + logger.info("Inititalising field: {} as {}", fieldName, initMethod); + + if (initMethod.equals("fixedValue")) { + initializeFixedValue(field); + } else if (initMethod.equals("default")) { + } else { + logger.warn("'{}': Invalid initialisation: set to 'default'", initMethod); + } + } + + private void initializeFixedValue(Field field) { + String value = field.getInitialisation().lookup("value"); + if (value != null && value.startsWith("uniform")) { + field.setInternalField("internalField " + value); + Fields[] parallelFields = model.getFields().getParallelFields(); + if (parallelFields != null) { + for (int i = 0; i < parallelFields.length; i++) { + Field subField = parallelFields[i].get(field.getName()); + subField.setInternalField("internalField " + value); + } + } + } + if (field.getName().equals(Fields.P) || field.getName().equals(Fields.P_RGH)) { + writeValueOnProcBoundary(field); + } + } + + private void writeValueOnProcBoundary(Field field) { + for (Patch patch : model.getPatches()) { + if (patch.getPhisicalType().isProcessor()) { + Dictionary momentum = patch.getBoundaryConditions().getMomentum(); + if (momentum.found(Fields.P)) { + Dictionary p = momentum.subDict(Fields.P); + p.add(Dictionary.VALUE, field.getInitialisation().lookup("value")); + } + } + } + } +} diff --git a/src/eu/engys/gui/casesetup/materials/AbstractIncompressibleMaterialsPanel.java b/src/eu/engys/gui/casesetup/materials/AbstractIncompressibleMaterialsPanel.java new file mode 100644 index 0000000..4d44303 --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/AbstractIncompressibleMaterialsPanel.java @@ -0,0 +1,159 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import static eu.engys.core.project.constant.TransportProperties.CP_KEY; +import static eu.engys.core.project.constant.TransportProperties.LAMBDA_KEY; +import static eu.engys.core.project.constant.TransportProperties.MATERIAL_NAME_KEY; +import static eu.engys.core.project.constant.TransportProperties.MU_KEY; +import static eu.engys.core.project.constant.TransportProperties.NU_KEY; +import static eu.engys.core.project.constant.TransportProperties.PRT_KEY; +import static eu.engys.core.project.constant.TransportProperties.P_REF_KEY; +import static eu.engys.core.project.constant.TransportProperties.RHO_KEY; +import static eu.engys.core.project.constant.TransportProperties.SIGMA_KEY; +import static eu.engys.core.project.constant.TransportProperties.T_REF_KEY; +import static eu.engys.util.Symbols.CP; +import static eu.engys.util.Symbols.DENSITY; +import static eu.engys.util.Symbols.DOT; +import static eu.engys.util.Symbols.MINUS_ONE; +import static eu.engys.util.Symbols.MU_MEASURE; +import static eu.engys.util.Symbols.NU_MEASURE; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DimensionedScalar; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.modules.materials.MaterialsBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.util.DimensionalUnits; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.StringField; + +public abstract class AbstractIncompressibleMaterialsPanel implements IncompressibleMaterialsPanel, PropertyChangeListener { + + public static final String REFERENCE_TEMPERATURE_K_LABEL = "Reference Temperature [K]"; + public static final String REFERENCE_ABSOLUTE_PRESSURE_PA_LABEL = "Reference (absolute) Pressure [Pa]"; + public static final String THERMAL_CONDUCTIVITY_LABEL = "Thermal Conductivity [W/m" + DOT + "K]"; + public static final String TURBULENT_PRANDTL_NUMBER_LABEL = "Turbulent Prandtl Number"; + public static final String SPECIFIC_HEAT_CAPACITY_LABEL = "Specific Heat Capacity " + CP; + public static final String KINEMATIC_VISCOSITY_LABEL = "Kinematic Viscosity " + NU_MEASURE; + public static final String DYNAMIC_VISCOSITY_LABEL = "Dynamic Viscosity " + MU_MEASURE; + public static final String DENSITY_LABEL = "Density " + DENSITY; + public static final String THERMAL_EXPANTION_COEFF_LABEL = "Thermal Expansion Coefficient [K" + MINUS_ONE + "]"; + + protected DictionaryModel incompressibleModel = new DictionaryModel("newMaterial", getEmptyMaterial()); + + private StringField nameField; + private DoubleField rho; + private DoubleField mu; + private DoubleField nu; + + protected PanelBuilder builder; + protected MaterialsBuilder materialsBuilder; + + public AbstractIncompressibleMaterialsPanel() { + this.builder = new PanelBuilder(); + } + + public abstract Dictionary getMaterial(Model model); + + public abstract void setMaterial(Dictionary material); + + @Override + public void setEnabled(boolean enabled) { + builder.setEnabled(enabled); + } + + @Override + public void stateChanged(State state) { + } + + @Override + public StringField getNameField() { + return nameField; + } + + protected void buildIncompressibleMaterialPanel() { + builder.addComponent("Name", nameField = incompressibleModel.bindLabel(MATERIAL_NAME_KEY)); + builder.addComponent(DENSITY_LABEL, rho = incompressibleModel.bindDimensionedDouble(RHO_KEY, DimensionalUnits.KG_M3, 0D, Double.MAX_VALUE)); + builder.addComponent(DYNAMIC_VISCOSITY_LABEL, mu = incompressibleModel.bindDimensionedDouble(MU_KEY, DimensionalUnits.KG_MS, 0D, Double.MAX_VALUE)); + builder.addComponent(KINEMATIC_VISCOSITY_LABEL, nu = incompressibleModel.bindDimensionedDouble(NU_KEY, DimensionalUnits.M2_S, 0D, Double.MAX_VALUE)); + + nameField.setEnabled(false); + + rho.addPropertyChangeListener("value", this); + mu.addPropertyChangeListener("value", this); + nu.addPropertyChangeListener("value", this); + + builder.addComponent(SPECIFIC_HEAT_CAPACITY_LABEL, incompressibleModel.bindDimensionedDouble(CP_KEY, DimensionalUnits.M2_S2K, 0D, Double.MAX_VALUE)); + builder.addComponent(TURBULENT_PRANDTL_NUMBER_LABEL, incompressibleModel.bindDimensionedDouble(PRT_KEY, DimensionalUnits.NONE, 0D, Double.MAX_VALUE)); + builder.addComponent(THERMAL_CONDUCTIVITY_LABEL, incompressibleModel.bindDimensionedDouble(LAMBDA_KEY, DimensionalUnits.KGM_S3K, 0D, Double.MAX_VALUE)); + builder.addComponent(REFERENCE_ABSOLUTE_PRESSURE_PA_LABEL, incompressibleModel.bindDimensionedDouble(P_REF_KEY, DimensionalUnits.KG_MS2, 0D, Double.MAX_VALUE)); + builder.addComponent(REFERENCE_TEMPERATURE_K_LABEL, incompressibleModel.bindDimensionedDouble(T_REF_KEY, DimensionalUnits.K, 0D, Double.MAX_VALUE)); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getSource() == nu) { + double rhoValue = rho.getDoubleValue(); + double nuValue = nu.getDoubleValue(); + + mu.setDoubleValue(nuValue * rhoValue); + } else if (evt.getSource() == rho || evt.getSource() == mu) { + double rhoValue = rho.getDoubleValue(); + double muValue = mu.getDoubleValue(); + + nu.setDoubleValue(rhoValue == 0.0 ? 0.0 : muValue / rhoValue); + } + } + + protected void adjustNuIfNeeded(Dictionary transportProps) { + if (transportProps != null && !transportProps.found(NU_KEY)) { + if (transportProps.found(RHO_KEY) && transportProps.found(MU_KEY)) { + double rho = Double.valueOf(transportProps.lookupScalar(RHO_KEY).doubleValue()); + double mu = Double.valueOf(transportProps.lookupScalar(MU_KEY).doubleValue()); + double nuValue = mu == 0.0 ? 0.0 : mu / rho; + transportProps.add(new DimensionedScalar(NU_KEY, Double.toString(nuValue), DimensionalUnits.M2_S)); + } + } + } + + @Override + public Dictionary saveSigma(Model model, Dictionary sigmaDict) { + Dictionary dict = new Dictionary(SIGMA_KEY); + if (model.getState().getMultiphaseModel().isMultiphase()) { + if (sigmaDict.found(SIGMA_KEY)) { + dict.add(sigmaDict.lookupScalar(SIGMA_KEY)); + } + } + return dict; + } + +} diff --git a/src/eu/engys/gui/casesetup/materials/AbstractMaterialsBuilder.java b/src/eu/engys/gui/casesetup/materials/AbstractMaterialsBuilder.java new file mode 100644 index 0000000..b6189e8 --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/AbstractMaterialsBuilder.java @@ -0,0 +1,113 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.materials; + +import static eu.engys.core.project.constant.ThermophysicalProperties.CP_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.LAMBDA_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MATERIAL_NAME_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MU_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.NU_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PRT_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PR_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.P_REF_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.RHO_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TRANSPORT_MODEL_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.T_REF_KEY; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DimensionedScalar; +import eu.engys.core.dictionary.DimensionedScalar.Dimensions; +import eu.engys.core.modules.materials.MaterialsBuilder; +import eu.engys.core.project.Model; + +public abstract class AbstractMaterialsBuilder implements MaterialsBuilder { + + @Override + public Dictionary saveIncompressible(Model model, Dictionary materialDict) { + String materialName = materialDict.lookup(MATERIAL_NAME_KEY); + + Dictionary transportProperties = new Dictionary(materialName); + transportProperties.add(MATERIAL_NAME_KEY, materialName); + + String transportModel = materialDict.lookup(TRANSPORT_MODEL_KEY); + transportProperties.add(TRANSPORT_MODEL_KEY, transportModel); + + if (materialDict.found(transportModel + "Coeffs")) { + transportProperties.add(materialDict.subDict(transportModel + "Coeffs")); + } + + if (materialDict.found(RHO_KEY)) { + transportProperties.add(materialDict.lookupScalar(RHO_KEY)); + } + + if (materialDict.found(MU_KEY)) { + transportProperties.add(materialDict.lookupScalar(MU_KEY)); + } + + if (materialDict.found(NU_KEY)) { + transportProperties.add(materialDict.lookupScalar(NU_KEY)); + } else if (materialDict.found(RHO_KEY) && materialDict.found(MU_KEY)) { + DimensionedScalar rho = materialDict.lookupScalar(RHO_KEY); + DimensionedScalar mu = materialDict.lookupScalar(MU_KEY); + + double nuValue = mu.doubleValue() / rho.doubleValue(); + Dimensions nuDimensions = mu.getDimensions().divide(rho.getDimensions()); + + DimensionedScalar nu = new DimensionedScalar(NU_KEY, Double.toString(nuValue), nuDimensions); + + transportProperties.add(nu); + } + + if (materialDict.found(CP_KEY)) { + transportProperties.add(materialDict.lookupScalar(CP_KEY)); + } + if (materialDict.found(PRT_KEY)) { + transportProperties.add(materialDict.lookupScalar(PRT_KEY)); + } + if (materialDict.found(PR_KEY)) { + transportProperties.add(materialDict.lookupScalar(PR_KEY)); + } + if (materialDict.found(LAMBDA_KEY)) { + transportProperties.add(materialDict.lookupScalar(LAMBDA_KEY)); + } + + if (materialDict.found(P_REF_KEY)) { + transportProperties.add(materialDict.lookupScalar(P_REF_KEY)); + } + if (materialDict.found(getBetaKey())) { + transportProperties.add(materialDict.lookupScalar(getBetaKey())); + } + if (materialDict.found(T_REF_KEY)) { + transportProperties.add(materialDict.lookupScalar(T_REF_KEY)); + } + + // System.out.println("MaterialsBuilder.saveIncompressible() "+transportProperties); + + return transportProperties; + } + + protected abstract String getBetaKey(); +} diff --git a/src/eu/engys/gui/casesetup/materials/AbstractMaterialsReader.java b/src/eu/engys/gui/casesetup/materials/AbstractMaterialsReader.java new file mode 100644 index 0000000..5177e63 --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/AbstractMaterialsReader.java @@ -0,0 +1,66 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import static eu.engys.core.project.constant.TransportProperties.MATERIAL_NAME_KEY; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.constant.ThermophysicalProperties; +import eu.engys.core.project.constant.TransportProperties; +import eu.engys.core.project.materials.Material; +import eu.engys.core.project.materials.Materials; +import eu.engys.core.project.materials.MaterialsReader; +import eu.engys.util.progress.ProgressMonitor; + +public abstract class AbstractMaterialsReader implements MaterialsReader { + + @Override + public void readSingle_Material(Materials materials, TransportProperties tpp, ProgressMonitor monitor) { + readMaterial(materials, tpp, monitor); + } + + @Override + public void readSingle_Material(Materials materials, ThermophysicalProperties tfp, ProgressMonitor monitor) { + readMaterial(materials, tfp, monitor); + } + + private void readMaterial(Materials materials, Dictionary tfp, ProgressMonitor monitor) { + Dictionary dict = new Dictionary(tfp); + dict.setFoamFile(null); + if (dict.isEmpty()) { + monitor.warning("No material found", 1); + return; + } else { + if (!dict.found(MATERIAL_NAME_KEY)) { + dict.add(MATERIAL_NAME_KEY, "material"); + } + String name = dict.lookup(MATERIAL_NAME_KEY); + dict.setName(name); + materials.add(new Material(name, dict)); + monitor.info(name, 1); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/materials/AbstractMaterialsWriter.java b/src/eu/engys/gui/casesetup/materials/AbstractMaterialsWriter.java new file mode 100644 index 0000000..e816c10 --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/AbstractMaterialsWriter.java @@ -0,0 +1,58 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.constant.ThermophysicalProperties; +import eu.engys.core.project.constant.TransportProperties; +import eu.engys.core.project.materials.Materials; +import eu.engys.core.project.materials.MaterialsWriter; + +public abstract class AbstractMaterialsWriter implements MaterialsWriter { + + private static final Logger logger = LoggerFactory.getLogger(AbstractMaterialsWriter.class); + + @Override + public void writeSingle_IncompressibleMaterial(Materials materials, TransportProperties tpp) { + if (materials.size() == 1) { + tpp.merge(materials.get(0).getDictionary()); + } else { + logger.warn("Multiphase solution choosen but '{}' materials found", materials.size()); + } + } + + @Override + public void writeSingle_CompressibleMaterial(Materials materials, ThermophysicalProperties tfp) { + if (materials.size() == 1) { + tfp.merge(materials.get(0).getDictionary()); + } else { + logger.warn("Multiphase solution choosen but '{}' materials found", materials.size()); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/materials/CompressibleMaterialsPanel.java b/src/eu/engys/gui/casesetup/materials/CompressibleMaterialsPanel.java new file mode 100644 index 0000000..479fd2e --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/CompressibleMaterialsPanel.java @@ -0,0 +1,144 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import static eu.engys.core.project.constant.ThermophysicalProperties.CONSTANT_CP_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CONST_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CP_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.ENERGY_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.EQUATION_OF_STATE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HE_PSI_THERMO_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HF_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MIXTURE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MOL_WEIGHT_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MU_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.N_MOLES_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PERFECT_GAS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PR_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PURE_MIXTURE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SENSIBLE_ENTHALPY_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SPECIE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMODYNAMICS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_TYPE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TRANSPORT_KEY; +import static eu.engys.core.project.constant.TransportProperties.MATERIAL_NAME_KEY; +import static eu.engys.util.Symbols.CP; +import static eu.engys.util.Symbols.HF; +import static eu.engys.util.Symbols.MU_MEASURE; + +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.textfields.StringField; + +public interface CompressibleMaterialsPanel { + + static final String MOLECULAR_WEIGHT_KG_KMOL_LABEL = "Molecular Weight [kg/kmol]"; + static final String NUMBER_OF_MOLES_LABEL = "Number Of Moles"; + static final String NAME_LABEL = "Name"; + static final String EQUATION_OF_STATE_LABEL = "Equation Of State"; + static final String PERFECT_GAS_LABEL = "Perfect Gas"; + static final String SUTHERLAND_TEMPERATURE_TS_LABEL = "Sutherland Temperature (Ts)"; + static final String SUTHERLAND_COEFFICIENT_AS_LABEL = "Sutherland Coefficient (As)"; + static final String PRANDTL_NUMBER_LABEL = "Prandtl Number"; + static final String DYNAMIC_VISCOSITY_LABEL = "Dynamic Viscosity " + MU_MEASURE; + static final String SUTHERLAND_S_LABEL = "Sutherland's"; + static final String CONSTANT_LABEL = "Constant"; + static final String TRANSPORT_PROPERTIES_LABEL = "Transport Properties"; + static final String THERMODYNAMIC_MODEL_LABEL = "Thermodynamic Model"; + static final String LOW_CP_LABEL = "Low Cp"; + static final String HIGH_CP_LABEL = "High Cp"; + static final String HEAT_OF_FUSION_LABEL = "Heat Of Fusion " + HF; + static final String HEAT_CAPACITY_LABEL = "Heat Capacity " + CP; + static final String JANAF_LABEL = "JANAF"; + static final String CONSTANT_CP_LABEL = "Constant Cp"; + + public static Dictionary defaultDictionary = new Dictionary("newMaterial"){ + { + add(MATERIAL_NAME_KEY, "newMaterial"); + add(new Dictionary(THERMO_TYPE_KEY){ + { + add(TYPE, HE_PSI_THERMO_KEY); + add(MIXTURE_KEY, PURE_MIXTURE_KEY); + add(TRANSPORT_KEY, CONST_KEY); + add(THERMO_KEY, CONSTANT_CP_KEY); + add(EQUATION_OF_STATE_KEY, PERFECT_GAS_KEY); + add(SPECIE_KEY, SPECIE_KEY); + add(ENERGY_KEY, SENSIBLE_ENTHALPY_KEY); + } + }); + add(new Dictionary(MIXTURE_KEY){ + { + add(new Dictionary(EQUATION_OF_STATE_KEY)); + add(new Dictionary(TRANSPORT_KEY){ + { + add(MU_KEY, "0.0"); + add(PR_KEY, "0.0"); + } + }); + add(new Dictionary(THERMODYNAMICS_KEY){ + { + add(CP_KEY, "0.0"); + add(HF_KEY, "0.0"); + } + }); + add(new Dictionary(SPECIE_KEY){ + { + add(N_MOLES_KEY, "0"); + add(MOL_WEIGHT_KEY, "0.0"); + } + }); + } + }); + } + }; + + Dictionary getEmptyMaterial(); + + Dictionary getMaterial(Model model); + + void setMaterial(Dictionary material); + + JPanel getPanel(); + + void setEnabled(boolean enabled); + + void buildThermodynamicModelPanel(); + + void buildTransportPropertiesPanel(); + + void buildEquationOfStatePanel(); + + void buildThermophysicalModelPanel(); + + void stateChanged(State state); + + StringField getNameField(); + +} diff --git a/src/eu/engys/gui/casesetup/materials/IncompressibleMaterialsPanel.java b/src/eu/engys/gui/casesetup/materials/IncompressibleMaterialsPanel.java new file mode 100644 index 0000000..eec96ea --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/IncompressibleMaterialsPanel.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.textfields.StringField; + +public interface IncompressibleMaterialsPanel { + + Dictionary getEmptyMaterial(); + + Dictionary getMaterial(Model model); + + void setMaterial(Dictionary material); + + JPanel getPanel(); + + void setEnabled(boolean enabled); + + void stateChanged(State state); + + Dictionary saveSigma(Model model, Dictionary sigmaDict); + + StringField getNameField(); + + +} diff --git a/src/eu/engys/gui/casesetup/materials/MaterialsTreeNodeManager.java b/src/eu/engys/gui/casesetup/materials/MaterialsTreeNodeManager.java new file mode 100644 index 0000000..a4c65a6 --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/MaterialsTreeNodeManager.java @@ -0,0 +1,212 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import java.awt.Component; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreePath; + +import eu.engys.core.project.Model; +import eu.engys.core.project.materials.Material; +import eu.engys.core.project.materials.Materials; +import eu.engys.gui.casesetup.materials.panels.MaterialsPanel; +import eu.engys.gui.tree.AbstractSelectionHandler; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.SelectionHandler; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class MaterialsTreeNodeManager extends DefaultTreeNodeManager { + + private Map materialsMap; + private SelectionHandler selectionHandler; + + public MaterialsTreeNodeManager(Model model, MaterialsPanel materialsPanel) { + super(model, materialsPanel); + this.selectionHandler = new MaterialsSelectionHandler(materialsPanel); + this.materialsMap = new HashMap<>(); + } + + @Override + public void update(Observable o, final Object arg) { + if (arg instanceof Materials) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + loadTree(); + expandTree(); + } + }); + } + } + + private void loadTree() { + clear(); + for (Material material : model.getMaterials()) { + addMaterial(material); + } + treeChanged(root); + } + + private void expandTree() { + if (getTree() != null) { + getTree().expandNode(getRoot()); + } + } + + private void addMaterial(Material material) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(material); + root.add(node); + nodeMap.put(material, node); + materialsMap.put(node, material); + } + + public Material[] getSelectedValues() { + if (getTree() != null) { + TreePath[] selectionPaths = getTree().getSelectionPaths(); + if (selectionPaths != null) { + Material[] materials = new Material[selectionPaths.length]; + for (int i = 0; i < selectionPaths.length; i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPaths[i].getLastPathComponent(); + Material material = materialsMap.get(node); + materials[i] = material; + } + return materials; + } + return new Material[0]; + } + return new Material[0]; + } + + public void setSelectedValue(Material material) { + if (getTree() != null) { + DefaultMutableTreeNode selectedNode = nodeMap.get(material); + if (selectedNode != null) { + getTree().setSelectedNode(selectedNode); + } else { + getTree().setSelectedNode(getRoot()); + } + } + } + + public void clear() { + // clear node before selection handler! + clearNode(root); + selectionHandler.clear(); + nodeMap.clear(); + materialsMap.clear(); + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public Class getRendererClass() { + return Material.class; + } + + @Override + public DefaultTreeCellRenderer getRenderer() { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object userObject = node.getUserObject(); + + if (userObject instanceof Material) { + Material material = (Material) userObject; + if (model.getMaterials().size() > 1) { + String phase = "[phase" + (model.getMaterials().indexOf(material) + 1) + "]"; + setText("" + material.getName() + " " + "" + phase + ""); + } else { + setText(material.getName()); + } + } + setIcon(null); + return this; + } + }; + } + + @Override + public SelectionHandler getSelectionHandler() { + return selectionHandler; + } + + private final class MaterialsSelectionHandler extends AbstractSelectionHandler { + + private MaterialsPanel panel; + private Material[] currentSelection; + + public MaterialsSelectionHandler(MaterialsPanel panel) { + this.panel = panel; + } + + @Override + public void handleSelection(boolean fire3DEvent, Object... selection) { + if (currentSelection != null && currentSelection.length > 0) { + panel.saveMaterials(currentSelection); + } + if (TreeUtil.isConsistent(selection, Material.class)) { + this.currentSelection = Arrays.copyOf(selection, selection.length, Material[].class); + } else { + this.currentSelection = new Material[0]; + } + panel.updateSelection(currentSelection); + panel.updateButtons(currentSelection.length > 0); + } + + @Override + public void handleVisibility(VisibleItem item) { + } + + @Override + public void process3DSelectionEvent(Picker picker, Actor actor, boolean keep) { + } + + @Override + public void process3DVisibilityEvent(boolean selected) { + } + + @Override + public void clear() { + currentSelection = null; + } + } + +} diff --git a/src/eu/engys/gui/casesetup/materials/StandardCompressibleMaterialsPanel.java b/src/eu/engys/gui/casesetup/materials/StandardCompressibleMaterialsPanel.java new file mode 100644 index 0000000..95ca98d --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/StandardCompressibleMaterialsPanel.java @@ -0,0 +1,196 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.materials; + +import static eu.engys.core.project.constant.ThermophysicalProperties.AS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.A_KEYS; +import static eu.engys.core.project.constant.ThermophysicalProperties.CONSTANT_CP_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CONST_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CP_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.EQUATION_OF_STATE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HF_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HIGH_CP_COEFFS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.JANAF_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.LOW_CP_COEFFS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MATERIAL_NAME_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MOL_WEIGHT_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MU_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.N_MOLES_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PERFECT_GAS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PR_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SUTHERLAND_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TCOMMON_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THIGH_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TLOW_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TRANSPORT_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TS_KEY; +import static eu.engys.util.ui.ComponentsFactory.labelArrayField; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.inject.Inject; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.modules.materials.MaterialsBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.builder.JComboBoxController; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.StringField; + +public class StandardCompressibleMaterialsPanel implements CompressibleMaterialsPanel { + + private DictionaryModel compressibleModel = new DictionaryModel(new Dictionary("")); + + private JComboBoxController transport; + private JComboBoxController thermo; + private MaterialsBuilder materialsBuilder; + + private PanelBuilder builder; + private StringField nameField; + + @Inject + public StandardCompressibleMaterialsPanel() { + this.builder = new PanelBuilder(); + this.materialsBuilder = new StandardMaterialsBuilder(); + buildCompressibleMaterialPanel(); + } + + @Override + public Dictionary getEmptyMaterial() { + return new Dictionary(defaultDictionary); + } + + @Override + public StringField getNameField() { + return nameField; + } + + @Override + public JPanel getPanel() { + return builder.getPanel(); + } + + @Override + public void setEnabled(boolean enabled) { + builder.setEnabled(enabled); + } + + @Override + public void stateChanged(State state) { + } + + private void buildCompressibleMaterialPanel() { + buildThermophysicalModelPanel(); + buildTransportPropertiesPanel(); + buildThermodynamicModelPanel(); + buildEquationOfStatePanel(); + + /* JANAF works only for SUTHERLAND */ + transport.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (transport.getSelectedIndex() == 0) { + thermo.addDisabledItem(JANAF_LABEL); + thermo.setSelectedItem(CONSTANT_CP_LABEL); + } else { + thermo.clearDisabledIndexes(); + } + } + }); + transport.setSelectedItem(CONSTANT_LABEL); + } + + @Override + public void buildThermophysicalModelPanel() { + builder.addComponent(NAME_LABEL, nameField = compressibleModel.bindLabel(MATERIAL_NAME_KEY)); + builder.addComponent(NUMBER_OF_MOLES_LABEL, compressibleModel.bindIntegerPositive(N_MOLES_KEY)); + builder.addComponent(MOLECULAR_WEIGHT_KG_KMOL_LABEL, compressibleModel.bindDoublePositive(MOL_WEIGHT_KEY)); + nameField.setEnabled(false); + } + + @Override + public void buildTransportPropertiesPanel() { + transport = (JComboBoxController) builder.startChoice(TRANSPORT_PROPERTIES_LABEL, compressibleModel.bindComboBoxController(TRANSPORT_KEY)); + + builder.startGroup(CONST_KEY, CONSTANT_LABEL); + builder.addComponent(DYNAMIC_VISCOSITY_LABEL, compressibleModel.bindDoublePositive(MU_KEY)); + builder.addComponent(PRANDTL_NUMBER_LABEL, compressibleModel.bindDoublePositive(PR_KEY)); + builder.endGroup(); + + builder.startGroup(SUTHERLAND_KEY, SUTHERLAND_S_LABEL); + builder.addComponent(SUTHERLAND_COEFFICIENT_AS_LABEL, compressibleModel.bindDoublePositive(AS_KEY)); + builder.addComponent(SUTHERLAND_TEMPERATURE_TS_LABEL, compressibleModel.bindDoublePositive(TS_KEY)); + builder.endGroup(); + + builder.endChoice(); + } + + @Override + public void buildThermodynamicModelPanel() { + thermo = (JComboBoxController) builder.startChoice(THERMODYNAMIC_MODEL_LABEL, compressibleModel.bindComboBoxController(THERMO_KEY)); + + builder.startGroup(CONSTANT_CP_KEY, CONSTANT_CP_LABEL); + builder.addComponent(HEAT_CAPACITY_LABEL, compressibleModel.bindDoublePositive(CP_KEY)); + builder.addComponent(HEAT_OF_FUSION_LABEL, compressibleModel.bindDoublePositive(HF_KEY)); + builder.endGroup(); + + builder.startGroup(JANAF_KEY, JANAF_LABEL); + builder.addComponent(TLOW_KEY, compressibleModel.bindDoublePositive(TLOW_KEY)); + builder.addComponent(THIGH_KEY, compressibleModel.bindDoublePositive(THIGH_KEY)); + builder.addComponent(TCOMMON_KEY, compressibleModel.bindDoublePositive(TCOMMON_KEY)); + builder.addComponent(labelArrayField(A_KEYS)); + builder.addComponent(HIGH_CP_LABEL, compressibleModel.bindArray(HIGH_CP_COEFFS_KEY, 7)); + builder.addComponent(labelArrayField(A_KEYS)); + builder.addComponent(LOW_CP_LABEL, compressibleModel.bindArray(LOW_CP_COEFFS_KEY, 7)); + builder.endGroup(); + + builder.endChoice(); + } + + @Override + public void buildEquationOfStatePanel() { + String[] EOS_KEYS = { PERFECT_GAS_KEY };// , "ICOPolynomial" }; + String[] EOS_LABELS = { PERFECT_GAS_LABEL };// , "Polymomial f(T)" }; + builder.addComponent(EQUATION_OF_STATE_LABEL, compressibleModel.bindChoice(EQUATION_OF_STATE_KEY, EOS_KEYS, EOS_LABELS)).setEnabled(false); + } + + @Override + public Dictionary getMaterial(Model model) { + return materialsBuilder.saveCompressible(model, compressibleModel.getDictionary()); + } + + @Override + public void setMaterial(Dictionary material) { + compressibleModel.setDictionary(materialsBuilder.toGUIFormat(material)); + } + +} diff --git a/src/eu/engys/gui/casesetup/materials/StandardIncompressibleMaterialsPanel.java b/src/eu/engys/gui/casesetup/materials/StandardIncompressibleMaterialsPanel.java new file mode 100644 index 0000000..b0b467f --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/StandardIncompressibleMaterialsPanel.java @@ -0,0 +1,110 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import static eu.engys.core.project.constant.TransportProperties.BETA_OS_KEY; +import static eu.engys.core.project.constant.TransportProperties.CP_KEY; +import static eu.engys.core.project.constant.TransportProperties.LAMBDA_KEY; +import static eu.engys.core.project.constant.TransportProperties.MATERIAL_NAME_KEY; +import static eu.engys.core.project.constant.TransportProperties.MU_KEY; +import static eu.engys.core.project.constant.TransportProperties.NEWTONIAN_COEFFS_KEY; +import static eu.engys.core.project.constant.TransportProperties.NEWTONIAN_KEY; +import static eu.engys.core.project.constant.TransportProperties.NU_KEY; +import static eu.engys.core.project.constant.TransportProperties.PRT_KEY; +import static eu.engys.core.project.constant.TransportProperties.PR_KEY; +import static eu.engys.core.project.constant.TransportProperties.P_REF_KEY; +import static eu.engys.core.project.constant.TransportProperties.RHO_KEY; +import static eu.engys.core.project.constant.TransportProperties.TRANSPORT_MODEL_KEY; +import static eu.engys.core.project.constant.TransportProperties.T_REF_KEY; + +import javax.swing.JPanel; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DimensionedScalar; +import eu.engys.core.project.Model; +import eu.engys.util.DimensionalUnits; + +public class StandardIncompressibleMaterialsPanel extends AbstractIncompressibleMaterialsPanel { + + public static final String LAMINAR_PRANDTL_NUMBER_LABEL = "Laminar Prandtl Number"; + + @Inject + public StandardIncompressibleMaterialsPanel() { + super(); + this.materialsBuilder = new StandardMaterialsBuilder(); + buildIncompressibleMaterialPanel(); + } + + @Override + public Dictionary getMaterial(Model model) { + return materialsBuilder.saveIncompressible(model, incompressibleModel.getDictionary()); + } + + @Override + public void setMaterial(Dictionary material) { + adjustNuIfNeeded(material); + incompressibleModel.setDictionary(new Dictionary(material.getName(), material)); + } + + @Override + protected void buildIncompressibleMaterialPanel() { + super.buildIncompressibleMaterialPanel(); + builder.addComponent(THERMAL_EXPANTION_COEFF_LABEL, incompressibleModel.bindDimensionedDouble(BETA_OS_KEY, DimensionalUnits._K, 0D, Double.MAX_VALUE)); + builder.addComponent(LAMINAR_PRANDTL_NUMBER_LABEL, incompressibleModel.bindDimensionedDouble(PR_KEY, DimensionalUnits.NONE, 0D, Double.MAX_VALUE)); + } + + @Override + public JPanel getPanel() { + return builder.removeMargins().getPanel(); + } + + @Override + public Dictionary getEmptyMaterial() { + return new Dictionary(defaultDictionary); + } + + public static Dictionary defaultDictionary = new Dictionary("newMaterial") { + { + add(MATERIAL_NAME_KEY, "newMaterial"); + add(TRANSPORT_MODEL_KEY, NEWTONIAN_KEY); + add(new Dictionary(NEWTONIAN_COEFFS_KEY)); + add(new DimensionedScalar(RHO_KEY, "0.0", DimensionalUnits.KG_M3)); + add(new DimensionedScalar(RHO_KEY, "0.0", DimensionalUnits.KG_M3)); + add(new DimensionedScalar(MU_KEY, "0.0", DimensionalUnits.KG_MS)); + add(new DimensionedScalar(NU_KEY, "0.0", DimensionalUnits.M2_S)); + add(new DimensionedScalar(CP_KEY, "0.0", DimensionalUnits.M2_S2K)); + add(new DimensionedScalar(PRT_KEY, "0.0", DimensionalUnits.NONE)); + add(new DimensionedScalar(LAMBDA_KEY, "0.0", DimensionalUnits.KGM_S3K)); + add(new DimensionedScalar(P_REF_KEY, "0.0", DimensionalUnits.KG_MS2)); + add(new DimensionedScalar(T_REF_KEY, "0.0", DimensionalUnits.K)); + add(new DimensionedScalar(BETA_OS_KEY, "0.0", DimensionalUnits._K)); + add(new DimensionedScalar(PR_KEY, "0.0", DimensionalUnits.NONE)); + } + }; + +} diff --git a/src/eu/engys/gui/casesetup/materials/StandardMaterialsBuilder.java b/src/eu/engys/gui/casesetup/materials/StandardMaterialsBuilder.java new file mode 100644 index 0000000..ed57f5c --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/StandardMaterialsBuilder.java @@ -0,0 +1,222 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import static eu.engys.core.project.constant.ThermophysicalProperties.AS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.BETA_OS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CONSTANT_CP_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.CONST_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.DEFAULT_MATERIAL_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.ENERGY_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.EQUATION_OF_STATE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HE_PSI_THERMO_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HE_RHO_THERMO_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HF_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.HIGH_CP_COEFFS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.JANAF_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.LOW_CP_COEFFS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MATERIAL_NAME_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MIXTURE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MOL_WEIGHT_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.MU_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.N_MOLES_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PR_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.PURE_MIXTURE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SENSIBLE_ENTHALPY_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SENSIBLE_INTERNAL_ENERGY_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SPECIE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.SUTHERLAND_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TCOMMON_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMODYNAMICS_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_MODEL_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THERMO_TYPE_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.THIGH_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TLOW_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TRANSPORT_KEY; +import static eu.engys.core.project.constant.ThermophysicalProperties.TS_KEY; +import static eu.engys.core.project.constant.TransportProperties.CP0_KEY; +import static eu.engys.core.project.constant.TransportProperties.CP_KEY; +import static eu.engys.core.project.constant.TransportProperties.RHO_CP0_KEY; +import static eu.engys.core.project.constant.TransportProperties.RHO_KEY; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; + +public class StandardMaterialsBuilder extends AbstractMaterialsBuilder { + + @Override + protected String getBetaKey() { + return BETA_OS_KEY; + } + + @Override + public Dictionary saveIncompressible(Model model, Dictionary materialDict) { + Dictionary transportProperties = super.saveIncompressible(model, materialDict); + if (materialDict.found(CP_KEY)) { + transportProperties.add(CP0_KEY, materialDict.lookupScalar(CP_KEY).getValue()); + } + if (materialDict.found(RHO_KEY)) { + transportProperties.add(RHO_CP0_KEY, materialDict.lookupScalar(RHO_KEY).getValue()); + } + return transportProperties; + } + + @Override + public Dictionary saveCompressible(Model model, Dictionary materialGUIDict) { + String type = model != null ? (model.getState().isBuoyant() ? HE_RHO_THERMO_KEY : HE_PSI_THERMO_KEY) : materialGUIDict.lookup(THERMO_MODEL_KEY); + String energy = model != null && model.getState().isHighMach() && model.getState().getSolverFamily().isPimple() ? SENSIBLE_INTERNAL_ENERGY_KEY : SENSIBLE_ENTHALPY_KEY; + String thermo = materialGUIDict.found(THERMO_KEY) ? materialGUIDict.lookup(THERMO_KEY) : ""; + String transport = materialGUIDict.found(TRANSPORT_KEY) ? materialGUIDict.lookup(TRANSPORT_KEY) : ""; + + Dictionary thermoDict = new Dictionary(THERMO_TYPE_KEY); + thermoDict.add(Dictionary.TYPE, type); + thermoDict.add(MIXTURE_KEY, PURE_MIXTURE_KEY); + thermoDict.add(TRANSPORT_KEY, transport.equals(CONST_KEY) ? CONST_KEY : SUTHERLAND_KEY); + thermoDict.add(THERMO_KEY, materialGUIDict.lookup(THERMO_KEY)); + thermoDict.add(EQUATION_OF_STATE_KEY, materialGUIDict.lookup(EQUATION_OF_STATE_KEY)); + thermoDict.add(SPECIE_KEY, SPECIE_KEY); + thermoDict.add(ENERGY_KEY, energy); + + /* SPECIES */ + Dictionary specieDict = new Dictionary(SPECIE_KEY); + specieDict.add(N_MOLES_KEY, materialGUIDict.lookup(N_MOLES_KEY)); + specieDict.add(MOL_WEIGHT_KEY, materialGUIDict.lookup(MOL_WEIGHT_KEY)); + + /* THERMODYNAMICS */ + Dictionary thermodynamicsDict = new Dictionary(THERMODYNAMICS_KEY); + if (thermo.equals(CONSTANT_CP_KEY)) { + thermodynamicsDict.add(CP_KEY, materialGUIDict.lookup(CP_KEY)); + thermodynamicsDict.add(HF_KEY, materialGUIDict.lookup(HF_KEY)); + } else if (thermo.equals(JANAF_KEY)) { + thermodynamicsDict.add(TLOW_KEY, materialGUIDict.lookup(TLOW_KEY)); + thermodynamicsDict.add(THIGH_KEY, materialGUIDict.lookup(THIGH_KEY)); + thermodynamicsDict.add(TCOMMON_KEY, materialGUIDict.lookup(TCOMMON_KEY)); + thermodynamicsDict.add(HIGH_CP_COEFFS_KEY, materialGUIDict.lookup(HIGH_CP_COEFFS_KEY)); + thermodynamicsDict.add(LOW_CP_COEFFS_KEY, materialGUIDict.lookup(LOW_CP_COEFFS_KEY)); + } + + /* TRANSPORT */ + Dictionary transportDict = new Dictionary(TRANSPORT_KEY); + if (transport.equals(CONST_KEY)) { + transportDict.add(MU_KEY, materialGUIDict.lookup(MU_KEY)); + transportDict.add(PR_KEY, materialGUIDict.lookup(PR_KEY)); + } else if (transport.equals(SUTHERLAND_KEY)) { + transportDict.add(AS_KEY, materialGUIDict.lookup(AS_KEY)); + transportDict.add(TS_KEY, materialGUIDict.lookup(TS_KEY)); + } + + Dictionary mixtureDict = new Dictionary(MIXTURE_KEY); + mixtureDict.add(specieDict); + mixtureDict.add(thermodynamicsDict); + mixtureDict.add(transportDict); + + String materialName = materialGUIDict.lookup(MATERIAL_NAME_KEY); + Dictionary thermophysicalProperties = new Dictionary(materialName); + thermophysicalProperties.add(MATERIAL_NAME_KEY, materialName); + thermophysicalProperties.add(thermoDict); + thermophysicalProperties.add(mixtureDict); + + // System.out.println("MaterialsBuilder.saveCompressible() "+thermophysicalProperties); + return thermophysicalProperties; + } + + @Override + public Dictionary loadCompressible(Model model) { + Dictionary thermophysicalProperties = model.getProject().getConstantFolder().getThermophysicalProperties(); + // System.out.println("MaterialsBuilder.decodeCompressible()"+thermophysicalProperties); + + Dictionary d = new Dictionary(""); + if (thermophysicalProperties.found(THERMO_TYPE_KEY)) { + Dictionary thermoType = thermophysicalProperties.subDict(THERMO_TYPE_KEY); + + d.add(THERMO_MODEL_KEY, thermoType.lookup(Dictionary.TYPE)); + d.add(TRANSPORT_KEY, thermoType.lookup(TRANSPORT_KEY)); + d.add(THERMO_KEY, thermoType.lookup(THERMO_KEY)); + d.add(EQUATION_OF_STATE_KEY, thermoType.lookup(EQUATION_OF_STATE_KEY)); + + if (thermophysicalProperties.found(MATERIAL_NAME_KEY)) + d.add(MATERIAL_NAME_KEY, thermophysicalProperties.lookup(MATERIAL_NAME_KEY)); + else + d.add(MATERIAL_NAME_KEY, DEFAULT_MATERIAL_KEY); + + if (thermophysicalProperties.found(MIXTURE_KEY)) { + Dictionary mixture = thermophysicalProperties.subDict(MIXTURE_KEY); + + /* SPECIES */ + Dictionary speciesDict = mixture.subDict(SPECIE_KEY); + d.merge(speciesDict); + + /* THERMODYNAMICS */ + Dictionary thermodynamicsDict = mixture.subDict(THERMODYNAMICS_KEY); + d.merge(thermodynamicsDict); + + /* TRANSPORT */ + Dictionary transportDict = mixture.subDict(TRANSPORT_KEY); + d.merge(transportDict); + } + } + + return d; + } + + @Override + public Dictionary toGUIFormat(Dictionary thermophysicalProperties) { + // System.out.println("MaterialsBuilder.decodeCompressible()"+thermophysicalProperties); + Dictionary d = new Dictionary(""); + + if (thermophysicalProperties.found(THERMO_TYPE_KEY)) { + Dictionary thermoType = thermophysicalProperties.subDict(THERMO_TYPE_KEY); + + d.add(THERMO_MODEL_KEY, thermoType.lookup(Dictionary.TYPE)); + d.add(TRANSPORT_KEY, thermoType.lookup(TRANSPORT_KEY)); + d.add(THERMO_KEY, thermoType.lookup(THERMO_KEY)); + d.add(EQUATION_OF_STATE_KEY, thermoType.lookup(EQUATION_OF_STATE_KEY)); + + } + if (thermophysicalProperties.found(MATERIAL_NAME_KEY)) + d.add(MATERIAL_NAME_KEY, thermophysicalProperties.lookup(MATERIAL_NAME_KEY)); + else + d.add(MATERIAL_NAME_KEY, thermophysicalProperties.getName()); + + if (thermophysicalProperties.found(MIXTURE_KEY)) { + Dictionary mixture = thermophysicalProperties.subDict(MIXTURE_KEY); + + /* SPECIES */ + if (mixture.found(SPECIE_KEY)) + d.merge(mixture.subDict(SPECIE_KEY)); + + /* THERMODYNAMICS */ + if (mixture.found(THERMODYNAMICS_KEY)) + d.merge(mixture.subDict(THERMODYNAMICS_KEY)); + + /* TRANSPORT */ + if (mixture.found(TRANSPORT_KEY)) + d.merge(mixture.subDict(TRANSPORT_KEY)); + } + + return d; + } +} diff --git a/src/eu/engys/gui/casesetup/materials/StandardMaterialsReader.java b/src/eu/engys/gui/casesetup/materials/StandardMaterialsReader.java new file mode 100644 index 0000000..693dc0c --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/StandardMaterialsReader.java @@ -0,0 +1,87 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StandardMaterialsReader extends AbstractMaterialsReader { + + private static final Logger logger = LoggerFactory.getLogger(StandardMaterialsReader.class); + + @Inject + public StandardMaterialsReader() { + } + +// @Override +// public void readMultiphase_IncompressibleMaterials(Materials materials, Dictionary transportProperties) { +// if (transportProperties.found("phases")) { +// String[] phases = transportProperties.lookupArray("phases"); +// if (phases.length == 2) { +// +// Dictionary dict1 = new Dictionary(transportProperties.subDict(phases[0])); +// if (!dict1.isEmpty()) { +// if (!dict1.found("materialName")) { +// dict1.add("materialName", "material1"); +// } +// String name1 = dict1.lookup("materialName"); +// dict1.setName(name1); +// materials.add(new Material(name1, dict1)); +// } +// +// Dictionary dict2 = new Dictionary(transportProperties.subDict(phases[1])); +// if (!dict2.isEmpty()) { +// if (!dict2.found("materialName")) { +// dict2.add("materialName", "material2"); +// } +// String name2 = dict2.lookup("materialName"); +// dict2.setName(name2); +// materials.add(new Material(name2, dict2)); +// } +// +// if (transportProperties.found("sigma")) { +// String sigmaValue = transportProperties.lookup("sigma"); +// materials.get(0).getDictionary().add("sigma", sigmaValue); +// materials.get(1).getDictionary().add("sigma", sigmaValue); +// } else if (dict1.found("sigma")) { +// String sigmaValue = dict1.lookup("sigma"); +// materials.get(1).getDictionary().add("sigma", sigmaValue); +// } else if (dict2.found("sigma")) { +// String sigmaValue = dict2.lookup("sigma"); +// materials.get(0).getDictionary().add("sigma", sigmaValue); +// } +// } else { +// logger.warn("Multiphase case but wrong phases number found in transportProperties: " + phases.length); +// } +// +// } else { +// logger.warn("Multiphase case but no phases found in transportProperties"); +// } +// } + +} diff --git a/src/eu/engys/gui/casesetup/materials/StandardMaterialsWriter.java b/src/eu/engys/gui/casesetup/materials/StandardMaterialsWriter.java new file mode 100644 index 0000000..673d1c2 --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/StandardMaterialsWriter.java @@ -0,0 +1,69 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.materials; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StandardMaterialsWriter extends AbstractMaterialsWriter { + + private static final Logger logger = LoggerFactory.getLogger(AbstractMaterialsWriter.class); + +// @Override +// public void writeMultiphase_IncompressibleMaterials(Materials materials, Dictionary tpp) { +// if (materials.size() == 2) { +// Material mat1 = materials.get(0); +// Material mat2 = materials.get(1); +// +// String mat1Name = mat1.getName(); +// String mat2Name = mat2.getName(); +// +// tpp.add(PHASES_KEY, "(" + mat1Name + " " + mat2Name + ")"); +// +// Dictionary dict1 = new Dictionary(mat1.getDictionary()); +// dict1.remove(SIGMA_KEY); +// dict1.setName(mat1Name); +// tpp.add(dict1); +// +// Dictionary dict2 = new Dictionary(mat2.getDictionary()); +// dict2.remove(SIGMA_KEY); +// dict2.setName(mat2Name); +// tpp.add(dict2); +// +// String sigmaValue = "0.0"; +// if (mat1.getDictionary().found(SIGMA_KEY)) { +// sigmaValue = mat1.getDictionary().lookup(SIGMA_KEY); +// } else if (mat2.getDictionary().found(SIGMA_KEY)) { +// sigmaValue = mat2.getDictionary().lookup(SIGMA_KEY); +// } +// tpp.add(new DimensionedScalar(SIGMA_KEY, sigmaValue, "[1 0 -2 0 0 0 0 ]")); +// +// } else { +// logger.warn("Multiphase solution choosen but '{}' materials found", materials.size()); +// } +// } + +} diff --git a/src/eu/engys/gui/casesetup/materials/panels/MaterialParametersPanel.java b/src/eu/engys/gui/casesetup/materials/panels/MaterialParametersPanel.java new file mode 100644 index 0000000..dce648b --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/panels/MaterialParametersPanel.java @@ -0,0 +1,131 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.materials.panels; + +import java.awt.CardLayout; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.gui.casesetup.materials.CompressibleMaterialsPanel; +import eu.engys.gui.casesetup.materials.IncompressibleMaterialsPanel; +import eu.engys.util.ui.textfields.StringField; + +public class MaterialParametersPanel extends JPanel { + + private static final String INCOMPRESSIBLE = "Incompressible"; + private static final String COMPRESSIBLE = "Compressible"; + private static final String NONE = "None"; + + private CompressibleMaterialsPanel compressiblePanel; + private IncompressibleMaterialsPanel incompressiblePanel; + + private String selected = NONE; + + public MaterialParametersPanel(CompressibleMaterialsPanel compressiblePanel, IncompressibleMaterialsPanel incompressiblePanel) { + super(new CardLayout()); + setName("Material Parameters"); + + this.compressiblePanel = compressiblePanel; + this.incompressiblePanel = incompressiblePanel; + + JPanel compPanel = compressiblePanel.getPanel(); + JPanel incompPanel = incompressiblePanel.getPanel(); + + compPanel.setName("Compressible Panel"); + incompPanel.setName("Incompressible Panel"); + incompPanel.setBorder(BorderFactory.createTitledBorder("Material Parameters")); + + add(compPanel, COMPRESSIBLE); + add(incompPanel, INCOMPRESSIBLE); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + compressiblePanel.setEnabled(enabled); + incompressiblePanel.setEnabled(enabled); + } + + public void load(Model model) { + if (model.getState().isCompressible()) { + selected = COMPRESSIBLE; + ((CardLayout) getLayout()).show(this, COMPRESSIBLE); + } else if (model.getState().isIncompressible()) { + selected = INCOMPRESSIBLE; + ((CardLayout) getLayout()).show(this, INCOMPRESSIBLE); + } + } + + public void show(State state) { + if (state.isCompressible()) { + selected = COMPRESSIBLE; + compressiblePanel.stateChanged(state); + ((CardLayout) getLayout()).show(this, COMPRESSIBLE); + } else if (state.isIncompressible()) { + selected = INCOMPRESSIBLE; + incompressiblePanel.stateChanged(state); + ((CardLayout) getLayout()).show(this, INCOMPRESSIBLE); + } + } + + public Dictionary getEmptyMaterial(Model model) { + if (model.getState().isCompressible()) { + return compressiblePanel.getEmptyMaterial(); + } else { + return incompressiblePanel.getEmptyMaterial(); + } + } + + public Dictionary getMaterial(Model model) { + if (model.getState().isCompressible()) { + return compressiblePanel.getMaterial(model); + } else { + return incompressiblePanel.getMaterial(model); + } + } + + public StringField getNameField(Model model) { + if (model.getState().isCompressible()) { + return compressiblePanel.getNameField(); + } else { + return incompressiblePanel.getNameField(); + } + } + + public void setMaterial(Dictionary material) { + if (selected.equals(COMPRESSIBLE)) { + compressiblePanel.setMaterial(material); + } else { + incompressiblePanel.setMaterial(material); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/materials/panels/MaterialsDatabasePanel.java b/src/eu/engys/gui/casesetup/materials/panels/MaterialsDatabasePanel.java new file mode 100644 index 0000000..063ab1d --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/panels/MaterialsDatabasePanel.java @@ -0,0 +1,444 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.materials.panels; + +import static eu.engys.core.project.constant.ThermophysicalProperties.MATERIAL_NAME_KEY; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.project.Model; +import eu.engys.gui.casesetup.materials.CompressibleMaterialsPanel; +import eu.engys.gui.casesetup.materials.IncompressibleMaterialsPanel; +import eu.engys.util.PrefUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class MaterialsDatabasePanel extends JPanel { + + public static final String NEW_LABEL = "New"; + public static final String COPY_LABEL = "Copy"; + public static final String REMOVE_LABEL = "Remove"; + + public static final String NEW_TOOLTIP = "Create New Material"; + public static final String COPY_TOOLTIP = "Copy Currently Selected Material"; + public static final String REMOVE_TOOLTIP = "Remove Currently Selected Material"; + + public static final String COPY_OF_SUFFIX = "_copy"; + + private final Action newMaterial = new NewMaterialAction(); + private final Action copyMaterial = new CopyMaterialAction(); + private final Action removeMaterial = new RemoveMaterialAction(); + + private MaterialParametersPanel parametersPanel; + + private DefaultMaterialsListListener materialListener; + private UserMaterialsListListener userListener; + + private DefaultListModel materialsListModel; + private DefaultListModel userListModel; + + private JList defaultMaterialsList; + private JList userMaterialsList; + + private Model model; + private Map userMaterials = new HashMap(); + + @Inject + public MaterialsDatabasePanel(final Model model, CompressibleMaterialsPanel compressiblePanel, IncompressibleMaterialsPanel incompressiblePanel) { + super(new BorderLayout()); + this.model = model; + + materialListener = new DefaultMaterialsListListener(); + userListener = new UserMaterialsListListener(); + + materialsListModel = new DefaultListModel(); + userListModel = new DefaultListModel(); + + defaultMaterialsList = new JList(materialsListModel); + defaultMaterialsList.setName("materials.library.list"); + defaultMaterialsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + userMaterialsList = new JList(userListModel); + userMaterialsList.setName("user.library.list"); + userMaterialsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + defaultMaterialsList.addListSelectionListener(materialListener); + userMaterialsList.addListSelectionListener(userListener); + + parametersPanel = new MaterialParametersPanel(compressiblePanel, incompressiblePanel); + parametersPanel.setEnabled(false); + + JSplitPane leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + leftSplitPane.setOneTouchExpandable(false); + leftSplitPane.setTopComponent(configureList(defaultMaterialsList, "Default Library")); + leftSplitPane.setBottomComponent(configureList(userMaterialsList, "User Library")); + + JComponent buttonsPanel = UiUtil.getCommandColumn(getButtons()); + buttonsPanel.setBorder(BorderFactory.createEmptyBorder(UiUtil.TWO_SPACES, UiUtil.TWO_SPACES, 0, UiUtil.TWO_SPACES)); + + JSplitPane mainSplitPane = new JSplitPane(); + mainSplitPane.setDividerLocation(150); + mainSplitPane.setOneTouchExpandable(false); + mainSplitPane.setLeftComponent(leftSplitPane); + JScrollPane comp = new JScrollPane(parametersPanel); + comp.setBorder(BorderFactory.createEmptyBorder()); + mainSplitPane.setRightComponent(comp); + + add(mainSplitPane, BorderLayout.CENTER); + add(buttonsPanel, BorderLayout.EAST); + } + + private List getButtons() { + List buttons = new ArrayList<>(); + JButton newMaterialButton = new JButton(newMaterial); + JButton copyMaterialButton = new JButton(copyMaterial); + JButton removeMaterialButton = new JButton(removeMaterial); + + newMaterialButton.setName(NEW_LABEL); + copyMaterialButton.setName(COPY_LABEL); + removeMaterialButton.setName(REMOVE_LABEL); + + copyMaterial.setEnabled(false); + removeMaterial.setEnabled(false); + + buttons.add(newMaterialButton); + buttons.add(copyMaterialButton); + buttons.add(removeMaterialButton); + return buttons; + } + + private JComponent configureList(JList list, String label) { + JScrollPane scrollPane = new JScrollPane(list); + scrollPane.setBorder(BorderFactory.createTitledBorder(label)); + list.setOpaque(false); + list.setBackground(getBackground().darker().brighter()); + list.setSelectionBackground(getBackground().darker()); + list.setSelectionForeground(Color.WHITE); + list.setCellRenderer(new DefaultListCellRenderer()); + return scrollPane; + } + + public void load() { + updateDefaultMaterialsList(); + + loadUserMaterials(); + updateUserMaterialsList(); + + parametersPanel.show(model.getState()); + } + + private void loadUserMaterials() { + userMaterials.clear(); + + String userMaterialsProperties = PrefUtil.getString(PrefUtil.MATERIALS_USER_LIB + model.getState().getFlow(), null); + if (userMaterialsProperties != null) { + Dictionary userDictionary = DictionaryUtils.readDictionary(userMaterialsProperties); + + if (userDictionary.found("materials")) { + for (Dictionary matDict : userDictionary.subDict("materials").getDictionaries()) { + try { + if (model.getState().isCompressible()) { + if (matDict.found("thermoType")) { + userMaterials.put(matDict.getName(), matDict); + } + } else { + userMaterials.put(matDict.getName(), matDict); + } + + } catch (Exception e) { + System.out.println("INVALID MATERIAL DICTIONARY: " + matDict.getName()); + } + } + } + } + } + + public void saveUserMaterials() { + saveCurrentSelectedUserDefinedMaterial(); + Dictionary userMaterialsProperties = new Dictionary("materials"); + for (Dictionary mat : userMaterials.values()) { + userMaterialsProperties.add(mat); + } + PrefUtil.putString(PrefUtil.MATERIALS_USER_LIB + model.getState().getFlow(), userMaterialsProperties.toString()); + } + + public Dictionary getMaterial() { + return parametersPanel.getMaterial(model); + } + + private void updateUserMaterialsList() { + userMaterialsList.removeListSelectionListener(userListener); + int selection = userMaterialsList.getSelectedIndex(); + userListModel.clear(); + for (String mat : userMaterials.keySet()) { + userListModel.addElement(mat); + } + userMaterialsList.setSelectedIndex(selection); + userMaterialsList.addListSelectionListener(userListener); + } + + private void updateDefaultMaterialsList() { + defaultMaterialsList.removeListSelectionListener(materialListener); + materialsListModel.clear(); + Collection materials = null; + if (model.getState().isCompressible()) { + materials = model.getMaterialsDatabase().getCompressibleMaterials(); + } else { + materials = model.getMaterialsDatabase().getIncompressibleMaterials(); + } + for (Dictionary mat : materials) { + materialsListModel.addElement(mat.lookup(MATERIAL_NAME_KEY)); + } + defaultMaterialsList.addListSelectionListener(materialListener); + } + + private final class DefaultMaterialsListListener implements ListSelectionListener { + @Override + public void valueChanged(ListSelectionEvent e) { + if (!e.getValueIsAdjusting() && e.getSource() == defaultMaterialsList) { + String key = (String) defaultMaterialsList.getSelectedValue(); + if (key == null) + return; + + clearSelectionOnUserMaterialsList(); + + saveCurrentSelectedUserDefinedMaterial(); + + if (model.getState().isCompressible()) { + setMaterialToParametersPanel(new Dictionary(model.getMaterialsDatabase().getCompressibleMaterialsMap().get(key))); + } else { + setMaterialToParametersPanel(new Dictionary(model.getMaterialsDatabase().getIncompressibleMaterialsMap().get(key))); + } + + parametersPanel.getNameField(model).setEnabled(false); + + copyMaterial.setEnabled(true); + removeMaterial.setEnabled(false); + parametersPanel.setEnabled(false); + } + } + } + + private final class UserMaterialsListListener implements ListSelectionListener { + @Override + public void valueChanged(ListSelectionEvent e) { + if (!e.getValueIsAdjusting() && e.getSource() == userMaterialsList) { + String key = (String) userMaterialsList.getSelectedValue(); + if (key == null) + return; + + clearSelectionOnDefaultMaterialsList(); + + saveCurrentSelectedUserDefinedMaterial(); + + Dictionary dict = new Dictionary(userMaterials.get(key)); + setMaterialToParametersPanel(dict); + + parametersPanel.getNameField(model).setEnabled(true); + + copyMaterial.setEnabled(true); + removeMaterial.setEnabled(true); + parametersPanel.setEnabled(true); + } + } + } + + private void saveCurrentSelectedUserDefinedMaterial() { + Dictionary currentMaterial = parametersPanel.getMaterial(model); + if (userMaterials.keySet().contains(currentMaterial.getName())) { + // If name is changed + String oldMaterialName = currentMaterial.getName(); + String newMaterialName = currentMaterial.lookup(MATERIAL_NAME_KEY); + + userMaterials.remove(oldMaterialName); + Dictionary newMaterialDict = new Dictionary(newMaterialName, currentMaterial); + userMaterials.put(newMaterialName, newMaterialDict); + + updateUserMaterialsList(); + } + + } + + private void setMaterialToParametersPanel(Dictionary material) { + parametersPanel.getNameField(model).removePropertyChangeListener(nameChangeListener); + parametersPanel.setMaterial(material); + parametersPanel.getNameField(model).addPropertyChangeListener(nameChangeListener); + } + + /* + * Actions + */ + + private final class NewMaterialAction extends ViewAction { + public NewMaterialAction() { + super(NEW_LABEL, NEW_TOOLTIP); + } + + @Override + public void actionPerformed(ActionEvent e) { + clearSelectionOnAllLists(); + + Dictionary emptyDict = parametersPanel.getEmptyMaterial(model); + + String validMaterialName = getValidMaterialName(emptyDict.getName()); + Dictionary newMaterialDict = new Dictionary(validMaterialName, emptyDict); + newMaterialDict.add(MATERIAL_NAME_KEY, validMaterialName); + + userMaterials.put(validMaterialName, newMaterialDict); + updateUserMaterialsList(); + userMaterialsList.setSelectedValue(validMaterialName, true); + } + } + + private final class CopyMaterialAction extends ViewAction { + + public CopyMaterialAction() { + super(COPY_LABEL, COPY_TOOLTIP); + } + + @Override + public void actionPerformed(ActionEvent e) { + clearSelectionOnAllLists(); + + Dictionary currentlySelectedMaterial = parametersPanel.getMaterial(model); + + String validMaterialName = getValidMaterialName(currentlySelectedMaterial.getName()); + Dictionary copyMaterial = new Dictionary(validMaterialName, currentlySelectedMaterial); + copyMaterial.add(MATERIAL_NAME_KEY, validMaterialName); + + userMaterials.put(validMaterialName, copyMaterial); + updateUserMaterialsList(); + userMaterialsList.setSelectedValue(validMaterialName, true); + } + + } + + private final class RemoveMaterialAction extends ViewAction { + public RemoveMaterialAction() { + super(REMOVE_LABEL, REMOVE_TOOLTIP); + } + + @Override + public void actionPerformed(ActionEvent e) { + String key = (String) userMaterialsList.getSelectedValue(); + if (key == null) + return; + userMaterials.remove(key); + updateUserMaterialsList(); + defaultMaterialsList.setSelectedIndex(0); + } + } + + private void clearSelectionOnAllLists() { + clearSelectionOnDefaultMaterialsList(); + clearSelectionOnUserMaterialsList(); + } + + private void clearSelectionOnDefaultMaterialsList() { + defaultMaterialsList.removeListSelectionListener(userListener); + defaultMaterialsList.clearSelection(); + defaultMaterialsList.addListSelectionListener(userListener); + } + + private void clearSelectionOnUserMaterialsList() { + userMaterialsList.removeListSelectionListener(userListener); + userMaterialsList.clearSelection(); + userMaterialsList.addListSelectionListener(userListener); + } + + private String getValidMaterialName(String materialname) { + Map materials = null; + + if (model.getState().isCompressible()) { + materials = model.getMaterialsDatabase().getCompressibleMaterialsMap(); + } else { + materials = model.getMaterialsDatabase().getIncompressibleMaterialsMap(); + } + + String uniqueMaterialName = materialname; + while (materials.containsKey(uniqueMaterialName)) { + uniqueMaterialName = uniqueMaterialName + COPY_OF_SUFFIX; + } + while (userMaterials.containsKey(uniqueMaterialName)) { + uniqueMaterialName = uniqueMaterialName + COPY_OF_SUFFIX; + } + return uniqueMaterialName; + } + + /* + * Listeners + */ + + PropertyChangeListener nameChangeListener = new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + String oldname = (String) evt.getOldValue(); + if (oldname != null) { + String newName = (String) evt.getNewValue(); + + Dictionary currentMaterial = parametersPanel.getMaterial(model); + + userMaterials.remove(oldname); + Dictionary newMaterialDict = new Dictionary(newName, currentMaterial); + userMaterials.put(newName, newMaterialDict); + + updateUserMaterialsList(); + userMaterialsList.setSelectedValue(newName, true); + } + } + } + }; +} diff --git a/src/eu/engys/gui/casesetup/materials/panels/MaterialsPanel.java b/src/eu/engys/gui/casesetup/materials/panels/MaterialsPanel.java new file mode 100644 index 0000000..3d91ea4 --- /dev/null +++ b/src/eu/engys/gui/casesetup/materials/panels/MaterialsPanel.java @@ -0,0 +1,359 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.materials.panels; + +import static eu.engys.core.project.constant.TransportProperties.MATERIAL_NAME_KEY; +import static eu.engys.gui.casesetup.materials.panels.MaterialsDatabasePanel.COPY_OF_SUFFIX; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.materials.Material; +import eu.engys.core.project.materials.Materials; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.StateBuilder; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.casesetup.materials.CompressibleMaterialsPanel; +import eu.engys.gui.casesetup.materials.IncompressibleMaterialsPanel; +import eu.engys.gui.casesetup.materials.MaterialsTreeNodeManager; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; + +public class MaterialsPanel extends AbstractGUIPanel { + + public static final String MATERIALS = "Materials"; + private static final String MATERIAL_CHANGED_WARNING = "A material has been changed.\nAll fields default settings are going to be reset now.\nContinue?"; + + private JDialog dialog; + + private MaterialParametersPanel parametersPanel; + + private MaterialsTreeNodeManager treeNodeManager; + private Material materialToChange; + + private CardLayout centerPanelLayout; + private JPanel centerPanel; + + private JButton changeMaterialButton; + + private PanelBuilder parametersBuilder; + + private Set modules; + + private CompressibleMaterialsPanel compressiblePanel; + private IncompressibleMaterialsPanel incompressiblePanel; + + private MaterialsDatabasePanel materialsDatabasePanel; + + @Inject + public MaterialsPanel(Model model, MaterialsDatabasePanel materialsDatabasePanel, CompressibleMaterialsPanel compressiblePanel, IncompressibleMaterialsPanel incompressiblePanel, Set modules) { + super(MATERIALS, model); + this.materialsDatabasePanel = materialsDatabasePanel; + this.compressiblePanel = compressiblePanel; + this.incompressiblePanel = incompressiblePanel; + this.modules = modules; + this.treeNodeManager = new MaterialsTreeNodeManager(model, this); + model.addObserver(treeNodeManager); + } + + protected JComponent layoutComponents() { + centerPanelLayout = new CardLayout(); + centerPanel = new JPanel(centerPanelLayout); + centerPanel.add(new JLabel(), "none"); + + parametersPanel = new MaterialParametersPanel(compressiblePanel, incompressiblePanel); + + parametersBuilder = new PanelBuilder(); + parametersBuilder.addComponent(parametersPanel); + + ModulesUtil.configureMaterialsView(modules, parametersBuilder); + + centerPanel.add(parametersBuilder.removeMargins().getPanel(), "material"); + + PanelBuilder mainbuilder = new PanelBuilder(); + mainbuilder.addComponent(createButtonsPanel()); + mainbuilder.addComponent(centerPanel); + + return mainbuilder.removeMargins().getPanel(); + } + + private JComponent createButtonsPanel() { + List actionsList = new ArrayList(); + changeMaterialButton = new JButton(new ChangeMaterialAction()); + changeMaterialButton.setName("Change Material"); + changeMaterialButton.setEnabled(false); + actionsList.add(changeMaterialButton); + + JComponent buttonsPanel = UiUtil.getCommandRow(actionsList); + buttonsPanel.setBorder(BorderFactory.createEmptyBorder()); + return buttonsPanel; + } + + private void buildDialog() { + JButton okButton = new JButton(new OkDialogAction()); + okButton.setName("OK"); + + JButton cancelButton = new JButton(new CancelDialogAction()); + cancelButton.setName("Cancel"); + + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + + dialog = new JDialog(UiUtil.getActiveWindow(), "Materials Database", JDialog.DEFAULT_MODALITY_TYPE); + dialog.setName("materials.database.dialog"); + dialog.setSize(700, 500); + dialog.setLocationRelativeTo(null); + dialog.getContentPane().setLayout(new BorderLayout()); + dialog.getContentPane().add(materialsDatabasePanel, BorderLayout.CENTER); + dialog.getContentPane().add(buttonsPanel, BorderLayout.SOUTH); + dialog.getRootPane().setDefaultButton(okButton); + } + + @Override + public void load() { + materialsDatabasePanel.load(); + parametersPanel.load(model); + } + + @Override + public void save() { + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) treeNodeManager.getSelectedValues()); + } + + @Override + public void clear() { + super.clear(); + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) new Material[0]); + } + + @Override + public void stateChanged() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + State state = model.getState(); + + parametersPanel.show(state); + materialsDatabasePanel.load(); + + Materials materials = model.getMaterials(); + if (!materials.isEmpty()) { + for (Material material : materials) { + for (ApplicationModule module : modules) { + if (module.getMaterialsView() != null) { + module.getMaterialsView().updateDefaultMaterial(material); + } + } + updateSelection(material); + saveMaterials(material); + } + } + + } + }); + } + + public void updateSelection(Material... ms) { + if (ms.length == 1) { + Material material = ms[0]; + centerPanelLayout.show(centerPanel, "material"); + parametersPanel.setMaterial(material.getDictionary()); + for (ApplicationModule module : modules) { + if (module.getMaterialsView() != null) + module.getMaterialsView().updateGUIFromModel(material); + } + } else { + centerPanelLayout.show(centerPanel, "none"); + } + + } + + public void saveMaterials(Material... selection) { + if (selection != null && selection.length == 1) { + Material material = selection[0]; + Dictionary d = new Dictionary(parametersPanel.getMaterial(model)); + material.setDictionary(d); + + for (ApplicationModule module : modules) { + if (module.getMaterialsView() != null) { + module.getMaterialsView().updateModelFromGUI(material); + } + } + } + } + + public void updateButtons(boolean enable) { + changeMaterialButton.setEnabled(enable); + } + + private final class ChangeMaterialAction extends AbstractAction { + + public ChangeMaterialAction() { + super("Change Material"); + } + + @Override + public void actionPerformed(ActionEvent e) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (dialog == null) { + buildDialog(); + } + materialToChange = treeNodeManager.getSelectedValues()[0]; + dialog.setVisible(true); + } + }); + } + } + + private final class OkDialogAction extends AbstractAction { + + public OkDialogAction() { + super("OK"); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (model.getState().getMultiphaseModel().isMultiphase()) { + int retVal = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), MATERIAL_CHANGED_WARNING, "Material Changed", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); + if (retVal != JOptionPane.OK_OPTION) { + return; + } + + } + materialsDatabasePanel.saveUserMaterials(); + dialog.setVisible(false); + parametersPanel.getNameField(model).setEnabled(false); + changeMaterial(); + } + + private void changeMaterial() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + Material newMaterial = getNewMaterial(); + if (model.getState().getMultiphaseModel().isMultiphase()) { + StateBuilder.changeMaterial(model, modules); + } else { + model.materialsChanged(); + } + treeNodeManager.setSelectedValue(newMaterial); + save(); + } + }); + } + + private Material getNewMaterial() { + int index = -1; + if (materialToChange != null) { + index = model.getMaterials().indexOf(materialToChange); + model.getMaterials().remove(materialToChange); + materialToChange = null; + } + + Dictionary dictionary = materialsDatabasePanel.getMaterial(); + + Material material = null; + + if (modelAlreadyContainsMaterial(dictionary.getName())) { + Dictionary newDict = new Dictionary(dictionary); + String newName = dictionary.getName() + COPY_OF_SUFFIX; + newDict.setName(newName); + newDict.add(MATERIAL_NAME_KEY, newName); + material = new Material(newName, newDict); + dictionary = newDict; + } else { + material = new Material(dictionary.getName(), dictionary); + } + + if (index != -1) { + model.getMaterials().add(index, material); + } else { + model.getMaterials().add(material); + } + parametersPanel.setMaterial(dictionary); + return material; + } + + private boolean modelAlreadyContainsMaterial(String name) { + for (Material mat : model.getMaterials()) { + if (mat.getName().equals(name)) { + return true; + } + } + return false; + } + } + + private final class CancelDialogAction extends AbstractAction implements Runnable { + + public CancelDialogAction() { + super("Cancel"); + } + + @Override + public void actionPerformed(ActionEvent e) { + SwingUtilities.invokeLater(this); + } + + @Override + public void run() { + dialog.setVisible(false); + } + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + +} diff --git a/src/eu/engys/gui/casesetup/phases/PhasesPanel.java b/src/eu/engys/gui/casesetup/phases/PhasesPanel.java new file mode 100644 index 0000000..cb4da28 --- /dev/null +++ b/src/eu/engys/gui/casesetup/phases/PhasesPanel.java @@ -0,0 +1,93 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.phases; + +import javax.swing.JComponent; + +import eu.engys.core.project.Model; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.builder.PanelBuilder; + +public class PhasesPanel extends DefaultGUIPanel { + + public static final String PHASES = "Phases"; + + private PhasesView phasesView; + + public PhasesPanel(Model model, PhasesView phasesView) { + super(PHASES, model); + this.phasesView = phasesView; + } + + @Override + public String getKey() { + return PHASES + "_" + phasesView.getClass().getCanonicalName(); + } + + @Override + public void load() { + phasesView.load(model); + } + + @Override + public void save() { + phasesView.save(model); + } + + @Override + public void stateChanged() { + rebuildPanel(); + } + + @Override + public void materialsChanged() { + rebuildPanel(); + } + + private void rebuildPanel() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + removeAll(); + layoutPanel(); + load(); + } + }); + } + + @Override + protected JComponent layoutComponents() { + PanelBuilder builder = new PanelBuilder(); + phasesView.layoutComponents(builder); + return builder.removeMargins().getPanel(); + } + + @Override + public int getIndex() { + return 2; + } +} diff --git a/src/eu/engys/gui/casesetup/phases/PhasesView.java b/src/eu/engys/gui/casesetup/phases/PhasesView.java new file mode 100644 index 0000000..7d87080 --- /dev/null +++ b/src/eu/engys/gui/casesetup/phases/PhasesView.java @@ -0,0 +1,39 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.phases; + +import eu.engys.core.project.Model; +import eu.engys.util.ui.builder.PanelBuilder; + +public interface PhasesView { + + void layoutComponents(PanelBuilder parametersBuilder); + + void load(Model model); + + void save(Model model); + +} diff --git a/src/eu/engys/gui/casesetup/run/StandardTable15.java b/src/eu/engys/gui/casesetup/run/StandardTable15.java new file mode 100644 index 0000000..c56a3b8 --- /dev/null +++ b/src/eu/engys/gui/casesetup/run/StandardTable15.java @@ -0,0 +1,123 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.run; + +import java.util.Set; + +import javax.inject.Inject; + +import eu.engys.core.project.state.Solver; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.Table15; + +public class StandardTable15 implements Table15 { + + @Inject + public StandardTable15() { + } + + @Override + public void updateSolverFamilies(State state, Set families) { + if (state.getSolverType().isSegregated()) { + if (state.isLowMach()) { + if (state.isSteady()) { + families.add(SolverFamily.SIMPLE); + } else if (state.isTransient()) { + if (state.isCompressible()) { + families.add(SolverFamily.PIMPLE); + } else if (state.isIncompressible()) { + if (state.isEnergy() || state.getMultiphaseModel().isMultiphase()) { + families.add(SolverFamily.PIMPLE); + } else { + families.add(SolverFamily.PIMPLE); + families.add(SolverFamily.PISO); + } + } else { + // NONE + } + } else { + // NONE + } + } else if (state.isHighMach()) { + families.add(SolverFamily.PIMPLE); + } else { + // NONE + } + } else { + // NONE + } + } + + @Override + public void updateSolver(State state) { + if (state.getSolverType().isSegregated()) { + String solverName = ""; + + if (state.getMultiphaseModel().isMultiphase()) { + /* in modules */ + } else if (state.getSolverFamily().isSimple()) { + if (state.isCompressible()) { + if (state.isBuoyant()) { + solverName = BUOYANT_SIMPLE_FOAM; + } else { + solverName = RHO_SIMPLE_FOAM; + } + } else if (state.isIncompressible()) { + if (state.isEnergy()) { + solverName = BUOYANT_BOUSSINESQ_SIMPLE_FOAM; + } else { + solverName = SIMPLE_FOAM; + } + } + } else if (state.getSolverFamily().isPiso()) { + if (state.isIncompressible()) { + solverName = PISO_FOAM; + } + } else if (state.getSolverFamily().isPimple()) { + if (state.isCompressible()) { + if (state.isBuoyant()) { + solverName = BUOYANT_PIMPLE_FOAM; + } else { + if (state.isHighMach()) { + solverName = SONIC_FOAM; + } else { + solverName = RHO_PIMPLE_FOAM; + } + } + } else if (state.isIncompressible()) { + if (state.isEnergy()) { + solverName = BUOYANT_BOUSSINESQ_PIMPLE_FOAM; + } else { + solverName = PIMPLE_FOAM; + } + } + } + state.setSolver(new Solver(solverName)); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/schemes/AdvectionSchemes.java b/src/eu/engys/gui/casesetup/schemes/AdvectionSchemes.java new file mode 100644 index 0000000..ba13e0d --- /dev/null +++ b/src/eu/engys/gui/casesetup/schemes/AdvectionSchemes.java @@ -0,0 +1,300 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.schemes; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.ListField; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.ControlDict; +import eu.engys.core.project.system.FvSchemes; + +public class AdvectionSchemes { + + private static final Logger logger = LoggerFactory.getLogger(AdvectionSchemes.class); + + static class SchemeTemplate { + private final String key; + private final String label; + private final Dictionary functions; + + public SchemeTemplate(String key, String label, Dictionary functions) { + this.key = key; + this.label = label; + this.functions = functions; + } + + @Override + public String toString() { + return label; + } + + public boolean hasValue1() { + return key.contains("%f"); + } + + public boolean hasValue2() { + return key.contains("%f %f"); + } + + public boolean hasValue3() { + return StringUtils.countMatches(key, "%f") == 3; + } + + public boolean equalsIgnoringValues(String field, String schemeKey) { + String keyWithFieldName = key.replace("%s", gradName(field)); + + String[] schemeKeyTokens = schemeKey.split("\\s+"); + String[] keyWithFieldNameTokens = keyWithFieldName.split("\\s+"); + + if (schemeKeyTokens.length != keyWithFieldNameTokens.length) + return false; + + for (int i = 0; i < schemeKeyTokens.length; i++) { + if (schemeKeyTokens[i].equals(keyWithFieldNameTokens[i])) { + continue; + } else if (keyWithFieldNameTokens[i].equals("%f")) { + continue; + } else { + return false; + } + } + return true; + } + + public List extractValues(String field, String schemeKey) { + String keyWithFieldName = key.replace("%s", gradName(field)); + + String[] schemeKeyTokens = schemeKey.split("\\s+"); + String[] keyWithFieldNameTokens = keyWithFieldName.split("\\s+"); + + List values = new ArrayList(); + for (int i = 0; i < schemeKeyTokens.length; i++) { + if (keyWithFieldNameTokens[i].equals("%f")) { + values.add(Double.parseDouble(schemeKeyTokens[i])); + } + } + return values; + } + + public Dictionary getFunctions() { + return functions; + } + } + + static class Scheme { + private SchemeTemplate template; + private String field; + private double value1; + private double value2; + private double value3; + + public void setField(String field) { + this.field = field; + } + + public String getField() { + return field; + } + + public void setValue1(double value1) { + this.value1 = value1; + } + + public double getValue1() { + return value1; + } + + public void setValue2(double value2) { + this.value2 = value2; + } + + public double getValue2() { + return value2; + } + + public void setValue3(double value3) { + this.value3 = value3; + } + + public double getValue3() { + return value3; + } + + public void setTemplate(SchemeTemplate template) { + this.template = template; + } + + public SchemeTemplate getTemplate() { + return template; + } + } + + private ArrayList scalar = new ArrayList(); + private ArrayList vector = new ArrayList(); + private Model model; + + public AdvectionSchemes(Model model) { + this.model = model; + + Dictionary defaultSchemes = model.getDefaults().getDefaultSchemes(); + if (defaultSchemes != null) { + ListField scalarSchemes = defaultSchemes.getList("scalar"); + ListField vectorSchemes = defaultSchemes.getList("vector"); + + for (DefaultElement el : scalarSchemes.getListElements()) { + if (el instanceof Dictionary) { + Dictionary d = (Dictionary) el; + addScalarScheme(new SchemeTemplate(d.lookup("key"), d.lookup("label"), d.subDict("functions"))); + } + } + + for (DefaultElement el : vectorSchemes.getListElements()) { + if (el instanceof Dictionary) { + Dictionary d = (Dictionary) el; + addVectorScheme(new SchemeTemplate(d.lookup("key"), d.lookup("label"), d.subDict("functions"))); + } + } + } else { + logger.warn("Advection schemes defaults not found!"); + } + } + + public void addScalarScheme(SchemeTemplate scheme) { + scalar.add(scheme); + } + + public void addVectorScheme(SchemeTemplate scheme) { + vector.add(scheme); + } + + public List getScalarSchemes() { + return scalar; + } + + public List getVectorSchemes() { + return vector; + } + + public void writeScheme(Scheme scheme) { + FvSchemes fvSchemes = model.getProject().getSystemFolder().getFvSchemes(); + Dictionary divSchemes = fvSchemes.getDivSchemes(); + String gradName = gradName(scheme.field); + String divName = div(gradName); + String value = ""; + if (divSchemes != null && scheme.getTemplate() != null) { + String keyWithFieldName = scheme.template.key.replace("%s", gradName); + if (scheme.template.hasValue1()) { + if (scheme.template.hasValue3()) { + value = String.format(keyWithFieldName, scheme.value1, scheme.value2, scheme.value3); + } else if (scheme.template.hasValue2()) { + value = String.format(keyWithFieldName, scheme.value1, scheme.value2); + } else { + value = String.format(keyWithFieldName, scheme.value1); + } + } else { + value = keyWithFieldName; + } + divSchemes.add(divName, value); + + if (scheme.getTemplate().functions != null) { + ControlDict controlDict = model.getProject().getSystemFolder().getControlDict(); + controlDict.functionObjectsToDict(); + Dictionary functions = controlDict.subDict("functions"); + if (functions == null) { + functions = new Dictionary("functions"); + controlDict.add(functions); + } + functions.merge(scheme.getTemplate().functions); + controlDict.functionObjectsToList(); + } + } + } + + public Scheme readScheme(String field) { + String schemeKey = readSchemeKeyFor(div(gradName(field))); + SchemeTemplate template = searchTemplate(field, schemeKey); + Scheme scheme = new Scheme(); + if (template != null) { + List values = template.extractValues(field, schemeKey); + scheme.setTemplate(template); + scheme.setField(field); + scheme.setValue1(values.size() > 0 ? values.get(0) : 0); + scheme.setValue2(values.size() > 1 ? values.get(1) : 0); + scheme.setValue3(values.size() > 2 ? values.get(2) : 0); + } else { + logger.error("Template Scheme {} not found for field {}", schemeKey, field); + } + + return scheme; + } + + private String readSchemeKeyFor(String divName) { + FvSchemes fvSchemes = model.getProject().getSystemFolder().getFvSchemes(); + Dictionary divSchemes = fvSchemes.getDivSchemes(); + if(divSchemes != null){ + if(divSchemes.found(divName)){ + return divSchemes.lookup(divName); + } else { + logger.error(String.format("Scheme Key not found for div '%s'", divName)); + return ""; + } + } else { + logger.error("DivSchemes is NULL"); + return ""; + } + } + + private SchemeTemplate searchTemplate(String field, String scheme) { + List templates = field.startsWith("U") ? vector : scalar; + for (SchemeTemplate t : templates) { + if (t.equalsIgnoringValues(field, scheme)) { + return t; + } + } + return null; + } + + private static String div(String gradName) { + return String.format("div(phi,%s)", gradName); + } + + private static String gradName(String field) { + if (field.equals("ILambda")) + return "Ii_h"; + else + return field; + } + +} diff --git a/src/eu/engys/gui/casesetup/schemes/NumericalSchemesPanel.java b/src/eu/engys/gui/casesetup/schemes/NumericalSchemesPanel.java new file mode 100644 index 0000000..d44bb38 --- /dev/null +++ b/src/eu/engys/gui/casesetup/schemes/NumericalSchemesPanel.java @@ -0,0 +1,261 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.schemes; + +import static eu.engys.core.project.zero.fields.Fields.AOA; +import static eu.engys.core.project.zero.fields.Fields.CO2; +import static eu.engys.core.project.zero.fields.Fields.EPSILON; +import static eu.engys.core.project.zero.fields.Fields.ILAMBDA; +import static eu.engys.core.project.zero.fields.Fields.K; +import static eu.engys.core.project.zero.fields.Fields.NU_TILDA; +import static eu.engys.core.project.zero.fields.Fields.OMEGA; +import static eu.engys.core.project.zero.fields.Fields.SMOKE; +import static eu.engys.core.project.zero.fields.Fields.T; +import static eu.engys.core.project.zero.fields.Fields.U; +import static eu.engys.core.project.zero.fields.Fields.W; +import static eu.engys.util.ui.ComponentsFactory.doubleField; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.text.ParseException; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPanel; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryModel.DictionaryError; +import eu.engys.core.dictionary.model.DictionaryModel.DictionaryListener; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.FvSchemes; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; + +public class NumericalSchemesPanel extends DefaultGUIPanel { + + public static final String NUMERICAL_SCHEMES = "Numerical Schemes"; + public static final String LAPLACIAN_LABEL = "Laplacian"; + public static final String ADVECTION_LABEL = "Advection"; + + public static final String NON_ORTHOGONAL_CORRECTION_LABEL = "Non-orthogonal Correction"; + public static final String GAUSS_LINEAR_LIMITED = "Gauss linear limited"; + public static final String GAUSS_LINEAR_LIMITED_CORRECTED = "Gauss linear limited corrected"; + public static final String GAUSS_LINEAR_UNCORRECTED = "Gauss linear uncorrected"; + public static final String GAUSS_LINEAR_CORRECTED = "Gauss linear corrected"; + + private DictionaryModel laplaceModel; + private DictionaryModel snGradModel; + + private PanelBuilder laplacianBuilder; + private PanelBuilder advectionBuilder; + + private AdvectionSchemes schemes; + + private Map schemePanelsMap = new LinkedHashMap(); + + @Inject + public NumericalSchemesPanel(Model model) { + super(NUMERICAL_SCHEMES, model); + } + + @Override + protected JComponent layoutComponents() { + laplaceModel = new DictionaryModel(new Dictionary("laplacianSchemes")); + snGradModel = new DictionaryModel(new Dictionary("snGradSchemes")); + + DoubleField field = doubleField(0.0, 1.0); + laplacianBuilder = new PanelBuilder(); + laplacianBuilder.addComponent(NON_ORTHOGONAL_CORRECTION_LABEL, field).addPropertyChangeListener(new LaplacianFieldHandler("default", field)); + try { + field.commitEdit(); + } catch (ParseException e) { + e.printStackTrace(); + } + + schemes = new AdvectionSchemes(model); + + advectionBuilder = new PanelBuilder(); + JPanel advectionPanel = advectionBuilder.removeMargins().getPanel(); + advectionPanel.setBorder(BorderFactory.createTitledBorder(ADVECTION_LABEL)); + advectionPanel.setName(ADVECTION_LABEL); + + JPanel laplacianPanel = laplacianBuilder.removeMargins().getPanel(); + laplacianPanel.setBorder(BorderFactory.createTitledBorder(LAPLACIAN_LABEL)); + laplacianPanel.setName(LAPLACIAN_LABEL); + + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(advectionPanel); + builder.addComponent(laplacianPanel); + + return builder.removeMargins().getPanel(); + } + + private void rebuildPanel() { + if (model.getProject() != null) { + FvSchemes fvSchemes = model.getProject().getSystemFolder().getFvSchemes(); + if (fvSchemes != null) { + Dictionary divSchemes = fvSchemes.getDivSchemes(); + Dictionary laplacianSchemes = fvSchemes.getLaplacianSchemes(); + + if (divSchemes != null && laplacianSchemes != null) { + + laplaceModel.setDictionary(laplacianSchemes); + + advectionBuilder.clear(); + schemePanelsMap.clear(); + + buildFieldPanel(advectionBuilder, U); + for (Field field : model.getFields().getMultiphaseUFields()) { + buildFieldPanel(advectionBuilder, field.getName()); + } + + buildFieldPanel(advectionBuilder, K); + buildFieldPanel(advectionBuilder, EPSILON); + buildFieldPanel(advectionBuilder, OMEGA); + buildFieldPanel(advectionBuilder, NU_TILDA); + buildFieldPanel(advectionBuilder, T); + buildFieldPanel(advectionBuilder, W); + buildFieldPanel(advectionBuilder, ILAMBDA); + buildFieldPanel(advectionBuilder, CO2); + buildFieldPanel(advectionBuilder, AOA); + buildFieldPanel(advectionBuilder, SMOKE); + } + } + } + } + + private void buildFieldPanel(PanelBuilder advectionBuilder, String fieldName) { + + Fields fields = getModel().getFields(); + if (fields.containsKey(fieldName)) { + SchemePanel schemePanel = new SchemePanel(schemes, fieldName); + schemePanel.load(); + schemePanelsMap.put(fieldName, schemePanel); + advectionBuilder.addComponent(fieldName, schemePanel.getPanel()); + } + } + + @Override + public void load() { + rebuildPanel(); + } + + @Override + public void save() { + for (SchemePanel panel : schemePanelsMap.values()) { + panel.save(); + } + } + + @Override + public void materialsChanged() { + rebuildLater(); + } + + @Override + public void stateChanged() { + rebuildLater(); + } + + @Override + public void fieldsChanged() { + rebuildLater(); + } + + private void rebuildLater() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + rebuildPanel(); + } + }); + } + + class LaplacianFieldHandler implements PropertyChangeListener, DictionaryListener { + private String key; + private DoubleField field; + + public LaplacianFieldHandler(String key, DoubleField field) { + this.key = key; + this.field = field; + laplaceModel.addDictionaryListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + String laplacianValue; + String snGradValue; + double value = field.getDoubleValue(); + if (value == 0) { + laplacianValue = GAUSS_LINEAR_UNCORRECTED; + snGradValue = "uncorrected"; + } else if (value == 1) { + laplacianValue = GAUSS_LINEAR_CORRECTED; + snGradValue = "corrected"; + } else { + laplacianValue = GAUSS_LINEAR_LIMITED + " " + Double.toString(value); + snGradValue = "limited" + " " + Double.toString(value); + } + laplaceModel.getDictionary().add("default", laplacianValue); + snGradModel.getDictionary().add("default", snGradValue); + } + } + + @Override + public void dictionaryChanged() throws DictionaryError { + if (laplaceModel.getDictionary().found(key)) { + String laplacianValue = laplaceModel.getDictionary().lookup(key); + double value; + if (laplacianValue.equals(GAUSS_LINEAR_UNCORRECTED)) { + value = 0; + } else if (laplacianValue.equals(GAUSS_LINEAR_CORRECTED)) { + value = 1; + } else if (laplacianValue.startsWith(GAUSS_LINEAR_LIMITED_CORRECTED)) { + laplacianValue = laplacianValue.replace(GAUSS_LINEAR_LIMITED_CORRECTED, ""); + value = Double.parseDouble(laplacianValue); + } else if (laplacianValue.startsWith(GAUSS_LINEAR_LIMITED)) { + laplacianValue = laplacianValue.replace(GAUSS_LINEAR_LIMITED, ""); + value = Double.parseDouble(laplacianValue); + } else { + throw new DictionaryError("Unknown Laplacian Scheme: " + laplacianValue); + } + + field.setValue(value); + } + } + } +} diff --git a/src/eu/engys/gui/casesetup/schemes/SchemePanel.java b/src/eu/engys/gui/casesetup/schemes/SchemePanel.java new file mode 100644 index 0000000..7b993e1 --- /dev/null +++ b/src/eu/engys/gui/casesetup/schemes/SchemePanel.java @@ -0,0 +1,136 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.schemes; + +import static eu.engys.util.ui.ComponentsFactory.doubleField; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JComboBox; +import javax.swing.JComponent; + +import net.java.dev.designgridlayout.Componentizer; +import eu.engys.gui.casesetup.schemes.AdvectionSchemes.Scheme; +import eu.engys.gui.casesetup.schemes.AdvectionSchemes.SchemeTemplate; +import eu.engys.util.ui.textfields.DoubleField; + +public class SchemePanel { + + private String fieldName; + private DoubleField value1; + private DoubleField value2; + private DoubleField value3; + private JComboBox choice; + private AdvectionSchemes schemes; + + public SchemePanel(AdvectionSchemes schemes, String fieldName) { + this.schemes = schemes; + this.fieldName = fieldName; + + layoutComponents(); + } + + void load() { + Scheme scheme = schemes.readScheme(fieldName); + choice.setSelectedItem(scheme.getTemplate()); + value1.setDoubleValue(scheme.getValue1()); + value2.setDoubleValue(scheme.getValue2()); + value3.setDoubleValue(scheme.getValue3()); + } + + void save() { + Scheme scheme = new Scheme(); + scheme.setField(fieldName); + scheme.setTemplate(choice.getItemAt(choice.getSelectedIndex())); + scheme.setValue1(value1.getDoubleValue()); + scheme.setValue2(value2.getDoubleValue()); + scheme.setValue3(value3.getDoubleValue()); + schemes.writeScheme(scheme); + } + + private void layoutComponents() { + value1 = doubleField(); + value2 = doubleField(); + value3 = doubleField(); + + value1.setVisible(false); + value2.setVisible(false); + value3.setVisible(false); + + value1.setName(fieldName + ".0"); + value2.setName(fieldName + ".1"); + value3.setName(fieldName + ".2"); + + choice = new JComboBox(); + choice.setName(fieldName); + + if (fieldName.equals("U")) { + for (SchemeTemplate scheme : schemes.getVectorSchemes()) { + choice.addItem(scheme); + } + } else { + for (SchemeTemplate scheme : schemes.getScalarSchemes()) { + choice.addItem(scheme); + } + } + + choice.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SchemeTemplate scheme = choice.getItemAt(choice.getSelectedIndex()); + if (scheme != null) { + value1.setVisible(scheme.hasValue1()); + value2.setVisible(scheme.hasValue2()); + value3.setVisible(scheme.hasValue3()); + } + } + }); + + // PropertyChangeListener listener = new PropertyChangeListener() { + // @Override + // public void propertyChange(PropertyChangeEvent evt) { + // if (evt.getPropertyName().equals("value")) { + // choice.setSelectedIndex(choice.getSelectedIndex()); + // if (choice.getSelectedIndex() == 5) { + // choice.setEnabled(false); + // } else { + // choice.setEnabled(true); + // } + // } + // } + // }; + + // value1.addPropertyChangeListener(listener); + // value2.addPropertyChangeListener(listener); + // advectionBuilder.addComponent(name, row); + } + + JComponent getPanel() { + return Componentizer.create().minToPref(choice).minAndMore(value1).minAndMore(value2).minAndMore(value3).component(); + } +} diff --git a/src/eu/engys/gui/casesetup/solution/AbstractSolutionModellingPanel.java b/src/eu/engys/gui/casesetup/solution/AbstractSolutionModellingPanel.java new file mode 100644 index 0000000..e8d0fcf --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/AbstractSolutionModellingPanel.java @@ -0,0 +1,419 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.modules.solutionmodelling.SolutionModellingPanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.TurbulenceModel; +import eu.engys.core.project.state.BuoyancyBuilder; +import eu.engys.core.project.state.Flow; +import eu.engys.core.project.state.Mach; +import eu.engys.core.project.state.Method; +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.state.SolverType; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.StateBuilder; +import eu.engys.core.project.state.Table15; +import eu.engys.core.project.state.ThermalState; +import eu.engys.core.project.state.Time; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.gui.casesetup.solution.panels.AbstractThermalPanel; +import eu.engys.gui.casesetup.solution.panels.GPanel; +import eu.engys.gui.casesetup.solution.panels.MultiphasePanel; +import eu.engys.gui.casesetup.solution.panels.SolutionStatePanel; +import eu.engys.gui.casesetup.solution.panels.TurbulencePanel; +import eu.engys.util.ui.ChooserPanel; +import eu.engys.util.ui.UiUtil; + +public abstract class AbstractSolutionModellingPanel extends DefaultGUIPanel implements SolutionModellingPanel { + + private static final Logger logger = LoggerFactory.getLogger(AbstractSolutionModellingPanel.class); + + private static final String STATE_CHANGED_WARNING = "Solution state has been changed.\nAll fields default settings are going to be reset now.\nContinue?"; + + public static final String SOLUTION_MODELLING = "Solution Modelling"; + + protected Set modules; + private Table15 solversTable; + + private SolutionStatePanel solutionStatePanel; + private MultiphasePanel multiphasePanel; + private AbstractThermalPanel thermalPanel; + private GPanel gPanel; + private TurbulencePanel turbulencePanel; + + public AbstractSolutionModellingPanel(Model model, Table15 solversTable, Set modules) { + super(SOLUTION_MODELLING, model); + this.solversTable = solversTable; + this.modules = modules; + } + + @Override + protected JComponent layoutComponents() { + JPanel topPanel = new JPanel(new GridBagLayout()); + + solutionStatePanel = new SolutionStatePanel(modules, isSolutionStatePanelVisible()); + + turbulencePanel = new TurbulencePanel(); + + multiphasePanel = createMultiphasePanel(); + final PropertyChangeListener multiphaseListener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("selection")) { + fix(); + } + } + }; + multiphasePanel.setListener(multiphaseListener); + + thermalPanel = createThermalPanel(); + ActionListener thermalListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fix(); + } + }; + thermalPanel.setThermalListener(thermalListener); + + gPanel = new GPanel(); + + PropertyChangeListener solutionStateListener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("selection")) { + multiphasePanel.removeListener(); + thermalPanel.removeListeners(); + + fix(); + + thermalPanel.addListeners(); + multiphasePanel.addListener(); + } + } + }; + solutionStatePanel.setListener(solutionStateListener); + + for (ApplicationModule m : modules) { + m.getSolutionView().buildDynamic(getDynamicBuilder()); + } + + for (ApplicationModule m : modules) { + m.getSolutionView().buildScalar(this); + } + + topPanel.add(solutionStatePanel, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + topPanel.add(turbulencePanel, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + + topPanel.add(multiphasePanel, new GridBagConstraints(0, 2, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + topPanel.add(thermalPanel, new GridBagConstraints(0, 3, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + topPanel.add(gPanel, new GridBagConstraints(0, 4, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + topPanel.add(getDynamicPanel(), new GridBagConstraints(0, 5, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + topPanel.add(getScalarsPanel(), new GridBagConstraints(0, 6, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + + topPanel.add(new JLabel(), new GridBagConstraints(0, 7, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + + fix(); + + return topPanel; + } + + protected abstract boolean isSolutionStatePanelVisible(); + + @Override + public void load() { + removeListeners(); + updateGUIFromState(); + addListeners(); + } + + @Override + public void save() { + if (stateHasChanged()) { + if (JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), STATE_CHANGED_WARNING, "State Changed", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { + _save(); + } else { + load(); + } + } + BuoyancyBuilder.save(model, gPanel.getGValue()); + } + + public void saveAnyway() { + _save(); + BuoyancyBuilder.save(model, gPanel.getGValue()); + } + + private void _save() { + updateStateFromGUI(); + StateBuilder.changeState(model, modules); + } + + private void updateStateFromGUI() { + State state = getStateFromGUI(); + model.setState(state); + } + + private boolean stateHasChanged() { + if (model.getPatches().isEmpty()) + return false; + + State state = model.getState(); + + SolverType solverType = solutionStatePanel.getSolverType(); + Time time = solutionStatePanel.getTime(); + Flow flow = solutionStatePanel.getFlow(); + Method method = solutionStatePanel.getMethod(); + Mach mach = solutionStatePanel.getMach(); + + boolean energy = thermalPanel.isEnergySelected(); + boolean buoyant = thermalPanel.isBuoyancySelected(); + + MultiphaseModel multiphase = this.multiphasePanel.getSelectedModel(); + int phases = this.multiphasePanel.getPhasesNumber(); + + TurbulenceModel turbulenceModel = turbulencePanel.getSelectedTurbulenceModel(); + + if (state.getSolverType() != solverType) { + logger.info("SOLVER TYPE [{} -> {}]", state.getSolverType(), solverType); + return true; + } + if (state.getFlow() != flow) { + logger.info("FLOW [{} -> {}]", state.getFlow(), flow); + return true; + } + if (state.getTime() != time) { + logger.info("TIME [{} -> {}]", state.getTime(), time); + return true; + } + if (state.getMethod() != method) { + logger.info("METHOD [{} -> {}]", state.getMethod(), method); + return true; + } + if (state.getMach() != mach) { + logger.info("MACH [{} -> {}]", state.getMach(), mach); + return true; + } + if (state.isEnergy() != energy) { + logger.info("ENERGY [{} -> {}]", state.isEnergy(), energy); + return true; + } + if (state.isBuoyant() != buoyant) { + logger.info("BUOYANT [{} -> {}]", state.isBuoyant(), buoyant); + return true; + } + if (turbulenceModel != null && !turbulenceModel.equals(state.getTurbulenceModel())) { + logger.info("TURBULENCE [{} -> {}]", state.getTurbulenceModel(), turbulenceModel); + return true; + } + if (state.getMultiphaseModel() != multiphase) { + logger.info("MULTIPHASE [{} -> {}]", state.getMultiphaseModel().getLabel(), multiphase.getLabel()); + return true; + } + if (state.getPhases() != phases) { + logger.info("PHASEs [{} -> {}]", state.getPhases(), phases); + return true; + } + + for (ApplicationModule m : modules) { + if (m.getSolutionView().hasChanged()) { + return true; + } + } + + return false; + } + + private State getStateFromGUI() { + State state = new State(); + + SolverType solverType = solutionStatePanel.getSolverType(); + Time time = solutionStatePanel.getTime(); + Flow flow = solutionStatePanel.getFlow(); + Method method = solutionStatePanel.getMethod(); + Mach mach = solutionStatePanel.getMach(); + + boolean energy = thermalPanel.isEnergySelected(); + boolean buoyant = thermalPanel.isBuoyancySelected(); + + MultiphaseModel multiphase = this.multiphasePanel.getSelectedModel(); + int phases = this.multiphasePanel.getPhasesNumber(); + + TurbulenceModel turbulenceModel = turbulencePanel.getSelectedTurbulenceModel(); + + if (state.getSolverType() != solverType) { + state.setSolverType(solverType); + } + if (state.getFlow() != flow) { + state.setFlow(flow); + } + if (state.getTime() != time) { + state.setTime(time); + } + if (state.getMethod() != method) { + state.setMethod(method); + } + if (state.getMach() != mach) { + state.setMach(mach); + } + if (state.isEnergy() != energy) { + state.setEnergy(energy); + } + if (state.isBuoyant() != buoyant) { + state.setBuoyant(buoyant); + } + if (turbulenceModel != null && !turbulenceModel.equals(state.getTurbulenceModel())) { + state.setTurbulenceModel(turbulenceModel); + } + if (state.getMultiphaseModel() != multiphase) { + state.setMultiphaseModel(multiphase); + } + if (state.getPhases() != phases) { + state.setPhases(phases); + } + + ModulesUtil.updateStateFromGUI(modules); + + // Solver Families + Set solverFamilies = new LinkedHashSet(); + solversTable.updateSolverFamilies(state, solverFamilies); + ModulesUtil.updateSolverFamilies(modules, state, solverFamilies); + + if (solverFamilies.isEmpty()) { + state.setSolverFamily(SolverFamily.NONE); + } else { + state.setSolverFamily(solverFamilies.iterator().next()); + } + + // Solver + solversTable.updateSolver(state); + ModulesUtil.updateSolver(modules, state); + + return state; + } + + private void updateGUIFromState() { + State state = model.getState(); + + solutionStatePanel.updateFromState(state); + solutionStatePanel.fix(new SolutionState(state)); + + multiphasePanel.updateFromState(state); + + thermalPanel.updateEnergyFromState(state); + thermalPanel.updateBuoyancyFromState(state); + gPanel.updateFromState(model, state); + + turbulencePanel.updateFromState(model, state); + + for (ApplicationModule m : modules) { + m.getSolutionView().updateGUIFromState(state); + } + } + + private void fix() { + SolutionState ss = solutionStatePanel.getSolutionState(); + solutionStatePanel.fix(ss); + multiphasePanel.fixSolutionState(ss); + for (ApplicationModule m : modules) { + m.getSolutionView().fixSolutionState(ss); + } + + MultiphaseModel mm = multiphasePanel.getSelectedModel(); + multiphasePanel.fixMultiphase(mm); + for (ApplicationModule m : modules) { + m.getSolutionView().fixMultiphase(mm); + } + + thermalPanel.fixEnergy(ss, mm); + thermalPanel.fixBuoyancy(ss, mm); + + ThermalState ts = thermalPanel.getThermalState(); + gPanel.fix(ss, mm, ts); + for (ApplicationModule m : modules) { + m.getSolutionView().fixThermal(ss, ts); + } + + turbulencePanel.fixSolutionState(model, ss); + } + + private void removeListeners() { + multiphasePanel.removeListener(); + thermalPanel.removeListeners(); + solutionStatePanel.removeListeners(); + } + + private void addListeners() { + multiphasePanel.addListener(); + thermalPanel.addListeners(); + solutionStatePanel.addListeners(); + } + + @Override + public ChooserPanel getSolverTypePanel() { + return solutionStatePanel.getSolverTypePanel(); + } + + @Override + public MultiphasePanel getMultiphasePanel() { + return multiphasePanel; + } + + protected abstract AbstractThermalPanel createThermalPanel(); + + protected abstract MultiphasePanel createMultiphasePanel(); + + protected abstract JComponent getDynamicPanel(); + + protected abstract JComponent getScalarsPanel(); + + // For test purpose only + public void setModules(Set modules) { + this.modules = modules; + } +} diff --git a/src/eu/engys/gui/casesetup/solution/StandardSolutionModellingPanel.java b/src/eu/engys/gui/casesetup/solution/StandardSolutionModellingPanel.java new file mode 100644 index 0000000..09ec993 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/StandardSolutionModellingPanel.java @@ -0,0 +1,109 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution; + +import java.util.Set; + +import javax.inject.Inject; +import javax.swing.JComponent; +import javax.swing.JLabel; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.Table15; +import eu.engys.gui.casesetup.solution.panels.AbstractThermalPanel; +import eu.engys.gui.casesetup.solution.panels.MultiphasePanel; +import eu.engys.util.ui.builder.PanelBuilder; + +public class StandardSolutionModellingPanel extends AbstractSolutionModellingPanel { + + @Inject + public StandardSolutionModellingPanel(Model model, Table15 solversTable, Set modules) { + super(model, solversTable, modules); + } + + @Override + protected MultiphasePanel createMultiphasePanel() { + return new MultiphasePanel(modules) { + public void fixSolutionState(SolutionState ss) { + if (ss.areSolverTypeAndTimeAndFlowAndTurbulenceChoosen()) { + if (ss.isCoupled() || ss.isSteady() || ss.isCompressible()) { + if (isMultiphaseOn()) { + setMultiphaseOff(); + } + multiphaseBuilder.setEnabled(false); + phasesNumber.setIntValue(1); + phasesNumber.setEnabled(false); + } else { + multiphaseBuilder.setEnabled(true); + // MODULES + } + } else { + multiphaseBuilder.setEnabled(false); + phasesNumber.setIntValue(1); + phasesNumber.setEnabled(false); + } + } + }; + } + + @Override + protected boolean isSolutionStatePanelVisible() { + return false; + } + + @Override + protected AbstractThermalPanel createThermalPanel() { + return new StandardThermalPanel(modules); + } + + @Override + public PanelBuilder getDynamicBuilder() { + return new PanelBuilder(); + } + + @Override + public PanelBuilder getScalarsBuilderLeft() { + return new PanelBuilder(); + } + + @Override + public PanelBuilder getScalarsBuilderRight() { + return new PanelBuilder(); + } + + @Override + protected JComponent getDynamicPanel() { + return new JLabel(); + } + + @Override + protected JComponent getScalarsPanel() { + return new JLabel(); + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/StandardThermalPanel.java b/src/eu/engys/gui/casesetup/solution/StandardThermalPanel.java new file mode 100644 index 0000000..e105a9f --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/StandardThermalPanel.java @@ -0,0 +1,72 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution; + +import java.util.Set; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.SolutionState; +import eu.engys.gui.casesetup.solution.panels.AbstractThermalPanel; + +public class StandardThermalPanel extends AbstractThermalPanel { + + public StandardThermalPanel(Set modules) { + super(modules); + } + + @Override + public void fixEnergy(SolutionState ss, MultiphaseModel mm) { + if (ss.areSolverTypeAndTimeAndFlowAndTurbulenceChoosen()) { + energy.setEnabled(true); + boolean isMultiphaseOn = mm.isOn(); + boolean isMultiphaseOff = mm.isOff(); + if (ss.isCompressible()) { + if ((isMultiphaseOn && energy.isSelected()) || (isMultiphaseOff && !energy.isSelected())) { + energy.doClick(); + } + energy.setEnabled(false); + } else if (ss.isIncompressible()) { + if (energy.isSelected() && isMultiphaseOn) { + energy.doClick(); + } + energy.setEnabled(isMultiphaseOff); + } + } else { + energy.setEnabled(false); + } + + if (ss.areSolverTypeAndTimeAndFlowAndTurbulenceChoosen()) { + if (ss.isTransient() && ss.isLES()) { + if (energy.isSelected()) { + energy.doClick(); + } + energy.setEnabled(false); + } + } + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/AbstractThermalPanel.java b/src/eu/engys/gui/casesetup/solution/panels/AbstractThermalPanel.java new file mode 100644 index 0000000..e115e7a --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/AbstractThermalPanel.java @@ -0,0 +1,164 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import java.awt.BorderLayout; +import java.awt.event.ActionListener; +import java.util.Set; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JPanel; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.ThermalState; +import eu.engys.util.ui.builder.PanelBuilder; + +public abstract class AbstractThermalPanel extends JPanel { + + public static final String BUOYANCY = "Buoyancy"; + public static final String ENERGY = "Energy"; + public static final String THERMAL = "Thermal"; + + private Set modules; + private ActionListener listener; + protected JCheckBox energy; + private JCheckBox buoyancy; + + public AbstractThermalPanel(Set modules) { + super(new BorderLayout()); + this.modules = modules; + layoutComponents(); + } + + + private void layoutComponents() { + PanelBuilder builder = new PanelBuilder(); + this.energy = (JCheckBox) builder.startCheck(ENERGY); + + this.buoyancy = (JCheckBox) builder.startCheck(BUOYANCY); + buoyancy.setName(BUOYANCY); + builder.endCheck(); + + for (ApplicationModule m : modules) { + m.getSolutionView().buildThermal(builder); + } + + builder.endCheck(false); + + JPanel panel = builder.getPanel(); + panel.setBorder(BorderFactory.createTitledBorder(AbstractThermalPanel.THERMAL)); + add(panel, BorderLayout.CENTER); + } + + public abstract void fixEnergy(SolutionState ss, MultiphaseModel mm); + + public void fixBuoyancy(SolutionState ss, MultiphaseModel mm) { + if (ss.areSolverTypeAndTimeAndFlowAndTurbulenceChoosen()) { + if (ss.isCoupled()) { + if (buoyancy.isSelected()) { + buoyancy.setEnabled(true); + buoyancy.doClick(); + } + buoyancy.setEnabled(false); + } else { + boolean isTransientCompressibleLES = ss.isTransient() && ss.isCompressible() && ss.isLES(); + buoyancy.setEnabled(true); + if (buoyancy.isSelected() && (!energy.isSelected() || isTransientCompressibleLES || ss.isHighMach())) { + buoyancy.doClick(); + } + buoyancy.setEnabled(energy.isSelected() && !isTransientCompressibleLES && ss.isLowMach()); + } + } else { + buoyancy.setEnabled(false); + } + } + + public void updateEnergyFromState(State state) { + boolean energyEnabled = energy.isEnabled(); + energy.setEnabled(true); + if (state.isEnergy()) { + if (!energy.isSelected()) { + energy.doClick(); + } + } else { + if (energy.isSelected()) { + energy.doClick(); + } + } + energy.setEnabled(energyEnabled); + fixEnergy(new SolutionState(state), state.getMultiphaseModel()); + } + + public void updateBuoyancyFromState(State state) { + boolean buoyancyEnabled = buoyancy.isEnabled(); + buoyancy.setEnabled(true); + if (state.isBuoyant()) { + if (!buoyancy.isSelected()) { + buoyancy.doClick(); + } + } else { + if (buoyancy.isSelected()) { + buoyancy.doClick(); + } + } + buoyancy.setEnabled(buoyancyEnabled); + fixBuoyancy(new SolutionState(state), state.getMultiphaseModel()); + } + + public ThermalState getThermalState() { + ThermalState ts = new ThermalState(); + ts.setEnergy(energy.isSelected()); + ts.setBuoyancy(buoyancy.isSelected()); + return ts; + } + + public void removeListeners() { + energy.removeActionListener(listener); + buoyancy.removeActionListener(listener); + } + + public void addListeners() { + energy.addActionListener(listener); + buoyancy.addActionListener(listener); + } + + public void setThermalListener(ActionListener listener) { + this.listener = listener; + } + + public boolean isEnergySelected(){ + return energy.isSelected(); + } + + public boolean isBuoyancySelected(){ + return buoyancy.isSelected(); + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/FlowPanel.java b/src/eu/engys/gui/casesetup/solution/panels/FlowPanel.java new file mode 100644 index 0000000..810d495 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/FlowPanel.java @@ -0,0 +1,71 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import static eu.engys.core.project.state.SolutionState.COMPRESSIBLE; +import static eu.engys.core.project.state.SolutionState.INCOMPRESSIBLE; +import eu.engys.core.project.state.Flow; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.ChooserPanel; + +public class FlowPanel extends ChooserPanel { + + public static final String FLOW = "Flow"; + + public FlowPanel() { + super(FLOW); + addChoice(COMPRESSIBLE); + addChoice(INCOMPRESSIBLE); + } + + public void updateFromState(State state) { + if (state.isCompressible()) + select(COMPRESSIBLE); + else if (state.isIncompressible()) + select(INCOMPRESSIBLE); + else + selectNone(); + + } + + public Flow getFlow() { + String selectedState = getSelectedState(); + if (selectedState.equals(COMPRESSIBLE)) + return Flow.COMPRESSIBLE; + else if (selectedState.equals(INCOMPRESSIBLE)) + return Flow.INCOMPRESSIBLE; + return Flow.NONE; + } + + public boolean isCompressible() { + return getSelectedState().equals(COMPRESSIBLE); + } + + public boolean isIncompressible() { + return getSelectedState().equals(INCOMPRESSIBLE); + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/GPanel.java b/src/eu/engys/gui/casesetup/solution/panels/GPanel.java new file mode 100644 index 0000000..7d4d032 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/GPanel.java @@ -0,0 +1,102 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import static eu.engys.util.ui.ComponentsFactory.doublePointField; + +import java.awt.BorderLayout; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.ThermalState; +import eu.engys.util.Symbols; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; + +public class GPanel extends JPanel { + + public static final String G = "g [m/s" + Symbols.SQUARE + "]"; + public static final String GRAVITY = "Gravity"; + private PanelBuilder builder; + private DoubleField[] gFields; + + public GPanel() { + super(new BorderLayout()); + layoutComponents(); + } + + private void layoutComponents() { + builder = new PanelBuilder(); + gFields = doublePointField(0.0, 0.0, -9.81); + builder.addComponent(GPanel.G, gFields); + JPanel gPanel = builder.getPanel(); + gPanel.setBorder(BorderFactory.createTitledBorder(GPanel.GRAVITY)); + add(gPanel, BorderLayout.CENTER); + } + + public void fix(SolutionState ss, MultiphaseModel mm, ThermalState ts) { + if (ss.areSolverTypeAndTimeAndFlowAndTurbulenceChoosen()) { + if (mm.isOn()) { + builder.setEnabled(true); + } else if (ts.isBuoyancy()) { + builder.setEnabled(true); + } else { + builder.setEnabled(false); + } + } else { + builder.setEnabled(false); + } + } + + public void updateFromState(Model model, State state) { + Dictionary g = model.getProject().getConstantFolder().getG(); + if (g != null && g.found("value")) { + String[] gValues = g.lookupArray("value"); + try { + double x = Double.parseDouble(gValues[0]); + double y = Double.parseDouble(gValues[1]); + double z = Double.parseDouble(gValues[2]); + + gFields[0].setValue(x); + gFields[1].setValue(y); + gFields[2].setValue(z); + } catch (Exception e) { + } + } + fix(new SolutionState(state), state.getMultiphaseModel(), new ThermalState(state)); + } + + public double[] getGValue() { + return new double[] { gFields[0].getDoubleValue(), gFields[1].getDoubleValue(), gFields[2].getDoubleValue() }; + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/MachPanel.java b/src/eu/engys/gui/casesetup/solution/panels/MachPanel.java new file mode 100644 index 0000000..797abd0 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/MachPanel.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import eu.engys.core.project.state.Mach; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.ChooserPanel; + +public class MachPanel extends ChooserPanel { + + public static final String MACH = "Mach"; + + public MachPanel() { + super(MACH); + addChoice(SolutionState.LO_MACH); + addChoice(SolutionState.HI_MACH); + } + + public void updateFromState(State state) { + if (state.isLowMach()) + select(SolutionState.LO_MACH); + else if (state.isHighMach()) + select(SolutionState.HI_MACH); + else + selectNone(); + + } + + public Mach getMach() { + String selectedState = getSelectedState(); + if (selectedState.equals(SolutionState.HI_MACH)) + return Mach.HIGH; + else if (selectedState.equals(SolutionState.LO_MACH)) + return Mach.LOW; + return Mach.NONE; + } + + public boolean isHighMach() { + return getSelectedState().equals(SolutionState.HI_MACH); + } + + public boolean isLowMach() { + return getSelectedState().equals(SolutionState.LO_MACH); + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/MethodPanel.java b/src/eu/engys/gui/casesetup/solution/panels/MethodPanel.java new file mode 100644 index 0000000..116980e --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/MethodPanel.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import eu.engys.core.project.state.Method; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.ChooserPanel; + +public class MethodPanel extends ChooserPanel { + + public static final String TURBULENCE = "Turbulence"; + + public MethodPanel() { + super(TURBULENCE); + addChoice(SolutionState.RANS); + addChoice(SolutionState.LES_DES); + } + + public void updateFromState(State state) { + if (state.isLES()) + select(SolutionState.LES_DES); + else if (state.isRANS()) + select(SolutionState.RANS); + else + selectNone(); + + } + + public Method getMethod() { + String selectedState = getSelectedState(); + if (selectedState.equals(SolutionState.LES_DES)) + return Method.LES; + else if (selectedState.equals(SolutionState.RANS)) + return Method.RANS; + return Method.NONE; + } + + public boolean isLES() { + return getSelectedState().equals(SolutionState.LES_DES); + } + + public boolean isRAS() { + return getSelectedState().equals(SolutionState.RANS); + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/MultiphaseChooserPanel.java b/src/eu/engys/gui/casesetup/solution/panels/MultiphaseChooserPanel.java new file mode 100644 index 0000000..62cde4a --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/MultiphaseChooserPanel.java @@ -0,0 +1,101 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; + +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.util.ui.ChooserPanel; + +public class MultiphaseChooserPanel { + + private ChooserPanel chooserPanel; + private Map solvers = new HashMap<>(); + + public MultiphaseChooserPanel() { + chooserPanel = new ChooserPanel("", false); + } + + public void addMultiphaseChoice(MultiphaseModel multiphase) { + chooserPanel.addChoice(multiphase.getLabel()); + solvers.put(multiphase.getLabel(), multiphase); + } + + public MultiphaseModel getSelectedMultiphase() { + String selectedState = chooserPanel.getSelectedState(); + return selectedState == ChooserPanel.NONE ? MultiphaseModel.OFF : solvers.get(selectedState); + } + + public void select(MultiphaseModel model) { + chooserPanel.select(model.getLabel()); + } + + public void selectNone() { + chooserPanel.selectNone(); + } + + public void addListener(PropertyChangeListener listener) { + chooserPanel.addPropertyChangeListener(listener); + } + + public void removeListener(PropertyChangeListener listener) { + chooserPanel.removePropertyChangeListener(listener); + } + + public boolean isMultiphaseOff() { + return chooserPanel.getSelectedState().equals(MultiphaseModel.OFF_LABEL); + } + + public void setMultiphaseOff() { + chooserPanel.select(MultiphaseModel.OFF_LABEL); + } + + public JComponent getChooserPanel() { + return chooserPanel; + } + + public void enableChoice(MultiphaseModel mm) { + AbstractButton button = chooserPanel.getButton(mm.getLabel()); + if (!button.isEnabled()) { + button.setEnabled(true); + } + } + + public void disableChoice(MultiphaseModel mm) { + AbstractButton button = chooserPanel.getButton(mm.getLabel()); + if (button.isSelected()) { + select(MultiphaseModel.OFF); + } + if (button.isEnabled()) { + button.setEnabled(false); + } + } +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/MultiphasePanel.java b/src/eu/engys/gui/casesetup/solution/panels/MultiphasePanel.java new file mode 100644 index 0000000..c81c66c --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/MultiphasePanel.java @@ -0,0 +1,159 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import java.awt.BorderLayout; +import java.beans.PropertyChangeListener; +import java.util.Set; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.solutionmodelling.MultiphaseBuilder; +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.SpinnerField; + +public class MultiphasePanel extends JPanel implements MultiphaseBuilder { + + public static final String PHASES_LABEL = "Phases"; + private static final String MULTIPHASE = "Multiphase"; + + protected SpinnerField phasesNumber; + protected MultiphaseChooserPanel multiphaseChooser; + protected PanelBuilder multiphaseBuilder; + private PropertyChangeListener listener; + + public MultiphasePanel(Set modules) { + super(new BorderLayout()); + + multiphaseChooser = new MultiphaseChooserPanel(); + multiphaseChooser.addMultiphaseChoice(MultiphaseModel.OFF); + + phasesNumber = ComponentsFactory.spinnerField(2, Integer.MAX_VALUE); + phasesNumber.setEnabled(false); + + PanelBuilder phaseBuilderLeft = new PanelBuilder(); + PanelBuilder phaseBuilderRight = new PanelBuilder(); + phaseBuilderLeft.addComponent(multiphaseChooser.getChooserPanel()); + phaseBuilderRight.addComponent(PHASES_LABEL, phasesNumber); + + multiphaseBuilder = new PanelBuilder(); + multiphaseBuilder.addComponent(phaseBuilderLeft.removeMargins().getPanel(), phaseBuilderRight.removeMargins().getPanel()); + multiphaseBuilder.getPanel().setBorder(BorderFactory.createTitledBorder(MULTIPHASE)); + + add(multiphaseBuilder.getPanel()); + + for (ApplicationModule m : modules) { + m.getSolutionView().buildMultiphase(this); + } + } + + public void updateFromState(State state) { + MultiphaseModel multiphaseModel = state.getMultiphaseModel(); + if (multiphaseModel != null) { + multiphaseChooser.select(multiphaseModel); + } else { + multiphaseChooser.selectNone(); + } + if (multiphaseModel.isMultiphase()) { + phasesNumber.setIntValue(Math.max(2, state.getPhases())); + } else { + phasesNumber.setIntValue(1); + } + + fixSolutionState(new SolutionState(state)); + fixMultiphase(getSelectedModel()); + } + + public void fixSolutionState(SolutionState solutionState) { + } + + public void fixMultiphase(MultiphaseModel mm) { + if (mm.isOff()) { + phasesNumber.setIntValue(1); + phasesNumber.setEnabled(false); + } + } + + @Override + public void addMultiphaseChoice(MultiphaseModel mm) { + multiphaseChooser.addMultiphaseChoice(mm); + } + + public MultiphaseChooserPanel getPhasesPanel() { + return multiphaseChooser; + } + + @Override + public SpinnerField getPhasesField() { + return phasesNumber; + } + + public int getPhasesNumber() { + return phasesNumber.getIntValue(); + } + + public MultiphaseModel getSelectedModel() { + return multiphaseChooser.getSelectedMultiphase(); + } + + public void addListener() { + multiphaseChooser.addListener(listener); + } + + public void removeListener() { + multiphaseChooser.removeListener(listener); + } + + public boolean isMultiphaseOn() { + return !isMultiphaseOff(); + } + + public boolean isMultiphaseOff() { + return multiphaseChooser.isMultiphaseOff(); + } + + protected void setMultiphaseOff() { + multiphaseChooser.setMultiphaseOff(); + } + + public void enableChoice(MultiphaseModel mm) { + multiphaseChooser.enableChoice(mm); + } + + public void disableChoice(MultiphaseModel mm) { + multiphaseChooser.disableChoice(mm); + } + + public void setListener(PropertyChangeListener listener) { + this.listener = listener; + } +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/SolutionStatePanel.java b/src/eu/engys/gui/casesetup/solution/panels/SolutionStatePanel.java new file mode 100644 index 0000000..c870451 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/SolutionStatePanel.java @@ -0,0 +1,225 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.beans.PropertyChangeListener; +import java.util.Set; + +import javax.swing.JPanel; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.state.Flow; +import eu.engys.core.project.state.Mach; +import eu.engys.core.project.state.Method; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.SolverType; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.Time; + +public class SolutionStatePanel extends JPanel { + + protected SolverTypePanel solverTypePanel; + protected TimePanel timePanel; + protected FlowPanel flowPanel; + protected MethodPanel methodPanel; + protected MachPanel machPanel; + + private PropertyChangeListener listener; + private Set modules; + + public SolutionStatePanel(Set modules, boolean visibleSolverType) { + super(new GridBagLayout()); + this.modules = modules; + layoutComponents(visibleSolverType); + } + + public void setListener(PropertyChangeListener listener) { + this.listener = listener; + } + + private void layoutComponents(boolean visibleSolverType) { + solverTypePanel = new SolverTypePanel(); + timePanel = new TimePanel(); + flowPanel = new FlowPanel(); + methodPanel = new MethodPanel(); + machPanel = new MachPanel(); + + + if (visibleSolverType) { + add(solverTypePanel, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + add(timePanel, new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + add(flowPanel, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + add(methodPanel, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + add(machPanel, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + } else { + add(timePanel, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + add(flowPanel, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + add(methodPanel, new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + add(machPanel, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + } + + for (ApplicationModule m : modules) { + m.getSolutionView().buildSolution(solverTypePanel); + } + } + + public void updateFromState(State state) { + solverTypePanel.updateFromState(state); + timePanel.updateFromState(state); + flowPanel.updateFromState(state); + methodPanel.updateFromState(state); + machPanel.updateFromState(state); + } + + public void fix(SolutionState ss) { + if (ss.isSolverNone()) { + timePanel.setEnabled(false); + methodPanel.setEnabled(false); + flowPanel.setEnabled(false); + machPanel.setEnabled(false); + } else { + timePanel.setEnabled(true); + if (ss.isSegregated()) { + if (ss.isTimeNone()) { + methodPanel.setEnabled(false); + flowPanel.setEnabled(false); + machPanel.setEnabled(false); + } else { + methodPanel.setEnabled(true); + flowPanel.setEnabled(true); + machPanel.setEnabled(true); + if (ss.isSteady()) { + methodPanel.setEnabled(false); + methodPanel.select(SolutionState.RANS); + machPanel.setEnabled(false); + machPanel.select(SolutionState.LO_MACH); + } else if (ss.isTransient()) { + if (ss.isFlowNone()) { + methodPanel.setEnabled(false); + machPanel.setEnabled(false); + } else { + methodPanel.setEnabled(true); + if (ss.isCompressible()) { + machPanel.setEnabled(true); + if (ss.isMachNone()) { + machPanel.select(SolutionState.LO_MACH); + } + } else if (ss.isIncompressible()) { + machPanel.setEnabled(false); + machPanel.select(SolutionState.LO_MACH); + } + } + } + } + } else if (ss.isCoupled()) { + flowPanel.select(SolutionState.INCOMPRESSIBLE); + flowPanel.setEnabled(false); + methodPanel.select(SolutionState.RANS); + methodPanel.setEnabled(false); + machPanel.select(SolutionState.LO_MACH); + machPanel.setEnabled(false); + } + } + } + + public SolutionState getSolutionState() { + SolutionState ss = new SolutionState(); + ss.time = timePanel.getSelectedState(); + ss.flow = flowPanel.getSelectedState(); + ss.turbulence = methodPanel.getSelectedState(); + ss.solver = solverTypePanel.getSelectedState(); + ss.mach = machPanel.getSelectedState(); + return ss; + } + + public void removeListeners() { + solverTypePanel.removePropertyChangeListener(listener); + timePanel.removePropertyChangeListener(listener); + flowPanel.removePropertyChangeListener(listener); + methodPanel.removePropertyChangeListener(listener); + machPanel.removePropertyChangeListener(listener); + } + + public void addListeners() { + solverTypePanel.addPropertyChangeListener(listener); + timePanel.addPropertyChangeListener(listener); + flowPanel.addPropertyChangeListener(listener); + methodPanel.addPropertyChangeListener(listener); + machPanel.addPropertyChangeListener(listener); + } + + public SolverTypePanel getSolverTypePanel() { + return solverTypePanel; + } + + public SolverType getSolverType() { + return solverTypePanel.getSolverType(); + } + + public Time getTime() { + return timePanel.getTime(); + } + + public Flow getFlow() { + return flowPanel.getFlow(); + } + + public Method getMethod() { + return methodPanel.getMethod(); + } + + public Mach getMach() { + return machPanel.getMach(); + } + + public boolean isCoupled() { + return solverTypePanel.isCoupled(); + } + + public boolean isSegregated() { + return solverTypePanel.isSegregated(); + } + + public boolean isCompressible() { + return flowPanel.isCompressible(); + } + + public boolean isIncompressible() { + return flowPanel.isIncompressible(); + } + + public boolean isLES() { + return methodPanel.isLES(); + } + + public boolean isRAS() { + return methodPanel.isRAS(); + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/SolverTypePanel.java b/src/eu/engys/gui/casesetup/solution/panels/SolverTypePanel.java new file mode 100644 index 0000000..9ffff3d --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/SolverTypePanel.java @@ -0,0 +1,71 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.SolverType; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.ChooserPanel; + +public class SolverTypePanel extends ChooserPanel { + + public static final String SOLVER_TYPE = "Solver Type"; + + public SolverTypePanel() { + super(SOLVER_TYPE, false); + addChoice(SolutionState.SEGREGATED); + addChoice(SolutionState.COUPLED); + getButton(SolutionState.COUPLED).setEnabled(false); + } + + public void updateFromState(State state) { + if (state.getSolverType().isSegregated()) { + select(SolutionState.SEGREGATED); + } else if (state.getSolverType().isCoupled()) { + select(SolutionState.COUPLED); + } else { + selectNone(); + } + } + + public SolverType getSolverType() { + String selectedState = getSelectedState(); + if (selectedState.equals(SolutionState.SEGREGATED)) + return SolverType.SEGREGATED; + if (selectedState.equals(SolutionState.COUPLED)) + return SolverType.COUPLED; + return SolverType.NONE; + } + + public boolean isCoupled() { + return getSelectedState().equals(SolutionState.COUPLED); + } + + public boolean isSegregated() { + return getSelectedState().equals(SolutionState.SEGREGATED); + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/TimePanel.java b/src/eu/engys/gui/casesetup/solution/panels/TimePanel.java new file mode 100644 index 0000000..61bc0c7 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/TimePanel.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import static eu.engys.core.project.state.SolutionState.STEADY; +import static eu.engys.core.project.state.SolutionState.TRANSIENT; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.Time; +import eu.engys.util.ui.ChooserPanel; + +public class TimePanel extends ChooserPanel { + + public static final String TIME = "Time"; + + public TimePanel() { + super(TimePanel.TIME); + addChoice(STEADY); + addChoice(TRANSIENT); + } + + public void updateFromState(State state) { + if (state.isSteady()) + select(STEADY); + else if (state.isTransient()) + select(TRANSIENT); + else + selectNone(); + } + + public Time getTime() { + String selectedState = getSelectedState(); + if (selectedState.equals(STEADY)) + return Time.STEADY; + else if (selectedState.equals(TRANSIENT)) + return Time.TRANSIENT; + return Time.NONE; + } + + public boolean isSteady() { + return getSelectedState().equals(STEADY); + } + + public boolean isTransient() { + return getSelectedState().equals(TRANSIENT); + } + +} diff --git a/src/eu/engys/gui/casesetup/solution/panels/TurbulencePanel.java b/src/eu/engys/gui/casesetup/solution/panels/TurbulencePanel.java new file mode 100644 index 0000000..e3cc9c6 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solution/panels/TurbulencePanel.java @@ -0,0 +1,119 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solution.panels; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.util.List; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; + +import eu.engys.core.project.Model; +import eu.engys.core.project.TurbulenceModel; +import eu.engys.core.project.state.Flow; +import eu.engys.core.project.state.Method; +import eu.engys.core.project.state.SolutionState; +import eu.engys.core.project.state.SolverType; +import eu.engys.core.project.state.State; +import eu.engys.util.ui.builder.PanelBuilder; + +public class TurbulencePanel extends JPanel { + + public static final String TURBULENCE_MODEL = "Turbulence Model"; + private JComboBox modelsCombo; + + public TurbulencePanel() { + super(new BorderLayout()); + layoutComponents(); + } + + private void layoutComponents() { + modelsCombo = new JComboBox(); + modelsCombo.setPrototypeDisplayValue(new TurbulenceModel("", "MMMMMMM")); + final ListCellRenderer renderer = modelsCombo.getRenderer(); + modelsCombo.setRenderer(new ListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, TurbulenceModel value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (c instanceof JLabel && value instanceof TurbulenceModel) { + TurbulenceModel model = (TurbulenceModel) value; + ((JLabel) c).setText(model.getDescription()); + } + return c; + } + }); + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(TurbulencePanel.TURBULENCE_MODEL, modelsCombo); + add(builder.margins(.5, 0, .5, 0).getPanel(), BorderLayout.CENTER); + } + + public TurbulenceModel getSelectedTurbulenceModel() { + return (TurbulenceModel) modelsCombo.getSelectedItem(); + } + + public void updateTurbulenceModels(Model model, SolverType solvertype, Method method, Flow flow) { + Object selectedItem = modelsCombo.getSelectedItem(); + + List models = model.getTurbulenceModels().getModelsForState(solvertype, method, flow); + modelsCombo.removeAllItems(); + TurbulenceModel laminar = null; + for (TurbulenceModel turbModel : models) { + modelsCombo.addItem(turbModel); + if (turbModel.getType().isLaminar()) { + laminar = turbModel; + } + } + + if (((DefaultComboBoxModel) modelsCombo.getModel()).getIndexOf(selectedItem) < 0) { + modelsCombo.setSelectedItem(laminar); + } else { + modelsCombo.setSelectedItem(selectedItem); + } + } + + public void updateFromState(Model model, State state) { + updateTurbulenceModels(model, state.getSolverType(), state.getMethod(), state.getFlow()); + + if (state.getTurbulenceModel() != null) { + modelsCombo.setSelectedItem(state.getTurbulenceModel()); + } else { + modelsCombo.setSelectedIndex(-1); + } + } + + public void fixSolutionState(Model model, SolutionState ss) { + SolverType solvertype = ss.isCoupled() ? SolverType.COUPLED : ss.isSegregated() ? SolverType.SEGREGATED : SolverType.NONE; + Method method = ss.isLES() ? Method.LES : ss.isRANS() ? Method.RANS : Method.NONE; + Flow flow = ss.isCompressible() ? Flow.COMPRESSIBLE : ss.isIncompressible() ? Flow.INCOMPRESSIBLE : Flow.NONE; + updateTurbulenceModels(model, solvertype, method, flow); + } + +} diff --git a/src/eu/engys/gui/casesetup/solver/SolverSettingsBuilder.java b/src/eu/engys/gui/casesetup/solver/SolverSettingsBuilder.java new file mode 100644 index 0000000..84ea771 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solver/SolverSettingsBuilder.java @@ -0,0 +1,200 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solver; + +import static eu.engys.core.project.system.ControlDict.MAX_ALPHA_CO_KEY; +import static eu.engys.core.project.system.ControlDict.MAX_CO_KEY; +import static eu.engys.core.project.system.FvSolution.EQUATIONS_KEY; +import static eu.engys.core.project.system.FvSolution.FIELDS_KEY; +import static eu.engys.core.project.system.FvSolution.N_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.N_NON_ORTHOGONAL_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.N_OUTER_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.RELAXATION_FACTORS_KEY; +import static eu.engys.core.project.system.FvSolution.RESIDUAL_CONTROL_KEY; +import static eu.engys.core.project.system.FvSolution.RHO_MAX_KEY; +import static eu.engys.core.project.system.FvSolution.RHO_MIN_KEY; +import static eu.engys.core.project.system.FvSolution.SONIC_KEY; +import static eu.engys.core.project.zero.fields.Fields.FINAL; +import static eu.engys.core.project.zero.fields.Fields.P; +import static eu.engys.core.project.zero.fields.Fields.P_RGH; +import static eu.engys.core.project.zero.fields.Fields.RHO; +import eu.engys.core.dictionary.DefaultElement; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.casesetup.solver.panels.SolverPanel; + +public class SolverSettingsBuilder { + + public static void build(Model model, SolverPanel solverPanel) { + Dictionary fvSolution = model.getProject().getSystemFolder().getFvSolution(); + Dictionary solverDictionary = solverPanel.getSolverDictionary(); + Dictionary relaxationDictionary = solverPanel.getRelaxationFactorsDictionary(); + Dictionary residualDictionary = solverPanel.getResidualControlDictionary(); + + buildSolverSection(fvSolution, solverDictionary, residualDictionary); + buildRelaxationFactorsSection(fvSolution, relaxationDictionary); + + if (model.getState().isHighMach()) { + fvSolution.add(SONIC_KEY, "true"); + } else if (fvSolution.found(SONIC_KEY)) { + fvSolution.remove(SONIC_KEY); + } + } + + private static void buildSolverSection(Dictionary fvSolution, Dictionary solverDictionary, Dictionary residualControl) { + Dictionary solver = fvSolution.subDict(solverDictionary.getName()); // SIMPLE-PIMPLEorPISO + if (solver != null) { + if (solverDictionary.found(N_NON_ORTHOGONAL_CORRECTORS_KEY)) { + solver.add(N_NON_ORTHOGONAL_CORRECTORS_KEY, solverDictionary.lookup(N_NON_ORTHOGONAL_CORRECTORS_KEY)); + } + if (solverDictionary.found(N_CORRECTORS_KEY)) { + solver.add(N_CORRECTORS_KEY, solverDictionary.lookup(N_CORRECTORS_KEY)); + } + if (solverDictionary.found(N_OUTER_CORRECTORS_KEY)) { + solver.add(N_OUTER_CORRECTORS_KEY, solverDictionary.lookup(N_OUTER_CORRECTORS_KEY)); + } + if (solverDictionary.found(RHO_MIN_KEY)) { + solver.add(solverDictionary.lookupScalar(RHO_MIN_KEY)); + } + if (solverDictionary.found(RHO_MAX_KEY)) { + solver.add(solverDictionary.lookupScalar(RHO_MAX_KEY)); + } + if (solverDictionary.found(MAX_CO_KEY)) { + solver.add(MAX_CO_KEY, solverDictionary.lookupString(MAX_CO_KEY)); + } + if (solverDictionary.found(MAX_ALPHA_CO_KEY)) { + solver.add(MAX_ALPHA_CO_KEY, solverDictionary.lookupString(MAX_ALPHA_CO_KEY)); + } + if (residualControl != null) { + if (solver.found(RESIDUAL_CONTROL_KEY)) { + solver.subDict(RESIDUAL_CONTROL_KEY).merge(residualControl); + } else { + solver.add(residualControl); + } + } else { + if (solver.found(RESIDUAL_CONTROL_KEY)) { + solver.remove(RESIDUAL_CONTROL_KEY); + } + } + } + } + + private static void buildRelaxationFactorsSection(Dictionary fvSolution, Dictionary relFactorsDictionaryForGUI) { + Dictionary relaxationFactors = fvSolution.subDict(RELAXATION_FACTORS_KEY); + if (relaxationFactors != null) { + relaxationFactors.merge(encodeRelaxactionFactorsForSaving(relFactorsDictionaryForGUI)); + } + } + + private static Dictionary encodeRelaxactionFactorsForSaving(Dictionary relFactorsDictionaryForGUI) { + Dictionary relFactorsDict = new Dictionary(RELAXATION_FACTORS_KEY); + Dictionary fieldsDict = new Dictionary(FIELDS_KEY); + Dictionary equationsDict = new Dictionary(EQUATIONS_KEY); + relFactorsDict.add(fieldsDict); + relFactorsDict.add(equationsDict); + + for (FieldElement field : relFactorsDictionaryForGUI.getFields()) { + String name = field.getName(); + if (goesToFieldSection(name)) { + fieldsDict.add(name, relFactorsDictionaryForGUI.lookup(name)); + } else { + equationsDict.add(name, relFactorsDictionaryForGUI.lookup(name)); + } + } + return relFactorsDict; + } + + private static boolean goesToFieldSection(String name) { + boolean isP = name.equals(P) || name.equals(P + FINAL); + boolean isPrgh = name.equals(P_RGH) || name.equals(P_RGH + FINAL); + boolean isRho = name.equals(RHO) || name.equals(RHO + FINAL); + return isP || isPrgh || isRho; + } + + /** + * li mette tutti in un unico dictionary + */ + public static Dictionary decodeRelaxationFactorsForGUI(Model model, Dictionary relaxationFactorsDict) { + if (relaxationFactorsDict.found(FIELDS_KEY)) { // formato nuovo + Dictionary fieldsDict = relaxationFactorsDict.subDict(FIELDS_KEY); + Dictionary equationsDict = relaxationFactorsDict.subDict(EQUATIONS_KEY); + Dictionary relFactorsDictionaryForGUI = new Dictionary(RELAXATION_FACTORS_KEY); + for (FieldElement field : fieldsDict.getFields()) { + String name = field.getName(); + relFactorsDictionaryForGUI.add(name, fieldsDict.lookup(name)); + } + for (FieldElement field : equationsDict.getFields()) { + String name = field.getName(); + relFactorsDictionaryForGUI.add(name, equationsDict.lookup(name)); + } + fixAlphas(model, relFactorsDictionaryForGUI); + return relFactorsDictionaryForGUI; + } else { // ho il vecchio formato + return new Dictionary(relaxationFactorsDict); + } + } + + private static void fixAlphas(Model model, Dictionary relFactorsDictionaryForGUI) { + for (FieldElement field : relFactorsDictionaryForGUI.getFields()) { + String name = field.getName(); + if (model.getState().getMultiphaseModel().isMultiphase()) { + if (model.getFields().containsKey(Fields.ALPHA_1)) { + fixAlphasForVOF(model, relFactorsDictionaryForGUI, name); + } else { + fixAlphasForEuler(model, relFactorsDictionaryForGUI, name); + } + } + + } + } + + private static void fixAlphasForVOF(Model model, Dictionary relFactorsDictionaryForGUI, String name) { + if (name.equals("\"" + Fields.ALPHA + ".*\"")) { + DefaultElement alpha = relFactorsDictionaryForGUI.remove(name); + alpha.setName(Fields.ALPHA_1); + relFactorsDictionaryForGUI.add(alpha); + } else if (name.equals("\"" + Fields.ALPHA + ".*Final\"")) { + DefaultElement alpha = relFactorsDictionaryForGUI.remove(name); + alpha.setName(Fields.ALPHA_1 + "Final"); + relFactorsDictionaryForGUI.add(alpha); + } + } + + private static void fixAlphasForEuler(Model model, Dictionary relFactorsDictionaryForGUI, String name) { + if (name.equals("\"" + Fields.ALPHA + ".*\"")) { + DefaultElement alpha = relFactorsDictionaryForGUI.remove(name); + alpha.setName(Fields.ALPHA + "." + model.getMaterials().getFirstMaterialName()); + relFactorsDictionaryForGUI.add(alpha); + } else if (name.equals("\"" + Fields.ALPHA + ".*Final\"")) { + DefaultElement alpha = relFactorsDictionaryForGUI.remove(name); + alpha.setName(Fields.ALPHA + "." + model.getMaterials().getFirstMaterialName() + "Final"); + relFactorsDictionaryForGUI.add(alpha); + } + } + +} diff --git a/src/eu/engys/gui/casesetup/solver/SolverSettingsPanel.java b/src/eu/engys/gui/casesetup/solver/SolverSettingsPanel.java new file mode 100644 index 0000000..a1c51b1 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solver/SolverSettingsPanel.java @@ -0,0 +1,357 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solver; + +import static eu.engys.core.project.state.SolverFamily.CENTRAL; +import static eu.engys.core.project.state.SolverFamily.COUPLED; +import static eu.engys.core.project.state.SolverFamily.PIMPLE; +import static eu.engys.core.project.state.SolverFamily.PISO; +import static eu.engys.core.project.state.SolverFamily.SIMPLE; +import static eu.engys.core.project.system.FvSchemes.FV_SCHEMES; +import static eu.engys.core.project.system.FvSolution.FV_SOLUTION; +import static eu.engys.core.project.system.SystemFolder.SYSTEM; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.Table15; +import eu.engys.core.project.system.SystemFolder; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.gui.casesetup.solver.panels.CentralSettingsPanel; +import eu.engys.gui.casesetup.solver.panels.CoupledSettingsPanel; +import eu.engys.gui.casesetup.solver.panels.PimpleSettingsPanel; +import eu.engys.gui.casesetup.solver.panels.PisoSettingsPanel; +import eu.engys.gui.casesetup.solver.panels.SimpleSettingsPanel; +import eu.engys.gui.casesetup.solver.panels.SolverPanel; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; + +public class SolverSettingsPanel extends DefaultGUIPanel { + + private static final String EMPTY = "EMPTY"; + private static final String STATE_CHANGED_WARNING = "Solution state has been changed.\nAll fields default settings are going to be reset now.\nContinue?"; + + public static final String SOLVER_SETTINGS = "Solver Settings"; + public static final String SOLUTION_ALGORITHM_LABEL = "Solution Algorithm"; + + private JComboBox algorithmCombo; + private ActionListener algorithmActionListener; + + private Map solverPanelMap = new LinkedHashMap<>(); + private Table15 solversTable; + private Set modules; + + @Inject + public SolverSettingsPanel(Model model, Table15 solversTable, Set modules) { + super(SOLVER_SETTINGS, model); + this.solversTable = solversTable; + this.modules = modules; + } + + @Override + protected JComponent layoutComponents() { + solverPanelMap.put(SIMPLE, new SimpleSettingsPanel()); + solverPanelMap.put(PIMPLE, new PimpleSettingsPanel()); + solverPanelMap.put(PISO, new PisoSettingsPanel()); + solverPanelMap.put(CENTRAL, new CentralSettingsPanel()); + solverPanelMap.put(COUPLED, new CoupledSettingsPanel()); + + final CardLayout cardLayout = new CardLayout(); + final JPanel cardLayoutPanel = new JPanel(cardLayout); + cardLayoutPanel.add(new JLabel(""), EMPTY); + cardLayoutPanel.setOpaque(false); + + algorithmCombo = createAlgorithmsCombo(cardLayout, cardLayoutPanel); + algorithmActionListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionevent) { + SolverFamily selectedType = (SolverFamily) algorithmCombo.getSelectedItem(); + if (selectedType != null) { + cardLayout.show(cardLayoutPanel, selectedType.getKey()); + fixPIMPLE_PISOSolver(model); + fixPIMPLE_CENTRALSolver(model); + solverPanelMap.get(selectedType).load(model); + } else { + cardLayout.show(cardLayoutPanel, EMPTY); + } + } + }; + algorithmCombo.addActionListener(algorithmActionListener); + + PanelBuilder comboBuilder = new PanelBuilder(); + comboBuilder.addComponent(SOLUTION_ALGORITHM_LABEL, algorithmCombo); + + PanelBuilder cardBuilder = new PanelBuilder(); + cardBuilder.addComponent(cardLayoutPanel); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(comboBuilder.margins(0, 0, 1, 0).getPanel(), BorderLayout.NORTH); + panel.add(cardBuilder.removeMargins().getPanel(), BorderLayout.CENTER); + return panel; + } + + private JComboBox createAlgorithmsCombo(final CardLayout cardLayout, final JPanel cardLayoutPanel) { + JComboBox combo = new JComboBox(); + combo.setPrototypeDisplayValue(SolverFamily.CENTRAL); + final ListCellRenderer renderer = combo.getRenderer(); + combo.setRenderer(new ListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, SolverFamily value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (c instanceof JLabel && value instanceof SolverFamily) { + SolverFamily model = (SolverFamily) value; + ((JLabel) c).setText(model.getKey()); + } + return c; + } + }); + + combo.setEnabled(false); + for (SolverFamily solver : solverPanelMap.keySet()) { + cardLayoutPanel.add(solverPanelMap.get(solver).getPanel(), solver.getKey()); + } + combo.setSelectedIndex(-1); + return combo; + } + + @Override + public void stateChanged() { + loadLater(); + } + + @Override + public void materialsChanged() { + loadLater(); + } + + @Override + public void fieldsChanged() { + loadLater(); + } + + private void loadLater() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + load(); + } + }); + } + + @Override + public void load() { + if (model.hasProject()) { + Set solverFamilies = new LinkedHashSet<>(); + solversTable.updateSolverFamilies(model.getState(), solverFamilies); + ModulesUtil.updateSolverFamilies(modules, model.getState(), solverFamilies); + + loadSolverPanels(model, solverFamilies); + populateCombo(solverFamilies); + fixComboSelection(); + } + } + + private void loadSolverPanels(Model model, Set solverFamiliesForState) { + Dictionary fvSolution = model.getProject().getSystemFolder().getFvSolution(); + if (fvSolution != null) { + leaveOneSolverDictionaryOnFvSolution(fvSolution); + for (SolverFamily family : solverFamiliesForState) { + solverPanelMap.get(family).load(model); + } + } + } + + private void leaveOneSolverDictionaryOnFvSolution(Dictionary fvSolution) { + if (fvSolution.found(SolverFamily.SIMPLE.getKey())) { + if (fvSolution.found(SolverFamily.PIMPLE.getKey()) || fvSolution.found(SolverFamily.PISO.getKey()) || fvSolution.found(SolverFamily.CENTRAL.getKey())) { + fvSolution.remove(SolverFamily.SIMPLE.getKey()); + } + } + } + + private void populateCombo(Set solverFamiliesForState) { + algorithmCombo.removeAllItems(); + algorithmCombo.removeActionListener(algorithmActionListener); + for (SolverFamily algo : solverFamiliesForState) { + algorithmCombo.addItem(algo); + } + algorithmCombo.addActionListener(algorithmActionListener); + } + + private void fixComboSelection() { + algorithmCombo.setEnabled(true); + SolverFamily solverFamily = model.getState().getSolverFamily(); + if (solverFamily.isNone() || algorithmCombo.getItemCount() == 0) { + algorithmCombo.setSelectedIndex(-1); + algorithmCombo.setEnabled(false); + } else { + algorithmCombo.setEnabled(true); + boolean itemNotInComboBox = ((DefaultComboBoxModel) algorithmCombo.getModel()).getIndexOf(solverFamily) == -1; + if (itemNotInComboBox) { + algorithmCombo.setSelectedIndex(0); + } else { + algorithmCombo.setSelectedItem(solverFamily); + } + if (algorithmCombo.getItemCount() < 2) { + algorithmCombo.setEnabled(false); + } + } + } + + @Override + public boolean canStop() { + if (stateHasChanged()) { + if (JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), STATE_CHANGED_WARNING, "State Changed", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { + return true; + } else { + return false; + } + } + return true; + } + + @Override + public void save() { + fixPIMPLE_PISOSolver(model); + fixPIMPLE_CENTRALSolver(model); + if (algorithmCombo.getSelectedIndex() != -1) { + SolverPanel selectedSolverPanel = solverPanelMap.get(algorithmCombo.getSelectedItem()); + SolverSettingsBuilder.build(model, selectedSolverPanel); + } + } + + private boolean stateHasChanged() { + State state = model.getState(); + SolverFamily family = state.getSolverFamily(); + if (state.isTransient() && state.isIncompressible()) { + return family.isPiso() && isPIMPLE() || family.isPimple() && isPISO(); + } + if (state.isTransient() && state.isCompressible() && state.isHighMach()) { + return family.isCentral() && isPIMPLE() || family.isPimple() && isCENTRAL(); + } + return false; + } + + private boolean isCENTRAL() { + SolverFamily selectedItem = (SolverFamily) algorithmCombo.getSelectedItem(); + return selectedItem.isCentral(); + } + + private boolean isPISO() { + SolverFamily selectedItem = (SolverFamily) algorithmCombo.getSelectedItem(); + return selectedItem.isPiso(); + } + + private boolean isPIMPLE() { + SolverFamily selectedItem = (SolverFamily) algorithmCombo.getSelectedItem(); + return selectedItem.isPimple(); + } + + private void fixPIMPLE_PISOSolver(Model model) { + State state = model.getState(); + if (state.isTransient() && state.isIncompressible()) { + SystemFolder systemFolder = model.getProject().getSystemFolder(); + Dictionary fvSolution = systemFolder.getFvSolution(); + + Dictionary stateData = model.getDefaults().getDefaultStateData(); + Dictionary pisoSolution = stateData.subDict("pisoFoamRAS").subDict(SYSTEM).subDict(FV_SOLUTION); + Dictionary pimpleSolution = stateData.subDict("pimpleFoamRAS").subDict(SYSTEM).subDict(FV_SOLUTION); + + if (isPISO() && fvSolution.found(SolverFamily.PIMPLE.getKey())) { + systemFolder.setFvSolution(pisoSolution); + state.setSolverFamily(SolverFamily.PISO); + solversTable.updateSolver(state); + ModulesUtil.updateSolver(modules, state); + model.solverChanged(); + } else if (isPIMPLE() && fvSolution.found(SolverFamily.PISO.getKey())) { + systemFolder.setFvSolution(pimpleSolution); + state.setSolverFamily(SolverFamily.PIMPLE); + solversTable.updateSolver(state); + ModulesUtil.updateSolver(modules, state); + model.solverChanged(); + } + } + } + + private void fixPIMPLE_CENTRALSolver(Model model) { + State state = model.getState(); + if (state.isTransient() && state.isCompressible() && state.isHighMach()) { + SystemFolder systemFolder = model.getProject().getSystemFolder(); + if (isCENTRAL() && state.getSolverFamily().isPimple()) { + state.setSolverFamily(SolverFamily.CENTRAL); + solversTable.updateSolver(state); + ModulesUtil.updateSolver(modules, state); + + Dictionary stateData = model.getDefaults().getDefaultsFor(state); + Dictionary solutionDict = stateData.subDict(SYSTEM).subDict(FV_SOLUTION); + Dictionary schemesDict = stateData.subDict(SYSTEM).subDict(FV_SCHEMES); + + systemFolder.setFvSolution(solutionDict); + systemFolder.setFvSchemes(schemesDict); + + model.solverChanged(); + } else if (isPIMPLE() && state.getSolverFamily().isCentral()) { + state.setSolverFamily(SolverFamily.PIMPLE); + solversTable.updateSolver(state); + ModulesUtil.updateSolver(modules, state); + + Dictionary stateData = model.getDefaults().getDefaultsFor(state); + Dictionary solutionDict = stateData.subDict(SYSTEM).subDict(FV_SOLUTION); + Dictionary schemesDict = stateData.subDict(SYSTEM).subDict(FV_SCHEMES); + + systemFolder.setFvSolution(solutionDict); + systemFolder.setFvSchemes(schemesDict); + + model.solverChanged(); + } + } + } + +} diff --git a/src/eu/engys/gui/casesetup/solver/panels/CentralSettingsPanel.java b/src/eu/engys/gui/casesetup/solver/panels/CentralSettingsPanel.java new file mode 100644 index 0000000..629907c --- /dev/null +++ b/src/eu/engys/gui/casesetup/solver/panels/CentralSettingsPanel.java @@ -0,0 +1,76 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.solver.panels; + +import static eu.engys.core.project.system.FvSolution.RELAXATION_FACTORS_KEY; +import static eu.engys.core.project.system.FvSolution.RESIDUAL_CONTROL_KEY; + +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.SolverFamily; + +public class CentralSettingsPanel implements SolverPanel { + + private DictionaryModel centralDictModel; + + public CentralSettingsPanel() { + centralDictModel = new DictionaryModel(new Dictionary(getKey())); + } + + @Override + public String getKey() { + return SolverFamily.CENTRAL.getKey(); + } + + @Override + public JPanel getPanel() { + return new JPanel(); + } + + @Override + public Dictionary getSolverDictionary() { + return centralDictModel.getDictionary(); + } + + @Override + public Dictionary getRelaxationFactorsDictionary() { + return new Dictionary(RELAXATION_FACTORS_KEY); + } + + @Override + public Dictionary getResidualControlDictionary() { + return new Dictionary(RESIDUAL_CONTROL_KEY); + } + + @Override + public void load(Model model) { + } + +} diff --git a/src/eu/engys/gui/casesetup/solver/panels/CoupledSettingsPanel.java b/src/eu/engys/gui/casesetup/solver/panels/CoupledSettingsPanel.java new file mode 100644 index 0000000..05464de --- /dev/null +++ b/src/eu/engys/gui/casesetup/solver/panels/CoupledSettingsPanel.java @@ -0,0 +1,74 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solver.panels; + +import static eu.engys.core.project.system.FvSolution.RELAXATION_FACTORS_KEY; + +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.SolverFamily; + +public class CoupledSettingsPanel implements SolverPanel { + + private DictionaryModel coupledDictModel; + + public CoupledSettingsPanel() { + coupledDictModel = new DictionaryModel(new Dictionary(getKey())); + } + + @Override + public String getKey() { + return SolverFamily.COUPLED.getKey(); + } + + @Override + public JPanel getPanel() { + return new JPanel(); + } + + @Override + public Dictionary getSolverDictionary() { + return coupledDictModel.getDictionary(); + } + + @Override + public Dictionary getRelaxationFactorsDictionary() { + return new Dictionary(RELAXATION_FACTORS_KEY); + } + + @Override + public Dictionary getResidualControlDictionary() { + return null; + } + + @Override + public void load(Model model) { + } + +} diff --git a/src/eu/engys/gui/casesetup/solver/panels/PimpleSettingsPanel.java b/src/eu/engys/gui/casesetup/solver/panels/PimpleSettingsPanel.java new file mode 100644 index 0000000..b051f8b --- /dev/null +++ b/src/eu/engys/gui/casesetup/solver/panels/PimpleSettingsPanel.java @@ -0,0 +1,238 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solver.panels; + +import static eu.engys.core.project.system.ControlDict.MAX_ALPHA_CO_KEY; +import static eu.engys.core.project.system.ControlDict.MAX_CO_KEY; +import static eu.engys.core.project.system.FvSolution.FV_SOLUTION; +import static eu.engys.core.project.system.FvSolution.N_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.N_NON_ORTHOGONAL_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.N_OUTER_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.RELAXATION_FACTORS_KEY; +import static eu.engys.core.project.system.FvSolution.REL_TOLERANCE_KEY; +import static eu.engys.core.project.system.FvSolution.RESIDUAL_CONTROL_KEY; +import static eu.engys.core.project.system.FvSolution.RHO_MAX_KEY; +import static eu.engys.core.project.system.FvSolution.RHO_MIN_KEY; +import static eu.engys.core.project.system.FvSolution.TOLERANCE_KEY; +import static eu.engys.core.project.system.SystemFolder.SYSTEM; +import static eu.engys.core.project.zero.fields.Fields.FINAL; +import static eu.engys.core.project.zero.fields.Fields.P; +import static eu.engys.core.project.zero.fields.Fields.P_RGH; +import static eu.engys.core.project.zero.fields.Fields.RHO; + +import java.awt.BorderLayout; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.casesetup.solver.SolverSettingsBuilder; +import eu.engys.util.DimensionalUnits; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; + +public class PimpleSettingsPanel implements SolverPanel { + + public static final String COURANT_NUMBER_LABEL = "Courant Number"; + public static final String MAX_COURANT_ALPHA_LABEL = "Max Courant Alpha"; + public static final String MAX_COURANT_NUMBER_LABEL = "Max Courant Number"; + + private DictionaryModel pimpleDictModel; + + private DictionaryModel relaxationFactorsDictModel; + private Map pimpleResidualMap; + + private JPanel relaxationFactorsPanel; + private JPanel residualControlPanel; + + private PanelBuilder builder; + + private JComponent pimpleRhoMin; + private JComponent pimpleRhoMax; + + private JComponent maxCourantNumber; + private JComponent maxAlphaCourant; + + public PimpleSettingsPanel() { + relaxationFactorsDictModel = new DictionaryModel(new Dictionary(RELAXATION_FACTORS_KEY)); + pimpleResidualMap = new HashMap<>(); + + pimpleDictModel = new DictionaryModel(new Dictionary(getKey())); + + builder = new PanelBuilder(); + builder.addComponent(OUTER_CORRECTORS_LABEL, pimpleDictModel.bindIntegerPositive(N_OUTER_CORRECTORS_KEY)); + builder.addComponent(CORRECTORS_LABEL, pimpleDictModel.bindIntegerPositive(N_CORRECTORS_KEY)); + builder.addComponent(NON_ORTHOGONAL_CORRECTORS_LABEL, pimpleDictModel.bindIntegerPositive(N_NON_ORTHOGONAL_CORRECTORS_KEY)); + pimpleRhoMin = builder.addComponent(RHO_MIN_LABEL, pimpleDictModel.bindDimensionedDouble(RHO_MIN_KEY, DimensionalUnits.KG_M3)); + pimpleRhoMax = builder.addComponent(RHO_MAX_LABEL, pimpleDictModel.bindDimensionedDouble(RHO_MAX_KEY, DimensionalUnits.KG_M3)); + pimpleRhoMin.setEnabled(false); + pimpleRhoMax.setEnabled(false); + + PanelBuilder courantBuilder = new PanelBuilder(); + maxCourantNumber = courantBuilder.addComponent(MAX_COURANT_NUMBER_LABEL, pimpleDictModel.bindDouble(MAX_CO_KEY)); + maxAlphaCourant = courantBuilder.addComponent(MAX_COURANT_ALPHA_LABEL, pimpleDictModel.bindDouble(MAX_ALPHA_CO_KEY)); + maxCourantNumber.setEnabled(false); + maxAlphaCourant.setEnabled(false); + courantBuilder.getPanel().setBorder(BorderFactory.createTitledBorder(COURANT_NUMBER_LABEL)); + courantBuilder.getPanel().setName(COURANT_NUMBER_LABEL); + builder.addFill(courantBuilder.getPanel()); + + residualControlPanel = new JPanel(new BorderLayout()); + residualControlPanel.setOpaque(false); + residualControlPanel.setBorder(BorderFactory.createTitledBorder(RESIDUAL_CONTROL_LABEL)); + residualControlPanel.setName(RESIDUAL_CONTROL_LABEL); + builder.addFill(residualControlPanel); + + relaxationFactorsPanel = new JPanel(new BorderLayout()); + relaxationFactorsPanel.setOpaque(false); + relaxationFactorsPanel.setBorder(BorderFactory.createTitledBorder(RELAXATION_FACTORS_LABEL)); + relaxationFactorsPanel.setName(RELAXATION_FACTORS_LABEL); + builder.addFill(relaxationFactorsPanel); + } + + @Override + public String getKey() { + return SolverFamily.PIMPLE.getKey(); + } + + @Override + public Dictionary getSolverDictionary() { + return pimpleDictModel.getDictionary(); + } + + @Override + public Dictionary getRelaxationFactorsDictionary() { + return relaxationFactorsDictModel.getDictionary(); + } + + @Override + public Dictionary getResidualControlDictionary() { + return getPimpleResidualDictionary(); + } + + @Override + public JPanel getPanel() { + return builder.removeMargins().getPanel(); + } + + @Override + public void load(Model model) { + residualControlPanel.removeAll(); + DictionaryPanelBuilder residualBuilder = new DictionaryPanelBuilder(); + residualControlPanel.add(residualBuilder.getPanel()); + + relaxationFactorsPanel.removeAll(); + DictionaryPanelBuilder relaxationBuilder = new DictionaryPanelBuilder(); + relaxationFactorsPanel.add(relaxationBuilder.getPanel()); + + pimpleResidualMap.clear(); + + Fields fields = model.getFields(); + + Dictionary fvSolution = model.getProject().getSystemFolder().getFvSolution(); + if (fvSolution != null) { + Dictionary PIMPLEDict = fvSolution.subDict(getKey()); + pimpleDictModel.setDictionary(PIMPLEDict != null ? new Dictionary(PIMPLEDict) : getDictionaryFromDefaults(model)); + + residualBuilder.addComponent("", new JLabel(RELATIVE_TOLERANCE_LABEL), new JLabel(TOLERANCE_LABEL)); + for (Field field : fields.orderedFieldsExcludingPassiveScalars()) { + String fieldName = field.getName(); + DictionaryModel fieldModel = new DictionaryModel(new Dictionary(fieldName)); + DoubleField relativeTolerance = fieldModel.bindDouble(REL_TOLERANCE_KEY, 0.0, 1.0); + DoubleField tolerance = fieldModel.bindDouble(TOLERANCE_KEY, 0.0, 1.0); + pimpleResidualMap.put(fieldName, fieldModel); + residualBuilder.addComponent(fieldName, relativeTolerance, tolerance); + } + for (Field field : fields.orderedFields()) { + String fieldName = field.getName(); + + DoubleField normalField = relaxationFactorsDictModel.bindDouble(fieldName, 0.0, 1.0); + normalField.setName(fieldName); + + JComponent finalField = null; + JLabel finalLabel = null; + if (P_RGH.equals(fieldName) || P.equals(fieldName) || RHO.equals(fieldName)) { + finalLabel = new JLabel(""); + finalField = new JLabel(""); + } else { + finalLabel = new JLabel(fieldName + FINAL); + finalField = relaxationFactorsDictModel.bindDouble(fieldName + FINAL, 0.0, 1.0); + } + finalField.setName(fieldName + FINAL); + relaxationBuilder.addComponent(new JLabel(fieldName), normalField, finalLabel, finalField); + } + + if (PIMPLEDict != null && PIMPLEDict.found(RESIDUAL_CONTROL_KEY)) { + Dictionary residualControlDict = PIMPLEDict.subDict(RESIDUAL_CONTROL_KEY); + for (String key : pimpleResidualMap.keySet()) { + pimpleResidualMap.get(key).setDictionary(residualControlDict.subDict(key)); + } + } + + if (fvSolution.found(RELAXATION_FACTORS_KEY)) { + Dictionary relaxationFactors = fvSolution.subDict(RELAXATION_FACTORS_KEY); + Dictionary relaxationFactorsForGUI = SolverSettingsBuilder.decodeRelaxationFactorsForGUI(model, relaxationFactors); + relaxationFactorsDictModel.setDictionary(relaxationFactorsForGUI); + } + + } + updatePanel(model); + } + + private Dictionary getDictionaryFromDefaults(Model model) { + Dictionary stateData = model.getDefaults().getDefaultStateData(); + Dictionary pimpleSolution = stateData.subDict("pimpleFoamRAS").subDict(SYSTEM).subDict(FV_SOLUTION); + return pimpleSolution.subDict(getKey()); + } + + private void updatePanel(Model model) { + boolean isLTS = model.getState().isSteady() && model.getState().getMultiphaseModel().isMultiphase(); + maxAlphaCourant.setEnabled(isLTS); + maxCourantNumber.setEnabled(isLTS); + + pimpleRhoMin.setEnabled(model.getState().isCompressible()); + pimpleRhoMax.setEnabled(model.getState().isCompressible()); + } + + private Dictionary getPimpleResidualDictionary() { + Dictionary dictionary = new Dictionary(RESIDUAL_CONTROL_KEY); + for (DictionaryModel dm : pimpleResidualMap.values()) { + dictionary.add(dm.getDictionary()); + } + return dictionary; + } + +} diff --git a/src/eu/engys/gui/casesetup/solver/panels/PisoSettingsPanel.java b/src/eu/engys/gui/casesetup/solver/panels/PisoSettingsPanel.java new file mode 100644 index 0000000..17c265a --- /dev/null +++ b/src/eu/engys/gui/casesetup/solver/panels/PisoSettingsPanel.java @@ -0,0 +1,154 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.solver.panels; + +import static eu.engys.core.project.system.FvSolution.FV_SOLUTION; +import static eu.engys.core.project.system.FvSolution.N_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.N_NON_ORTHOGONAL_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.RELAXATION_FACTORS_KEY; +import static eu.engys.core.project.system.FvSolution.RESIDUAL_CONTROL_KEY; +import static eu.engys.core.project.system.FvSolution.RHO_MAX_KEY; +import static eu.engys.core.project.system.FvSolution.RHO_MIN_KEY; +import static eu.engys.core.project.system.SystemFolder.SYSTEM; + +import java.awt.BorderLayout; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.state.State; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.casesetup.solver.SolverSettingsBuilder; +import eu.engys.util.DimensionalUnits; +import eu.engys.util.ui.textfields.DoubleField; + +public class PisoSettingsPanel implements SolverPanel { + + private DictionaryModel pisoDictModel; + + private DictionaryModel relaxationFactorsDictModel; + private JPanel relaxationFactorsPanel; + + private DictionaryPanelBuilder builder; + + private JComponent pisoRhoMin; + private JComponent pisoRhoMax; + + public PisoSettingsPanel() { + relaxationFactorsDictModel = new DictionaryModel(new Dictionary(RELAXATION_FACTORS_KEY)); + + pisoDictModel = new DictionaryModel(new Dictionary(getKey())); + + builder = new DictionaryPanelBuilder(); + builder.addComponent(CORRECTORS_LABEL, pisoDictModel.bindIntegerPositive(N_CORRECTORS_KEY)); + builder.addComponent(NON_ORTHOGONAL_CORRECTORS_LABEL, pisoDictModel.bindIntegerPositive(N_NON_ORTHOGONAL_CORRECTORS_KEY)); + pisoRhoMin = builder.addComponent(RHO_MIN_LABEL, pisoDictModel.bindDimensionedDouble(RHO_MIN_KEY, DimensionalUnits.KG_M3)); + pisoRhoMax = builder.addComponent(RHO_MAX_LABEL, pisoDictModel.bindDimensionedDouble(RHO_MAX_KEY, DimensionalUnits.KG_M3)); + + relaxationFactorsPanel = new JPanel(new BorderLayout()); + relaxationFactorsPanel.setOpaque(false); + relaxationFactorsPanel.setBorder(BorderFactory.createTitledBorder(RELAXATION_FACTORS_LABEL)); + relaxationFactorsPanel.setName(RELAXATION_FACTORS_LABEL); + builder.addFill(relaxationFactorsPanel); + } + + @Override + public String getKey() { + return SolverFamily.PISO.getKey(); + } + + @Override + public JPanel getPanel() { + return builder.removeMargins().getPanel(); + } + + @Override + public Dictionary getSolverDictionary() { + return pisoDictModel.getDictionary(); + } + + @Override + public Dictionary getRelaxationFactorsDictionary() { + return relaxationFactorsDictModel.getDictionary(); + } + + @Override + public Dictionary getResidualControlDictionary() { + return new Dictionary(RESIDUAL_CONTROL_KEY); + } + + @Override + public void load(Model model) { + relaxationFactorsPanel.removeAll(); + DictionaryPanelBuilder relaxationBuilder = new DictionaryPanelBuilder(); + relaxationFactorsPanel.add(relaxationBuilder.getPanel()); + + Fields fields = model.getFields(); + + Dictionary fvSolution = model.getProject().getSystemFolder().getFvSolution(); + if (fvSolution != null) { + Dictionary PISODict = fvSolution.subDict(getKey()); + pisoDictModel.setDictionary(PISODict != null ? new Dictionary(PISODict) : getDictionaryFromDefaults(model)); + + for (Field field : fields.orderedFields()) { + String fieldName = field.getName(); + DoubleField textField = relaxationFactorsDictModel.bindDouble(fieldName, 0.0, 1.0); + textField.setEnabled(false); + relaxationBuilder.addComponent(fieldName, textField); + } + + if (fvSolution.found(RELAXATION_FACTORS_KEY)) { + Dictionary relaxationFactors = fvSolution.subDict(RELAXATION_FACTORS_KEY); + Dictionary relaxationFactorsForGUI = SolverSettingsBuilder.decodeRelaxationFactorsForGUI(model, relaxationFactors); + relaxationFactorsDictModel.setDictionary(relaxationFactorsForGUI); + } + + updatePanel(model); + } + } + + private Dictionary getDictionaryFromDefaults(Model model) { + Dictionary stateData = model.getDefaults().getDefaultStateData(); + Dictionary pisoSolution = stateData.subDict("pisoFoamRAS").subDict(SYSTEM).subDict(FV_SOLUTION); + return pisoSolution.subDict(getKey()); + } + + protected void updatePanel(Model model) { + State state = model.getState(); + boolean isCompressible = state.isCompressible(); + pisoRhoMin.setEnabled(isCompressible); + pisoRhoMax.setEnabled(isCompressible); + } + +} diff --git a/src/eu/engys/gui/casesetup/solver/panels/SimpleSettingsPanel.java b/src/eu/engys/gui/casesetup/solver/panels/SimpleSettingsPanel.java new file mode 100644 index 0000000..b60cb61 --- /dev/null +++ b/src/eu/engys/gui/casesetup/solver/panels/SimpleSettingsPanel.java @@ -0,0 +1,147 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.casesetup.solver.panels; + +import static eu.engys.core.project.system.FvSolution.N_NON_ORTHOGONAL_CORRECTORS_KEY; +import static eu.engys.core.project.system.FvSolution.RELAXATION_FACTORS_KEY; +import static eu.engys.core.project.system.FvSolution.RESIDUAL_CONTROL_KEY; + +import java.awt.BorderLayout; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.SolverFamily; +import eu.engys.core.project.zero.fields.Field; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.casesetup.solver.SolverSettingsBuilder; + +public class SimpleSettingsPanel implements SolverPanel { + + private DictionaryPanelBuilder builder; + + private DictionaryModel simpleDictModel; + private DictionaryModel relaxationFactorsDictModel; + private DictionaryModel residualControlDict; + + private JPanel relaxationFactorsPanel; + private JPanel residualControlPanel; + + public SimpleSettingsPanel() { + relaxationFactorsDictModel = new DictionaryModel(new Dictionary(RELAXATION_FACTORS_KEY)); + residualControlDict = new DictionaryModel(new Dictionary(RESIDUAL_CONTROL_KEY)); + + simpleDictModel = new DictionaryModel(new Dictionary(getKey())); + + builder = new DictionaryPanelBuilder(); + builder.addComponent(NON_ORTHOGONAL_CORRECTORS_LABEL, simpleDictModel.bindIntegerPositive(N_NON_ORTHOGONAL_CORRECTORS_KEY)); + + residualControlPanel = new JPanel(new BorderLayout()); + residualControlPanel.setOpaque(false); + residualControlPanel.setBorder(BorderFactory.createTitledBorder(RESIDUAL_CONTROL_LABEL)); + residualControlPanel.setName(RESIDUAL_CONTROL_LABEL); + builder.addFill(residualControlPanel); + + relaxationFactorsPanel = new JPanel(new BorderLayout()); + relaxationFactorsPanel.setOpaque(false); + relaxationFactorsPanel.setBorder(BorderFactory.createTitledBorder(RELAXATION_FACTORS_LABEL)); + relaxationFactorsPanel.setName(RELAXATION_FACTORS_LABEL); + builder.addFill(relaxationFactorsPanel); + } + + @Override + public String getKey() { + return SolverFamily.SIMPLE.getKey(); + } + + @Override + public JPanel getPanel() { + return builder.removeMargins().getPanel(); + } + + @Override + public Dictionary getSolverDictionary() { + return simpleDictModel.getDictionary(); + } + + @Override + public Dictionary getRelaxationFactorsDictionary() { + return relaxationFactorsDictModel.getDictionary(); + } + + @Override + public Dictionary getResidualControlDictionary() { + return residualControlDict.getDictionary(); + } + + @Override + public void load(Model model) { + residualControlPanel.removeAll(); + DictionaryPanelBuilder residualBuilder = new DictionaryPanelBuilder(); + residualControlPanel.add(residualBuilder.getPanel()); + + relaxationFactorsPanel.removeAll(); + DictionaryPanelBuilder relaxationBuilder = new DictionaryPanelBuilder(); + relaxationFactorsPanel.add(relaxationBuilder.getPanel()); + + Fields fields = model.getFields(); + + Dictionary fvSolution = model.getProject().getSystemFolder().getFvSolution(); + + + if (fvSolution != null) { + Dictionary SIMPLEDict = fvSolution.subDict(getKey()); + simpleDictModel.setDictionary(SIMPLEDict != null ? new Dictionary(SIMPLEDict) : new Dictionary(getKey())); + +// System.out.println("SimpleSettingsPanel.load(): " + fields.orderedFieldsExcludingPassiveScalars()); + + for (Field field : fields.orderedFieldsExcludingPassiveScalars()) { + String fieldName = field.getName(); + residualBuilder.addComponent(fieldName, residualControlDict.bindDouble(fieldName, 0.0, 1.0)); + } + + for (Field field : fields.orderedFields()) { + String fieldName = field.getName(); + relaxationBuilder.addComponent(fieldName, relaxationFactorsDictModel.bindDouble(fieldName, 0.0, 1.0)); + } + + if (SIMPLEDict != null && SIMPLEDict.found(RESIDUAL_CONTROL_KEY)) { + residualControlDict.setDictionary(SIMPLEDict.subDict(RESIDUAL_CONTROL_KEY)); + } + if (fvSolution.found(RELAXATION_FACTORS_KEY)) { + Dictionary relaxationFactors = fvSolution.subDict(RELAXATION_FACTORS_KEY); + Dictionary relaxationFactorsForGUI = SolverSettingsBuilder.decodeRelaxationFactorsForGUI(model, relaxationFactors); + relaxationFactorsDictModel.setDictionary(relaxationFactorsForGUI); + } + } + } + +} diff --git a/src/eu/engys/gui/casesetup/solver/panels/SolverPanel.java b/src/eu/engys/gui/casesetup/solver/panels/SolverPanel.java new file mode 100644 index 0000000..950563e --- /dev/null +++ b/src/eu/engys/gui/casesetup/solver/panels/SolverPanel.java @@ -0,0 +1,57 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.casesetup.solver.panels; + +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; + +public interface SolverPanel { + + public static final String OUTER_CORRECTORS_LABEL = "Outer Correctors"; + public static final String CORRECTORS_LABEL = "Correctors"; + public static final String NON_ORTHOGONAL_CORRECTORS_LABEL = "Non-orthogonal Correctors"; + public static final String RHO_MIN_LABEL = "Rho Min"; + public static final String RHO_MAX_LABEL = "Rho Max"; + public static final String RESIDUAL_CONTROL_LABEL = "Residual Control"; + public static final String RELAXATION_FACTORS_LABEL = "Relaxation Factors"; + public static final String RELATIVE_TOLERANCE_LABEL = "Relative Tolerance"; + public static final String TOLERANCE_LABEL = "Tolerance"; + + Dictionary getSolverDictionary(); + + Dictionary getRelaxationFactorsDictionary(); + + Dictionary getResidualControlDictionary(); + + void load(Model model); + + JPanel getPanel(); + + String getKey(); + +} diff --git a/src/eu/engys/gui/custom/CustomFileDialog.java b/src/eu/engys/gui/custom/CustomFileDialog.java new file mode 100644 index 0000000..fa7dbf1 --- /dev/null +++ b/src/eu/engys/gui/custom/CustomFileDialog.java @@ -0,0 +1,501 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.custom; + +import static eu.engys.core.project.constant.ConstantFolder.CONSTANT; +import static eu.engys.core.project.custom.CustomFileType.DICTIONARY; +import static eu.engys.core.project.custom.CustomFileType.DIRECTORY; +import static eu.engys.core.project.custom.CustomFileType.FIELD; +import static eu.engys.core.project.system.SystemFolder.SYSTEM; +import static eu.engys.util.ui.ComponentsFactory.selectField; +import static eu.engys.util.ui.ComponentsFactory.selectFieldWithItemSupport; +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.awt.BorderLayout; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.FileFilter; +import java.util.Arrays; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import eu.engys.core.project.Model; +import eu.engys.core.project.custom.CustomFile; +import eu.engys.core.project.custom.CustomFileType; +import eu.engys.core.project.custom.CustomUtils; +import eu.engys.core.project.system.CaseSetupDict; +import eu.engys.core.project.system.CustomNodeDict; +import eu.engys.core.project.system.RunDict; +import eu.engys.util.ui.JComboBoxWithItemsSupport; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.StringField; +import eu.engys.util.ui.textfields.verifiers.AbstractVerifier; +import eu.engys.util.ui.textfields.verifiers.AbstractVerifier.ValidationStatusListener; + +public class CustomFileDialog { + + public static final String CUSTOM_DIALOG_NAME = "custom.dialog"; + + public static final String TITLE = "New Custom File"; + + public static final String VALUE_LABEL = "Value"; + public static final String NAME_LABEL = "Name"; + public static final String TYPE_LABEL = "Type"; + public static final String PARENT_LABEL = "Parent"; + public static final String DEFAULT_NAME = "newFile"; + public static final String NEW_NAME = "New ..."; + + public static final String CANCEL_LABEL = "Cancel"; + public static final String CREATE_NEW_LABEL = "Create New"; + + private static final String[] VETOED_DICT_LIST = new String[] { RunDict.RUN_DICT, CaseSetupDict.CASE_SETUP_DICT, CustomNodeDict.CUSTOM_NODE_DICT }; + + private JComboBoxWithItemsSupport typeCombo; + private JComboBox parentCombo; + private JComboBox namesCombo; + private StringField nameField; + private JDialog dialog; + private JButton okButton; + private Model model; + + private PropertyChangeListener enableOKButtonListener; + private PropertyChangeListener enableTYPESComboListener; + private PropertyChangeListener updateNamesCombo; + + private static final int LOAD = 0; + private static final int NEW = 1; + private static final int CANCEL = 2; + + public CustomFileDialog(Model model) { + this.model = model; + + dialog = new JDialog(UiUtil.getActiveWindow(), ModalityType.APPLICATION_MODAL); + dialog.setTitle(TITLE); + dialog.setSize(300, 200); + dialog.setLocationRelativeTo(null); + dialog.setName(CUSTOM_DIALOG_NAME); + + PanelBuilder builder = new PanelBuilder(); + namesCombo = createNamesCombo(); + nameField = createNameField(); + parentCombo = createParentCombo(); + typeCombo = createTypeCombo(); + + builder.addComponent(PARENT_LABEL, parentCombo); + builder.addComponent(TYPE_LABEL, typeCombo); + builder.addComponent(NAME_LABEL, namesCombo); + builder.addComponent(VALUE_LABEL, nameField); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(builder.getPanel(), BorderLayout.CENTER); + mainPanel.add(createButtonsPanel(), BorderLayout.SOUTH); + + dialog.add(mainPanel); + dialog.getRootPane().setDefaultButton(okButton); + + enableOKButtonListener = new EnableOkButtonListener(); + enableTYPESComboListener = new EnableTypesComboListener(); + updateNamesCombo = new UpdateNamesCombo(); + } + + private StringField createNameField() { + StringField newFoNameField = stringField(DEFAULT_NAME); + ((AbstractVerifier) newFoNameField.getInputVerifier()).setValidationStatusListener(new ValidationStatusListener() { + @Override + public void validatePassed() { + okButton.setEnabled(true); + } + + @Override + public void validateFailed() { + okButton.setEnabled(false); + } + }); + return newFoNameField; + } + + private JComboBox createNamesCombo() { + JComboBox namesCombo = selectField(); + namesCombo.addPropertyChangeListener(new EnableNameFieldListener()); + return namesCombo; + } + + private JComboBoxWithItemsSupport createTypeCombo() { + JComboBoxWithItemsSupport typeCombo = selectFieldWithItemSupport(CustomFileType.keys(), CustomFileType.labels()); + typeCombo.setSelectedIndex(-1); + typeCombo.addPropertyChangeListener(enableOKButtonListener); + typeCombo.addPropertyChangeListener(updateNamesCombo); + return typeCombo; + } + + private JComboBox createParentCombo() { + JComboBox parentCombo = selectField(); + parentCombo.setSelectedIndex(-1); + parentCombo.addPropertyChangeListener(enableTYPESComboListener); + parentCombo.addPropertyChangeListener(updateNamesCombo); + return parentCombo; + } + + private JPanel createButtonsPanel() { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + okButton = new JButton(new AddCustomFile()); + okButton.setEnabled(false); + okButton.setName("ok"); + panel.add(okButton); + + JButton cancelButton = new JButton(new AbstractAction("Cancel") { + + @Override + public void actionPerformed(ActionEvent e) { + resetAndClose(); + } + + }); + cancelButton.setName("cancel"); + panel.add(cancelButton); + return panel; + } + + private void resetAndClose() { + nameField.setText(DEFAULT_NAME); + typeCombo.setSelectedIndex(-1); + disposeDialog(); + } + + private void disposeDialog() { + dialog.setVisible(false); + dialog.dispose(); + dialog = null; + } + + public void show(CustomFile parent) { + removeListeners(); + updateNamesCombo(parent); + updateParentCombo(parent); + fixTypeCombo(parentCombo.getSelectedItem()); + addListeners(); + dialog.setVisible(true); + } + + private void updateParentCombo(CustomFile selected) { + List parentFiles = model.getCustom().getParentFiles(); + for (CustomFile customFile : parentFiles) { + parentCombo.addItem(customFile); + } + parentCombo.setSelectedItem(selected); + } + + private void updateNamesCombo(CustomFile parent) { + namesCombo.removeAllItems(); + namesCombo.addItem(NEW_NAME); + + if (parent != null && typeCombo.getSelectedItem() != null) { + _updateNamesCombo(parent); + } + namesCombo.setSelectedItem(0); + } + + private void _updateNamesCombo(CustomFile parent) { + List children = parent.getChildrenNames(); + File parentFile = CustomUtils.getFiles(model, parent).get(0); + if (parentFile.exists()) { + addNames(children, parentFile); + } + } + + private void addNames(List children, File parentFile) { + if (isTypeSelected(DIRECTORY)) { + addDirectoryNames(children, parentFile); + } else if (isTypeSelected(DICTIONARY)) { + addDictionaryNames(children, parentFile); + } else if (isTypeSelected(FIELD)) { + addFieldsNames(children, parentFile); + } + } + + private void addDictionaryNames(final List children, File parentFile) { + for (File f : parentFile.listFiles(new ValidDictionaryFileFilter(children))) { + namesCombo.addItem(f.getName()); + } + } + + private void addFieldsNames(final List children, File parentFile) { + for (File f : parentFile.listFiles(new ValidFieldFileFilter(children))) { + namesCombo.addItem(f.getName()); + } + } + + private void addDirectoryNames(final List children, File parentFile) { + for (File f : parentFile.listFiles(new ValidDirectoryFileFilter(children))) { + namesCombo.addItem(f.getName()); + } + } + + private boolean isTypeSelected(CustomFileType type) { + return typeCombo.getSelectedItem().equals(type.getKey()); + } + + private boolean isNewFile() { + return namesCombo.getSelectedIndex() == 0; + } + + private void removeListeners() { + typeCombo.removePropertyChangeListener(enableOKButtonListener); + typeCombo.removePropertyChangeListener(updateNamesCombo); + parentCombo.removePropertyChangeListener(enableTYPESComboListener); + parentCombo.removePropertyChangeListener(updateNamesCombo); + } + + private void addListeners() { + typeCombo.addPropertyChangeListener(enableOKButtonListener); + typeCombo.addPropertyChangeListener(updateNamesCombo); + parentCombo.addPropertyChangeListener(enableTYPESComboListener); + parentCombo.addPropertyChangeListener(updateNamesCombo); + } + + private class AddCustomFile extends AbstractAction { + + public AddCustomFile() { + super("OK"); + } + + @Override + public void actionPerformed(ActionEvent e) { + addFile(); + } + + private void addFile() { + String type = typeCombo.getItemAt(typeCombo.getSelectedIndex()); + CustomFile parent = parentCombo.getItemAt(parentCombo.getSelectedIndex()); + + if (parent == null) { + JOptionPane.showMessageDialog(dialog, "Please, specify a parent for the file", "Warning", JOptionPane.WARNING_MESSAGE); + return; + } + + String fileName = getValidName(parent, nameField.getText()); + CustomFileType fileType = CustomFileType.valueOf(type.toUpperCase()); + CustomFile customFile = new CustomFile(parent, fileType, fileName); + + File file = CustomUtils.getFiles(model, customFile).get(0); + boolean exists = file.exists(); + + if (exists && !customFile.getType().isDirectory()) { + if (isNewFile()) { + boolean parallel = model.getProject().isParallel(); + String suffix = (customFile.getType().isField() && parallel) ? "Template" : "from File"; + Object[] options = { "Load " + suffix, CREATE_NEW_LABEL, CANCEL_LABEL }; + String message = customFile.getName() + " already exists, please select an action."; + int retVal = JOptionPane.showOptionDialog(dialog, message, "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options, options[0]); + switch (retVal) { + case CANCEL: + return; + case NEW: + break; + case LOAD: + CustomUtils.loadFromDisk(fileName, customFile, file); + break; + default: + break; + } + } else { + CustomUtils.loadFromDisk(fileName, customFile, file); + } + + } + model.getCustom().add(customFile); + model.customFileChanged(customFile); + resetAndClose(); + } + + private String getValidName(CustomFile parent, String text) { + if (!isValidName(parent, text)) { + return getValidName(parent, text + "_copy"); + } + return text; + } + + private boolean isValidName(CustomFile parent, String text) { + for (CustomFile cf : parent.getChildren()) { + if (cf.getName().equals(text)) { + return false; + } + } + return true; + } + + } + + private class EnableOkButtonListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + okButton.setEnabled(evt.getNewValue() != null); + } + } + + } + + private class UpdateNamesCombo implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + updateNamesCombo((CustomFile) parentCombo.getSelectedItem()); + } + } + } + + private class EnableNameFieldListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + if (isNewFile()) { + nameField.setText(DEFAULT_NAME); + nameField.setEnabled(true); + } else { + Object selectedItem = namesCombo.getSelectedItem(); + nameField.setText(selectedItem != null ? selectedItem.toString() : DEFAULT_NAME); + nameField.setEnabled(false); + } + } + } + + } + + private class EnableTypesComboListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + fixTypeCombo(evt.getNewValue()); + } + } + + } + + public void fixTypeCombo(Object selectedItem) { + if (selectedItem != null) { + switch (selectedItem.toString()) { + case "0": + typeCombo.clearDisabledIndexes(); + if (typeCombo.getSelectedItem() == DICTIONARY.getKey()) { + typeCombo.setSelectedItem(FIELD.getKey()); + } + // typeCombo.addDisabledIndex(directoryIndex); + typeCombo.addDisabledItem(DICTIONARY.getKey()); + break; + case SYSTEM: + case CONSTANT: + default: + typeCombo.clearDisabledIndexes(); + if (typeCombo.getSelectedItem() == FIELD.getKey()) { + typeCombo.setSelectedItem(DICTIONARY.getKey()); + } + typeCombo.addDisabledItem(FIELD.getKey()); + break; + } + } else { + typeCombo.setSelectedIndex(-1); + typeCombo.clearDisabledIndexes(); + } + } + + private class ValidDictionaryFileFilter implements FileFilter { + + private List children; + + public ValidDictionaryFileFilter(List children) { + this.children = children; + } + + @Override + public boolean accept(File pathname) { + boolean isFile = pathname.isFile(); + boolean isVisible = !pathname.isHidden(); + boolean isValidName = !pathname.getName().endsWith("~"); + boolean isNotAlreadyUsed = !children.contains(pathname.getName()); + boolean isNotVetoed = !Arrays.asList(VETOED_DICT_LIST).contains(pathname.getName()); + return isFile && isVisible && isValidName && isNotAlreadyUsed && isNotVetoed; + } + + } + + private class ValidFieldFileFilter implements FileFilter { + + private List children; + + public ValidFieldFileFilter(List children) { + this.children = children; + } + + @Override + public boolean accept(File pathname) { + boolean isFile = pathname.isFile(); + boolean isVisible = !pathname.isHidden(); + boolean isValidName = !pathname.getName().endsWith("~"); + boolean isNotAlreadyUsed = !children.contains(pathname.getName()); + boolean isFieldName = model.getFields().orderedFieldsNames().contains(pathname.getName()) || isDynamic(pathname.getName()); + + return isFile && isVisible && isValidName && isNotAlreadyUsed && isFieldName; + } + + private boolean isDynamic(String name) { + return name.equals("pointMotionU") || name.equals("pointDisplacement"); + } + } + + private class ValidDirectoryFileFilter implements FileFilter { + + private List children; + + public ValidDirectoryFileFilter(List children) { + this.children = children; + } + + @Override + public boolean accept(File pathname) { + boolean isDir = pathname.isDirectory(); + boolean isVisible = !pathname.isHidden(); + boolean isNotAlreadyUsed = !children.contains(pathname.getName()); + return isDir && isVisible && isNotAlreadyUsed && isNotAlreadyUsed; + } + } + +} diff --git a/src/eu/engys/gui/custom/CustomNodePanel.java b/src/eu/engys/gui/custom/CustomNodePanel.java new file mode 100644 index 0000000..393b474 --- /dev/null +++ b/src/eu/engys/gui/custom/CustomNodePanel.java @@ -0,0 +1,365 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.custom; + +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +import net.java.dev.designgridlayout.Componentizer; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryEditor; +import eu.engys.core.dictionary.FileEditor; +import eu.engys.core.project.Model; +import eu.engys.core.project.custom.Custom.ConstantDirectory; +import eu.engys.core.project.custom.Custom.SystemDirectory; +import eu.engys.core.project.custom.Custom.ZeroDirectory; +import eu.engys.core.project.custom.CustomFile; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.StringField; + +public class CustomNodePanel extends AbstractGUIPanel { + + public static final String ADD_LABEL = "Add"; + public static final String REMOVE_LABEL = "Remove"; + + public static final String CUSTOM = "Custom"; + public static final String FILE_NAME_LABEL = "File Name"; + public static final String FILE_TYPE_LABEL = "File Type"; + public static final String FILE_PARENT_LABEL = "File Parent"; + public static final String EDIT_LABEL = "Edit"; + + private CustomTreeNodeManager treeNodeManager; + private JButton newButton; + private JButton removeButton; + private StringField typeField; + private StringField nameField; + private StringField parentField; + private JButton editButton; + + @Inject + public CustomNodePanel(Model model) { + super(CUSTOM, model); + this.treeNodeManager = new CustomTreeNodeManager(model, this); + model.addObserver(treeNodeManager); + } + + @Override + protected JComponent layoutComponents() { + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(createButtonsPanel()); + builder.addComponent(createNameTypePanel()); + + return builder.removeMargins().getPanel(); + } + + private JComponent createButtonsPanel() { + List actionsList = new ArrayList(); + + newButton = new JButton(getAddFileAction()); + newButton.setName(ADD_LABEL); + + removeButton = new JButton(getRemoveFileAction()); + removeButton.setName(REMOVE_LABEL); + removeButton.setEnabled(false); + + actionsList.add(newButton); + actionsList.add(removeButton); + + JComponent buttonsPanel = UiUtil.getCommandRow(actionsList); + buttonsPanel.setBorder(BorderFactory.createEmptyBorder()); + return buttonsPanel; + } + + private JComponent createNameTypePanel() { + PanelBuilder nameTypeBuider = new PanelBuilder(); + + initNameField(); + initParentField(); + initTypeField(); + initEditButton(); + + nameTypeBuider.addComponent(FILE_NAME_LABEL, nameField); + nameTypeBuider.addComponent(FILE_TYPE_LABEL, typeField); + nameTypeBuider.addComponent(FILE_PARENT_LABEL, parentField); + nameTypeBuider.addComponent(EDIT_LABEL, Componentizer.create().minToPref(editButton).prefAndMore(new JLabel()).component()); + + return nameTypeBuider.removeMargins().getPanel(); + } + + private void initEditButton() { + editButton = new JButton(getEditFileAction()); + editButton.setName(EDIT_LABEL); + editButton.setEnabled(false); + } + + private void initTypeField() { + typeField = stringField(); + typeField.setEnabled(false); + } + + private void initParentField() { + parentField = stringField(); + parentField.setEnabled(false); + } + + private void initNameField() { + nameField = stringField(); + nameField.setEnabled(false); + } + + public boolean canRemoveSelectedCustomFile(CustomFile[] currentSelection) { + if (!isSomethingSelected(currentSelection)) { + return false; + } else { + boolean notZero = !(currentSelection[0] instanceof ZeroDirectory); + boolean notConstant = !(currentSelection[0] instanceof ConstantDirectory); + boolean notSystem = !(currentSelection[0] instanceof SystemDirectory); + return notZero && notConstant && notSystem; + } + } + + public boolean canEditSelectedCustomFile(CustomFile[] currentSelection) { + if (!isSomethingSelected(currentSelection)) { + return false; + } else { + boolean notDirectory = !(currentSelection[0].getType().isDirectory()); + return notDirectory; + } + } + + public boolean canAddCustomFileToSelectedFile(CustomFile[] currentSelection) { + if (isSomethingSelected(currentSelection)) { + return currentSelection[0].getType().isDirectory(); + } else { + return false; + } + } + + private boolean isSomethingSelected(CustomFile[] selection) { + if (selection == null) { + return false; + } + if (selection.length == 0) { + return false; + } + if (selection.length == 1 && selection[0] == null) { + return false; + } + return true; + } + + public void updateSelection(CustomFile[] currentSelection) { + updateTypeField(currentSelection); + updateParentField(currentSelection); + updateNameField(currentSelection); + updateAddButton(currentSelection); + updateEditButton(currentSelection); + updateRemoveButton(currentSelection); + } + + private void updateAddButton(CustomFile[] currentSelection) { + newButton.setEnabled(canAddCustomFileToSelectedFile(currentSelection)); + } + + private void updateRemoveButton(CustomFile[] currentSelection) { + removeButton.setEnabled(canRemoveSelectedCustomFile(currentSelection)); + } + + private void updateEditButton(CustomFile[] currentSelection) { + if (currentSelection != null && currentSelection.length > 0) { + if (currentSelection.length == 1 && currentSelection[0] != null) { + editButton.setEnabled(!currentSelection[0].getType().isDirectory()); + } else { + editButton.setEnabled(false); + } + } + } + + private void updateTypeField(CustomFile... currentSelection) { + if (currentSelection != null && currentSelection.length > 0) { + if (currentSelection.length == 1 && currentSelection[0] != null) { + typeField.setText(currentSelection[0].getType() != null ? currentSelection[0].getType().getLabel() : ""); + } else { + StringBuilder sb = new StringBuilder(); + for (CustomFile file : currentSelection) { + sb.append(file.getType().getLabel() + " "); + } + typeField.setText(sb.toString()); + } + } + } + + private void updateParentField(CustomFile... currentSelection) { + if (currentSelection != null && currentSelection.length > 0) { + if (currentSelection.length == 1 && currentSelection[0] != null) { + parentField.setText(currentSelection[0].getParent().getName()); + } else { + StringBuilder sb = new StringBuilder(); + for (CustomFile file : currentSelection) { + sb.append(file.getParent().getName() + " "); + } + parentField.setText(sb.toString()); + parentField.setEnabled(false); + } + } + } + + private void updateNameField(CustomFile... currentSelection) { + if (currentSelection != null && currentSelection.length > 0) { + if (currentSelection.length == 1 && currentSelection[0] != null) { + nameField.setText(currentSelection[0].getName()); + } else { + StringBuilder sb = new StringBuilder(); + for (CustomFile file : currentSelection) { + sb.append(file.getName() + " "); + } + nameField.setText(sb.toString()); + } + } + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + + public AbstractAction getAddFileAction() { + return new AddAction(); + } + + public AbstractAction getRemoveFileAction() { + return new RemoveAction(); + } + + public AbstractAction getEditFileAction() { + return new EditAction(); + } + + private class AddAction extends AbstractAction { + + public AddAction() { + super(ADD_LABEL); + } + + @Override + public void actionPerformed(ActionEvent e) { + addFile(); + + } + } + + private class RemoveAction extends AbstractAction { + + public RemoveAction() { + super(REMOVE_LABEL); + } + + @Override + public void actionPerformed(ActionEvent e) { + removeSelectedFiles(); + } + } + + private class EditAction extends AbstractAction { + + public EditAction() { + super(EDIT_LABEL); + } + + @Override + public void actionPerformed(ActionEvent e) { + editSelectedFile(); + } + } + + private void addFile() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + CustomFileDialog dialog = new CustomFileDialog(model); + dialog.show(treeNodeManager.getSelectedValue()); + updateRemoveButton(treeNodeManager.getSelectedValues()); + editSelectedFile(); + } + }); + } + + private void removeSelectedFiles() { + CustomFile[] selectedValue = treeNodeManager.getSelectedValues(); + for (CustomFile customFile : selectedValue) { + model.getCustom().remove(customFile); + } + model.customChanged(); + } + + private void editSelectedFile() { + final CustomFile customFile = treeNodeManager.getSelectedValue(); + Runnable onShowRunnable = new Runnable() { + @Override + public void run() { + editButton.setEnabled(false); + } + }; + Runnable onDisposeRunnable = new Runnable() { + @Override + public void run() { + editButton.setEnabled(true); + } + }; + Runnable onOKRunnable = new Runnable() { + @Override + public void run() { + customFile.setChanged(true); + } + }; + if (customFile != null) { + if (customFile.getType().isDictionary() || customFile.getType().isField()) { + Dictionary dictionaryToEdit = customFile.getDictionary(); + DictionaryEditor.getInstance().show(SwingUtilities.getWindowAncestor(this), dictionaryToEdit, onShowRunnable, onDisposeRunnable, onOKRunnable); + } else if (customFile.getType().isRaw()) { + List rawContent = customFile.getRawFileContent(); + FileEditor.getInstance().show(SwingUtilities.getWindowAncestor(this), rawContent, customFile.getName(), onShowRunnable, onDisposeRunnable, onOKRunnable); + } else { + // do nothing + } + } + } +} diff --git a/src/eu/engys/gui/custom/CustomTreeNodeManager.java b/src/eu/engys/gui/custom/CustomTreeNodeManager.java new file mode 100644 index 0000000..6cb2e58 --- /dev/null +++ b/src/eu/engys/gui/custom/CustomTreeNodeManager.java @@ -0,0 +1,293 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.custom; + +import java.awt.Component; +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JPopupMenu; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreePath; + +import eu.engys.core.project.Model; +import eu.engys.core.project.custom.Custom; +import eu.engys.core.project.custom.CustomFile; +import eu.engys.core.project.custom.CustomUtils; +import eu.engys.gui.tree.AbstractSelectionHandler; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.SelectionHandler; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.Symbols; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class CustomTreeNodeManager extends DefaultTreeNodeManager { + + private SelectionHandler selectionHandler; + private Map filesMap = new HashMap<>(); + private CustomNodePanel panel; + private AbstractAction addFileAction; + private AbstractAction removeFileAction; + private AbstractAction editFileAction; + + public CustomTreeNodeManager(Model model, final CustomNodePanel panel) { + super(model, panel); + this.selectionHandler = new CustomSelectionHandler(panel); + this.panel = panel; + } + + @Override + public void update(Observable o, final Object arg) { + if (arg instanceof CustomFile || arg instanceof Custom) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + loadTree(); + expandTree(arg); + } + }); + } + } + + private void loadTree() { + clear(); + load(model.getCustom().getRoot()); + treeChanged(root); + } + + private void load(CustomFile file) { + if (file != null) { + _load(file); + } + } + + private void _load(CustomFile file) { + if (file.getName() != null) { + CustomFile parent = file.getParent(); + if (parent != null && nodeMap.containsKey(parent)) { + addNode(nodeMap.get(parent), file); + } else { + addNode(root, file); + } + } + for (CustomFile child : file.getChildren()) { + load(child); + } + } + + private void addNode(DefaultMutableTreeNode parent, CustomFile file) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(file); + parent.add(node); + filesMap.put(node, file); + nodeMap.put(file, node); + } + + private void expandTree(final Object arg) { + if (getTree() != null) { + getTree().expandNode(getRoot()); + if (arg instanceof CustomFile) { + CustomFile file = (CustomFile) arg; + setSelectedValue(file); + } + } + } + + @Override + public PopUpBuilder getPopUpBuilder() { + this.addFileAction = panel.getAddFileAction(); + this.removeFileAction = panel.getRemoveFileAction(); + this.editFileAction = panel.getEditFileAction(); + return new PopUpBuilder() { + @Override + public void populate(JPopupMenu popUp) { + popUp.add(addFileAction).setName((String) addFileAction.getValue(Action.NAME)); + popUp.add(removeFileAction).setName((String) removeFileAction.getValue(Action.NAME)); + popUp.add(editFileAction).setName((String) editFileAction.getValue(Action.NAME)); + } + }; + } + + public CustomFile[] getSelectedValues() { + if (getTree() != null) { + TreePath[] selectionPaths = getTree().getSelectionPaths(); + if (selectionPaths != null) { + CustomFile[] files = new CustomFile[selectionPaths.length]; + for (int i = 0; i < selectionPaths.length; i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPaths[i].getLastPathComponent(); + CustomFile file = filesMap.get(node); + files[i] = file; + } + return files; + } + } + return new CustomFile[0]; + } + + public CustomFile getSelectedValue() { + CustomFile[] values = getSelectedValues(); + return values.length > 0 ? values[0] : null; + } + + private void setSelectedValue(CustomFile file) { + DefaultMutableTreeNode selectedNode = nodeMap.get(file); + if (getTree() != null) { + if (selectedNode != null) { + getTree().setSelectedNode(selectedNode); + } + } + } + + public void clear() { + // clear node before selection handler! + clearNode(root); + selectionHandler.clear(); + nodeMap.clear(); + filesMap.clear(); + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public Class getRendererClass() { + return CustomFile.class; + } + + public DefaultTreeCellRenderer getRenderer() { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object userObject = node.getUserObject(); + + if (userObject instanceof CustomFile) { + CustomFile item = (CustomFile) userObject; + text(item); + icon(item); + } else { + setIcon(null); + } + return this; + } + + private void text(CustomFile item) { + if (model.getProject() != null && model.getProject().isParallel() && CustomUtils.isVirtualFolder(item)) { + String hint = "[processor0 .. " + (model.getProject().getProcessors() - 1) + "]"; + setText(getLabelWithHint(item.getName(), hint)); + } else if (item.getType().isDictionary() || item.getType().isField() || item.getType().isRaw()) { + File file = CustomUtils.getFiles(model, item).get(0); + if (file.exists()) { + if (item.hasChanged()) { + setText(getLabelWithHint(item.getName(), "*")); + } else { + setText(item.getName()); + } + } else { + setText(getLabelWithHint(item.getName(), Symbols.PLUS_UPPERCASE)); + } + } else { + setText(item.getName()); + } + } + + private String getLabelWithHint(String label, String hint) { + return "" + label + " " + "" + hint + ""; + } + + private void icon(CustomFile item) { + if (item.getType().isDirectory()) { + setIcon(getDefaultOpenIcon()); + } else { + setIcon(getDefaultLeafIcon()); + } + } + }; + } + + @Override + public SelectionHandler getSelectionHandler() { + return selectionHandler; + } + + public final class CustomSelectionHandler extends AbstractSelectionHandler { + + private final CustomNodePanel panel; + private CustomFile[] currentSelection; + + public CustomSelectionHandler(CustomNodePanel panel) { + this.panel = panel; + } + + @Override + public void handleSelection(boolean fire3DEvent, Object... selection) { + if (currentSelection != null && currentSelection.length > 0) { + // panel.saveSurfaces(currentSelection); + } + if (TreeUtil.isConsistent(selection, CustomFile.class)) { + this.currentSelection = Arrays.copyOf(selection, selection.length, CustomFile[].class); + } else { + this.currentSelection = new CustomFile[0]; + } + + panel.updateSelection(currentSelection); + updateActions(); + } + + private void updateActions() { + addFileAction.setEnabled(panel.canAddCustomFileToSelectedFile(getSelectedValues())); + removeFileAction.setEnabled(panel.canRemoveSelectedCustomFile(getSelectedValues())); + editFileAction.setEnabled(panel.canEditSelectedCustomFile(getSelectedValues())); + } + + @Override + public void handleVisibility(VisibleItem item) { + } + + @Override + public void process3DSelectionEvent(Picker picker, Actor actor, boolean keep) { + } + + @Override + public void process3DVisibilityEvent(boolean selected) { + } + + public void clear() { + currentSelection = null; + } + } +} diff --git a/src/eu/engys/gui/events/EventManager.java b/src/eu/engys/gui/events/EventManager.java new file mode 100644 index 0000000..7d7fe54 --- /dev/null +++ b/src/eu/engys/gui/events/EventManager.java @@ -0,0 +1,287 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.events; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.EventListener; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class EventManager { + + public interface Condition { + public abstract boolean matches(Object obj, Event event, Object obj1); + } + + public interface Event extends Serializable { + public abstract Object getPayload(); + } + + public interface GenericEventListener extends EventListener { + public abstract void eventTriggered(Object obj, Event event); + } + + public interface EventExceptionHandler { + public abstract void handleException(Exception exception); + } + + public interface EventManagerExtension { + public abstract void afterTriggerEvent(Object obj, Event event, Object obj1); + + public abstract void afterRegisterEventListener(GenericEventListener genericeventlistener, Class class1, Condition condition, Map map); + } + + private EventManagerExtension eventManagerExtension; + private ExecutorService scheduler; + private Timer timer; + private EventExceptionHandler exceptionHandler; + protected Map> eventSubscriptionLists; + private Map> contextSubscriptionsMap; + + private static EventManager eventManager = new EventManager(); + + private static boolean asynchronous = true; + + private EventManager() { + scheduler = Executors.newCachedThreadPool(); + timer = new Timer(); + exceptionHandler = new EventExceptionHandler() { + + @Override + public void handleException(Exception ex) { + ex.printStackTrace(System.err); + } + }; + eventSubscriptionLists = new HashMap>(); + contextSubscriptionsMap = new HashMap>(); + } + + public static void registerEventListener(GenericEventListener receiver, Class eventClass) { + eventManager.registerEventListener(null, receiver, eventClass, null); + } + + public static void registerEventListener(Object context, GenericEventListener receiver, Class eventClass) { + eventManager.registerEventListener(context, receiver, eventClass, null); + } + + public static void unregisterAllEventSubscriptions() { + eventManager.eventSubscriptionLists = new HashMap>(); + } + + public static void unregisterEventSubscriptions(Class eventClass) { + eventManager.eventSubscriptionLists.remove(eventClass.getName()); + } + + public static void registerEventListener(GenericEventListener receiver, Class eventClass, Condition condition) { + eventManager.registerEventListener(null, receiver, eventClass, condition); + } + + private synchronized void registerEventListener(Object context, GenericEventListener receiver, Class eventClass, Condition condition) { + Map subcriptionList = eventSubscriptionLists.get(eventClass.getName()); + if (subcriptionList == null) { + subcriptionList = new HashMap(); + eventSubscriptionLists.put(eventClass.getName(), subcriptionList); + } + EventSubscription subscription = new EventSubscription(receiver, eventClass, condition); + if (!subcriptionList.containsKey(Integer.valueOf(subscription.hashCode()))) + subcriptionList.put(Integer.valueOf(subscription.hashCode()), subscription); + manageContext(context, subscription); + if (eventManagerExtension != null) + eventManagerExtension.afterRegisterEventListener(receiver, eventClass, condition, eventSubscriptionLists); + } + + private void manageContext(Object context, EventSubscription subscription) { + if (context != null) { + List subscriptionsAssociatedWithContext = contextSubscriptionsMap.get(context); + if (subscriptionsAssociatedWithContext == null) { + subscriptionsAssociatedWithContext = new ArrayList(); + contextSubscriptionsMap.put(context, subscriptionsAssociatedWithContext); + } + subscriptionsAssociatedWithContext.add(subscription); + } + } + + public synchronized void unregisterEventListener(GenericEventListener receiver, Class eventClass) { + EventSubscription tempSubscription = new EventSubscription(receiver, eventClass, null); + Map subcriptionList = eventSubscriptionLists.get(eventClass.getName()); + if (subcriptionList.containsKey(Integer.valueOf(tempSubscription.hashCode()))) + subcriptionList.remove(Integer.valueOf(tempSubscription.hashCode())); + } + + public synchronized void unregisterAllEventListenersForContext(Object context) { + List subscriptionsAssociatedWithContext = contextSubscriptionsMap.get(context); + for (EventSubscription eventSubscription : subscriptionsAssociatedWithContext) { + unregisterEventListener(eventSubscription.getReceiver(), eventSubscription.getEventClass()); + } + + } + + public static boolean waitUntilTriggered(Class eventClass) { + return eventManager.waitUntilTriggered(eventClass, 1000); + } + + public boolean waitUntilTriggered(Class eventClass, long timeout) { + EventWatcher eventWatcher = new EventWatcher(this, eventClass); + return eventWatcher.waitUntilTriggeredThenUnregister(timeout); + } + + public boolean waitUntilTriggered(Class eventClass, long timeout, Condition condition) { + EventWatcher eventWatcher = new EventWatcher(this, eventClass, condition); + return eventWatcher.waitUntilTriggeredThenUnregister(timeout); + } + + public static void triggerEvent(Object sender, Event event) { + eventManager.triggerEvent(sender, event, null); + } + + public synchronized void triggerEvent(Object sender, Event event, Object conditionalExpression) { + Map subscriptionList = eventSubscriptionListsForClass(event.getClass()); + if (subscriptionList != null && !subscriptionList.isEmpty()) { + for (EventSubscription eventSubscription : subscriptionList.values()) { + if (isASubscriptionForThatEvent(event, eventSubscription) && satisfyCondition(sender, event, conditionalExpression, eventSubscription)){ + if(asynchronous){ + invokeHandlerMethodAsynchronously(sender, event, eventSubscription.getReceiver()); + } else { + invokeHandlerMethodSynchronously(sender, event, eventSubscription.getReceiver()); + } + } + } + } + if (eventManagerExtension != null) + eventManagerExtension.afterTriggerEvent(sender, event, conditionalExpression); + } + + private boolean satisfyCondition(Object sender, Event event, Object conditionalExpression, EventSubscription eventSubscription) { + return eventSubscription.getCondition() == null || conditionalExpression != null && eventSubscription.getCondition().matches(sender, event, conditionalExpression); + } + + private boolean isASubscriptionForThatEvent(Event event, EventSubscription eventSubscription) { + return eventSubscription.getEventClass().isAssignableFrom(event.getClass()); + } + + private Map eventSubscriptionListsForClass(Class klass) { + String className = klass.getName(); + // System.out.println("className: "+className); + if (eventSubscriptionLists.containsKey(className)) + return eventSubscriptionLists.get(className); + for (Class interfaceClass : klass.getInterfaces()) { + String interfaceClassName = interfaceClass.getName(); + // System.out.println("interfaceClassName: "+interfaceClassName); + if (eventSubscriptionLists.containsKey(interfaceClassName)) + return eventSubscriptionLists.get(interfaceClassName); + } + if (klass.getSuperclass() != null) { + return eventSubscriptionListsForClass((Class) klass.getSuperclass()); + } + return null; + } + + public synchronized void triggerFutureEvent(Object sender, Event event, long delay, TimeUnit timeUnit) { + triggerFutureEvent(sender, event, null, delay, timeUnit); + } + + public synchronized void triggerFutureEvent(final Object sender, final Event event, final Object conditionalExpression, long delay, TimeUnit timeUnit) { + timer.schedule(new TimerTask() { + + @Override + public void run() { + triggerEvent(sender, event, conditionalExpression); + } + + }, TimeUnit.MILLISECONDS.convert(delay, timeUnit)); + } + + public synchronized void triggerPeriodicEvent(Object sender, Event event, long initialDelay, long delay, TimeUnit timeUnit) { + triggerPeriodicEvent(sender, event, null, initialDelay, delay, timeUnit); + } + + public synchronized void triggerPeriodicEvent(final Object sender, final Event event, final Object conditionalExpression, long initialDelay, long delay, TimeUnit timeUnit) { + long delayInMs = TimeUnit.MILLISECONDS.convert(initialDelay, timeUnit); + long periodInMs = TimeUnit.MILLISECONDS.convert(delay, timeUnit); + timer.scheduleAtFixedRate(new TimerTask() { + + @Override + public void run() { + triggerEvent(sender, event, conditionalExpression); + } + + }, delayInMs, periodInMs); + } + + private void invokeHandlerMethodAsynchronously(final Object sender, final Event event, final GenericEventListener receiver) { + scheduler.submit(new Runnable() { + + @Override + public void run() { + try { + receiver.eventTriggered(sender, event); + } catch (Exception ex) { + exceptionHandler.handleException(ex); + } + } + }); + } + + private void invokeHandlerMethodSynchronously(final Object sender, final Event event, final GenericEventListener receiver) { + try { + receiver.eventTriggered(sender, event); + } catch (Exception ex) { + exceptionHandler.handleException(ex); + } + } + + public static void setAsynchronous(boolean asynchronous) { + EventManager.asynchronous = asynchronous; + } + + public EventManagerExtension getEventManagerExtension() { + return eventManagerExtension; + } + + public static void setEventManagerExtension(EventManagerExtension eventManagerExtension) { + eventManager.eventManagerExtension = eventManagerExtension; + } + + public void setEventExceptionHandler(EventExceptionHandler eventExceptionHandler) { + exceptionHandler = eventExceptionHandler; + } + + public EventExceptionHandler getEventExceptionHandler() { + return exceptionHandler; + } + + public void shutdown() { + timer.cancel(); + scheduler.shutdownNow(); + } +} diff --git a/src/eu/engys/gui/events/EventObject.java b/src/eu/engys/gui/events/EventObject.java new file mode 100644 index 0000000..fa552e2 --- /dev/null +++ b/src/eu/engys/gui/events/EventObject.java @@ -0,0 +1,45 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events; + +import eu.engys.gui.events.EventManager.Event; + +public class EventObject implements Event { + + public EventObject() { + } + + public EventObject(Object payload) { + this.payload = payload; + } + + public Object getPayload() { + return payload; + } + + private Object payload; +} diff --git a/src/eu/engys/gui/events/EventSubscription.java b/src/eu/engys/gui/events/EventSubscription.java new file mode 100644 index 0000000..a07e3fa --- /dev/null +++ b/src/eu/engys/gui/events/EventSubscription.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events; + +import eu.engys.gui.events.EventManager.Condition; +import eu.engys.gui.events.EventManager.Event; +import eu.engys.gui.events.EventManager.GenericEventListener; + +public class EventSubscription { + + public EventSubscription(GenericEventListener receiver, Class eventClass, Condition condition) { + this.receiver = receiver; + this.eventClass = eventClass; + this.condition = condition; + } + + public GenericEventListener getReceiver() { + return receiver; + } + + public Class getEventClass() { + return eventClass; + } + + public int hashCode() { + return (new StringBuilder()).append(receiver.hashCode()).append(eventClass.getName()).append("").toString().hashCode(); + } + + public Condition getCondition() { + return condition; + } + + private GenericEventListener receiver; + private Class eventClass; + private Condition condition; +} diff --git a/src/eu/engys/gui/events/EventWatcher.java b/src/eu/engys/gui/events/EventWatcher.java new file mode 100644 index 0000000..6913bb1 --- /dev/null +++ b/src/eu/engys/gui/events/EventWatcher.java @@ -0,0 +1,120 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events; + +import eu.engys.gui.events.EventManager.Condition; +import eu.engys.gui.events.EventManager.Event; +import eu.engys.gui.events.EventManager.GenericEventListener; + +public class EventWatcher { + + private boolean triggered; + private final Object lockObject; + private Class eventClass; + private Condition condition; + private GenericEventListener eventListener; + private Object eventPayload; + private EventManager eventManager; + + public EventWatcher(EventManager eventManager, Class eventClass) { + this(eventManager, eventClass, null); + } + + public EventWatcher(EventManager eventManager, Class eventClass, Condition condition) { + triggered = false; + lockObject = new Object(); + this.eventManager = eventManager; + this.eventClass = eventClass; + this.condition = condition; + registerEventListener(eventClass, condition); + } + + private synchronized void registerEventListener(Class eventClass, Condition condition) { + createEventListener(); + if (condition != null) + EventManager.registerEventListener(eventListener, eventClass, condition); + else + EventManager.registerEventListener(eventListener, eventClass); + } + + private synchronized void createEventListener() { + eventListener = new GenericEventListener() { + + public synchronized void eventTriggered(Object sender, Event event) { + synchronized (lockObject) { + eventPayload = event.getPayload(); + triggered = true; + lockObject.notifyAll(); + } + } + }; + } + + public synchronized void unregisterEvent() { + eventManager.unregisterEventListener(eventListener, eventClass); + } + + public boolean hasBeenTriggered() { + if (triggered) { + triggered = false; + return true; + } + return false; + } + + public boolean waitUntilTriggeredThenUnregister(long timeout) { + boolean result = waitUntilTriggered(timeout); + unregisterEvent(); + return result; + } + + public boolean waitUntilTriggered(long timeout) { + if (hasBeenTriggered()) + return true; + try { + synchronized (lockObject) { + lockObject.wait(timeout); + } + } catch (InterruptedException e) { + } + return hasBeenTriggered(); + } + + public void reEnableEventWatcher() { + triggered = false; + registerEventListener(eventClass, condition); + } + + public Object getEventPayload() { + return eventPayload; + } + + public Class getEvent() { + return eventClass; + } + +} diff --git a/src/eu/engys/gui/events/application/ApplicationEvent.java b/src/eu/engys/gui/events/application/ApplicationEvent.java new file mode 100644 index 0000000..4fb2654 --- /dev/null +++ b/src/eu/engys/gui/events/application/ApplicationEvent.java @@ -0,0 +1,33 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.application; + +import eu.engys.gui.events.EventManager.Event; + +public interface ApplicationEvent extends Event { + +} diff --git a/src/eu/engys/gui/events/application/BaseMeshTypeChangedEvent.java b/src/eu/engys/gui/events/application/BaseMeshTypeChangedEvent.java new file mode 100644 index 0000000..6368c06 --- /dev/null +++ b/src/eu/engys/gui/events/application/BaseMeshTypeChangedEvent.java @@ -0,0 +1,37 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.application; + +import eu.engys.gui.events.EventObject; + +public class BaseMeshTypeChangedEvent extends EventObject implements ApplicationEvent{ + + public BaseMeshTypeChangedEvent() { + super(); + } + +} diff --git a/src/eu/engys/gui/events/application/OpenMonitorEvent.java b/src/eu/engys/gui/events/application/OpenMonitorEvent.java new file mode 100644 index 0000000..947cffe --- /dev/null +++ b/src/eu/engys/gui/events/application/OpenMonitorEvent.java @@ -0,0 +1,37 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.application; + +import eu.engys.gui.events.EventObject; + +public class OpenMonitorEvent extends EventObject implements ApplicationEvent { + + public OpenMonitorEvent() { + super(); + } + +} diff --git a/src/eu/engys/gui/events/view3D/ActorExtractEvent.java b/src/eu/engys/gui/events/view3D/ActorExtractEvent.java new file mode 100644 index 0000000..0b21f47 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/ActorExtractEvent.java @@ -0,0 +1,49 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.gui.events.EventObject; + +public class ActorExtractEvent extends EventObject { + + private String actorName; + private String newName; + + public ActorExtractEvent(String actorName, String newName) { + super(); + this.actorName = actorName; + this.newName = newName; + } + + public String getActorName() { + return actorName; + } + + public String getNewName() { + return newName; + } +} diff --git a/src/eu/engys/gui/events/view3D/ActorPopUpEvent.java b/src/eu/engys/gui/events/view3D/ActorPopUpEvent.java new file mode 100644 index 0000000..121292d --- /dev/null +++ b/src/eu/engys/gui/events/view3D/ActorPopUpEvent.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import java.awt.event.MouseEvent; + +import eu.engys.gui.events.EventObject; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; + +public class ActorPopUpEvent extends EventObject { + + private Actor actor; + private Picker picker; + private MouseEvent event; + + + public ActorPopUpEvent(MouseEvent event, Picker picker, Actor actor) { + this.picker = picker; + this.actor = actor; + this.event = event; + } + + public Actor getActor() { + return actor; + } + + public Picker getPicker() { + return picker; + } + + public MouseEvent getMouseEvent() { + return event; + } + +} diff --git a/src/eu/engys/gui/events/view3D/ActorSelectionEvent.java b/src/eu/engys/gui/events/view3D/ActorSelectionEvent.java new file mode 100644 index 0000000..41556ee --- /dev/null +++ b/src/eu/engys/gui/events/view3D/ActorSelectionEvent.java @@ -0,0 +1,57 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.gui.events.EventObject; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; + +public class ActorSelectionEvent extends EventObject { + + private Actor actor; + private Picker picker; + private boolean keep; + + public ActorSelectionEvent(Picker picker, Actor actor, boolean keep) { + super(); + this.picker = picker; + this.actor = actor; + this.keep = keep; + } + + public Actor getActor() { + return actor; + } + + public Picker getPicker() { + return picker; + } + + public boolean isKeep() { + return keep; + } +} diff --git a/src/eu/engys/gui/events/view3D/ActorVisibilityEvent.java b/src/eu/engys/gui/events/view3D/ActorVisibilityEvent.java new file mode 100644 index 0000000..f14f6eb --- /dev/null +++ b/src/eu/engys/gui/events/view3D/ActorVisibilityEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.gui.events.EventObject; + +public class ActorVisibilityEvent extends EventObject { + + private final boolean select; + + public ActorVisibilityEvent(boolean select) { + super(); + this.select = select; + } + + public boolean isSelect() { + return select; + } + +} diff --git a/src/eu/engys/gui/events/view3D/AddSTLEvent.java b/src/eu/engys/gui/events/view3D/AddSTLEvent.java new file mode 100644 index 0000000..dc838e1 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/AddSTLEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import java.util.EventObject; + +import eu.engys.core.project.geometry.surface.Stl; + +public class AddSTLEvent extends EventObject { + + private Stl stl; + + public AddSTLEvent(Object source, Stl stl) { + super(source); + this.stl = stl; + } + + public Stl getStl() { + return stl; + } + +} diff --git a/src/eu/engys/gui/events/view3D/AddSurfaceEvent.java b/src/eu/engys/gui/events/view3D/AddSurfaceEvent.java new file mode 100644 index 0000000..6a9c009 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/AddSurfaceEvent.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.events.EventObject; + +public class AddSurfaceEvent extends EventObject implements View3DEvent { + + private Surface[] surfaces; + private boolean resetZoom; + + public AddSurfaceEvent(boolean resetZoom, Surface... surfaces) { + super(surfaces); + this.resetZoom = resetZoom; + this.surfaces = surfaces; + } + + public AddSurfaceEvent(Surface... surfaces) { + this(true, surfaces); + } + + public Surface[] getSurfaces() { + return surfaces; + } + + public boolean isResetZoom() { + return resetZoom; + } +} diff --git a/src/eu/engys/gui/events/view3D/AxisEvent.java b/src/eu/engys/gui/events/view3D/AxisEvent.java new file mode 100644 index 0000000..3a4fa77 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/AxisEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.dictionary.model.AxisInfo; +import eu.engys.gui.events.EventObject; + +public class AxisEvent extends EventObject implements View3DEvent { + + private AxisInfo axisInfo; + + public AxisEvent(AxisInfo axisInfo) { + super(); + this.axisInfo = axisInfo; + } + + public AxisInfo getAxisInfo() { + return axisInfo; + } +} diff --git a/src/eu/engys/gui/events/view3D/BoxEvent.java b/src/eu/engys/gui/events/view3D/BoxEvent.java new file mode 100644 index 0000000..1b9b32e --- /dev/null +++ b/src/eu/engys/gui/events/view3D/BoxEvent.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.events.EventObject; +import eu.engys.util.ui.textfields.DoubleField; + +public class BoxEvent extends EventObject implements View3DEvent { + + private DoubleField[] min; + private DoubleField[] max; + private EventActionType action; + + public BoxEvent(DoubleField[] min, DoubleField[] max, EventActionType action) { + super(); + this.min = min; + this.max = max; + this.action = action; + } + + public DoubleField[] getMin() { + return min; + } + public void setMin(DoubleField[] min) { + this.min = min; + } + + public DoubleField[] getMax() { + return max; + } + public void setMax(DoubleField[] max) { + this.max = max; + } + + public EventActionType getAction() { + return action; + } + + public void setAction(EventActionType action) { + this.action = action; + } + +} diff --git a/src/eu/engys/gui/events/view3D/ChangeSurfaceEvent.java b/src/eu/engys/gui/events/view3D/ChangeSurfaceEvent.java new file mode 100644 index 0000000..35d54c1 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/ChangeSurfaceEvent.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.events.EventObject; + +public class ChangeSurfaceEvent extends EventObject implements View3DEvent { + + private Surface surface; + private final boolean resetZoom; + + public ChangeSurfaceEvent(Surface surface, boolean resetZoom) { + super(); + this.surface = surface; + this.resetZoom = resetZoom; + } + + public Surface getSurface() { + return surface; + } + + public boolean isResetZoom() { + return resetZoom; + } + +} diff --git a/src/eu/engys/gui/events/view3D/ColorSurfaceEvent.java b/src/eu/engys/gui/events/view3D/ColorSurfaceEvent.java new file mode 100644 index 0000000..e7e438b --- /dev/null +++ b/src/eu/engys/gui/events/view3D/ColorSurfaceEvent.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import java.awt.Color; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.events.EventObject; + +public class ColorSurfaceEvent extends EventObject implements View3DEvent { + + private Surface selection; + private Color color; + + public ColorSurfaceEvent(Surface selection, Color value) { + super(); + this.selection = selection; + this.color = value; + } + + public Surface getSelection() { + return selection; + } + + public Color getColor() { + return color; + } +} diff --git a/src/eu/engys/gui/events/view3D/LayersCoverageEvent.java b/src/eu/engys/gui/events/view3D/LayersCoverageEvent.java new file mode 100644 index 0000000..4742222 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/LayersCoverageEvent.java @@ -0,0 +1,64 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import javax.swing.JPanel; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.events.EventObject; +import eu.engys.gui.view3D.LayerInfo; + +public class LayersCoverageEvent extends EventObject implements View3DEvent { + + private EventActionType action; + private JPanel colorBar; + private LayerInfo layerInfo; + + public LayersCoverageEvent(LayerInfo layerInfo, JPanel colorBar, EventActionType action) { + super(); + this.layerInfo = layerInfo; + this.colorBar = colorBar; + this.action = action; + } + + public EventActionType getAction() { + return action; + } + + public JPanel getColorBar() { + return colorBar; + } + + public LayerInfo getLayerInfo() { + return layerInfo; + } + + public void setAction(EventActionType action) { + this.action = action; + } + +} diff --git a/src/eu/engys/gui/events/view3D/MeshQualityEvent.java b/src/eu/engys/gui/events/view3D/MeshQualityEvent.java new file mode 100644 index 0000000..60f38a9 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/MeshQualityEvent.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.events.EventObject; +import eu.engys.gui.view3D.QualityInfo; + +public class MeshQualityEvent extends EventObject implements View3DEvent { + + private EventActionType action; + private QualityInfo quality; + + public MeshQualityEvent(QualityInfo quality, EventActionType action) { + super(); + this.quality = quality; + this.action = action; + } + + public EventActionType getAction() { + return action; + } + + public void setAction(EventActionType action) { + this.action = action; + } + + public QualityInfo getQualityInfo() { + return quality; + } + +} diff --git a/src/eu/engys/gui/events/view3D/PlaneEvent.java b/src/eu/engys/gui/events/view3D/PlaneEvent.java new file mode 100644 index 0000000..2e53ed2 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/PlaneEvent.java @@ -0,0 +1,86 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.events.EventObject; +import eu.engys.util.ui.textfields.DoubleField; + +public class PlaneEvent extends EventObject implements View3DEvent { + + private DoubleField[] normal; + private DoubleField[] origin; + private EventActionType action; + private boolean interactive; + + public PlaneEvent(DoubleField[] origin, DoubleField[] normal, EventActionType action) { + super(); + this.origin = origin; + this.normal = normal; + this.action = action; + this.interactive = true; + } + + public PlaneEvent(DoubleField[] origin, DoubleField[] normal, EventActionType action, boolean interactive) { + super(); + this.origin = origin; + this.normal = normal; + this.action = action; + this.interactive = interactive; + } + + public DoubleField[] getOrigin() { + return origin; + } + + public void setOrigin(DoubleField[] origin) { + this.origin = origin; + } + + public DoubleField[] getNormal() { + return normal; + } + + public void setNormal(DoubleField[] normal) { + this.normal = normal; + } + + public EventActionType getAction() { + return action; + } + + public void setAction(EventActionType action) { + this.action = action; + } + + public void setInteractive(boolean interactive) { + this.interactive = interactive; + } + public boolean isInteractive() { + return interactive; + } +} diff --git a/src/eu/engys/gui/events/view3D/PointEvent.java b/src/eu/engys/gui/events/view3D/PointEvent.java new file mode 100644 index 0000000..4efdc27 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/PointEvent.java @@ -0,0 +1,66 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import java.awt.Color; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.events.EventObject; +import eu.engys.util.ui.textfields.DoubleField; + +public class PointEvent extends EventObject implements View3DEvent { + + private DoubleField[] field; + private Color color; + private String key; + private EventActionType action; + + public PointEvent(DoubleField[] field, String key, EventActionType action, Color color) { + super(); + this.field = field; + this.key = key; + this.action = action; + this.color = color; + } + + public DoubleField[] getPoint() { + return field; + } + + public String getKey() { + return key; + } + + public EventActionType getAction() { + return action; + } + + public Color getColor() { + return color; + } + +} diff --git a/src/eu/engys/gui/events/view3D/RemoveSurfaceEvent.java b/src/eu/engys/gui/events/view3D/RemoveSurfaceEvent.java new file mode 100644 index 0000000..468ee77 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/RemoveSurfaceEvent.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.events.EventObject; + +public class RemoveSurfaceEvent extends EventObject implements View3DEvent { + + private Surface[] surfaces; + private boolean resetZoom; + + public RemoveSurfaceEvent(boolean resetZoom, Surface... surfaces) { + super(); + this.resetZoom = resetZoom; + this.surfaces = surfaces; + } + + public RemoveSurfaceEvent(Surface... surfaces) { + this(false, surfaces); + } + + public Surface[] getSurfaces() { + return surfaces; + } + + public boolean isResetZoom() { + return resetZoom; + } +} diff --git a/src/eu/engys/gui/events/view3D/RenameSurfaceEvent.java b/src/eu/engys/gui/events/view3D/RenameSurfaceEvent.java new file mode 100644 index 0000000..0eb8c1a --- /dev/null +++ b/src/eu/engys/gui/events/view3D/RenameSurfaceEvent.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.events.EventObject; + +public class RenameSurfaceEvent extends EventObject implements View3DEvent { + + private Surface surface; + private String oldName; + private String newName; + + public RenameSurfaceEvent(Surface surface, String oldName, String newName) { + super(); + this.surface = surface; + this.newName = newName; + this.oldName = oldName; + } + + public Surface getSurface() { + return surface; + } + + public String getOldName() { + return oldName; + } + + public String getNewName() { + return newName; + } +} diff --git a/src/eu/engys/gui/events/view3D/ScalarBarWidgetEvent.java b/src/eu/engys/gui/events/view3D/ScalarBarWidgetEvent.java new file mode 100644 index 0000000..9c98a80 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/ScalarBarWidgetEvent.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.gui.events.EventObject; + +public class ScalarBarWidgetEvent extends EventObject implements View3DEvent { + + private boolean on; + + public ScalarBarWidgetEvent(boolean on) { + super(); + this.on = on; + } + + public boolean isOn() { + return on; + } +} diff --git a/src/eu/engys/gui/events/view3D/SelectCellZonesEvent.java b/src/eu/engys/gui/events/view3D/SelectCellZonesEvent.java new file mode 100644 index 0000000..dd26ab8 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/SelectCellZonesEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.gui.events.EventObject; + +public class SelectCellZonesEvent extends EventObject implements View3DEvent { + + private CellZone[] selection; + + public SelectCellZonesEvent(CellZone[] selection) { + super(); + this.selection = selection; + } + + public CellZone[] getSelection() { + return selection; + } +} diff --git a/src/eu/engys/gui/events/view3D/SelectPatchesEvent.java b/src/eu/engys/gui/events/view3D/SelectPatchesEvent.java new file mode 100644 index 0000000..f05cba8 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/SelectPatchesEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.events.EventObject; + +public class SelectPatchesEvent extends EventObject implements View3DEvent { + + private Patch[] selection; + + public SelectPatchesEvent(Patch[] patches) { + super(); + this.selection = patches; + } + + public Patch[] getSelection() { + return selection; + } +} diff --git a/src/eu/engys/gui/events/view3D/SelectSurfaceEvent.java b/src/eu/engys/gui/events/view3D/SelectSurfaceEvent.java new file mode 100644 index 0000000..00bd45a --- /dev/null +++ b/src/eu/engys/gui/events/view3D/SelectSurfaceEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.events.EventObject; + +public class SelectSurfaceEvent extends EventObject implements View3DEvent { + + private Surface[] selection; + + public SelectSurfaceEvent(Surface[] selection) { + super(); + this.selection = selection; + } + + public Surface[] getSelection() { + return selection; + } +} diff --git a/src/eu/engys/gui/events/view3D/SelectionEvent.java b/src/eu/engys/gui/events/view3D/SelectionEvent.java new file mode 100644 index 0000000..6a0102a --- /dev/null +++ b/src/eu/engys/gui/events/view3D/SelectionEvent.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.events.EventObject; +import eu.engys.gui.view3D.Selection; + +public class SelectionEvent extends EventObject implements View3DEvent { + + private EventActionType action; + private Selection selection; + + public SelectionEvent(Selection selection, EventActionType action) { + super(); + this.selection = selection; + this.action = action; + } + + public void setSelection(Selection selection) { + this.selection = selection; + } + + public Selection getSelection() { + return selection; + } + + public EventActionType getAction() { + return action; + } + + public void setAction(EventActionType action) { + this.action = action; + } + +} diff --git a/src/eu/engys/gui/events/view3D/TransformSurfaceEvent.java b/src/eu/engys/gui/events/view3D/TransformSurfaceEvent.java new file mode 100644 index 0000000..c9714fb --- /dev/null +++ b/src/eu/engys/gui/events/view3D/TransformSurfaceEvent.java @@ -0,0 +1,57 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.gui.events.EventObject; + +public class TransformSurfaceEvent extends EventObject implements View3DEvent{ + + private Surface[] surfaces; + private AffineTransform transformation; + private boolean save; + + public TransformSurfaceEvent(AffineTransform t, boolean save, Surface... surfaces) { + super(t); + this.save = save; + this.surfaces = surfaces; + this.transformation = t; + } + + public Surface[] getSurfaces() { + return surfaces; + } + + public AffineTransform getTransformation() { + return transformation; + } + + public boolean shouldSave() { + return save; + } +} diff --git a/src/eu/engys/gui/events/view3D/View3DEvent.java b/src/eu/engys/gui/events/view3D/View3DEvent.java new file mode 100644 index 0000000..53cbb22 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/View3DEvent.java @@ -0,0 +1,33 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.gui.events.EventManager.Event; + +public interface View3DEvent extends Event { + +} diff --git a/src/eu/engys/gui/events/view3D/VisibleItemEvent.java b/src/eu/engys/gui/events/view3D/VisibleItemEvent.java new file mode 100644 index 0000000..c652022 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/VisibleItemEvent.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.gui.events.EventObject; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class VisibleItemEvent extends EventObject implements View3DEvent { + + private VisibleItem selection; + private Object invoker; + + public VisibleItemEvent(Object invoker, VisibleItem selection) { + super(); + this.invoker = invoker; + this.selection = selection; + } + + public VisibleItem getSelection() { + return selection; + } + + public Object getInvoker() { + return invoker; + } + +} diff --git a/src/eu/engys/gui/events/view3D/VolumeReportEvent.java b/src/eu/engys/gui/events/view3D/VolumeReportEvent.java new file mode 100644 index 0000000..6376a6c --- /dev/null +++ b/src/eu/engys/gui/events/view3D/VolumeReportEvent.java @@ -0,0 +1,58 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import javax.vecmath.Point3d; + +import eu.engys.gui.events.EventObject; + +public class VolumeReportEvent extends EventObject implements View3DEvent { + + private final Point3d minAtLocation; + private final Point3d maxAtLocation; + private final String varName; + + public VolumeReportEvent(Point3d minAtLocation, Point3d maxAtLocation, String varName) { + super(); + this.minAtLocation = minAtLocation; + this.maxAtLocation = maxAtLocation; + this.varName = varName; + } + + public String getVarName() { + return varName; + } + + public Point3d getMinAtLocation() { + return minAtLocation; + } + + public Point3d getMaxAtLocation() { + return maxAtLocation; + } + +} diff --git a/src/eu/engys/gui/events/view3D/VolumeReportVisibilityEvent.java b/src/eu/engys/gui/events/view3D/VolumeReportVisibilityEvent.java new file mode 100644 index 0000000..a8b8e91 --- /dev/null +++ b/src/eu/engys/gui/events/view3D/VolumeReportVisibilityEvent.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.events.view3D; + +import eu.engys.gui.events.EventObject; + +public class VolumeReportVisibilityEvent extends EventObject implements View3DEvent { + + private String key; + private Kind kind; + private boolean visible; + + public enum Kind { + MIN, MAX; + + public boolean isMin() { + return this == MIN; + } + + public boolean isMax() { + return this == MAX; + } + } + + public VolumeReportVisibilityEvent(String key, Kind kind, boolean visible) { + super(); + this.key = key; + this.kind = kind; + this.visible = visible; + } + + public String getKey() { + return key; + } + + public Kind getKind() { + return kind; + } + + public boolean isVisible() { + return visible; + } + +} diff --git a/src/eu/engys/gui/mesh/GeometryPanel.java b/src/eu/engys/gui/mesh/GeometryPanel.java new file mode 100644 index 0000000..3fd8fe1 --- /dev/null +++ b/src/eu/engys/gui/mesh/GeometryPanel.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh; + +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.util.progress.ProgressMonitor; + +public interface GeometryPanel { + + void addSTL(); + + void addBox(); + + void addCylinder(); + + void addSphere(); + + void addRing(); + + void addPlane(); + + void renameSurface(String text); + + void changeSurface(Surface surface); + + Model getModel(); + + ProgressMonitor getMonitor(); + +} diff --git a/src/eu/engys/gui/mesh/Mesh.java b/src/eu/engys/gui/mesh/Mesh.java new file mode 100644 index 0000000..36e3e7f --- /dev/null +++ b/src/eu/engys/gui/mesh/Mesh.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +public @interface Mesh { + +} diff --git a/src/eu/engys/gui/mesh/Mesh3DElement.java b/src/eu/engys/gui/mesh/Mesh3DElement.java new file mode 100644 index 0000000..72547fe --- /dev/null +++ b/src/eu/engys/gui/mesh/Mesh3DElement.java @@ -0,0 +1,50 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh; + +import java.util.Set; + +import javax.inject.Inject; + +import eu.engys.gui.GUIPanel; +import eu.engys.gui.view.AbstractView3DElement; +import eu.engys.gui.view3D.CanvasPanel; + +public class Mesh3DElement extends AbstractView3DElement { + + @Inject + public Mesh3DElement(@Mesh Set panels) { + super(panels); + } + + @Override + public void load(CanvasPanel view3D) { + view3D.getMeshController().newContext(getClass()); + view3D.getGeometryController().newContext(getClass()); + } + +} diff --git a/src/eu/engys/gui/mesh/MeshElement.java b/src/eu/engys/gui/mesh/MeshElement.java new file mode 100644 index 0000000..988ba0f --- /dev/null +++ b/src/eu/engys/gui/mesh/MeshElement.java @@ -0,0 +1,115 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh; + +import java.util.Observable; +import java.util.Observer; +import java.util.Set; + +import javax.inject.Inject; +import javax.swing.SwingUtilities; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.Model; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.gui.Actions; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.mesh.actions.DefaultMeshActions; +import eu.engys.gui.view.AbstractViewElement; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElementPanel; +import eu.engys.util.plaf.ILookAndFeel; + +public class MeshElement extends AbstractViewElement { + + private static final Logger logger = LoggerFactory.getLogger(MeshElement.class); + + private ViewElementPanel viewElementPanel; + private Model model; + private Observer modelObserver; + + @Inject + public MeshElement(Model model, @Mesh String title, @Mesh Set panels, Set modules, @Mesh View3DElement view3DElement, @Mesh Actions actions, ILookAndFeel lookAndFeel) { + super(title, panels, modules, view3DElement, actions, lookAndFeel); + this.model = model; + } + + @Override + public void layoutComponents() { + viewElementPanel = new ViewElementPanel(this); + modelObserver = new Observer() { + @Override + public void update(Observable o, Object arg) { + logger.debug("Observerd a change: arg is " + arg.getClass()); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + ((DefaultMeshActions) actions).update(); + } + }); + } + }; + super.layoutComponents(); + } + + @Override + public int getPreferredWidth() { + return 650; + } + + @Override + public ViewElementPanel getPanel() { + return viewElementPanel; + } + + @Override + public void start() { + super.start(); + model.addObserver(modelObserver); + } + + @Override + public void stop() { + model.deleteObserver(modelObserver); + super.stop(); + } + + @Override + public ProjectReader getReader() { + return null; + } + + @Override + public ProjectWriter getWriter() { + return null; + } + +} diff --git a/src/eu/engys/gui/mesh/actions/AddIGES.java b/src/eu/engys/gui/mesh/actions/AddIGES.java new file mode 100644 index 0000000..fb8ef5c --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/AddIGES.java @@ -0,0 +1,153 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JOptionPane; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; + +import eu.engys.core.controller.actions.RunCommand; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.geometry.stl.ImportIGES; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.util.TempFolder; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.UiUtil; + +public abstract class AddIGES { + + private ProgressMonitor monitor; + private Model model; + + public AddIGES(Model model, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + } + + public void execute() { + IGESFileChooserWrapper fc = new IGESFileChooserWrapper(); + ReturnValue returnedValue = fc.showOpenDialog(); + + if (returnedValue.isApprove()) { + final File[] files = fc.getSelectedFiles(); + final AffineTransform[] transformations = fc.getSelectedTransform(); + final boolean split = fc.getIGESAccessory().getSplit(); + final double precision = fc.getIGESAccessory().getPrecision(); + + boolean filesOK = files != null && files.length > 0; + boolean transformationsOK = transformations != null && transformations.length > 0; + boolean sameLength = transformations.length == files.length; + if (filesOK && transformationsOK && sameLength) { + try { + convertIGES(files, transformations, split, precision); + } catch (IOException e) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Unable to load selected IGES: " + e.getMessage(), "File Type Error", JOptionPane.ERROR_MESSAGE); + } + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Unable to load selected IGES", "File Type Error", JOptionPane.ERROR_MESSAGE); + } + } + } + + public void convertIGES(File[] igesToCopy, final AffineTransform[] transformations, final boolean split, double precision) throws IOException { + final File[] copiedIgesList = new File[igesToCopy.length]; + final File[] createdStlList = new File[igesToCopy.length]; + final File tmpFolder = TempFolder.get(AddIGES.class.getSimpleName()); + + for (int i = 0; i < igesToCopy.length; i++) { + File iges = igesToCopy[i]; + FileUtils.copyFileToDirectory(iges, tmpFolder); + + copiedIgesList[i] = new File(tmpFolder, iges.getName()); + createdStlList[i] = new File(tmpFolder, FilenameUtils.removeExtension(iges.getName()) + ".stl"); + } + + Runnable loadSTLRunnable = new Runnable() { + @Override + public void run() { + monitor.setIndeterminate(false); + monitor.start("Loading IGES Files", false, new Runnable() { + @Override + public void run() { + Map fileMap = getSTLFilesToImport(createdStlList, split); + List keySet = new ArrayList(fileMap.keySet()); + List stls = new ArrayList<>(); + for (int i = 0; i < keySet.size(); i++) { + String key = keySet.get(i); + for (File stlFile : fileMap.get(key)) { + monitor.info(String.format("Loading %s ", stlFile.getAbsolutePath())); + + Stl stl = model.getGeometry().getFactory().readSTL(stlFile, monitor); + stl.setTransformation(transformations[i]); + stls.add(stl); + + } + } + postLoad(stls); + FileUtils.deleteQuietly(tmpFolder); + monitor.end(); + } + }); + } + }; + + RunCommand command = new ImportIGES(model, loadSTLRunnable, copiedIgesList, createdStlList, split, precision); + command.beforeExecute(); + command.executeClient(); + } + + private Map getSTLFilesToImport(File[] createdStlList, boolean split) { + final Map map = new LinkedHashMap(); + for (final File stl : createdStlList) { + if (split) { + File[] stlComponents = stl.getParentFile().listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.startsWith(FilenameUtils.removeExtension(stl.getName())) && name.contains("Component"); + } + }); + map.put(stl.getName(), stlComponents); + } else { + map.put(stl.getName(), new File[] { stl }); + } + } + return map; + } + + public abstract void postLoad(List stls); + +} diff --git a/src/eu/engys/gui/mesh/actions/AddSTL.java b/src/eu/engys/gui/mesh/actions/AddSTL.java new file mode 100644 index 0000000..3b7be8a --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/AddSTL.java @@ -0,0 +1,107 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh.actions; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JOptionPane; + +import org.apache.commons.io.FileUtils; + +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.util.ArchiveUtils; +import eu.engys.util.TempFolder; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.UiUtil; + +public abstract class AddSTL { + + private ProgressMonitor monitor; + private Model model; + + public AddSTL(Model model, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + } + + public void execute() { + STLFileChooserWrapper fc = new STLFileChooserWrapper(); + ReturnValue returnedValue = fc.showOpenDialog(); + + if (returnedValue.isApprove()) { + final File[] files = fc.getSelectedFiles(); + final AffineTransform[] transformations = fc.getSelectedTransform(); + + boolean filesOK = files != null && files.length > 0; + boolean transformationsOK = transformations != null && transformations.length > 0; + boolean sameLength = transformations.length == files.length; + if (filesOK && transformationsOK && sameLength) { + monitor.setIndeterminate(false); + monitor.start("Loading STL Files", false, new Runnable() { + @Override + public void run() { + List stls = new ArrayList<>(); + for (int i = 0; i < files.length; i++) { + File file = files[i]; + AffineTransform transform = transformations[i]; + + if (ArchiveUtils.isArchive(file)) { + File tmpFolder = TempFolder.get(AddSTL.class.getSimpleName()); + + List extractedFiles = ArchiveUtils.unarchive(file, tmpFolder); + for (File target : extractedFiles) { + monitor.info(String.format("Loading %s-%s ", file.getAbsolutePath(), target.getName())); + Stl stl = model.getGeometry().getFactory().readSTL(target, monitor); + stl.setTransformation(transform); + stls.add(stl); + } + FileUtils.deleteQuietly(tmpFolder); + } else { + monitor.info(String.format("Loading %s ", file.getAbsolutePath())); + Stl stl = model.getGeometry().getFactory().readSTL(file, monitor); + stl.setTransformation(transform); + stls.add(stl); + } + } + postLoad(stls); + monitor.end(); + } + }); + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Unable to load selected STLs", "File Type Error", JOptionPane.ERROR_MESSAGE); + } + } + } + + public abstract void postLoad(List stls); + +} diff --git a/src/eu/engys/gui/mesh/actions/DefaultMeshActions.java b/src/eu/engys/gui/mesh/actions/DefaultMeshActions.java new file mode 100644 index 0000000..90c3bc0 --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/DefaultMeshActions.java @@ -0,0 +1,164 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; + +import eu.engys.core.controller.Controller; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.gui.Actions; +import eu.engys.gui.mesh.panels.DefaultMeshAdvancedOptionsPanel; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public abstract class DefaultMeshActions implements Actions { + + public static final String ADVANCED_OPTIONS = "Advanced Options"; + protected Model model; + protected Controller controller; + protected ProgressMonitor monitor; + protected DefaultMeshAdvancedOptionsPanel generalOptionsPanel; + + protected final Action createMesh, checkMesh, deleteMesh, virtualMesh; + + public DefaultMeshActions(Model model, Controller controller, ProgressMonitor monitor, DefaultMeshAdvancedOptionsPanel generalOptionsPanel) { + this.model = model; + this.controller = controller; + this.monitor = monitor; + this.generalOptionsPanel = generalOptionsPanel; + + createMesh = ActionManager.getInstance().get("mesh.create"); + checkMesh = ActionManager.getInstance().get("mesh.check"); + deleteMesh = ActionManager.getInstance().get("mesh.delete"); + virtualMesh = ActionManager.getInstance().get("mesh.batch"); + } + + @Override + public void update() { + createMesh.setEnabled(!model.getGeometry().isEmpty()); + checkMesh.setEnabled(!model.getPatches().isEmpty()); + deleteMesh.setEnabled(!model.getPatches().isEmpty()); + } + + protected final Action openOptionsDialog = new ViewAction(OPEN_OPTIONS_DIALOG_LABEL, OPT_ICON, OPEN_OPTIONS_DIALOG_TOOLTIP) { + + private JDialog dialog; + + public void actionPerformed(ActionEvent e) { + // Commented because there seems to be no reason to save the case + // here + // controller.save(null); + createGeneralOptionsDialog(); + generalOptionsPanel.load(); + dialog.setVisible(true); + } + + private void createGeneralOptionsDialog() { + if (dialog == null) { + dialog = new JDialog(UiUtil.getActiveWindow()); + dialog.setName("general.options.dialog"); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.setName("general.options.panel"); + + JPanel buttonsPanel = new JPanel(new GridLayout(1, 2)); + JPanel leftButtonsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JPanel rightButtonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + buttonsPanel.add(leftButtonsPanel); + buttonsPanel.add(rightButtonsPanel); + + generalOptionsPanel.layoutPanel(); + mainPanel.add(generalOptionsPanel.getPanel(), BorderLayout.CENTER); + + AbstractAction saveAndCloseDialogAction = new AbstractAction("OK") { + @Override + public void actionPerformed(ActionEvent e) { + generalOptionsPanel.save(); + generalOptionsPanel.handleClose(); + dialog.setVisible(false); + } + }; + + AbstractAction cancelAction = new AbstractAction("Cancel") { + @Override + public void actionPerformed(ActionEvent e) { + generalOptionsPanel.handleClose(); + dialog.setVisible(false); + } + }; + + AbstractAction resetToDefaultsAction = new AbstractAction("Reset") { + @Override + public void actionPerformed(ActionEvent e) { + generalOptionsPanel.resetToDefaults(); + } + }; + + JButton okButton = new JButton(saveAndCloseDialogAction); + okButton.setName("OK"); + rightButtonsPanel.add(okButton); + + JButton cancelButton = new JButton(cancelAction); + cancelButton.setName("Cancel"); + rightButtonsPanel.add(cancelButton); + + JButton resetButton = new JButton(resetToDefaultsAction); + resetButton.setName("Reset"); + leftButtonsPanel.add(resetButton); + + mainPanel.add(buttonsPanel, BorderLayout.SOUTH); + + dialog.setTitle(ADVANCED_OPTIONS); + dialog.add(mainPanel); + dialog.setSize(600, 420); + dialog.setLocationRelativeTo(null); + dialog.setModal(false); + dialog.getRootPane().setDefaultButton(okButton); + } + } + }; + + /** + * Resources + */ + + public static final String OPEN_OPTIONS_DIALOG_LABEL = ResourcesUtil.getString("mesh.options.label"); + public static final String OPEN_OPTIONS_DIALOG_TOOLTIP = ResourcesUtil.getString("mesh.options.tooltip"); + public static final Icon OPT_ICON = ResourcesUtil.getIcon("general.options.icon"); +} diff --git a/src/eu/engys/gui/mesh/actions/IGESAccessory.java b/src/eu/engys/gui/mesh/actions/IGESAccessory.java new file mode 100644 index 0000000..e369c72 --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/IGESAccessory.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions; + +import javax.swing.JCheckBox; + +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; + +public class IGESAccessory extends STLAccessory { + + private JCheckBox split; + private DoubleField precision; + + public IGESAccessory(HelyxFileChooser chooser) { + super(chooser); + } + + @Override + public void layoutOptionsPanel(PanelBuilder optionsBuilder) { + super.layoutOptionsPanel(optionsBuilder); + + split = ComponentsFactory.checkField(); + precision = ComponentsFactory.doubleField(0.01, 0.0, 1.0); + + optionsBuilder.addComponent("Split by Component", split); + optionsBuilder.addComponent("Precision", precision); + } + + public double getPrecision() { + return precision.getDoubleValue(); + } + + public boolean getSplit() { + return split.isSelected(); + } +} diff --git a/src/eu/engys/gui/mesh/actions/IGESFileChooserWrapper.java b/src/eu/engys/gui/mesh/actions/IGESFileChooserWrapper.java new file mode 100644 index 0000000..1fcf7db --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/IGESFileChooserWrapper.java @@ -0,0 +1,78 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh.actions; + +import java.awt.HeadlessException; +import java.io.File; + +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.util.PrefUtil; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.UiUtil; + +public class IGESFileChooserWrapper { + + private IGESAccessory igesAccessory; + private HelyxFileChooser chooser; + public static final HelyxFileFilter IGES_FILTER = new HelyxFileFilter("IGES File (*.igs, *.iges)", "igs", "iges"); + + public IGESFileChooserWrapper() { + chooser = new HelyxFileChooser(PrefUtil.getWorkDir(PrefUtil.LAST_IMPORT_DIR).getAbsolutePath()); + chooser.setTitle("Open IGES"); + chooser.setSelectionMode(SelectionMode.FILES_ONLY); + chooser.setMultiSelectionEnabled(true); + igesAccessory = new IGESAccessory(chooser); + } + + public ReturnValue showOpenDialog() throws HeadlessException { + ReturnValue returnedValue = chooser.showOpenDialog(igesAccessory, UiUtil.getPreferredScreenSize(), IGES_FILTER); + if (returnedValue.isApprove()) { + final File[] files = getSelectedFiles(); + if (files != null && files.length > 0) { + PrefUtil.putFile(PrefUtil.LAST_IMPORT_DIR, files[0].getParentFile()); + } + } + return returnedValue; + } + + public File[] getSelectedFiles() { + if (chooser == null) + return new File[0]; + return chooser.getSelectedFiles(); + } + + public AffineTransform[] getSelectedTransform() { + return igesAccessory.getTransformations(); + } + + public IGESAccessory getIGESAccessory() { + return igesAccessory; + } +} diff --git a/src/eu/engys/gui/mesh/actions/RunBlockMesh.java b/src/eu/engys/gui/mesh/actions/RunBlockMesh.java new file mode 100644 index 0000000..f849f9e --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/RunBlockMesh.java @@ -0,0 +1,143 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.loadEnvironment; +import static eu.engys.core.OpenFOAMEnvironment.printHeader; +import static eu.engys.core.OpenFOAMEnvironment.printVariables; +import static eu.engys.core.project.constant.ConstantFolder.CONSTANT; +import static eu.engys.core.project.constant.ConstantFolder.POLY_MESH; +import static eu.engys.core.project.openFOAMProject.LOG; +import static eu.engys.util.OpenFOAMCommands.BLOCK_MESH; +import static eu.engys.util.OpenFOAMCommands.DECOMPOSE_PAR; + +import java.io.File; +import java.nio.file.Paths; + +import org.apache.commons.io.FileUtils; + +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.Controller.OpenOptions; +import eu.engys.core.controller.ScriptBuilder; +import eu.engys.core.controller.actions.AbstractRunCommand; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorHook; +import eu.engys.core.executor.ExecutorListener.ExecutorState; +import eu.engys.core.executor.ExecutorMonitor; +import eu.engys.core.executor.ExecutorTerminal; +import eu.engys.core.executor.TerminalExecutorMonitor; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.util.IOUtils; +import eu.engys.util.Util; + +public class RunBlockMesh extends AbstractRunCommand { + + public static final String ACTION_NAME = "Run Block Mesh"; + + public static final String BLOCK_MESH_LOG = "blockMesh.log"; + public static final String BLOCK_MESH_RUN = "block_mesh.run"; + public static final String BLOCK_MESH_BAT = "block_mesh.bat"; + + private File logFile; + + public RunBlockMesh(Model model, Controller controller) { + super(model, controller); + this.logFile = Paths.get(model.getProject().getBaseDir().getAbsolutePath(), LOG, BLOCK_MESH_LOG).toFile(); + } + + @Override + public void beforeExecute() { + IOUtils.clearFile(logFile); + clearPolyMesh(); + setupLogFolder(); + } + + private void clearPolyMesh() { + model.getProject().getZeroFolder().deleteMesh(); + } + + private void setupLogFolder() { + File log = new File(model.getProject().getBaseDir(), openFOAMProject.LOG); + if (!log.exists()) { + log.mkdir(); + } + } + + @Override + public void executeClient() { + File baseDir = model.getProject().getBaseDir(); + File script = getScript(); + + ExecutorTerminal terminal = new TerminalExecutorMonitor(logFile); + ExecutorMonitor monitor = new ExecutorMonitor(); + monitor.addHook(ExecutorState.FINISH, new FinishHook()); + + this.executor = Executor.script(script).description(ACTION_NAME).inFolder(baseDir).inTerminal(terminal).withMonitors(monitor).env(getEnvironment(model, BLOCK_MESH_LOG)); + executor.exec(); + } + + private File getScript() { + File file = new File(model.getProject().getBaseDir(), Util.isWindowsScriptStyle() ? BLOCK_MESH_BAT : BLOCK_MESH_RUN); + ScriptBuilder sb = new ScriptBuilder(); + writeScript(sb); + + IOUtils.writeLinesToFile(file, sb.getLines()); + + file.setExecutable(true); + return file; + } + + private void writeScript(ScriptBuilder sb) { + printHeader(sb, ACTION_NAME.toUpperCase()); + printVariables(sb); + loadEnvironment(sb); + writeCommand(sb); + } + + private void writeCommand(ScriptBuilder sb) { + sb.append(BLOCK_MESH()); + if (model.getProject().isParallel()) { + sb.append(DECOMPOSE_PAR()); + } + } + + private class FinishHook implements ExecutorHook { + @Override + public void run(ExecutorMonitor m) { + if (model.getProject().isParallel()) { + File polyMesh = Paths.get(model.getProject().getBaseDir().getAbsolutePath()).resolve(CONSTANT).resolve(POLY_MESH).toFile(); + FileUtils.deleteQuietly(polyMesh); + } + controller.reopenCase(OpenOptions.CURRENT_SETTINGS); + if(controller.getListener() != null){ + controller.getListener().afterBlockMesh(); + } + } + } + +} diff --git a/src/eu/engys/gui/mesh/actions/RunBlockMeshAction.java b/src/eu/engys/gui/mesh/actions/RunBlockMeshAction.java new file mode 100644 index 0000000..414f1ef --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/RunBlockMeshAction.java @@ -0,0 +1,85 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.Icon; + +import eu.engys.core.OpenFOAMEnvironment; +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.actions.RunCommand; +import eu.engys.core.project.Model; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class RunBlockMeshAction extends ViewAction { + + private Model model; + private Controller controller; + + public RunBlockMeshAction(Model model, Controller controller) { + super(BLOCK_LABEL, BLOCK_ICON, BLOCK_TOOLTIP); + this.model = model; + this.controller = controller; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (controller.isDemo()) { + UiUtil.showDemoMessage(); + } else { + if (OpenFOAMEnvironment.isEnvironementLoaded()) { + fixDecomposeParDict(); + controller.saveCase(model.getProject().getBaseDir()); + blockMesh(); + } else { + UiUtil.showCoreEnvironmentNotLoadedWarning(); + } + } + } + + private void blockMesh() { + RunCommand command = new RunBlockMesh(model, controller); + command.beforeExecute(); + command.executeClient(); + } + + private void fixDecomposeParDict() { + model.getProject().getSystemFolder().getDecomposeParDict().toHierarchical(model); + } + + /* + * Resources + */ + + private static final Icon BLOCK_ICON = ResourcesUtil.getIcon("block.mesh.create.icon"); + + private static final String BLOCK_LABEL = ResourcesUtil.getString("block.mesh.create.label"); + private static final String BLOCK_TOOLTIP = ResourcesUtil.getString("block.mesh.create.tooltip"); + +} diff --git a/src/eu/engys/gui/mesh/actions/STLAccessory.java b/src/eu/engys/gui/mesh/actions/STLAccessory.java new file mode 100644 index 0000000..72d1b06 --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/STLAccessory.java @@ -0,0 +1,292 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.File; +import java.util.EventObject; + +import javax.swing.DefaultCellEditor; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; +import javax.swing.text.JTextComponent; + +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.gui.Accessory; +import eu.engys.util.ui.CopyPasteSupport; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.groupcolumnheader.ColumnGroup; +import eu.engys.util.ui.groupcolumnheader.GroupableTableColumnModel; +import eu.engys.util.ui.groupcolumnheader.GroupableTableHeader; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; +import eu.engys.util.ui.textfields.StringField; + +public class STLAccessory implements Accessory { + + + public static final String GEOMETRY_IS_IN_MM = "Geometry is in mm"; + public static final String NAME = "stl.accessory"; + + private final String[] COLUMN_NAMES = { "Part Name", "X", "Y", "Z", "X", "Y", "Z", "X", "Y", "Z" }; + private DefaultTableModel tableModel; + private JTable table; + private AffineTransform[] transformations; + private JPanel panel; + private final HelyxFileChooser chooser; + private JCheckBox geometryInMm; + + public STLAccessory(HelyxFileChooser chooser) { + this.chooser = chooser; + + panel = new JPanel(new BorderLayout()); + panel.setName(NAME); + + PanelBuilder optionsBuilder = new PanelBuilder(); + layoutOptionsPanel(optionsBuilder); + layoutTable(); + + panel.add(optionsBuilder.getPanel(), BorderLayout.NORTH); + panel.add(new JScrollPane(table), BorderLayout.CENTER); + + panel.setPreferredSize(new Dimension(600, 600)); + + table.getColumnModel().getColumn(0).setPreferredWidth(120); + + table.getColumnModel().getColumn(1).setPreferredWidth(50); + table.getColumnModel().getColumn(2).setPreferredWidth(50); + table.getColumnModel().getColumn(3).setPreferredWidth(50); + + table.getColumnModel().getColumn(4).setPreferredWidth(50); + table.getColumnModel().getColumn(5).setPreferredWidth(50); + table.getColumnModel().getColumn(6).setPreferredWidth(50); + + table.getColumnModel().getColumn(7).setPreferredWidth(50); + table.getColumnModel().getColumn(8).setPreferredWidth(50); + table.getColumnModel().getColumn(9).setPreferredWidth(50); + + } + + public void layoutOptionsPanel(PanelBuilder optionsBuilder) { + geometryInMm = new JCheckBox(); + geometryInMm.setName("stl.accessory.mm"); + geometryInMm.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + updateScale(geometryInMm.isSelected()); + } + }); + optionsBuilder.addComponent(GEOMETRY_IS_IN_MM, geometryInMm); + } + + private void layoutTable() { + tableModel = new DefaultTableModel(COLUMN_NAMES, 0) { + @Override + public Class getColumnClass(int columnIndex) { + return columnIndex == 0 ? File.class : Double.class; + } + }; + table = new JTable() { + public boolean editCellAt(int row, int column, EventObject e) { + boolean result = super.editCellAt(row, column, e); + final Component editor = getEditorComponent(); + if (e instanceof KeyEvent && editor instanceof JTextComponent) { + ((JTextComponent) editor).selectAll(); + } + + return result; + } + + }; + table.setDefaultRenderer(File.class, new FileRenderer()); + table.setColumnModel(new GroupableTableColumnModel()); + table.setTableHeader(new GroupableTableHeader((GroupableTableColumnModel) table.getColumnModel())); + table.setModel(tableModel); + tableModel.addTableModelListener(new TableModelListener() { + @Override + public void tableChanged(TableModelEvent e) { + if (e.getType() == TableModelEvent.UPDATE) { + saveTransformations(); + } + } + }); + setupEditors(table); + + // Setup Column Groups + GroupableTableColumnModel cm = (GroupableTableColumnModel) table.getColumnModel(); + + ColumnGroup g_trans = new ColumnGroup("Translate"); + g_trans.add(cm.getColumn(1)); + g_trans.add(cm.getColumn(2)); + g_trans.add(cm.getColumn(3)); + + ColumnGroup g_rot = new ColumnGroup("Rotate"); + g_rot.add(cm.getColumn(4)); + g_rot.add(cm.getColumn(5)); + g_rot.add(cm.getColumn(6)); + + ColumnGroup g_scale = new ColumnGroup("Scale"); + g_scale.add(cm.getColumn(7)); + g_scale.add(cm.getColumn(8)); + g_scale.add(cm.getColumn(9)); + + cm.addColumnGroup(g_trans); + cm.addColumnGroup(g_rot); + cm.addColumnGroup(g_scale); + + CopyPasteSupport.addSupportTo(table); + } + + private void updateScale(boolean isInMM) { + for (int r=0; r 0) { + PrefUtil.putFile(PrefUtil.LAST_IMPORT_DIR, files[0].getParentFile()); + } + } + return returnedValue; + } + + public File[] getSelectedFiles() { + if (chooser == null) + return new File[0]; + return chooser.getSelectedFiles(); + } + + public AffineTransform[] getSelectedTransform() { + return stlAccessory.getTransformations(); + } + + public STLAccessory getStlAccessory() { + return stlAccessory; + } +} diff --git a/src/eu/engys/gui/mesh/actions/StandardMeshActions.java b/src/eu/engys/gui/mesh/actions/StandardMeshActions.java new file mode 100644 index 0000000..07d62a6 --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/StandardMeshActions.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh.actions; + +import static eu.engys.util.ui.UiUtil.createToolBarButton; +import static eu.engys.util.ui.UiUtil.createToolBarButtonBar; + +import javax.inject.Inject; +import javax.swing.Box; +import javax.swing.JToolBar; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; +import eu.engys.gui.mesh.panels.DefaultMeshAdvancedOptionsPanel; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.UiUtil; + +public class StandardMeshActions extends DefaultMeshActions { + + @Inject + public StandardMeshActions(Model model, Controller controller, ProgressMonitor monitor, DefaultMeshAdvancedOptionsPanel generalOptionsPanel) { + super(model, controller, monitor, generalOptionsPanel); + } + + @Override + public JToolBar toolbar() { + JToolBar toolbar = UiUtil.getToolbar("view.element.toolbar"); + + toolbar.add(createToolBarButton(createMesh)); + toolbar.add(Box.createHorizontalStrut(2)); + toolbar.add(createToolBarButton(checkMesh)); + toolbar.add(createToolBarButton(deleteMesh)); + toolbar.addSeparator(); + toolbar.add(createToolBarButton(openOptionsDialog)); + toolbar.add(Box.createHorizontalGlue()); + + return toolbar; + } +} diff --git a/src/eu/engys/gui/mesh/actions/geometry/CloneSurfaceAction.java b/src/eu/engys/gui/mesh/actions/geometry/CloneSurfaceAction.java new file mode 100644 index 0000000..9358e1c --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/geometry/CloneSurfaceAction.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions.geometry; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.AddSurfaceEvent; +import eu.engys.gui.mesh.panels.AbstractGeometryPanel; +import eu.engys.util.Util; +import eu.engys.util.ui.UiUtil; + +public class CloneSurfaceAction extends AbstractAction { + + public static final String CLONE = "Clone"; + + private Model model; + private Surface[] surfaces; + private AbstractGeometryPanel panel; + + public CloneSurfaceAction(Model model, AbstractGeometryPanel panel) { + super(CLONE); + this.model = model; + this.panel = panel; + } + + public void update(boolean enabled, Surface[] surfaces) { + this.surfaces = surfaces; + Type type = surfaces[0].getType(); + setEnabled(enabled && type != Type.STL && type != Type.SOLID); + } + + @Override + public void actionPerformed(ActionEvent e) { + panel.getTreeNodeManager().getTree().clearSelection(); + new CloneSurface(model, surfaces).execute(); + } + + private class CloneSurface { + private Surface[] surfaces; + private Model model; + + public CloneSurface(Model model, Surface[] surfaces) { + this.model = model; + this.surfaces = surfaces; + } + + public void execute() { + if (Util.isVarArgsNotNull(surfaces)) { + Surface original = surfaces[0]; + Dictionary dictionary = original.toDictionary(); + if (dictionary.isDictionary("surface") && dictionary.isDictionary("volume")) { + Surface surface = model.getGeometry().getFactory().loadSurface(new Dictionary("CopyOf" + dictionary.getName(), original.getGeometryDictionary()), model, null); + surface.fromDictionary(dictionary); + model.getGeometry().addSurface(surface); + model.geometryChanged(surface); + + EventManager.triggerEvent(this, new AddSurfaceEvent(surface)); + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Cannot Clone: Invalid Format", "Clone Error", JOptionPane.ERROR_MESSAGE); + } + } + } + } +} diff --git a/src/eu/engys/gui/mesh/actions/geometry/CopySurfaceAction.java b/src/eu/engys/gui/mesh/actions/geometry/CopySurfaceAction.java new file mode 100644 index 0000000..664106e --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/geometry/CopySurfaceAction.java @@ -0,0 +1,79 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions.geometry; + +import java.awt.Toolkit; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.mesh.panels.AbstractGeometryPanel; +import eu.engys.util.Util; + +public class CopySurfaceAction extends AbstractAction { + + public static final String COPY = "Copy"; + + private Surface[] surfaces; + private AbstractGeometryPanel panel; + + public CopySurfaceAction(AbstractGeometryPanel panel) { + super(COPY); + this.panel = panel; + } + + public void update(boolean enabled, Surface[] surfaces) { + this.surfaces = surfaces; + // Type type = surfaces[0].getType(); + setEnabled(enabled); + } + + @Override + public void actionPerformed(ActionEvent e) { + panel.saveSurfaces(surfaces); + new CopySurface(surfaces).execute(); + } + + private class CopySurface { + private Surface[] surfaces; + + public CopySurface(Surface[] surfaces) { + this.surfaces = surfaces; + } + + public void execute() { + if (Util.isVarArgsNotNull(surfaces)) { + Surface surface = surfaces[0]; + StringSelection contents = new StringSelection(surface.toDictionary().toString()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, contents); + } else { + // error + } + } + } +} diff --git a/src/eu/engys/gui/mesh/actions/geometry/ExtractLineAction.java b/src/eu/engys/gui/mesh/actions/geometry/ExtractLineAction.java new file mode 100644 index 0000000..d6dde76 --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/geometry/ExtractLineAction.java @@ -0,0 +1,72 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions.geometry; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.mesh.panels.DefaultGeometryActions; +import eu.engys.gui.mesh.panels.DefaultGeometryActions.Disable; +import eu.engys.gui.mesh.panels.DefaultGeometryActions.Enable; +import eu.engys.util.ui.UiUtil; + +public class ExtractLineAction extends AbstractAction { + + public static final String EXTRACT = "Extract"; + public static final String EXTRACT_NAME = EXTRACT + ".Lines"; + + private Model model; + private Surface[] surfaces; + + private DefaultGeometryActions actions; + + private Controller controller; + + public ExtractLineAction(Model model, Controller controller, DefaultGeometryActions actions) { + super(EXTRACT); + this.model = model; + this.controller = controller; + this.actions = actions; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (controller.isDemo()) { + UiUtil.showDemoMessage(); + } else { + new ExtractLinesDialog(UiUtil.getActiveWindow(), model, null).show(surfaces[0], new Disable(actions), new Enable(actions)); + } + } + + public void update(boolean enabled, Surface[] surfaces) { + this.surfaces = surfaces; + setEnabled(enabled && surfaces.length == 1); + } +} diff --git a/src/eu/engys/gui/mesh/actions/geometry/ExtractLinesDialog.java b/src/eu/engys/gui/mesh/actions/geometry/ExtractLinesDialog.java new file mode 100644 index 0000000..3804908 --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/geometry/ExtractLinesDialog.java @@ -0,0 +1,446 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions.geometry; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog.ModalityType; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.JToggleButton; +import javax.swing.SwingConstants; + +import vtk.vtkAppendPolyData; +import vtk.vtkPolyData; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.Region; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.AddSurfaceEvent; +import eu.engys.gui.events.view3D.BoxEvent; +import eu.engys.gui.events.view3D.RemoveSurfaceEvent; +import eu.engys.gui.view3D.Geometry3DController; +import eu.engys.util.ui.CheckBoxPanel; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.StringField; +import eu.engys.vtk.actions.ExtractLines; + +public class ExtractLinesDialog { + + private static final Icon ICON_ON = ResourcesUtil.getResourceIcon("eu/engys/resources/images/lightbulb16.png"); + private static final Icon ICON_OFF = ResourcesUtil.getResourceIcon("eu/engys/resources/images/lightbulb_off16.png"); + + + public static final String EXTRACT_LINES_DIALOG = "extract.lines.dialog"; + + public static final String TITLE = "Extract Feature Lines"; + public static final String FEATURE_ANGLE_LABEL = "Feature Angle"; + public static final String SURFACE_LABEL = "Surface"; + public static final String MANIFOLD_EDGES_LABEL = "Manifold Edges"; + public static final String NON_MANIFOLD_EDGES_LABEL = "Non-manifold Edges"; + public static final String BOUNDARY_EDGES_LABEL = "Boundary Edges"; + public static final String OUTSIDE_KEY = "outside"; + public static final String INSIDE_KEY = "inside"; + + public static final String MIN_LABEL = "Min"; + public static final String MAX_LABEL = "Max"; + public static final String OUTSIDE_LABEL = "Outside"; + public static final String INSIDE_LABEL = "Inside"; + public static final String APPLY_LABEL = "Apply"; + public static final String SAVE_LABEL = "Save"; + public static final String CANCEL_LABEL = "Cancel"; + + public static final String LINE_SUFFIX = "_line"; + + private final Model model; + + private JDialog dialog; + private DoubleField angle; + + private JCheckBox inside; + private DoubleField[] insideBoxMin; + private DoubleField[] insideBoxMax; + + private JCheckBox outside; + private DoubleField[] outsideBoxMin; + private DoubleField[] outsideBoxMax; + private StringField surfacesNameField; + + private Window parent; + + private JCheckBox boundaryEdges; + private JCheckBox nonManifoldEdges; + private JCheckBox manifoldEdges; + + private JToggleButton showInsideButton; + private JToggleButton showOutsideButton; + + private Surface surface; + + private FeatureLine line; + private Runnable onShow; + private Runnable onHide; + private Geometry3DController controller3d; + + // public static void main(String[] args) { + // new HelyxLookAndFeel().init(); + // Model model = new Model(); + // model.init(); + // + // model.getGeometry().addSurface(new Stl("a")); + // + // new ExtractLinesDialog(null, model, null).show(null, null, null); + // } + + public ExtractLinesDialog(Window parent, Model model, Geometry3DController controller3d) { + this.parent = parent; + this.model = model; + this.controller3d = controller3d; + + layoutComponents(); + } + + private void layoutComponents() { + surfacesNameField = ComponentsFactory.stringField(); + surfacesNameField.setEnabled(false); + + angle = ComponentsFactory.doubleField(30.0, 0.0, 180.0); + boundaryEdges = new JCheckBox(BOUNDARY_EDGES_LABEL, true); + nonManifoldEdges = new JCheckBox(NON_MANIFOLD_EDGES_LABEL, true); + manifoldEdges = new JCheckBox(MANIFOLD_EDGES_LABEL, true); + + inside = new JCheckBox(INSIDE_LABEL, false); + insideBoxMin = ComponentsFactory.doublePointField(8, 0.0); + insideBoxMax = ComponentsFactory.doublePointField(8, 1.0); + + outside = new JCheckBox(OUTSIDE_LABEL, false); + outsideBoxMin = ComponentsFactory.doublePointField(8, 0.0); + outsideBoxMax = ComponentsFactory.doublePointField(8, 1.0); + + showInsideButton = getShowBoxButton(insideBoxMin, insideBoxMax); + PanelBuilder insideBuilder = new PanelBuilder(); + insideBuilder.addComponent(MIN_LABEL, insideBoxMin[0], insideBoxMin[1], insideBoxMin[2], showInsideButton); + insideBuilder.addComponentAndSpan(MAX_LABEL, insideBoxMax); + JPanel insidePanel = new CheckBoxPanel(insideBuilder, inside); + insideBuilder.setEnabled(false); + + PanelBuilder outsideBuilder = new PanelBuilder(); + showOutsideButton = getShowBoxButton(outsideBoxMin, outsideBoxMax); + outsideBuilder.addComponent(MIN_LABEL, outsideBoxMin[0], outsideBoxMin[1], outsideBoxMin[2], showOutsideButton); + outsideBuilder.addComponentAndSpan(MAX_LABEL, outsideBoxMax); + JPanel outsidePanel = new CheckBoxPanel(outsideBuilder, outside); + outsideBuilder.setEnabled(false); + + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(SURFACE_LABEL, surfacesNameField); + builder.addComponent(FEATURE_ANGLE_LABEL, angle); + builder.addComponent(boundaryEdges); + builder.addComponent(nonManifoldEdges); + builder.addComponent(manifoldEdges); + builder.addComponent(insidePanel); + builder.addComponent(outsidePanel); + builder.addFill(new JSeparator()); + + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + buttonsPanel.add(new ApplyButton()); + buttonsPanel.add(new SaveButton()); + buttonsPanel.add(new CancelButton()); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(builder.getPanel(), BorderLayout.CENTER); + mainPanel.add(buttonsPanel, BorderLayout.SOUTH); + + setNames(); + + dialog = new JDialog(parent, ModalityType.MODELESS); + dialog.setName(EXTRACT_LINES_DIALOG); + dialog.setTitle(TITLE); + dialog.setSize(500, 420); + dialog.getContentPane().add(mainPanel); + dialog.setResizable(false); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + closeDialog(); + } + }); + } + + public void show(final Surface surface, Runnable onShow, Runnable onHide) { + this.surface = surface; + this.onShow = onShow; + this.onHide = onHide; + if (this.onShow != null) { + this.onShow.run(); + } + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + surfacesNameField.setText(surface.getName()); + dialog.setVisible(true); + } + }); + } + + private JToggleButton getShowBoxButton(final DoubleField[] min, final DoubleField[] max) { + final JToggleButton button = new JToggleButton(); + button.setAction(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (button.isSelected()) { + EventManager.triggerEvent(this, new BoxEvent(min, max, EventActionType.SHOW)); + } else { + EventManager.triggerEvent(this, new BoxEvent(min, max, EventActionType.HIDE)); + } + } + }); + button.setPreferredSize(new Dimension(36, 36)); + button.setIcon(ICON_OFF); + button.setSelectedIcon(ICON_ON); + button.setPressedIcon(ICON_ON); + button.setVerticalAlignment(SwingConstants.TOP); + button.setVerticalTextPosition(SwingConstants.CENTER); + return button; + } + + private void setNames() { + inside.setName(INSIDE_KEY); + showInsideButton.setName(INSIDE_KEY + ".show"); + insideBoxMin[0].setName(INSIDE_KEY + MIN_LABEL + "X"); + insideBoxMin[1].setName(INSIDE_KEY + MIN_LABEL + "Y"); + insideBoxMin[2].setName(INSIDE_KEY + MIN_LABEL + "Z"); + + insideBoxMax[0].setName(INSIDE_KEY + MAX_LABEL + "X"); + insideBoxMax[1].setName(INSIDE_KEY + MAX_LABEL + "Y"); + insideBoxMax[2].setName(INSIDE_KEY + MAX_LABEL + "Z"); + + outside.setName(OUTSIDE_KEY); + showOutsideButton.setName(OUTSIDE_KEY + ".show"); + outsideBoxMin[0].setName(OUTSIDE_KEY + MIN_LABEL + "X"); + outsideBoxMin[1].setName(OUTSIDE_KEY + MIN_LABEL + "Y"); + outsideBoxMin[2].setName(OUTSIDE_KEY + MIN_LABEL + "Z"); + + outsideBoxMax[0].setName(OUTSIDE_KEY + MAX_LABEL + "X"); + outsideBoxMax[1].setName(OUTSIDE_KEY + MAX_LABEL + "Y"); + outsideBoxMax[2].setName(OUTSIDE_KEY + MAX_LABEL + "Z"); + + } + + private void doExtract() { + hideLine(); + line = extractFeatureLines(); + showLine(); + } + + private void showLine() { + if (line != null) { + if (controller3d != null) { + controller3d.addSurfaces(line); + controller3d.render(); + } else { + EventManager.triggerEvent(this, new AddSurfaceEvent(false, line)); + } + } + } + + private void hideLine() { + if (line != null) { + if (controller3d != null) { + controller3d.removeSurfaces(line); + controller3d.render(); + } else { + EventManager.triggerEvent(this, new RemoveSurfaceEvent(false, line)); + } + } + } + + private FeatureLine extractFeatureLines() { + vtkPolyData input = getDatasetFrom(surface); + if (input != null) { + ExtractLines extract = new ExtractLines(); + extract.setInput(input); + extract.setAngle(angle.getDoubleValue()); + extract.setBoundary(boundaryEdges.isSelected()); + extract.setManifold(manifoldEdges.isSelected()); + extract.setNonmanifold(nonManifoldEdges.isSelected()); + + if (inside.isSelected()) { + extract.setInsideMin(new double[] { insideBoxMin[0].getDoubleValue(), insideBoxMin[1].getDoubleValue(), insideBoxMin[2].getDoubleValue() }); + extract.setInsideMax(new double[] { insideBoxMax[0].getDoubleValue(), insideBoxMax[1].getDoubleValue(), insideBoxMax[2].getDoubleValue() }); + } + if (outside.isSelected()) { + extract.setOutsideMin(new double[] { outsideBoxMin[0].getDoubleValue(), outsideBoxMin[1].getDoubleValue(), outsideBoxMin[2].getDoubleValue() }); + extract.setOutsideMax(new double[] { outsideBoxMax[0].getDoubleValue(), outsideBoxMax[1].getDoubleValue(), outsideBoxMax[2].getDoubleValue() }); + } + + vtkPolyData output = extract.execute(); + + String name = model.getGeometry().getALineName(surface.getName() + LINE_SUFFIX); + FeatureLine line = new FeatureLine(name); + line.setModified(true); + line.setDataSet(output); + line.setColor(Color.BLUE); + + return line; + } + + return null; + } + + private vtkPolyData getDatasetFrom(Surface surface) { + vtkPolyData dataset = null; + + if (surface != null) { + if (surface.hasRegions() && surface.getRegions().length > 0) { + if (surface.isSingleton()) { + dataset = surface.getRegions()[0].getTransformedDataSet(); + } else { + vtkAppendPolyData append = new vtkAppendPolyData(); + for (Region region : surface.getRegions()) { + append.AddInputData(region.getTransformedDataSet()); + } + append.Update(); + + dataset = append.GetOutput(); + } + } else { + dataset = surface.getTransformedDataSet(); + } + } + + return dataset; + } + + private void addLine() { + model.getGeometry().addLine(line); + model.geometryChanged(line); + } + + public Component getPanel() { + return dialog.getContentPane(); + } + + public FeatureLine getFeatureLine() { + return line; + } + + private void closeDialog() { + if (showInsideButton.isSelected()) { + showInsideButton.doClick(); + } + + if (showOutsideButton.isSelected()) { + showOutsideButton.doClick(); + } + + if (dialog != null) { + dialog.dispose(); + } + if (this.onHide != null) { + this.onHide.run(); + } + } + + class ApplyButton extends JButton { + public ApplyButton() { + super(new AbstractAction(APPLY_LABEL) { + @Override + public void actionPerformed(ActionEvent e) { + doExtract(); + } + }); + setName(APPLY_LABEL); + } + } + + class SaveButton extends JButton { + public SaveButton() { + super(new AbstractAction(SAVE_LABEL) { + @Override + public void actionPerformed(ActionEvent e) { + + doExtract(); + + addLine(); + + closeDialog(); + } + }); + setName(SAVE_LABEL); + } + } + + class CancelButton extends JButton { + public CancelButton() { + super(new AbstractAction(CANCEL_LABEL) { + @Override + public void actionPerformed(ActionEvent e) { + + hideLine(); + + closeDialog(); + } + }); + setName(CANCEL_LABEL); + } + + } + + /* + * Utils + */ + public void showTest(final Surface surface) { + this.surface = surface; + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + surfacesNameField.setText(surface.getName()); + } + }); + } + +} diff --git a/src/eu/engys/gui/mesh/actions/geometry/PasteSurfaceAction.java b/src/eu/engys/gui/mesh/actions/geometry/PasteSurfaceAction.java new file mode 100644 index 0000000..660d3a5 --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/geometry/PasteSurfaceAction.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions.geometry; + +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DictionaryUtils; +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.mesh.panels.AbstractGeometryPanel; +import eu.engys.util.Util; +import eu.engys.util.ui.UiUtil; + +public class PasteSurfaceAction extends AbstractAction { + + public static final String PASTE = "Paste"; + private Surface[] surfaces; + private AbstractGeometryPanel panel; + + public PasteSurfaceAction(AbstractGeometryPanel panel) { + super(PASTE); + this.panel = panel; + } + + public void update(boolean enabled, Surface[] surfaces) { + this.surfaces = surfaces; + // Type type = surfaces[0].getType(); + setEnabled(enabled); + } + + @Override + public void actionPerformed(ActionEvent e) { + panel.getTreeNodeManager().getTree().clearSelection(); + new PasteSurface(surfaces).execute(); + } + + private class PasteSurface { + private Surface[] surfaces; + + public PasteSurface(Surface[] surfaces) { + this.surfaces = surfaces; + } + + public void execute() { + if (Util.isVarArgsNotNull(surfaces)) { + Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(this); + try { + String dictionaryString = (String) contents.getTransferData(DataFlavor.stringFlavor); + Dictionary dictionary = DictionaryUtils.readDictionary(dictionaryString).getDictionaries().get(0); + if (dictionary.isDictionary("surface") && dictionary.isDictionary("layer")) { + for (Surface surface : surfaces) { + surface.fromDictionary(dictionary); + } + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Cannot Paste: Invalid Format", "Copy/Paste Error", JOptionPane.ERROR_MESSAGE); + } + } catch (Exception ee) { + ee.printStackTrace(); + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Cannot Paste: An Error Occurred", "Copy/Paste Error", JOptionPane.ERROR_MESSAGE); + } + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Cannot Paste: Empty Selection", "Copy/Paste Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} diff --git a/src/eu/engys/gui/mesh/actions/geometry/RemoveSurfaceAction.java b/src/eu/engys/gui/mesh/actions/geometry/RemoveSurfaceAction.java new file mode 100644 index 0000000..a1ac14d --- /dev/null +++ b/src/eu/engys/gui/mesh/actions/geometry/RemoveSurfaceAction.java @@ -0,0 +1,97 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.actions.geometry; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.MultiRegion; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.RemoveSurfaceEvent; + +public class RemoveSurfaceAction extends AbstractAction { + + public static final String REMOVE = "Remove"; + + private Model model; + private Surface[] surfaces; + + public RemoveSurfaceAction(Model model) { + super(REMOVE); + this.model = model; + } + + public void update(boolean enabled, Surface[] surfaces) { + this.surfaces = surfaces; + // Type type = surfaces[0].getType(); + // setEnabled(type != Type.SOLID); + setEnabled(enabled); + } + + @Override + public void actionPerformed(ActionEvent e) { + new RemoveSurface(model, surfaces).execute(); + } + + private class RemoveSurface { + private Surface[] surfaces; + private Model model; + + public RemoveSurface(Model model, Surface[] surfaces) { + this.model = model; + this.surfaces = surfaces; + } + + public void execute() { + if (surfaces[0].getType().isSolid()) { + MultiRegion parent = ((Solid) surfaces[0]).getParent(); + for (Surface surface : surfaces) { + Solid solid = (Solid) surface; + parent.removeRegion(solid.getName()); + EventManager.triggerEvent(this, new RemoveSurfaceEvent(solid)); + } + if (parent.getRegions().length > 0) { + parent.setModified(true); + model.geometryChanged(parent); + } else { + model.getGeometry().removeSurfaces(model, parent); + model.geometryChanged(parent); + + EventManager.triggerEvent(this, new RemoveSurfaceEvent(parent)); + } + } else { + model.getGeometry().removeSurfaces(model, surfaces); + model.geometryChanged(surfaces[0]); + + EventManager.triggerEvent(this, new RemoveSurfaceEvent(surfaces)); + } + } + } +} diff --git a/src/eu/engys/gui/mesh/panels/AbstractBaseMeshPanel.java b/src/eu/engys/gui/mesh/panels/AbstractBaseMeshPanel.java new file mode 100644 index 0000000..39e426e --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/AbstractBaseMeshPanel.java @@ -0,0 +1,281 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import static eu.engys.gui.mesh.panels.lines.AutomaticBaseMeshPanel.AUTOMATIC_LABEL; +import static eu.engys.gui.mesh.panels.lines.FromFileBaseMeshPanel.FROM_FILE_LABEL; +import static eu.engys.gui.mesh.panels.lines.UserDefinedBaseMeshPanel.USER_DEFINED_LABEL; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JComponent; +import javax.swing.JOptionPane; + +import eu.engys.core.controller.Controller; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Type; +import eu.engys.core.project.geometry.surface.PlaneRegion; +import eu.engys.core.project.system.BlockMeshDict; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.application.BaseMeshTypeChangedEvent; +import eu.engys.gui.events.view3D.RenameSurfaceEvent; +import eu.engys.gui.mesh.panels.lines.AutomaticBaseMeshPanel; +import eu.engys.gui.mesh.panels.lines.BoundingBoxFacesPanel; +import eu.engys.gui.mesh.panels.lines.FromFileBaseMeshPanel; +import eu.engys.gui.mesh.panels.lines.UserDefinedBaseMeshPanel; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.JComboBoxController; +import eu.engys.util.ui.textfields.StringField; + +public abstract class AbstractBaseMeshPanel extends AbstractGUIPanel { + + public static final String BASE_MESH = "Base Mesh"; + + public static final String BASE_MESH_TYPE_LABEL = "Base Mesh Type"; + + private BaseMeshTreeNodeManager treeNodeManager; + + protected JComboBoxController type; + protected ActionListener typeChangeListener; + + private PlaneRegion[] selectedPlane; + + private Controller controller; + + private AutomaticBaseMeshPanel automaticPanel; + private UserDefinedBaseMeshPanel userDefinedPanel; + private FromFileBaseMeshPanel fromFilePanel; + private BoundingBoxFacesPanel facesPanel; + + public AbstractBaseMeshPanel(Model model, Controller controller) { + super(BASE_MESH, model); + this.controller = controller; + this.treeNodeManager = new BaseMeshTreeNodeManager(model, this); + model.addObserver(treeNodeManager); + } + + protected JComponent layoutComponents() { + DictionaryPanelBuilder builder = new DictionaryPanelBuilder(); + + type = (JComboBoxController) builder.startChoice(BASE_MESH_TYPE_LABEL); + automaticPanel = new AutomaticBaseMeshPanel(model, builder); + userDefinedPanel = new UserDefinedBaseMeshPanel(model, builder); + fromFilePanel = new FromFileBaseMeshPanel(model, controller, builder); + builder.endChoice(); + + facesPanel = new BoundingBoxFacesPanel(new RenamePlaneListener()); + builder.addFill(facesPanel.getPanel()); + + type.addActionListener(typeChangeListener = new BaseMeshTypeChangeListener()); + return builder.removeMargins().getPanel(); + } + + @Override + public void load() { + SnappyHexMeshDict snappyDict = model.getProject().getSystemFolder().getSnappyHexMeshDict(); + BlockMeshDict blockMeshDict = model.getProject().getSystemFolder().getBlockMeshDict(); + if (snappyDict != null) { + loadSpacing(); + + type.removeActionListener(typeChangeListener); + loadBaseMeshType(snappyDict, blockMeshDict); + type.addActionListener(typeChangeListener); + } + } + + protected abstract void loadSpacing(); + + private void loadBaseMeshType(SnappyHexMeshDict snappyDict, BlockMeshDict blockMeshDict) { + userDefinedPanel.resetToDefault(); + if (snappyDict.isAutoBlockMesh()) { + type.setSelectedItem(AUTOMATIC_LABEL); + } else { + if (model.getGeometry().hasBlock()) { + type.setSelectedItem(USER_DEFINED_LABEL); + userDefinedPanel.load(); + } else { + if (blockMeshDict != null && blockMeshDict.isFromFile()) { + type.setSelectedItem(FROM_FILE_LABEL); + } else { + type.setSelectedItem(AUTOMATIC_LABEL); + } + } + } + } + + @Override + public void save() { + if (isUserDefined()) { + userDefinedPanel.save(); + saveSelectedPlane(); + } else if (isFromFile()) { + fromFilePanel.save(); + } else if (isAutomatic()) { + automaticPanel.save(); + } + } + + private void saveSelectedPlane() { + if (selectedPlane != null) { + facesPanel.save(selectedPlane); + } + } + + @Override + public void clear() { + facesPanel.setEnabled(false); + selectedPlane = null; + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + + private void updateBlock() { + if (isUserDefined()) { + userDefinedPanel.updateBlock(); + } else { + userDefinedPanel.turnOffShowBoxButton(); + if (isAutomatic()) { + automaticPanel.updateBlock(); + } else if (isFromFile()) { + fromFilePanel.updateBlock(); + } + } + } + + @Override + public void stop() { + super.stop(); + userDefinedPanel.turnOffShowBoxButton(); + } + + public void selectPlane(PlaneRegion[] selection) { + if (selection.length == 0) { + clear(); + } else if (selection.length == 1) { + facesPanel.selectPlane(selection); + selectedPlane = selection; + } else { + selectedPlane = selection; + facesPanel.setEnabled(true); + facesPanel.setPlaneName(getMultipleSelectionName()); + facesPanel.disableNameField(); + } + } + + private String getMultipleSelectionName() { + StringBuilder sb = new StringBuilder(); + for (PlaneRegion plane : selectedPlane) { + sb.append(plane.getName()); + sb.append(" "); + } + return sb.toString(); + } + + protected void setBaseMeshSpacing(double baseMeshSpacing) { + automaticPanel.setBaseMeshSpacing(baseMeshSpacing); + } + + protected double getBaseMeshSpacing() { + return automaticPanel.getBaseMeshSpacing(); + } + + public void saveSurfaces(PlaneRegion[] selection) { + Type type = selection[0].getType(); + List planes = new ArrayList<>(); + for (PlaneRegion plane : selection) { + if (plane.getType() != type) + continue; /* uniform selection */ + planes.add(plane); + } + facesPanel.save(planes.toArray(new PlaneRegion[0])); + } + + protected boolean isUserDefined() { + return String.valueOf(type.getSelectedItem()).equals(USER_DEFINED_LABEL); + } + + protected boolean isFromFile() { + return String.valueOf(type.getSelectedItem()).equals(FROM_FILE_LABEL); + } + + protected boolean isAutomatic() { + return String.valueOf(type.getSelectedItem()).equals(AUTOMATIC_LABEL); + } + + private class BaseMeshTypeChangeListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + // To tell the Controller to delete mesh scripts + EventManager.triggerEvent(this, new BaseMeshTypeChangedEvent()); + updateBlock(); + save(); + } + } + + private class RenamePlaneListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value") && evt.getSource() instanceof StringField) { + renamePlane(selectedPlane[0]); + } + } + + private void renamePlane(PlaneRegion plane) { + if (plane != null) { + String oldPatchName = plane.getPatchName(); + + String newName = facesPanel.getPlaneName(); + + if (model.getGeometry().contains(newName)) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Name already in use", "Name Error", JOptionPane.ERROR_MESSAGE); + return; + } + + plane.rename(newName); + String newPatchName = plane.getPatchName(); + plane.getParent().renameRegion(oldPatchName, newPatchName); + + treeNodeManager.getTree().repaint(); + + EventManager.triggerEvent(this, new RenameSurfaceEvent(plane, oldPatchName, newPatchName)); + } + } + + } + +} diff --git a/src/eu/engys/gui/mesh/panels/AbstractGeometryPanel.java b/src/eu/engys/gui/mesh/panels/AbstractGeometryPanel.java new file mode 100644 index 0000000..1c0f1a1 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/AbstractGeometryPanel.java @@ -0,0 +1,502 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import eu.engys.core.controller.Controller; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.presentation.Action; +import eu.engys.core.presentation.ActionContainer; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.AddSurfaceEvent; +import eu.engys.gui.events.view3D.ChangeSurfaceEvent; +import eu.engys.gui.events.view3D.RenameSurfaceEvent; +import eu.engys.gui.mesh.GeometryPanel; +import eu.engys.gui.mesh.actions.AddIGES; +import eu.engys.gui.mesh.actions.AddSTL; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.Util; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.JComboBoxController; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; + +public abstract class AbstractGeometryPanel extends AbstractGUIPanel implements GeometryPanel, ActionContainer { + + public static final String ZONES_LABEL = "Zones"; + public static final String LAYERS_LABEL = "Layers"; + public static final String REFINEMENT_LABEL = "Refinement"; + public static final String GEOMETRY = "Geometry"; + + public static final String DISTANCE_M_LABEL = "Distance [m]"; + + public static final String SURFACE_LABEL = "Surface"; + public static final String BAFFLE_LABEL = "Baffle"; + public static final String BOUNDARY_LABEL = "Boundary"; + public static final String INTERNAL_LABEL = "Internal"; + public static final String TYPE_LABEL = "Type"; + public static final String NAME_LABEL = "Name"; + public static final String CELL_ZONE_LABEL = "Cell Zone"; + public static final String LEVEL_LABEL = "Level"; + public static final String PROXIMITY_REFINEMENT_LABEL = "Proximity Refinement"; + public static final String FINAL_LAYER_THICKNESS_LABEL = "Final Layer Thickness"; + public static final String LAYER_STRETCHING_LABEL = "Layer Stretching"; + public static final String NUMBER_OF_LAYERS_LABEL = "Number of Layers"; + public static final String CELL_SIZE_LABEL = "Cell Size [m]"; + + public static final String INSIDE_LEVEL_LABEL = "Inside Level"; + public static final String OUTSIDE_LEVEL_LABEL = "Outside Level"; + public static final String DISTANCE_LEVEL_LABEL = "Distance Level"; + + public static final String MODE_LABEL = "Mode"; + public static final String NONE = "none"; + public static final String INSIDE = "inside"; + public static final String OUTSIDE = "outside"; + public static final String DISTANCE = "distance"; + public static final String NONE_LABEL = "None"; + public static final String INSIDE_LABEL = "Inside"; + public static final String OUTSIDE_LABEL = "Outside"; + public static final String DISTANCE_LABEL = "Distance"; + + private GeometryBuilder surfaceRegionsBuilder; + + protected DictionaryModel surfaceModel; + protected DictionaryModel volumeModel; + protected DictionaryModel layerModel; + protected DictionaryModel zoneModel; + + private GeometriesPanelBuilder geometriesPanel; + + protected PanelBuilder layersBuilder; + protected PanelBuilder surfaceBuilder; + protected PanelBuilder volumesBuilder; + protected PanelBuilder zonesBuilder; + + private JTabbedPane tabbedPane; + + protected final GeometryTreeNodeManager treeNodeManager; + + public AbstractGeometryPanel(Model model, Controller controller) { + super(GEOMETRY, model); + this.treeNodeManager = new GeometryTreeNodeManager(model, controller, this, getGeometryActions(controller)); + model.addObserver(treeNodeManager); + ActionManager.getInstance().parseActions(this); + } + + protected abstract DefaultGeometryActions getGeometryActions(Controller controller); + + @Override + protected JComponent layoutComponents() { + surfaceModel = new DictionaryModel(); + volumeModel = new DictionaryModel(); + layerModel = new DictionaryModel(); + zoneModel = new DictionaryModel(); + + geometriesPanel = new GeometriesPanelBuilder(this); + surfaceRegionsBuilder = new GeometryBuilder(geometriesPanel, surfaceModel, volumeModel, layerModel, zoneModel); + + tabbedPane = new JTabbedPane(); + tabbedPane.setName("geometry.tabbed.pane"); + tabbedPane.putClientProperty("Synthetica.tabbedPane.tabIndex", 0); + + JPanel refinemetPanel = getRefinemetPanel(); + JPanel layersPanel = getLayersPanel(); + JPanel zonesPanel = getZonesPanel(); + + refinemetPanel.setName("refinement.panel"); + layersPanel.setName("layers.panel"); + zonesPanel.setName("zones.panel"); + + tabbedPane.addTab(REFINEMENT_LABEL, refinemetPanel); + tabbedPane.addTab(LAYERS_LABEL, layersPanel); + tabbedPane.addTab(ZONES_LABEL, zonesPanel); + + PanelBuilder builder = new PanelBuilder(); + builder.addButtons(getShapeButtons()); + builder.addSeparator(""); + geometriesPanel.addComponents(builder); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(builder.removeMargins().getPanel(), BorderLayout.NORTH); + mainPanel.add(tabbedPane, BorderLayout.CENTER); + + tabbedPane.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + saveSurfaces(treeNodeManager.getSelectedValues()); + selectSurface(treeNodeManager.getSelectedValues()); + } + }); + + return mainPanel; + } + + protected abstract JButton[] getShapeButtons(); + + private JPanel getRefinemetPanel() { + PanelBuilder builder = new PanelBuilder(); + + JPanel surfacesPanel = getSurfacesPanel(); + JPanel volumesPanel = getVolumesPanel(); + + surfacesPanel.setName("refinement.surfaces"); + volumesPanel.setName("refinement.volumes"); + + builder.addComponent(surfacesPanel); + builder.addComponent(volumesPanel); + return builder.getPanel(); + } + + protected abstract JPanel getSurfacesPanel(); + + protected JPanel getVolumesPanel() { + volumesBuilder = new PanelBuilder(); + final JComboBoxController comboBoxController = volumeModel.bindComboBoxController("mode"); + volumesBuilder.startChoice(MODE_LABEL, comboBoxController); + + volumesBuilder.startGroup(NONE, NONE_LABEL); + volumesBuilder.endGroup(); + + volumesBuilder.startGroup(INSIDE, INSIDE_LABEL); + IntegerField inside = volumeModel.bindIntegerLevels("levels", INSIDE); + volumesBuilder.addComponent(INSIDE_LEVEL_LABEL, inside); + volumesBuilder.addComponent(CELL_SIZE_LABEL, new Size(model, inside)); + volumesBuilder.endGroup(); + + volumesBuilder.startGroup(OUTSIDE, OUTSIDE_LABEL); + IntegerField outside = volumeModel.bindIntegerLevels("levels", OUTSIDE); + volumesBuilder.addComponent(OUTSIDE_LEVEL_LABEL, outside); + volumesBuilder.addComponent(CELL_SIZE_LABEL, new Size(model, outside)); + volumesBuilder.endGroup(); + + volumesBuilder.startGroup(DISTANCE, DISTANCE_LABEL); + String[] columnNames = { DISTANCE_M_LABEL, LEVEL_LABEL }; + Class[] type = { Double.class, Integer.class }; + volumesBuilder.addComponent(DISTANCE_LEVEL_LABEL, volumeModel.bindTableLevels(columnNames, type)); + volumesBuilder.endGroup(); + + volumesBuilder.endChoice(); + + comboBoxController.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + boolean distanceRefinementOrNone = isDistanceRefinementOrNone(comboBoxController.getSelectedKey()); + surfaceBuilder.setEnabled(distanceRefinementOrNone || isCellZone()); + layersBuilder.setEnabled(distanceRefinementOrNone || isCellZone()); + } + }); + volumesBuilder.getPanel().setBorder(BorderFactory.createTitledBorder("Volumetric")); + return volumesBuilder.getPanel(); + } + + protected boolean isCellZone() { + return false; + } + + protected JPanel getLayersPanel() { + return new JPanel(); + } + + protected JPanel getZonesPanel() { + return new JPanel(); + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + + @Override + public void save() { + super.save(); + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) treeNodeManager.getSelectedValues()); + model.getGeometry().saveGeometry(model); + } + + @Override + public void stop() { + super.stop(); + geometriesPanel.stop(); + } + + public void saveSurfaces(Surface[] surfaces) { + surfaceRegionsBuilder.buildSurfaces(surfaces); + } + + @Override + public void changeSurface(Surface surface) { + surfaceRegionsBuilder.buildSurfaces(surface); + EventManager.triggerEvent(this, new ChangeSurfaceEvent(surface, false)); + } + + @Override + public void renameSurface(String newName) { + Surface[] selection = treeNodeManager.getSelectedValues(); + if (selection.length == 1) { + Surface surface = selection[0]; + + if (model.getGeometry().contains(newName)) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Name already in use", "Name Error", JOptionPane.ERROR_MESSAGE); + return; + } + + String oldPatchName = surface.getPatchName(); + surface.rename(newName); + + surfaceRegionsBuilder.buildSurfaces(surface); + + treeNodeManager.refreshNode(surface); + + EventManager.triggerEvent(this, new RenameSurfaceEvent(surface, oldPatchName, surface.getPatchName())); + } + } + + @Override + public void clear() { + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) new Surface[0]); + } + + @Action(key = "mesh.stl") + public void addSTL() { + new AddSTL(model, monitor) { + @Override + public void postLoad(List stls) { + addSTL(stls.toArray(new Stl[0])); + } + }.execute(); + } + + @Action(key = "mesh.igs") + public void addIGES() { + new AddIGES(model, monitor) { + @Override + public void postLoad(List stls) { + addSTL(stls.toArray(new Stl[0])); + } + }.execute(); + } + + public void addSTL(Stl... stls) { + if (Util.isVarArgsNotNull(stls)) { + for (Stl stl : stls) { + getModel().getGeometry().addSurface(stl); + getModel().geometryChanged(stl); + } + EventManager.triggerEvent(this, new AddSurfaceEvent(stls)); + } + } + + @Action(key = "mesh.box") + public void addBox() { + treeNodeManager.clear(); + Surface box = model.getGeometry().getABox(); + + getModel().getGeometry().addSurface(box); + getModel().geometryChanged(box); + + EventManager.triggerEvent(this, new AddSurfaceEvent(box)); + } + + @Action(key = "mesh.cylinder") + public void addCylinder() { + treeNodeManager.clear(); + Surface cyl = model.getGeometry().getACylinder(); + + getModel().getGeometry().addSurface(cyl); + getModel().geometryChanged(cyl); + + EventManager.triggerEvent(this, new AddSurfaceEvent(cyl)); + } + + @Action(key = "mesh.sphere") + public void addSphere() { + treeNodeManager.clear(); + Surface sphere = model.getGeometry().getASphere(); + + getModel().getGeometry().addSurface(sphere); + getModel().geometryChanged(sphere); + + EventManager.triggerEvent(this, new AddSurfaceEvent(sphere)); + } + + @Action(key = "mesh.plane") + public void addPlane() { + treeNodeManager.clear(); + Surface plane = model.getGeometry().getAPlane(); + + getModel().getGeometry().addSurface(plane); + getModel().geometryChanged(plane); + + EventManager.triggerEvent(this, new AddSurfaceEvent(plane)); + } + + @Action(key = "mesh.ring") + public void addRing() { + treeNodeManager.clear(); + Surface ring = model.getGeometry().getARing(); + + getModel().getGeometry().addSurface(ring); + getModel().geometryChanged(ring); + + EventManager.triggerEvent(this, new AddSurfaceEvent(ring)); + } + + private boolean hasDistanceRefinementOrNone(Surface surface) { + Dictionary volumeDictionary = surface.getVolumeDictionary(); + if (volumeDictionary.found("mode")) { + String mode = volumeDictionary.lookup("mode"); + return isDistanceRefinementOrNone(mode); + } + return true; + } + + private boolean isDistanceRefinementOrNone(String mode) { + return mode == null || "distance".equals(mode) || "none".equals(mode); + } + + public void selectSurface(Surface[] surfaces) { + if (Util.isVarArgsNotNull(surfaces)) { + geometriesPanel.showPanel(surfaces); + + updateGUIOnSelection(surfaces[0]); + + selectATab(); + + Dictionary surfaceDictionary = surfaces[0].getSurfaceDictionary(); + Dictionary volumeDictionary = surfaces[0].getVolumeDictionary(); + Dictionary layerDictionary = surfaces[0].getLayerDictionary(); + Dictionary zoneDictionary = surfaces[0].getZoneDictionary(); + + // System.out.println("DefaultGeometryPanel.selectSurface() "+surfaceDictionary+volumeDictionary+layerDictionary); + + surfaceModel.setDictionary(new Dictionary(surfaceDictionary)); + volumeModel.setDictionary(new Dictionary(volumeDictionary)); + layerModel.setDictionary(new Dictionary(layerDictionary)); + zoneModel.setDictionary(new Dictionary(zoneDictionary)); + } else { + deselectAll(); + } + } + + public void deselectAll() { + geometriesPanel.showPanel(null); + + surfaceModel.setDictionary(new Dictionary("")); + volumeModel.setDictionary(new Dictionary("")); + layerModel.setDictionary(new Dictionary("")); + zoneModel.setDictionary(new Dictionary("")); + + updateGUIOnSelection(null); + } + + protected void updateGUIOnSelection(Surface surface) { + if (surface == null) { + surfaceBuilder.setEnabled(false); + volumesBuilder.setEnabled(false); + layersBuilder.setEnabled(false); + zonesBuilder.setEnabled(false); + } else { + surfaceBuilder.setEnabled(true); + volumesBuilder.setEnabled(true); + layersBuilder.setEnabled(true); + zonesBuilder.setEnabled(true); + + surfaceBuilder.setEnabled(surface.hasSurfaceRefinement() && hasDistanceRefinementOrNone(surface)); + volumesBuilder.setEnabled(surface.hasVolumeRefinement()); + layersBuilder.setEnabled(surface.hasLayers()); + zonesBuilder.setEnabled(surface.hasZones()); + } + } + + private void selectATab() { + if (tabbedPane.isEnabledAt(tabbedPane.getSelectedIndex())) + return; + for (int i = 0; i < tabbedPane.getTabCount(); i++) { + if (tabbedPane.isEnabledAt(i)) { + tabbedPane.setSelectedIndex(i); + return; + } + } + } + + @Override + public boolean isDemo() { + return false; + } + + public static class Size extends DoubleField { + private Model model; + private IntegerField level; + + public Size(Model model, IntegerField level) { + super(3); + this.model = model; + this.level = level; + setEnabled(false); + PropertyChangeListener listener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + recalculate(); + } + } + }; + level.addPropertyChangeListener(listener); + } + + public void recalculate() { + if (level.getValue() != null) { + double[] d1 = model.getGeometry().getCellSize(level.getIntValue()); + setDoubleValue(d1[0]); + } else { + setValue(null); + } + } + } + +} diff --git a/src/eu/engys/gui/mesh/panels/BaseMeshTreeNodeManager.java b/src/eu/engys/gui/mesh/panels/BaseMeshTreeNodeManager.java new file mode 100644 index 0000000..2dfdddb --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/BaseMeshTreeNodeManager.java @@ -0,0 +1,267 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import java.awt.Component; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreePath; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Geometry; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.MultiPlane; +import eu.engys.core.project.geometry.surface.PlaneRegion; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.SelectSurfaceEvent; +import eu.engys.gui.tree.AbstractSelectionHandler; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.SelectionHandler; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Geometry3DController; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.Util; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.checkboxtree.RootVisibleItem; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class BaseMeshTreeNodeManager extends DefaultTreeNodeManager { + + private static final Logger logger = LoggerFactory.getLogger(BaseMeshTreeNodeManager.class); + + private Map surfaceMap; + private SelectionHandler selectionHandler; + + public BaseMeshTreeNodeManager(Model model, AbstractBaseMeshPanel panel) { + super(model, panel); + this.selectionHandler = new BlockMeshSelectionHandler(panel); + this.surfaceMap = new HashMap<>(); + } + + @Override + public void update(Observable o, final Object arg) { + if (arg instanceof MultiPlane || arg instanceof Geometry) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + loadTree(); + selectVisibleItems(); + expandTree(); + } + }); + } else if (arg instanceof Patches) { + selectVisibleItems(); + } + } + + private void loadTree() { + clear(); + + if (model.getGeometry().hasBlock()) { + MultiPlane block = model.getGeometry().getBlock(); + DefaultMutableTreeNode parentNode = new DefaultMutableTreeNode(new RootVisibleItem(block.getName())); + root.add(parentNode); + + for (Surface region : block.getRegions()) { + addSurface(parentNode, region); + } + treeChanged(root); + } + } + + private void selectVisibleItems() { + if (model.getPatches().isEmpty()) + getTree().getCheckManager().selectNode(getRoot()); + else + getTree().getCheckManager().deselectNode(getRoot()); + } + + private void expandTree() { + if (getTree() != null) { + if (model.getGeometry().hasBlock()) { + getTree().expandNode(getRoot()); + } + } + } + + private void addSurface(DefaultMutableTreeNode parent, Surface surface) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(surface); + parent.add(node); + nodeMap.put(surface, node); + surfaceMap.put(node, surface); + } + + public Surface[] getSelectedValues() { + if (getTree() != null) { + TreePath[] selectionPaths = getTree().getSelectionPaths(); + Surface[] surfaces = new Surface[selectionPaths.length]; + for (int i = 0; i < selectionPaths.length; i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPaths[i].getLastPathComponent(); + Surface surface = surfaceMap.get(node); + surfaces[i] = surface; + } + return surfaces; + } + return new Surface[0]; + } + + public void clear() { + // clear node before selection handler! + clearNode(root); + selectionHandler.clear(); + nodeMap.clear(); + surfaceMap.clear(); + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public Class getRendererClass() { + return PlaneRegion.class; + } + + public DefaultTreeCellRenderer getRenderer() { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object userObject = node.getUserObject(); + + if (userObject instanceof PlaneRegion) { + PlaneRegion surface = (PlaneRegion) userObject; + setText(surface.getName()); + } + setIcon(null); + return this; + } + }; + } + + @Override + public SelectionHandler getSelectionHandler() { + return selectionHandler; + } + + private final class BlockMeshSelectionHandler extends AbstractSelectionHandler { + private PlaneRegion[] currentSelection; + private AbstractBaseMeshPanel panel; + + public BlockMeshSelectionHandler(AbstractBaseMeshPanel panel) { + this.panel = panel; + } + + @Override + public void handleSelection(boolean fire3DEvent, Object... selection) { + saveCurrentSelection(); + + boolean isValidSelection = TreeUtil.isConsistent(selection, PlaneRegion.class); + if (isValidSelection) { + handleValidSelection(fire3DEvent, selection); + } else { + boolean shouldClearSelection = TreeUtil.isConsistent(currentSelection, PlaneRegion.class); + if(shouldClearSelection){ + clearSelection(fire3DEvent); + } + } + } + + private void saveCurrentSelection() { + if (Util.isVarArgsNotNull(currentSelection)) { + panel.saveSurfaces(currentSelection); + } + } + + private void handleValidSelection(boolean fire3DEvent, Object... selection) { + logger.debug("handleSelection: {} selected, fire3D {} {}", selection.length, fire3DEvent, selection.length == 1 ? ", selection is: " + selection[0] : ""); + + // update current selection + this.currentSelection = Arrays.copyOf(selection, selection.length, PlaneRegion[].class); + panel.selectPlane(currentSelection); + + if (fire3DEvent) { + EventManager.triggerEvent(this, new SelectSurfaceEvent(currentSelection)); + } + } + + private void clearSelection(boolean fire3DEvent) { + clear(); + panel.clear(); + if (fire3DEvent) { + EventManager.triggerEvent(this, new SelectSurfaceEvent(new PlaneRegion[0])); + } + } + + @Override + public void handleVisibility(VisibleItem item) { + if (Util.isVarArgsNotNull(currentSelection) && Arrays.asList(currentSelection).contains(item)) { + panel.selectPlane(currentSelection); + EventManager.triggerEvent(this, new SelectSurfaceEvent(currentSelection)); + } + + } + + @Override + public void process3DSelectionEvent(Picker picker, Actor actor, boolean keep) { + if (getTree() != null && picker instanceof Geometry3DController && actor.getVisibleItem() instanceof Surface) { + Surface surface = (Surface) actor.getVisibleItem(); + DefaultMutableTreeNode selectedNode = nodeMap.get(surface); + if (selectedNode != null) { + getTree().setSelectedNode(selectedNode); + } + } + } + + @Override + public void process3DVisibilityEvent(boolean selected) { + if (getTree() != null) { + if (selected) { + // getTree().getCheckManager().selectNode(getRoot()); + } else { + getTree().getCheckManager().deselectNode(getRoot()); + } + } + } + + public void clear() { + currentSelection = null; + } + } + +} diff --git a/src/eu/engys/gui/mesh/panels/BoundaryMeshTreeNodeManager.java b/src/eu/engys/gui/mesh/panels/BoundaryMeshTreeNodeManager.java new file mode 100644 index 0000000..08dc7e7 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/BoundaryMeshTreeNodeManager.java @@ -0,0 +1,263 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import java.awt.Component; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.cellzones.CellZones; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.SelectCellZonesEvent; +import eu.engys.gui.events.view3D.SelectPatchesEvent; +import eu.engys.gui.tree.AbstractSelectionHandler; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.SelectionHandler; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.checkboxtree.RootVisibleLoadableTreeNode; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class BoundaryMeshTreeNodeManager extends DefaultTreeNodeManager { + + private static final Logger logger = LoggerFactory.getLogger(BoundaryMeshTreeNodeManager.class); + + private Map patchesMap; + private Map cellZonesMap; + + private SelectionHandler selectionHandler; + private DefaultMutableTreeNode patches; + private DefaultMutableTreeNode cellZones; + + public BoundaryMeshTreeNodeManager(Model model, GUIPanel panel) { + super(model, panel); + this.root = new RootVisibleLoadableTreeNode(panel.getTitle()); + this.selectionHandler = new BoundaryMeshSelectionHandler(); + this.patchesMap = new HashMap<>(); + this.cellZonesMap = new HashMap<>(); + + patches = new RootVisibleLoadableTreeNode("Patches"); + cellZones = new RootVisibleLoadableTreeNode("Cell Zones"); + root.add(patches); + root.add(cellZones); + } + + @Override + public void update(Observable o, final Object arg) { + if (arg instanceof Patches || arg instanceof CellZones) { + logger.debug("Observerd a change: arg is " + arg.getClass()); + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + selectionHandler.disable(); + loadTree(); + makeVisibleItemsChecked(); + expandTree(); + selectionHandler.enable(); + } + }); + } + } + + private void loadTree() { + logger.debug("Load 'Mesh' tree"); + clear(); + for (Patch patch : model.getPatches().patchesToDisplay()) { + addPatch(patches, patch); + } + for (CellZone zone : model.getCellZones()) { + addCellZone(cellZones, zone); + } + + treeChanged(root); + } + + private void makeVisibleItemsChecked() { + logger.debug("Make visible items checked: DO NOTHING!"); + } + + private void expandTree() { + getTree().expandNode(getRoot()); + } + + private void addPatch(DefaultMutableTreeNode parent, Patch patch) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(patch); + parent.add(node); + nodeMap.put(patch, node); + patchesMap.put(node, patch); + } + + private void addCellZone(DefaultMutableTreeNode parent, CellZone zone) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(zone); + parent.add(node); + nodeMap.put(zone, node); + cellZonesMap.put(node, zone); + } + + public void setSelectedValue(String name) { + } + + public void clear() { + // clear node before selection handler! + clearNode(patches); + clearNode(cellZones); + selectionHandler.clear(); + nodeMap.clear(); + patchesMap.clear(); + cellZonesMap.clear(); + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public Class getRendererClass() { + return VisibleItem.class; + } + + public DefaultTreeCellRenderer getRenderer() { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object userObject = node.getUserObject(); + + if (userObject instanceof VisibleItem) { + VisibleItem item = (VisibleItem) userObject; + setText(item.getName()); + } + setIcon(null); + return this; + } + }; + } + + @Override + public SelectionHandler getSelectionHandler() { + return selectionHandler; + } + + private final class BoundaryMeshSelectionHandler extends AbstractSelectionHandler { + + private VisibleItem[] currentSelection; + + @Override + public void handleSelection(boolean fire3DEvent, Object... selection) { + boolean isValidPatchSelection = TreeUtil.isConsistent(selection, Patch.class) && fire3DEvent; + boolean isValidCellZoneSelection = TreeUtil.isConsistent(selection, CellZone.class) && fire3DEvent; + if (isValidPatchSelection) { + handleValidPatchSelection(fire3DEvent, selection); + } else if (isValidCellZoneSelection) { + handleValidZoneSelection(fire3DEvent, selection); + } else { + handleInvalidSelection(); + } + } + + private void handleValidPatchSelection(boolean fire3DEvent, Object... selection) { + logger.debug("handleSelection: {} selected, fire3D {} {}", selection.length, fire3DEvent, selection.length == 1 ? ", selection is: " + selection[0] : ""); + + this.currentSelection = Arrays.copyOf(selection, selection.length, Patch[].class); + EventManager.triggerEvent(this, new SelectPatchesEvent((Patch[]) currentSelection)); + } + + private void handleValidZoneSelection(boolean fire3DEvent, Object... selection) { + logger.debug("handleSelection: {} selected, fire3D {} {}", selection.length, fire3DEvent, selection.length == 1 ? ", selection is: " + selection[0] : ""); + + this.currentSelection = Arrays.copyOf(selection, selection.length, CellZone[].class); + EventManager.triggerEvent(this, new SelectCellZonesEvent((CellZone[]) currentSelection)); + } + + private void handleInvalidSelection() { + boolean shouldClearPatchesSelection = TreeUtil.isConsistent(currentSelection, Patch.class); + boolean shouldClearZoneSelection = TreeUtil.isConsistent(currentSelection, CellZone.class); + + if (shouldClearPatchesSelection) { + EventManager.triggerEvent(this, new SelectPatchesEvent(new Patch[0])); + } else if (shouldClearZoneSelection) { + EventManager.triggerEvent(this, new SelectCellZonesEvent(new CellZone[0])); + } + } + + @Override + public void handleVisibility(VisibleItem item) { + logger.debug("handleVisibility: {}", item); + } + + @Override + public void process3DSelectionEvent(Picker picker, Actor actor, boolean keep) { + if (getTree() != null && picker.canPickMesh()) { + VisibleItem visibleItem = actor.getVisibleItem(); + DefaultMutableTreeNode selectedNode = nodeMap.get(visibleItem); + logger.debug("Handle selection from 3D {}", actor.getName()); + if (selectedNode != null) { + if (keep) { + getTree().addSelectedNode(selectedNode); + } else { + getTree().setSelectedNode(selectedNode); + } + } + } + } + + @Override + public void process3DVisibilityEvent(boolean selected) { + if (getTree() != null) { + if (selected) { + getTree().getCheckManager().selectNode(patches); + getTree().getCheckManager().selectNode(cellZones); + } else { + getTree().getCheckManager().deselectNode(patches); + getTree().getCheckManager().deselectNode(cellZones); + } + } + } + + @Override + public void clear() { + currentSelection = null; + } + } + +} diff --git a/src/eu/engys/gui/mesh/panels/DefaultBoundaryMeshPanel.java b/src/eu/engys/gui/mesh/panels/DefaultBoundaryMeshPanel.java new file mode 100644 index 0000000..d0be45a --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/DefaultBoundaryMeshPanel.java @@ -0,0 +1,232 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh.panels; + +import static eu.engys.util.ui.ComponentsFactory.labelField; + +import java.awt.Dimension; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import javax.inject.Inject; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JTextArea; + +import net.java.dev.designgridlayout.Componentizer; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.builder.PanelBuilder; + +public class DefaultBoundaryMeshPanel extends AbstractGUIPanel { + + public static final String TITLE = "Mesh"; + private static final DecimalFormat formatter = new DecimalFormat("#.###", new DecimalFormatSymbols(Locale.US)); + + private BoundaryMeshTreeNodeManager treeNodeManager; + + private JLabel name; + private JLabel path; + private JLabel created; + private JLabel cells; + private JLabel points; + private JLabel faces; + private JTextArea cellsPerLevel; + private JLabel memory; + + private JLabel xBounds; + private JLabel yBounds; + private JLabel zBounds; + + private PanelBuilder dataArrays; + + protected PanelBuilder builder; + + @Inject + public DefaultBoundaryMeshPanel(Model model) { + super(TITLE, model); + this.treeNodeManager = new BoundaryMeshTreeNodeManager(model, this); + model.addObserver(treeNodeManager); + } + + protected JComponent layoutComponents() { + PanelBuilder actions = new PanelBuilder(); + actions.getPanel().setBorder(BorderFactory.createTitledBorder("Actions")); + + Action createMesh = ActionManager.getInstance().get("mesh.create"); + Action editCreateMesh = ActionManager.getInstance().get("mesh.create.edit"); + Action checkMesh = ActionManager.getInstance().get("mesh.check"); + Action editCheckMesh = ActionManager.getInstance().get("mesh.check.edit"); + Action deleteMesh = ActionManager.getInstance().get("mesh.delete"); + + JButton runMeshButton = new JButton(createMesh); + JButton editMeshScriptButton = new JButton(editCreateMesh); + JButton checkMeshButton = new JButton(checkMesh); + JButton editCheckMeshButton = new JButton(editCheckMesh); + JButton deleteMeshButton = new JButton(deleteMesh); + + runMeshButton.setPreferredSize(new Dimension(120, runMeshButton.getPreferredSize().height)); + checkMeshButton.setPreferredSize(new Dimension(120, checkMeshButton.getPreferredSize().height)); + deleteMeshButton.setPreferredSize(new Dimension(120, checkMeshButton.getPreferredSize().height)); + + JComponent c1 = Componentizer.create().minToPref(runMeshButton).fixedPref(editMeshScriptButton).minAndMore(new JLabel()).component(); + JComponent c2 = Componentizer.create().minToPref(checkMeshButton).fixedPref(editCheckMeshButton).minAndMore(new JLabel()).component(); + JComponent c3 = Componentizer.create().minToPref(deleteMeshButton).fixedPref(new JLabel()).minAndMore(new JLabel()).component(); + actions.addComponent(c1); + actions.addComponent(c2); + actions.addComponent(c3); + + name = labelField(""); + path = labelField(""); + created = labelField(""); + + cells = labelField(""); + points = labelField(""); + faces = labelField(""); + + cellsPerLevel = ComponentsFactory.labelArea(); + cellsPerLevel.setEditable(false); + + memory = labelField(""); + + xBounds = labelField(""); + yBounds = labelField(""); + zBounds = labelField(""); + + PanelBuilder properties = new PanelBuilder(); + properties.getPanel().setBorder(BorderFactory.createTitledBorder("Properties")); + properties.addComponent("Name", name); + properties.addComponent("Path", path); + properties.addComponent("Created", created); + + PanelBuilder statistics = new PanelBuilder(); + statistics.getPanel().setBorder(BorderFactory.createTitledBorder("Statistics")); + statistics.addComponent("Number of Cells", cells); + statistics.addComponent("Number of Faces", faces); + statistics.addComponent("Number of Points", points); + statistics.addComponent("Cells per Refinement Level", cellsPerLevel); + // statistics.addComponent("Memory [MB]", memory); + + dataArrays = new PanelBuilder(); + dataArrays.getPanel().setBorder(BorderFactory.createTitledBorder("Data Arrays")); + + PanelBuilder bounds = new PanelBuilder(); + bounds.getPanel().setBorder(BorderFactory.createTitledBorder("Bounds")); + bounds.addComponent("X Range", xBounds); + bounds.addComponent("Y Range", yBounds); + bounds.addComponent("Z Range", zBounds); + + builder = new PanelBuilder(); + builder.addComponent(actions.getPanel()); + builder.addComponent(properties.getPanel()); + builder.addComponent(statistics.getPanel()); + builder.addComponent(dataArrays.getPanel()); + builder.addComponent(bounds.getPanel()); + + return builder.removeMargins().getPanel(); + } + + @Override + public void load() { + name.setText(model.getProject().getBaseDir().getName()); + path.setText(model.getProject().getBaseDir().getParent()); + + try { + Path basePath = model.getProject().getBaseDir().toPath(); + long lastModify = Files.getLastModifiedTime(basePath).toMillis(); + created.setText(DateFormat.getDateInstance().format(new Date(lastModify))); + } catch (Exception e) { + created.setText("-"); + } + + if (model.getMesh() != null) { + cells.setText(formatter.format(model.getMesh().getNumberOfCells())); + points.setText(formatter.format(model.getMesh().getNumberOfPoints())); + faces.setText(formatter.format(model.getMesh().getNumberOfFaces())); + + List cellsPerRefinementLevel = model.getMesh().getCellsPerRefinementLevel(); + String text = ""; + for (int i = 0; i < cellsPerRefinementLevel.size(); i++) { + if (i > 0) + text += "\n"; + text += i + "\t" + cellsPerRefinementLevel.get(i); + } + cellsPerLevel.setText(text); + + // memory.setText(formatter.format(model.getMesh().getMemorySize()/1024D)); + + double[] bounds = model.getMesh().getBounds(); + + xBounds.setText(getTextForBounds(bounds[0], bounds[1])); + yBounds.setText(getTextForBounds(bounds[2], bounds[3])); + zBounds.setText(getTextForBounds(bounds[4], bounds[5])); + } else { + cells.setText("-"); + points.setText("-"); + faces.setText("-"); + cellsPerLevel.setText(" - "); + // memory.setText("-"); + xBounds.setText("[- , -]"); + yBounds.setText("[- , -]"); + zBounds.setText("[- , -]"); + } + } + + private String getTextForBounds(double min, double max) { + if (areValid(min, max)) { + return "[" + formatter.format(min) + " , " + formatter.format(max) + "] (Delta " + formatter.format(max - min) + ")"; + } else { + return "[0 , 0]"; + } + } + + private boolean areValid(double min, double max) { + return min < Double.MAX_VALUE && max > -Double.MAX_VALUE; + } + + @Override + public void save() { + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + +} diff --git a/src/eu/engys/gui/mesh/panels/DefaultGeometryActions.java b/src/eu/engys/gui/mesh/panels/DefaultGeometryActions.java new file mode 100644 index 0000000..f77ce4c --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/DefaultGeometryActions.java @@ -0,0 +1,163 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import static eu.engys.gui.mesh.actions.geometry.ExtractLineAction.EXTRACT_NAME; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; + +import com.lowagie.text.Font; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.mesh.actions.geometry.CloneSurfaceAction; +import eu.engys.gui.mesh.actions.geometry.CopySurfaceAction; +import eu.engys.gui.mesh.actions.geometry.ExtractLineAction; +import eu.engys.gui.mesh.actions.geometry.PasteSurfaceAction; +import eu.engys.gui.mesh.actions.geometry.RemoveSurfaceAction; +import eu.engys.gui.tree.TreeNodeManager.PopUpBuilder; +import eu.engys.util.Util; + +public class DefaultGeometryActions implements PopUpBuilder { + + public static final String GENERAL = "General"; + public static final String LINES = "Lines"; + public static final String SURFACES = "Surfaces"; + + protected final Model model; + private final AbstractGeometryPanel panel; + + private final RemoveSurfaceAction remove; + private final CloneSurfaceAction clone; + private final CopySurfaceAction copy; + private final PasteSurfaceAction paste; + + private final ExtractLineAction extractLines; + + private boolean enabled = true; + + public DefaultGeometryActions(AbstractGeometryPanel panel, Controller controller) { + this.panel = panel; + this.model = panel.getModel(); + + this.remove = new RemoveSurfaceAction(model); + this.clone = new CloneSurfaceAction(model, panel); + this.copy = new CopySurfaceAction(panel); + this.paste = new PasteSurfaceAction(panel); + + // Lines + this.extractLines = new ExtractLineAction(model, controller, this); + } + + @Override + public void populate(JPopupMenu popUp) { + populateGeneralActions(popUp); + populateSurfaceActions(popUp); + populateLinesActions(popUp); + } + + private void populateGeneralActions(JPopupMenu popUp) { + popUp.add(new TitledSeparator(GENERAL)); + popUp.add(remove).setName(RemoveSurfaceAction.REMOVE); + popUp.add(clone).setName(CloneSurfaceAction.CLONE); + popUp.add(copy).setName(CopySurfaceAction.COPY); + popUp.add(paste).setName(PasteSurfaceAction.PASTE); + } + + protected void populateSurfaceActions(JPopupMenu popUp) { + } + + protected void populateLinesActions(JPopupMenu popUp) { + popUp.add(new TitledSeparator(LINES)); + popUp.add(extractLines).setName(EXTRACT_NAME); + } + + protected void updateActions(Surface[] surfaces) { + if (Util.isVarArgsNotNull(surfaces)) { + remove.update(isEnabled(), surfaces); + clone.update(isEnabled(), surfaces); + copy.update(isEnabled(), surfaces); + paste.update(isEnabled(), surfaces); + + extractLines.update(isEnabled(), surfaces); + } + } + + public static class TitledSeparator extends JPanel { + public TitledSeparator(String title) { + super(new GridBagLayout()); + setOpaque(false); + JLabel label = new JLabel(title); + label.setOpaque(false); + label.setFont(label.getFont().deriveFont(Font.BOLD)); + add(new JSeparator(), new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + add(label, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + add(new JSeparator(), new GridBagConstraints(2, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + } + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + public static class Enable implements Runnable { + private DefaultGeometryActions actions; + + public Enable(DefaultGeometryActions actions) { + this.actions = actions; + } + + @Override + public void run() { + actions.setEnabled(true); + } + } + + public static class Disable implements Runnable { + private DefaultGeometryActions actions; + + public Disable(DefaultGeometryActions actions) { + this.actions = actions; + } + + @Override + public void run() { + actions.setEnabled(false); + } + } +} diff --git a/src/eu/engys/gui/mesh/panels/DefaultMeshAdvancedOptionsPanel.java b/src/eu/engys/gui/mesh/panels/DefaultMeshAdvancedOptionsPanel.java new file mode 100644 index 0000000..04e0837 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/DefaultMeshAdvancedOptionsPanel.java @@ -0,0 +1,319 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import static eu.engys.core.project.system.SnappyHexMeshDict.ADD_LAYERS_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.CASTELLATED_MESH_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.ERROR_REDUCTION_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_BOUNDARY_SKEWNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_CONCAVE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_INTERNAL_SKEWNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_NON_ORTHO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MESH_QUALITY_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_AREA_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_DETERMINANT_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_FACE_WEIGHT_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_FLATNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_TET_QUALITY_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_TRIANGLE_TWIST_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_TWIST_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_VOL_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_VOL_RATIO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SMOOTH_SCALE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.SNAP_CONTROLS_KEY; + +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.util.TooltipUtils; +import eu.engys.util.ui.builder.PanelBuilder; + +public abstract class DefaultMeshAdvancedOptionsPanel extends DefaultGUIPanel { + + public static final String NAME = "general.options.tabbedPane"; + + public static final String GENERAL_LABEL = "General"; + public static final String CASTELLATED_MESH_CONTROLS_LABEL = "Refinements"; + public static final String SNAP_CONTROLS_LABEL = "Snapping"; + public static final String LAYERS_CONTROLS_LABEL = "Layers"; + public static final String QUALITY_CONTROLS_LABEL = "Quality"; + + // GENERAL + public static final String CASTELLATED_MESH_LABEL = "Castellated Mesh"; + public static final String CASTELLATED_MESH_TOOLTIP = "Generate a refined castellated mesh"; + public static final String SNAPPING_LABEL = "Snapping"; + public static final String SNAPPING_TOOLTIP = "Snap surface mesh points to the geometry and merge boundary faces"; + public static final String LAYERS_ADDITION_LABEL = "Layers Addition"; + public static final String LAYERS_ADDITION_TOOLTIP = "Perform generation of layers"; + public static final String DEBUG_LABEL = "Debug"; + public static final String DEBUG_TOOLTIP = "Control of debug output:" + TooltipUtils.NEW_LINE + "0: Write only final mesh" + TooltipUtils.NEW_LINE + "1: Write intermediate meshes" + TooltipUtils.NEW_LINE + "2: Write cell level information"; + public static final String MERGE_TOLERANCE_LABEL = "Merge Tolerance"; + public static final String MERGE_TOLERANCE_TOOLTIP = "Merge tolerance specified as a function of the initial bounding box size"; + + // CASTELLATED + public static final String MAX_LOCAL_CELLS_LABEL = "Max Local Cells"; + public static final String MAX_LOCAL_CELLS_TOOLTIP = "Termination of refinement if number of cells on processor n exceeds this value"; + public static final String MAX_GLOBAL_CELLS_LABEL = "Max Global Cells"; + public static final String MAX_GLOBAL_CELLS_TOOLTIP = "No further refinement if global number of cells exceeds this value"; + public static final String MIN_REFINEMENT_CELLS_LABEL = "Min Refinement Cells"; + public static final String MIN_REFINEMENT_CELLS_TOOLTIP = "Terminate refinement iteration if number of cells to refine falls below this value"; + public static final String MAX_LOAD_UNBALANCE_LABEL = "Max Load Unbalance"; + public static final String MAX_LOAD_UNBALANCE_TOOLTIP = "When running in parallel allow some imbalance in the number of cells per processor to avoid expensive re-balancing operations. This value is expressed as a fraction of perfect balance (i.e. overall number of cells / number of processors). Set to 0 will always perform balancing"; + public static final String CELLS_BETWEEN_LEVELS_LABEL = "Cells Between Levels"; + public static final String CELLS_BETWEEN_LEVELS_TOOLTIP = "Specify the number of buffer layers between two neighbouring volume refinement levels in the mesh"; + public static final String RESOLVE_FEATURE_ANGLE_LABEL = "Resolve Feature Angle"; + public static final String RESOLVE_FEATURE_ANGLE_TOOLTIP = "The surface is refined to the maximum level if local curvature is greater than this angle. Set to a negative value to disable"; + public static final String ALLOW_FREE_STANDING_ZONE_FACES_LABEL = "Allow Free Standing Zone Faces"; + public static final String ALLOW_FREE_STANDING_ZONE_FACES_TOOLTIP = "Allow free standing zone faces in addition to zone faces in between different cell zones. Can be set globally or on a per zone basis"; + + // SNAP + public static final String RELAX_ITERATIONS_SNAP_LABEL = "Correction Steps"; + public static final String RELAX_ITERATIONS_SNAP_TOOLTIP = "Maximum number of corrections steps to revert mesh back to error free state"; + public static final String TOLERANCE_LABEL = "Tolerance"; + public static final String TOLERANCE_TOOLTIP = "Relative distance for points to be attached by surface feature point"; + public static final String SMOOTH_PATCH_LABEL = "Smooth Patch"; + public static final String SMOOTH_PATCH_TOOLTIP = "Number of patch smoothing iterations performed finding correspondance to surface"; + public static final String SOLVER_ITERATIONS_LABEL = "Solver Iterations"; + public static final String SOLVER_ITERATIONS_TOOLTIP = "Specifies the number of displacement smoothing iterations"; + + // LAYERS + public static final String RELAX_ITERATIONS_LAYERS_LABEL = "Correction Steps"; + public static final String RELAX_ITERATIONS_LAYERS_TOOLTIP = "Number of correction steps to revert mesh back to error free state"; + public static final String RELAXED_ITERATIONS_LABEL = "Relaxed Layer Iterations"; + public static final String RELAXED_ITERATIONS_TOOLTIP = "Number of layer iterations before a set of relaxed mesh quality constraints are applied"; + public static final String MIN_MEDIAL_AXIS_ANGLE_LABEL = "Min Medial Axis Angle"; + public static final String MIN_MEDIAL_AXIS_ANGLE_TOOLTIP = "Angle used to select medial axis points"; + public static final String MAX_THICKNESS_TO_MEDIAL_RATIO_LABEL = "Max Thickness To Medial Ratio"; + public static final String MAX_THICKNESS_TO_MEDIAL_RATIO_TOOLTIP = "Reduce layer thickness where ratio of layer thickness to distance to medial axis is above this value"; + public static final String MAX_FACE_THICKNESS_RATIO_LABEL = "Max Face Thickness Ratio"; + public static final String MAX_FACE_THICKNESS_RATIO_TOOLTIP = "Measure of surface face warp-age. Layer growth is terminated on faces where this value is exceeded"; + public static final String INTERIOR_MESH_SMOOTHING_ITERATIONS_LABEL = "Interior Mesh Smoothing Iterations"; + public static final String INTERIOR_MESH_SMOOTHING_ITERATIONS_TOOLTIP = "Number of interior normals smoothing iterations performed before projecting the mesh"; + public static final String SURFACE_NORMALS_SMOOTHING_ITERATIONS_LABEL = "Surface Normals Smoothing Iterations"; + public static final String SURFACE_NORMALS_SMOOTHING_ITERATIONS_TOOLTIP = "Number of surface normals smoothing iterations performed before projecting the mesh"; + public static final String MIN_THICKNESS_LABEL = "Min Thickness"; + public static final String MIN_THICKNESS_TOOLTIP = "Relative measure of layer thickness, layers terminated if their thickness fall below this value"; +// public static final String RELATIVE_SIZES_LABEL = "Relative Sizes"; +// public static final String RELATIVE_SIZES_TOOLTIP = "Whether to use a relative or absolute sizing for layer control"; + public static final String FINAL_LAYER_THICKNESS_LABEL = "Final Layer Thickness"; + public static final String FINAL_LAYER_THICKNESS_TOOLTIP = "Requested thickness for final cell layer"; + public static final String EXPANSION_RATIO_LABEL = "Expansion Ratio"; + public static final String EXPANSION_RATIO_TOOLTIP = "Global setting of growth factor for layer growth. Can be overwritten locally on each patch"; + + // QUALITY + public static final String ERROR_REDUCTION_LABEL = "Error Reduction"; + public static final String ERROR_REDUCTION_TOOLTIP = "Ratio used for scaling of displacement during each error reduction iteration"; + public static final String SMOOTH_SCALE_LABEL = "Smooth Scale"; + public static final String SMOOTH_SCALE_TOOLTIP = "Number of sub-smoothing iterations during scaling back"; + public static final String MIN_TRIANGLE_TWIST_LABEL = "Min Triangle Twist"; + public static final String MIN_TRIANGLE_TWIST_TOOLTIP = "Minimum triangle twist. Set to a positive value for Fluent compatibility"; + public static final String MIN_VOL_RATIO_LABEL = "Min Vol Ratio"; + public static final String MIN_VOL_RATIO_TOOLTIP = "Minimum volume ratio between adjacent cells. Set to a negative value to disable"; + public static final String MIN_FACE_WEIGHT_LABEL = "Min Face Weight"; + public static final String MIN_FACE_WEIGHT_TOOLTIP = "Face based interpolation weight metric. Set to a negative value to disable"; + public static final String MIN_DETERMINANT_LABEL = "Min Determinant"; + public static final String MIN_DETERMINANT_TOOLTIP = "Minimum normalised cell-determinant. Set to a negative value to disable"; + public static final String MIN_TWIST_LABEL = "Min Twist"; + public static final String MIN_TWIST_TOOLTIP = "Minimum face twist. Set to a negative value to disable"; + public static final String MIN_AREA_LABEL = "Min Area"; + public static final String MIN_AREA_TOOLTIP = "Minimum face area. Set to a negative value to disable"; + public static final String MIN_TET_QUALITY_LABEL = "Min Tetrahedral Quality"; + public static final String MIN_TET_QUALITY_TOOLTIP = "Minimum quality of the tetrahedral elements formed by the face-centre and variable base point minimum decomposition triangles and the cell centre. This has to be a positive number for tracking to work. Set to a very large negative number (e.g. -1E30) to disable"; + public static final String MIN_VOL_LABEL = "Min Vol"; + public static final String MIN_VOL_TOOLTIP = "Minimum pyramid volume (absolute). Set to a very large negative number (e.g. -1E30) to disable"; + public static final String MIN_FLATNESS_LABEL = "Min Flatness"; + public static final String MIN_FLATNESS_TOOLTIP = "Ratio of projected area to actual area. Set to a negative value to disable"; + public static final String MAX_CONCAVE_LABEL = "Max Concave"; + public static final String MAX_CONCAVE_TOOLTIP = "Maximum concavity. Set to 180 to disable"; + public static final String MAX_INTERNAL_SKEWNESS_LABEL = "Max Internal Skewness"; + public static final String MAX_INTERNAL_SKEWNESS_TOOLTIP = "Maximum internal skewness. Set to a negative value to disable"; + public static final String MAX_BOUNDARY_SKEWNESS_LABEL = "Max Boundary Skewness"; + public static final String MAX_BOUNDARY_SKEWNESS_TOOLTIP = "Maximum boundary skewness. Set to a negative value to disable"; + public static final String MAX_NON_ORTHO_LABEL = "Max Non Ortho"; + public static final String MAX_NON_ORTHO_TOOLTIP = "Maximum non-orthogonality allowed. Set to 180 to disable"; + + protected DictionaryModel snappyHexMeshModel; + protected DictionaryModel castellatedMeshControlsModel; + protected DictionaryModel snapControlsModel; + protected DictionaryModel layersControlsModel; + protected DictionaryModel meshQualityControlsModel; + private boolean toDefaults = false; + + protected PanelBuilder qualityBuilder; + + public DefaultMeshAdvancedOptionsPanel(Model model) { + super("", model); + } + + @Override + protected JComponent layoutComponents() { + snappyHexMeshModel = new DictionaryModel(new Dictionary("")); + castellatedMeshControlsModel = new DictionaryModel(new Dictionary("")); + snapControlsModel = new DictionaryModel(new Dictionary("")); + layersControlsModel = new DictionaryModel(new Dictionary("")); + meshQualityControlsModel = new DictionaryModel(new Dictionary("")); + + JTabbedPane tabbedPane = new JTabbedPane(); + tabbedPane.setName(NAME); + tabbedPane.add(GENERAL_LABEL, createGeneralPanel()); + tabbedPane.add(CASTELLATED_MESH_CONTROLS_LABEL, createRefinementsPanel()); + tabbedPane.add(SNAP_CONTROLS_LABEL, createSnappingPanel()); + tabbedPane.add(LAYERS_CONTROLS_LABEL, createLayersPanel()); + tabbedPane.add(QUALITY_CONTROLS_LABEL, createQualityPanel()); + + return tabbedPane; + } + + protected abstract JPanel createGeneralPanel(); + + protected abstract JPanel createRefinementsPanel(); + + protected abstract JPanel createSnappingPanel(); + + protected abstract JPanel createLayersPanel(); + + protected JPanel createQualityPanel() { + qualityBuilder = new PanelBuilder("options.quality.panel"); + qualityBuilder.addComponent(MAX_NON_ORTHO_LABEL, meshQualityControlsModel.bindDoubleAngle_180(MAX_NON_ORTHO_KEY), MAX_NON_ORTHO_TOOLTIP); + qualityBuilder.addComponent(MAX_BOUNDARY_SKEWNESS_LABEL, meshQualityControlsModel.bindInteger(MAX_BOUNDARY_SKEWNESS_KEY), MAX_BOUNDARY_SKEWNESS_TOOLTIP); + qualityBuilder.addComponent(MAX_INTERNAL_SKEWNESS_LABEL, meshQualityControlsModel.bindInteger(MAX_INTERNAL_SKEWNESS_KEY), MAX_INTERNAL_SKEWNESS_TOOLTIP); + qualityBuilder.addComponent(MAX_CONCAVE_LABEL, meshQualityControlsModel.bindDoubleAngle_180(MAX_CONCAVE_KEY), MAX_CONCAVE_TOOLTIP); + qualityBuilder.addComponent(MIN_FLATNESS_LABEL, meshQualityControlsModel.bindDouble(MIN_FLATNESS_KEY), MIN_FLATNESS_TOOLTIP); + qualityBuilder.addComponent(MIN_VOL_LABEL, meshQualityControlsModel.bindDouble(MIN_VOL_KEY), MIN_VOL_TOOLTIP); + qualityBuilder.addComponent(MIN_TET_QUALITY_LABEL, meshQualityControlsModel.bindDouble(MIN_TET_QUALITY_KEY), MIN_TET_QUALITY_TOOLTIP); + qualityBuilder.addComponent(MIN_AREA_LABEL, meshQualityControlsModel.bindDouble(MIN_AREA_KEY), MIN_AREA_TOOLTIP); + qualityBuilder.addComponent(MIN_TWIST_LABEL, meshQualityControlsModel.bindDouble(MIN_TWIST_KEY), MIN_TWIST_TOOLTIP); + qualityBuilder.addComponent(MIN_DETERMINANT_LABEL, meshQualityControlsModel.bindDouble(MIN_DETERMINANT_KEY), MIN_DETERMINANT_TOOLTIP); + qualityBuilder.addComponent(MIN_FACE_WEIGHT_LABEL, meshQualityControlsModel.bindDouble(MIN_FACE_WEIGHT_KEY), MIN_FACE_WEIGHT_TOOLTIP); + qualityBuilder.addComponent(MIN_VOL_RATIO_LABEL, meshQualityControlsModel.bindDouble(MIN_VOL_RATIO_KEY), MIN_VOL_RATIO_TOOLTIP); + qualityBuilder.addComponent(MIN_TRIANGLE_TWIST_LABEL, meshQualityControlsModel.bindDouble(MIN_TRIANGLE_TWIST_KEY), MIN_TRIANGLE_TWIST_TOOLTIP); + qualityBuilder.addComponent(SMOOTH_SCALE_LABEL, meshQualityControlsModel.bindIntegerPositive(N_SMOOTH_SCALE_KEY), SMOOTH_SCALE_TOOLTIP); + qualityBuilder.addComponent(ERROR_REDUCTION_LABEL, meshQualityControlsModel.bindDouble(ERROR_REDUCTION_KEY), ERROR_REDUCTION_TOOLTIP); + return qualityBuilder.getPanel(); + } + + @Override + public void resetToDefaults() { + this.toDefaults = true; + load(); + this.toDefaults = false; + } + + // LOAD + + protected SnappyHexMeshDict getSnappyDict() { + SnappyHexMeshDict snappyDict = null; + if (toDefaults) { + snappyDict = model.getDefaults().getDefaultSnappyHexMeshDict(); + } else { + snappyDict = new SnappyHexMeshDict(model.getProject().getSystemFolder().getSnappyHexMeshDict()); + } + return snappyDict; + } + + protected abstract void loadCastellated(SnappyHexMeshDict snappyDict); + + protected void loadLayers(SnappyHexMeshDict snappyDict) { + if (snappyDict.found(ADD_LAYERS_CONTROLS_KEY)) { + Dictionary layersDict = new Dictionary(snappyDict.subDict(ADD_LAYERS_CONTROLS_KEY)); + snappyDict.remove(ADD_LAYERS_CONTROLS_KEY); + this.layersControlsModel.setDictionary(layersDict); + } + } + + protected void loadQuality(SnappyHexMeshDict snappyDict) { + if (snappyDict.found(MESH_QUALITY_CONTROLS_KEY)) { + Dictionary quality = new Dictionary(snappyDict.subDict(MESH_QUALITY_CONTROLS_KEY)); + snappyDict.remove(MESH_QUALITY_CONTROLS_KEY); + this.meshQualityControlsModel.setDictionary(quality); + } + } + + protected void loadSnap(SnappyHexMeshDict snappyDict) { + if (snappyDict.found(SNAP_CONTROLS_KEY)) { + Dictionary snap = new Dictionary(snappyDict.subDict(SNAP_CONTROLS_KEY)); + snappyDict.remove(SNAP_CONTROLS_KEY); + this.snapControlsModel.setDictionary(snap); + } + } + + // SAVE + + @Override + public void save() { + SnappyHexMeshDict snappyHexMeshDict = model.getProject().getSystemFolder().getSnappyHexMeshDict(); + + saveMisc(snappyHexMeshDict); + saveCastellatedSubDict(snappyHexMeshDict); + saveSnapControlsDict(snappyHexMeshDict); + saveLayersControlsDict(snappyHexMeshDict); + saveMeshQualityControlsDict(snappyHexMeshDict); + saveRepatchDict(snappyHexMeshDict); + + model.getProject().getSystemFolder().setSnappyHexMeshDict(snappyHexMeshDict); + } + + private void saveMisc(SnappyHexMeshDict snappyDict) { + snappyDict.merge(snappyHexMeshModel.getDictionary()); + } + + private void saveCastellatedSubDict(SnappyHexMeshDict snappyDict) { + Dictionary castellated = snappyDict.subDict(CASTELLATED_MESH_CONTROLS_KEY); + castellated.merge(castellatedMeshControlsModel.getDictionary()); + saveWrapperDict(snappyDict, castellated); + } + + private void saveSnapControlsDict(SnappyHexMeshDict snappyDict) { + Dictionary snap = snappyDict.subDict(SNAP_CONTROLS_KEY); + snap.merge(snapControlsModel.getDictionary()); + } + + private void saveLayersControlsDict(SnappyHexMeshDict snappyDict) { + Dictionary snap = snappyDict.subDict(ADD_LAYERS_CONTROLS_KEY); + snap.merge(layersControlsModel.getDictionary()); + } + + private void saveMeshQualityControlsDict(SnappyHexMeshDict snappyDict) { + Dictionary snap = snappyDict.subDict(MESH_QUALITY_CONTROLS_KEY); + snap.merge(meshQualityControlsModel.getDictionary()); + } + + protected void saveWrapperDict(SnappyHexMeshDict snappyDict, Dictionary castellated) { + } + + protected void saveRepatchDict(SnappyHexMeshDict snappyDict) { + } + + public void handleClose() { + } + +} diff --git a/src/eu/engys/gui/mesh/panels/FeatureLinesPanel.java b/src/eu/engys/gui/mesh/panels/FeatureLinesPanel.java new file mode 100644 index 0000000..9fe4d6e --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/FeatureLinesPanel.java @@ -0,0 +1,213 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import net.java.dev.designgridlayout.Componentizer; + +import com.google.inject.Inject; + +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.RenameSurfaceEvent; +import eu.engys.gui.mesh.panels.lines.ColorFeatureLineAction; +import eu.engys.gui.mesh.panels.lines.FeatureLinesRefinementTable; +import eu.engys.gui.mesh.panels.lines.ImportFeatureLineAction; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.Util; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.StringField; + +public class FeatureLinesPanel extends AbstractGUIPanel { + + public static final String LINES = "Lines"; + public static final String COLOR_LABEL = "Color"; + public static final String NAME_LABEL = "Name"; + public static final String REFINE_ONLY_LABEL = "Refine Only"; + public static final String REFINEMENTS_LABEL = "Refinements"; + public static final String REMOVE_LABEL = "Remove"; + + private PanelBuilder builder; + private StringField nameField; + private JCheckBox refineOnly; + private JButton colorButton; + private FeatureLine selectedLine; + private ColorFeatureLineAction colorLineAction; + private FeatureLinesRefinementTable refinementLevels; + private FeatureLinesTreeNodeManager treeNodeManager; + + private PropertyChangeListener renameAction; + + @Inject + public FeatureLinesPanel(Model model) { + super(LINES, model); + this.treeNodeManager = new FeatureLinesTreeNodeManager(model, this); + model.addObserver(treeNodeManager); + } + + @Override + protected JComponent layoutComponents() { + PanelBuilder builder = new PanelBuilder(); + builder.addRight(getButtons()); + builder.addComponent(createFeatureLinesPanel()); + + return builder.removeMargins().getPanel(); + } + + private JPanel createFeatureLinesPanel() { + renameAction = new PropertyChangeListener() { + @Override + public void propertyChange(java.beans.PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value") && evt.getSource() instanceof StringField) { + StringField field = (StringField) evt.getSource(); + renameSurface(field.getText()); + } + } + }; + nameField = ComponentsFactory.stringField(); + nameField.addPropertyChangeListener(renameAction); + + refineOnly = ComponentsFactory.checkField(); + + builder = new PanelBuilder(); + builder.addComponent(NAME_LABEL, nameField); + builder.addComponent(COLOR_LABEL, Componentizer.create().fixedPref(colorButton = new JButton(colorLineAction = new ColorFeatureLineAction(this))).component()); + if (hasRefineOnly()) { + builder.addComponent(REFINE_ONLY_LABEL, refineOnly); + } + builder.addComponent(REFINEMENTS_LABEL, refinementLevels = new FeatureLinesRefinementTable(model, null)); + builder.setEnabled(false); + + return builder.getPanel(); + } + + @Override + public void load() { + } + + @Override + public void save() { + super.save(); + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) treeNodeManager.getSelectedValues()); + } + + private void renameSurface(String newName) { + if (selectedLine != null) { + if (model.getGeometry().contains(newName)) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Name already in use", "Name Error", JOptionPane.ERROR_MESSAGE); + return; + } + + String oldPatchName = selectedLine.getName(); + selectedLine.rename(newName); + + treeNodeManager.refreshNode(selectedLine); + + EventManager.triggerEvent(this, new RenameSurfaceEvent(selectedLine, oldPatchName, selectedLine.getPatchName())); + } + } + + private JButton[] getButtons() { + final JButton fromFile = new JButton(new ImportFeatureLineAction(model)); + fromFile.setName(ImportFeatureLineAction.FROM_FILE_LABEL); + List buttons = new ArrayList<>(); + buttons.add(fromFile); + return buttons.toArray(new JButton[0]); + } + + public void selectLine(FeatureLine[] currentSelection) { + if (Util.isVarArgsNotNull(currentSelection)) { + StringBuilder sb = new StringBuilder(); + for (FeatureLine line : currentSelection) { + sb.append(line.getName()); + sb.append(" "); + } + nameField.setText(sb.toString()); + if (currentSelection.length == 1) { + builder.setEnabled(true); + this.selectedLine = currentSelection[0]; + + refineOnly.setSelected(selectedLine.isRefineOnly()); + + refinementLevels.setRefinements(selectedLine.getRefinements()); + refinementLevels.load(); + + colorLineAction.setCurrentColor(selectedLine.getColor()); + colorButton.setBackground(selectedLine.getColor()); + } else { + builder.setEnabled(false); + } + } else { + deselectAll(); + } + + } + + public void saveLine(FeatureLine[] currentSelection) { + if (currentSelection != null && currentSelection.length == 1) { + FeatureLine line = currentSelection[0]; + line.setRefineOnly(refineOnly.isSelected()); + line.setRefinements(refinementLevels.getRefinements()); + } + } + + public FeatureLine getSelectedLine() { + return selectedLine; + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + + public void deselectAll() { + nameField.setText(""); + builder.setEnabled(false); + } + + @Override + public void clear() { + treeNodeManager.getSelectionHandler().handleSelection(false, (Object[]) new FeatureLine[0]); + } + + protected boolean hasRefineOnly() { + return true; + } + +} diff --git a/src/eu/engys/gui/mesh/panels/FeatureLinesTreeNodeManager.java b/src/eu/engys/gui/mesh/panels/FeatureLinesTreeNodeManager.java new file mode 100644 index 0000000..e8b8acd --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/FeatureLinesTreeNodeManager.java @@ -0,0 +1,365 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/*--------------------------------*- Java -*---------------------------------*\ + |o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2013 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + |License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ +package eu.engys.gui.mesh.panels; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JPopupMenu; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreePath; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.core.project.geometry.Geometry; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.RemoveSurfaceEvent; +import eu.engys.gui.events.view3D.SelectSurfaceEvent; +import eu.engys.gui.tree.AbstractSelectionHandler; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.SelectionHandler; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.Util; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.checkboxtree.RootVisibleItem; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class FeatureLinesTreeNodeManager extends DefaultTreeNodeManager { + + private static final Logger logger = LoggerFactory.getLogger(FeatureLinesTreeNodeManager.class); + + private final Action removeAction = new RemoveAction(); + + private Map linesMap; + private FeatureLinesSelectionHandler selectionHandler; + + public FeatureLinesTreeNodeManager(Model model, FeatureLinesPanel panel) { + super(model, panel); + this.root = new DefaultMutableTreeNode(new RootVisibleItem(panel.getTitle())); + this.selectionHandler = new FeatureLinesSelectionHandler(panel); + this.linesMap = new HashMap<>(); + } + + @Override + public void update(Observable o, final Object arg) { + if (arg instanceof FeatureLine) { + logger.debug("Observerd a change: arg is " + arg.getClass()); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + loadTree(); + expandTree(arg); + } + }); + } else if (arg instanceof Geometry) { + logger.debug("Observerd a change: arg is Geometry"); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + selectionHandler.disable(); + loadTree(); + makeVisibleItemsChecked(); + expandTree(arg); + selectionHandler.enable(); + } + }); + } else if (arg instanceof Patches) { + logger.debug("Observerd a change: arg is Patches"); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + makeVisibleItemsChecked(); + } + }); + } + } + + private void loadTree() { + logger.debug("Load 'Geometry' tree"); + clear(); + for (FeatureLine line : model.getGeometry().getLines()) { + addLine(root, line); + } + treeChanged(root); + } + + private void addLine(DefaultMutableTreeNode parent, FeatureLine line) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(line); + parent.add(node); + nodeMap.put(line, node); + linesMap.put(node, line); + } + + private void makeVisibleItemsChecked() { + logger.debug("Make visible items checked"); + if (getTree() != null) { + if (model.getPatches() == null || model.getPatches().isEmpty()) + getTree().getCheckManager().selectNode(getRoot()); + else + getTree().getCheckManager().deselectNode(getRoot()); + } + } + + private void expandTree(final Object arg) { + if (getTree() != null) { + if (shouldExpand(arg)) { + logger.debug("Expand the tree"); + getTree().expandNode(getRoot()); + if (arg instanceof Surface) { + Surface surface = (Surface) arg; + setSelectedValue(surface); + } + } + } + } + + private boolean shouldExpand(final Object arg) { + return arg instanceof FeatureLine || arg instanceof Geometry; + } + + private void setSelectedValue(Surface surface) { + DefaultMutableTreeNode selectedNode = nodeMap.get(surface); + if (getTree() != null) { + if (surface.getPatchName() != null) { + getTree().setSelectedNode(selectedNode); + } + } + } + + public FeatureLine[] getSelectedValues() { + if (getTree() != null) { + TreePath[] selectionPaths = getTree().getSelectionPaths(); + if (selectionPaths != null) { + FeatureLine[] surfaces = new FeatureLine[selectionPaths.length]; + for (int i = 0; i < selectionPaths.length; i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPaths[i].getLastPathComponent(); + FeatureLine line = linesMap.get(node); + surfaces[i] = line; + } + return surfaces; + } + } + return new FeatureLine[0]; + } + + public void clear() { + // clear node before selection handler! + clearNode(root); + selectionHandler.clear(); + nodeMap.clear(); + linesMap.clear(); + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public Class getRendererClass() { + return FeatureLine.class; + } + + @Override + public DefaultTreeCellRenderer getRenderer() { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object userObject = node.getUserObject(); + + if (userObject instanceof Surface) { + Surface surface = (Surface) userObject; + setText(surface.getName()); + } + setIcon(null); + return this; + } + }; + } + + @Override + public SelectionHandler getSelectionHandler() { + return selectionHandler; + } + + @Override + public PopUpBuilder getPopUpBuilder() { + return new PopUpBuilder() { + @Override + public void populate(JPopupMenu popUp) { + popUp.add(removeAction); + } + }; + } + + private void updateActions() { + Surface[] surfaces = selectionHandler.currentSelection; + if (Util.isVarArgsNotNull(surfaces)) { + Type type = surfaces[0].getType(); + removeAction.setEnabled(type != Type.SOLID); + } + } + + private final class RemoveAction extends AbstractAction { + public RemoveAction() { + super("Remove"); + } + + @Override + public void actionPerformed(ActionEvent e) { + FeatureLine[] surfaces = getSelectedValues(); + + model.getGeometry().removeLines(surfaces); + model.geometryChanged(); + + EventManager.triggerEvent(this, new RemoveSurfaceEvent(surfaces)); + } + } + + public final class FeatureLinesSelectionHandler extends AbstractSelectionHandler { + + private final FeatureLinesPanel panel; + private FeatureLine[] currentSelection; + + public FeatureLinesSelectionHandler(FeatureLinesPanel panel) { + this.panel = panel; + } + + @Override + public void handleSelection(boolean fire3DEvent, Object... selection) { + saveCurrentSelection(); + + boolean isValidSelection = TreeUtil.isConsistent(selection, FeatureLine.class); + if (isValidSelection) { + handleValidSelection(fire3DEvent, selection); + } else { + boolean shouldClearSelection = TreeUtil.isConsistent(currentSelection, FeatureLine.class); + if (shouldClearSelection) { + clearSelection(fire3DEvent); + } + } + + } + + private void saveCurrentSelection() { + if (Util.isVarArgsNotNull(currentSelection)) { + panel.saveLine(currentSelection); + } + } + + private void handleValidSelection(boolean fire3DEvent, Object... selection) { + logger.debug("handleSelection: {} selected, fire3D {} {}", selection.length, fire3DEvent, selection.length == 1 ? ", selection is: " + selection[0] : ""); + + this.currentSelection = Arrays.copyOf(selection, selection.length, FeatureLine[].class); + panel.selectLine(currentSelection); + + if (fire3DEvent) { + EventManager.triggerEvent(this, new SelectSurfaceEvent(currentSelection)); + } + + updateActions(); + } + + private void clearSelection(boolean fire3DEvent) { + clear(); + panel.deselectAll(); + if (fire3DEvent) { + EventManager.triggerEvent(this, new SelectSurfaceEvent(new FeatureLine[0])); + } + } + + @Override + public void handleVisibility(VisibleItem item) { + logger.debug("handleVisibility: {}", item); + if (Util.isVarArgsNotNull(currentSelection) && Arrays.asList(currentSelection).contains(item)) { + panel.selectLine(currentSelection); + EventManager.triggerEvent(this, new SelectSurfaceEvent(currentSelection)); + } + } + + @Override + public void process3DSelectionEvent(Picker picker, Actor actor, boolean keep) { + } + + @Override + public void process3DVisibilityEvent(boolean selected) { + logger.debug("handle selection from check box"); + if (getTree() != null) { + if (selected) { + // getTree().getCheckManager().selectNode(getRoot()); + } else { + getTree().getCheckManager().deselectNode(getRoot()); + } + } + } + + public void clear() { + currentSelection = null; + } + } + +} diff --git a/src/eu/engys/gui/mesh/panels/GeometriesPanelBuilder.java b/src/eu/engys/gui/mesh/panels/GeometriesPanelBuilder.java new file mode 100644 index 0000000..27926c7 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/GeometriesPanelBuilder.java @@ -0,0 +1,517 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +import net.java.dev.designgridlayout.RowGroup; +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldChangeListener; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; +import eu.engys.core.project.geometry.surface.PlaneRegion; +import eu.engys.gui.mesh.GeometryPanel; +import eu.engys.gui.view3D.BoxEventButton; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.StringField; + +public class GeometriesPanelBuilder { + + public static final String BOX_NAME_LABEL = "Box Name"; + public static final String SPHERE_NAME_LABEL = "Sphere Name"; + public static final String CYLINDER_NAME_LABEL = "Cylinder Name"; + public static final String PLANE_NAME_LABEL = "Plane Name"; + public static final String RING_NAME_LABEL = "Ring Name"; + public static final String SURFACE_NAME_LABEL = "Surface Name"; + + public static final String OUTER_RADIUS_LABEL = "Outer Radius"; + public static final String INNER_RADIUS_LABEL = "Inner Radius"; + public static final String PATCH_NAME_LABEL = "Patch Name"; + public static final String NORMAL_LABEL = "Normal"; + public static final String ORIGIN_LABEL = "Origin"; + public static final String POINT_1_LABEL = "Point 1"; + public static final String POINT_2_LABEL = "Point 2"; + public static final String MIN_LABEL = "Min"; + public static final String MAX_LABEL = "Max"; + public static final String RADIUS_LABEL = "Radius"; + public static final String CENTRE_LABEL = "Centre"; + public static final int DECIMAL_PLACES = 4; + + private StringField stlNameField; + private StringField boxNameField; + private StringField cylinderNameField; + private StringField sphereNameField; + private StringField ringNameField; + private StringField planeNameField; + private StringField regionNameField; + + private DictionaryModel boxModel; + private DictionaryModel cylinderModel; + private DictionaryModel sphereModel; + private DictionaryModel ringModel; + private DictionaryModel planeModel; + private DictionaryModel planePointAndNormalModel; + + private PanelBuilder boxBuilder; + private PanelBuilder cylinderBuilder; + private PanelBuilder sphereBuilder; + private PanelBuilder ringBuilder; + private PanelBuilder planeBuilder; + private PanelBuilder regionBuilder; + private DictionaryModel stlModel; + PanelBuilder stlBuilder; + + private RowGroup boxGroup; + private RowGroup sphereGroup; + private RowGroup ringGroup; + private RowGroup planeGroup; + private RowGroup cylinderGroup; + private RowGroup stlGroup; + private RowGroup regionGroup; + private RowGroup noneGroup; + + private GeometryPanel meshPanel; + + private RowGroup selected; + Surface selectedSurface; + private PropertyChangeListener renameAction; + + private BoxEventButton showBoxButton; + + public GeometriesPanelBuilder(GeometryPanel panel) { + super(); + this.meshPanel = panel; + } + + public void addComponents(PanelBuilder builder) { + FieldChangeListener listener = new FieldChangeListener() { + + boolean adjusting = false; + + @Override + public void actionPerformed(ActionEvent e) { + } + + @Override + public void setAdjusting(boolean b) { + this.adjusting = b; + } + + @Override + public boolean isAdjusting() { + return adjusting; + } + + @Override + public void fieldChanged() { + if (!isAdjusting() && selectedSurface != null) { + meshPanel.changeSurface(selectedSurface); + } + } + }; + + addSTLComponent(builder, listener); + addBoxComponent(builder, listener); + addCylinderComponent(builder, listener); + addPlaneComponent(builder, listener); + addSphereComponent(builder, listener); + addRingComponent(builder, listener); + addNoneComponent(builder, listener); + + renameAction = new PropertyChangeListener() { + @Override + public void propertyChange(java.beans.PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value") && evt.getSource() instanceof StringField) { + StringField field = (StringField) evt.getSource(); + meshPanel.renameSurface(field.getText()); + } + } + }; + addRenameAction(); + + selected = noneGroup; + } + + private void addSTLComponent(PanelBuilder builder, FieldChangeListener listener) { + stlModel = new DictionaryModel(new Dictionary("")); + + stlBuilder = new PanelBuilder(); + stlBuilder.addComponent(SURFACE_NAME_LABEL, stlNameField = stringField()); + stlBuilder.getPanel().setBorder(BorderFactory.createTitledBorder("")); + + stlGroup = new RowGroup(); + builder.addComponentToGroup(stlGroup, stlBuilder.getPanel()); + stlGroup.hide(); + } + + private void addBoxComponent(PanelBuilder builder, FieldChangeListener listener) { + boxModel = new DictionaryModel(new Dictionary("")); + + DoubleField[] boxMin = boxModel.bindPoint(Surface.MIN_KEY, DECIMAL_PLACES, listener); + DoubleField[] boxMax = boxModel.bindPoint(Surface.MAX_KEY, DECIMAL_PLACES, listener); + showBoxButton = new BoxEventButton(boxMin, boxMax); + + boxBuilder = new PanelBuilder(); + boxBuilder.addComponent(BOX_NAME_LABEL, boxNameField = stringField()); + // boxBuilder.addComponent("", labelField("X"), labelField("Y"), labelField("Z")); + boxBuilder.addComponent(MIN_LABEL, boxMin[0], boxMin[1], boxMin[2], showBoxButton); + boxBuilder.addComponentAndSpan(MAX_LABEL, boxMax); + boxBuilder.getPanel().setBorder(BorderFactory.createTitledBorder("")); + + boxGroup = new RowGroup(); + builder.addComponentToGroup(boxGroup, boxBuilder.getPanel()); + boxGroup.hide(); + } + + private void addCylinderComponent(PanelBuilder builder, FieldChangeListener listener) { + cylinderModel = new DictionaryModel(new Dictionary("")); + + cylinderBuilder = new PanelBuilder(); + cylinderBuilder.addComponent(CYLINDER_NAME_LABEL, cylinderNameField = stringField()); + cylinderBuilder.addComponent(POINT_1_LABEL, cylinderModel.bindPoint(Surface.POINT1_KEY, DECIMAL_PLACES, listener)); + cylinderBuilder.addComponent(POINT_2_LABEL, cylinderModel.bindPoint(Surface.POINT2_KEY, DECIMAL_PLACES, listener)); + cylinderBuilder.addComponent(RADIUS_LABEL, cylinderModel.bindDouble(Surface.RADIUS_KEY, DECIMAL_PLACES, listener)); + cylinderBuilder.getPanel().setBorder(BorderFactory.createTitledBorder("")); + + cylinderGroup = new RowGroup(); + builder.addComponentToGroup(cylinderGroup, cylinderBuilder.getPanel()); + cylinderGroup.hide(); + } + + private void addPlaneComponent(PanelBuilder builder, FieldChangeListener listener) { + planeModel = new DictionaryModel(new Dictionary("")); + planePointAndNormalModel = new DictionaryModel(new Dictionary("")); + + planeBuilder = new PanelBuilder(); + planeBuilder.addComponent(PLANE_NAME_LABEL, planeNameField = stringField()); + planeBuilder.addComponent(ORIGIN_LABEL, planePointAndNormalModel.bindPoint(Surface.BASE_POINT_KEY, DECIMAL_PLACES, listener)); + planeBuilder.addComponent(NORMAL_LABEL, planePointAndNormalModel.bindPoint(Surface.NORMAL_VECTOR_KEY, DECIMAL_PLACES, listener)); + planeBuilder.getPanel().setBorder(BorderFactory.createTitledBorder("")); + + regionBuilder = new PanelBuilder(); + regionBuilder.addComponent(PATCH_NAME_LABEL, regionNameField = stringField()); + regionBuilder.getPanel().setBorder(BorderFactory.createTitledBorder("")); + + planeGroup = new RowGroup(); + builder.addComponentToGroup(planeGroup, planeBuilder.getPanel()); + planeGroup.hide(); + + regionGroup = new RowGroup(); + builder.addComponentToGroup(regionGroup, regionBuilder.getPanel()); + regionGroup.hide(); + } + + private void addSphereComponent(PanelBuilder builder, FieldChangeListener listener) { + sphereModel = new DictionaryModel(new Dictionary("")); + + sphereBuilder = new PanelBuilder(); + sphereBuilder.addComponent(SPHERE_NAME_LABEL, sphereNameField = stringField()); + sphereBuilder.addComponent(CENTRE_LABEL, sphereModel.bindPoint(Surface.CENTRE_KEY, DECIMAL_PLACES, listener)); + sphereBuilder.addComponent(RADIUS_LABEL, sphereModel.bindDouble(Surface.RADIUS_KEY, DECIMAL_PLACES, listener)); + sphereBuilder.getPanel().setBorder(BorderFactory.createTitledBorder("")); + + sphereGroup = new RowGroup(); + builder.addComponentToGroup(sphereGroup, sphereBuilder.getPanel()); + sphereGroup.hide(); + } + + private void addRingComponent(PanelBuilder builder, FieldChangeListener listener) { + ringModel = new DictionaryModel(new Dictionary("")); + + ringBuilder = new PanelBuilder(); + ringBuilder.addComponent(RING_NAME_LABEL, ringNameField = stringField()); + ringBuilder.addComponent(POINT_1_LABEL, ringModel.bindPoint(Surface.POINT1_KEY, DECIMAL_PLACES, listener)); + ringBuilder.addComponent(POINT_2_LABEL, ringModel.bindPoint(Surface.POINT2_KEY, DECIMAL_PLACES, listener)); + ringBuilder.addComponent(INNER_RADIUS_LABEL, ringModel.bindDouble(Surface.INNER_RADIUS_KEY, DECIMAL_PLACES, listener)); + ringBuilder.addComponent(OUTER_RADIUS_LABEL, ringModel.bindDouble(Surface.OUTER_RADIUS_KEY, DECIMAL_PLACES, listener)); + ringBuilder.getPanel().setBorder(BorderFactory.createTitledBorder("")); + + ringGroup = new RowGroup(); + builder.addComponentToGroup(ringGroup, ringBuilder.getPanel()); + ringGroup.hide(); + } + + private void addNoneComponent(PanelBuilder builder, FieldChangeListener listener) { + noneGroup = new RowGroup(); + builder.addComponentToGroup(noneGroup, new JLabel("Select or Add a geometry")); + noneGroup.show(); + } + + void addRenameAction() { + stlNameField.addPropertyChangeListener(renameAction); + boxNameField.addPropertyChangeListener(renameAction); + cylinderNameField.addPropertyChangeListener(renameAction); + sphereNameField.addPropertyChangeListener(renameAction); + ringNameField.addPropertyChangeListener(renameAction); + planeNameField.addPropertyChangeListener(renameAction); + regionNameField.addPropertyChangeListener(renameAction); + } + + void remRenameAction() { + stlNameField.removePropertyChangeListener(renameAction); + boxNameField.removePropertyChangeListener(renameAction); + cylinderNameField.removePropertyChangeListener(renameAction); + sphereNameField.removePropertyChangeListener(renameAction); + ringNameField.removePropertyChangeListener(renameAction); + planeNameField.removePropertyChangeListener(renameAction); + regionNameField.removePropertyChangeListener(renameAction); + } + + private void showSTL() { + hideSelectedInEDT(); + showInEDT(stlGroup); + } + + private void showBox() { + hideSelectedInEDT(); + showInEDT(boxGroup); + } + + private void showCylinder() { + hideSelectedInEDT(); + showInEDT(cylinderGroup); + } + + private void showSphere() { + hideSelectedInEDT(); + showInEDT(sphereGroup); + } + + private void showRing() { + hideSelectedInEDT(); + showInEDT(ringGroup); + } + + private void showPlane() { + hideSelectedInEDT(); + showInEDT(planeGroup); + } + + private void showRegion() { + hideSelectedInEDT(); + showInEDT(regionGroup); + } + + private void showNone() { + hideSelectedInEDT(); + showInEDT(noneGroup); + } + + private void showInEDT(final RowGroup group) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + group.show(); + selected = group; + } + }); + } + + private void hideSelectedInEDT() { + if (selected != null) + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + selected.hide(); + } + }); + } + + public void showPanel(Surface[] surfaces) { + stop(); + if (surfaces == null || surfaces.length == 0) { + showNone(); + selectedSurface = null; + return; + } + boolean singleSelection = surfaces.length == 1; + + Type type = surfaces[0].getType(); + String name; + boolean visible = true; + if (singleSelection) { + name = surfaces[0].getName(); + visible = surfaces[0].isVisible(); + } else { + StringBuilder sb = new StringBuilder(); + for (Surface surface : surfaces) { + sb.append(surface.getName()); + sb.append(" "); + visible = visible && surface.isVisible(); + } + name = sb.toString(); + } + + selectedSurface = surfaces[0]; + + Dictionary dict = surfaces[0].getGeometryDictionary(); + switch (type) { + case BOX: + showBox(); + boxModel.setDictionary(dict); + updatePanel(singleSelection, visible, name, boxNameField, boxBuilder); + break; + + case CYLINDER: + showCylinder(); + cylinderModel.setDictionary(dict); + updatePanel(singleSelection, visible, name, cylinderNameField, cylinderBuilder); + break; + + case SPHERE: + showSphere(); + sphereModel.setDictionary(dict); + updatePanel(singleSelection, visible, name, sphereNameField, sphereBuilder); + break; + case RING: + showRing(); + ringModel.setDictionary(dict); + updatePanel(singleSelection, visible, name, ringNameField, ringBuilder); + break; + + case STL: + showSTL(); + stlModel.setDictionary(dict); + updatePanel(singleSelection, visible, name, stlNameField, stlBuilder); + break; + + case PLANE: + showPlane(); + planePointAndNormalModel.setDictionary(dict.subDict("pointAndNormalDict")); + Dictionary copyDict = new Dictionary(dict); + copyDict.remove("pointAndNormalDict"); + planeModel.setDictionary(copyDict); + updatePanel(singleSelection, visible, name, planeNameField, planeBuilder); + break; + + case SOLID: + case REGION: + showRegion(); + updatePanel(singleSelection, visible, name, regionNameField, regionBuilder); + regionNameField.setEnabled(singleSelection && selectedSurface instanceof PlaneRegion); + break; + + case MULTI: + case LINE: + break; + } + } + + private void updatePanel(boolean singleSelection, boolean visible, String name, StringField nameField, PanelBuilder builder) { + remRenameAction(); + nameField.setValue(name); + if (visible) { + builder.setEnabled(true); + if (singleSelection) { + nameField.setEnabled(true); + builder.setEnabled(true); + } else { + nameField.setEnabled(false); + builder.setEnabled(false); + } + } else { + builder.setEnabled(false); + } + addRenameAction(); + } + + public Dictionary getBoxDictionary() { + Dictionary dict = boxModel.getDictionary(); + if (boxNameField.isEnabled()) { + String name = boxNameField.getText(); + dict.setName(name); + } + + return dict; + } + + public Dictionary getCylinderDictionary() { + Dictionary dict = cylinderModel.getDictionary(); + if (cylinderNameField.isEnabled()) { + String name = cylinderNameField.getText(); + dict.setName(name); + } + + return dict; + } + + public Dictionary getSphereDictionary() { + Dictionary dict = sphereModel.getDictionary(); + if (sphereNameField.isEnabled()) { + String name = sphereNameField.getText(); + dict.setName(name); + } + + return dict; + } + + public Dictionary getRingDictionary() { + Dictionary dict = ringModel.getDictionary(); + if (ringNameField.isEnabled()) { + String name = ringNameField.getText(); + dict.setName(name); + } + + return dict; + } + + public Dictionary getPlaneDictionary() { + Dictionary dict = planeModel.getDictionary(); + Dictionary subDict = planePointAndNormalModel.getDictionary(); + if (planeNameField.isEnabled()) { + String name = planeNameField.getText(); + dict.setName(name); + } + dict.add(subDict); + return dict; + } + + public Dictionary getSTLDictionary() { + Dictionary dict = stlModel.getDictionary(); + if (stlNameField.isEnabled()) + dict.add("name", stlNameField.getText()); + return dict; + } + + public String getRegionName() { + return regionNameField.getText(); + } + + public void stop() { + if (showBoxButton.isSelected()) { + showBoxButton.doClick(); + } + } +} diff --git a/src/eu/engys/gui/mesh/panels/GeometryBuilder.java b/src/eu/engys/gui/mesh/panels/GeometryBuilder.java new file mode 100644 index 0000000..071ca06 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/GeometryBuilder.java @@ -0,0 +1,182 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh.panels; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; +import eu.engys.util.Util; +import eu.engys.util.ui.TreeUtil; + +public class GeometryBuilder { + + private static final Logger logger = LoggerFactory.getLogger(GeometryBuilder.class); + + private GeometriesPanelBuilder geometriesPanel; + private DictionaryModel surfaceModel; + private DictionaryModel volumeModel; + private DictionaryModel layerModel; + private DictionaryModel zoneModel; + private boolean changeSurface; + private boolean changeVolume; + private boolean changeLayer; + private boolean changeZone; + + public GeometryBuilder(GeometriesPanelBuilder geometriesPanel, DictionaryModel surfaceModel, DictionaryModel volumeModel, DictionaryModel layerModel, DictionaryModel zoneModel) { + this.geometriesPanel = geometriesPanel; + this.surfaceModel = surfaceModel; + this.volumeModel = volumeModel; + this.layerModel = layerModel; + this.zoneModel = zoneModel; + } + + public void buildSurfaces(Surface... surfaces) { + if (Util.isVarArgsNotNull(surfaces)) { + Type type = surfaces[0].getType(); + Class typeClass = surfaces[0].getClass(); + + if (TreeUtil.isConsistent(surfaces, typeClass)) { + _buildSurfaces(type, surfaces); + } else { + logger.warn("Inconsistent selection"); + } + } + } + + private void _buildSurfaces(Type type, Surface... surfaces) { + changeSurface = !surfaces[0].getSurfaceDictionary().equals(surfaceModel.getDictionary()); + changeVolume = !surfaces[0].getVolumeDictionary().equals(volumeModel.getDictionary()); + changeLayer = !surfaces[0].getLayerDictionary().equals(layerModel.getDictionary()); + changeZone = !surfaces[0].getZoneDictionary().equals(zoneModel.getDictionary()); + + switch (type) { + case BOX: + buildBox(surfaces); + break; + case CYLINDER: + buildCylinder(surfaces); + break; + case SPHERE: + buildSphere(surfaces); + break; + case RING: + buildRing(surfaces); + break; + case PLANE: + buildPlane(surfaces); + break; + case STL: + buildSTL(surfaces); + break; + case REGION: + case SOLID: + buildRegion(surfaces); + break; + + default: + break; + } + } + + private void buildSTL(Surface... surfaces) { + for (Surface surface : surfaces) { + if (surfaces.length == 1) + surface.buildGeometryDictionary(geometriesPanel.getSTLDictionary()); + if (changeSurface) surface.buildSurfaceDictionary(surfaceModel.getDictionary()); + if (changeVolume) surface.buildVolumeDictionary(volumeModel.getDictionary()); + if (changeLayer) surface.buildLayerDictionary(layerModel.getDictionary()); + if (changeZone) surface.buildZoneDictionary(zoneModel.getDictionary()); + } + } + + private void buildRegion(Surface... surfaces) { + for (Surface surface : surfaces) { + if (changeSurface) surface.buildSurfaceDictionary(surfaceModel.getDictionary()); + if (changeVolume) surface.buildVolumeDictionary(volumeModel.getDictionary()); + if (changeLayer) surface.buildLayerDictionary(layerModel.getDictionary()); +// if (changeZone) surface.buildZoneDictionary(zoneModel.getDictionary()); + } + } + + private void buildBox(Surface... surfaces) { + for (Surface surface : surfaces) { + if (surfaces.length == 1) + surface.buildGeometryDictionary(geometriesPanel.getBoxDictionary()); + if (changeSurface) surface.buildSurfaceDictionary(surfaceModel.getDictionary()); + if (changeVolume) surface.buildVolumeDictionary(volumeModel.getDictionary()); + if (changeLayer) surface.buildLayerDictionary(layerModel.getDictionary()); + if (changeZone) surface.buildZoneDictionary(zoneModel.getDictionary()); + } + } + + private void buildCylinder(Surface... surfaces) { + for (Surface surface : surfaces) { + if (surfaces.length == 1) + surface.buildGeometryDictionary(geometriesPanel.getCylinderDictionary()); + if (changeSurface) surface.buildSurfaceDictionary(surfaceModel.getDictionary()); + if (changeVolume) surface.buildVolumeDictionary(volumeModel.getDictionary()); + if (changeLayer) surface.buildLayerDictionary(layerModel.getDictionary()); + if (changeZone) surface.buildZoneDictionary(zoneModel.getDictionary()); + } + } + + private void buildSphere(Surface... surfaces) { + for (Surface surface : surfaces) { + if (surfaces.length == 1) + surface.buildGeometryDictionary(geometriesPanel.getSphereDictionary()); + if (changeSurface) surface.buildSurfaceDictionary(surfaceModel.getDictionary()); + if (changeVolume) surface.buildVolumeDictionary(volumeModel.getDictionary()); + if (changeLayer) surface.buildLayerDictionary(layerModel.getDictionary()); + if (changeZone) surface.buildZoneDictionary(zoneModel.getDictionary()); + } + } + + private void buildRing(Surface... surfaces) { + for (Surface surface : surfaces) { + if (surfaces.length == 1) + surface.buildGeometryDictionary(geometriesPanel.getRingDictionary()); + if (changeSurface) surface.buildSurfaceDictionary(surfaceModel.getDictionary()); + if (changeVolume) surface.buildVolumeDictionary(volumeModel.getDictionary()); + if (changeLayer) surface.buildLayerDictionary(layerModel.getDictionary()); + if (changeZone) surface.buildZoneDictionary(zoneModel.getDictionary()); + } + } + + private void buildPlane(Surface... surfaces) { + for (Surface surface : surfaces) { + if (surfaces.length == 1) + surface.buildGeometryDictionary(geometriesPanel.getPlaneDictionary()); + if (changeSurface) surface.buildSurfaceDictionary(surfaceModel.getDictionary()); + if (changeVolume) surface.buildVolumeDictionary(volumeModel.getDictionary()); + if (changeLayer) surface.buildLayerDictionary(layerModel.getDictionary()); + if (changeZone) surface.buildZoneDictionary(zoneModel.getDictionary()); + } + } +} diff --git a/src/eu/engys/gui/mesh/panels/GeometryTreeNodeManager.java b/src/eu/engys/gui/mesh/panels/GeometryTreeNodeManager.java new file mode 100644 index 0000000..ab835f0 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/GeometryTreeNodeManager.java @@ -0,0 +1,353 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import java.awt.Component; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreePath; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.core.project.geometry.Geometry; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.BaseSurface; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.SelectSurfaceEvent; +import eu.engys.gui.tree.AbstractSelectionHandler; +import eu.engys.gui.tree.DefaultTreeNodeManager; +import eu.engys.gui.tree.SelectionHandler; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.Util; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.checkboxtree.RootVisibleItem; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class GeometryTreeNodeManager extends DefaultTreeNodeManager { + + private static final Logger logger = LoggerFactory.getLogger(GeometryTreeNodeManager.class); + + private Map surfaceMap; + private GeometrySelectionHandler selectionHandler; + private DefaultGeometryActions geometryActions; + + public GeometryTreeNodeManager(Model model, Controller controller, AbstractGeometryPanel panel, DefaultGeometryActions geometryActions) { + super(model, panel); + this.root = new DefaultMutableTreeNode(new RootVisibleItem(panel.getTitle())); + this.selectionHandler = new GeometrySelectionHandler(panel); + this.geometryActions = geometryActions; + this.surfaceMap = new HashMap<>(); + } + + @Override + public void update(Observable o, final Object arg) { + if (!(arg instanceof FeatureLine) && (arg instanceof Stl || arg instanceof BaseSurface)) { + logger.debug("Observerd a change: arg is " + arg.getClass()); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + selectionHandler.disable(); + loadTree(); + expandTree(arg); + selectionHandler.enable(); + selectArgument(arg); + } + }); + } else if (arg instanceof Geometry) { + logger.debug("Observerd a change: arg is Geometry"); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + selectionHandler.disable(); + loadTree(); + makeVisibleItemsChecked(); + expandTree(arg); + selectionHandler.enable(); + } + }); + } else if (arg instanceof Patches) { + logger.debug("Observerd a change: arg is Patches"); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + makeVisibleItemsChecked(); + } + }); + } + } + + private void selectArgument(Object arg) { + if (arg instanceof Surface) { + Surface surface = (Surface) arg; + setSelectedValue(surface); + } + } + + private void loadTree() { + logger.debug("Load 'Geometry' tree"); + clear(); + for (Surface surface : model.getGeometry().getSurfaces()) { + addSurface(root, surface); + if (surface.getType().isStl()) { + if (surface.isSingleton()) { + // do nothing + } else { + Stl stl = (Stl) surface; + DefaultMutableTreeNode parentNode = nodeMap.get(stl); + for (Surface region : stl.getRegions()) { + addSurface(parentNode, region); + } + } + } + } + treeChanged(root); + } + + private void addSurface(DefaultMutableTreeNode parent, Surface surface) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(surface); + parent.add(node); + nodeMap.put(surface, node); + surfaceMap.put(node, surface); + } + + private void makeVisibleItemsChecked() { + logger.debug("Make visible items checked"); + if (getTree() != null) { + if (model.getPatches() == null || model.getPatches().isEmpty()) + getTree().getCheckManager().selectNode(getRoot()); + else + getTree().getCheckManager().deselectNode(getRoot()); + } + } + + private void expandTree(final Object arg) { + if (getTree() != null) { + if (shouldExpand(arg)) { + logger.debug("Expand the tree"); + getTree().expandNode(getRoot()); + } + } + } + + private boolean shouldExpand(final Object arg) { + return arg instanceof Stl || arg instanceof BaseSurface || arg instanceof Geometry; + } + + private void setSelectedValue(Surface surface) { + DefaultMutableTreeNode selectedNode = nodeMap.get(surface); + if (getTree() != null) { + if (selectedNode != null) { + getTree().setSelectedNode(selectedNode); + } else { + getTree().setSelectedNode(getRoot()); + } + } + } + + public Surface[] getSelectedValues() { + if (getTree() != null) { + TreePath[] selectionPaths = getTree().getSelectionPaths(); + if (selectionPaths != null) { + Surface[] surfaces = new Surface[selectionPaths.length]; + for (int i = 0; i < selectionPaths.length; i++) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPaths[i].getLastPathComponent(); + Surface surface = surfaceMap.get(node); + surfaces[i] = surface; + } + return surfaces; + } + } + return new Surface[0]; + } + + public void clear() { + // clear node before selection handler! + clearNode(root); + selectionHandler.clear(); + nodeMap.clear(); + surfaceMap.clear(); + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public Class getRendererClass() { + return Surface.class; + } + + @Override + public DefaultTreeCellRenderer getRenderer() { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object userObject = node.getUserObject(); + + if (userObject instanceof Surface) { + Surface surface = (Surface) userObject; + setText(surface.getName()); + } + setIcon(null); + return this; + } + }; + } + + @Override + public SelectionHandler getSelectionHandler() { + return selectionHandler; + } + + @Override + public PopUpBuilder getPopUpBuilder() { + return geometryActions; + } + + public final class GeometrySelectionHandler extends AbstractSelectionHandler { + + private final AbstractGeometryPanel panel; + private Surface[] currentSelection; + + public GeometrySelectionHandler(AbstractGeometryPanel panel) { + this.panel = panel; + } + + @Override + public void handleSelection(boolean fire3DEvent, Object... selection) { + saveCurrentSelection(); + + boolean isValidSelection = TreeUtil.isConsistent(selection, Surface.class); + if (isValidSelection) { + handleValidSelection(fire3DEvent, selection); + } else { + boolean shouldClearSelection = TreeUtil.isConsistent(currentSelection, Surface.class); + if (shouldClearSelection) { + clearSelection(fire3DEvent); + } + } + } + + private void saveCurrentSelection() { + if (Util.isVarArgsNotNull(currentSelection)) { + panel.saveSurfaces(currentSelection); + } + } + + private void handleValidSelection(boolean fire3DEvent, Object... selection) { + logger.debug("handleSelection: {} selected, fire3D {} {}", selection.length, fire3DEvent, selection.length == 1 ? ", selection is: " + selection[0] : ""); + + this.currentSelection = Arrays.copyOf(selection, selection.length, Surface[].class); + panel.selectSurface(currentSelection); + + if (fire3DEvent) { + EventManager.triggerEvent(this, new SelectSurfaceEvent(currentSelection)); + } + + geometryActions.updateActions(currentSelection); + } + + private void clearSelection(boolean fire3DEvent) { + clear(); + panel.deselectAll(); + if (fire3DEvent) { + EventManager.triggerEvent(this, new SelectSurfaceEvent(new Surface[0])); + } + } + + @Override + public void handleVisibility(VisibleItem item) { + if (Util.isVarArgsNotNull(currentSelection) && Arrays.asList(currentSelection).contains(item)) { + logger.debug("handleVisibility: {}", item); + panel.selectSurface(currentSelection); + EventManager.triggerEvent(this, new SelectSurfaceEvent(currentSelection)); + } + } + + @Override + public void process3DSelectionEvent(Picker picker, Actor actor, boolean keep) { + if (getTree() != null && actor != null && actor.getVisibleItem() instanceof Surface) { + Surface surface = (Surface) actor.getVisibleItem(); + if (surface instanceof Solid && ((Solid) surface).getParent().isSingleton()) { + surface = ((Solid) surface).getParent(); + } + DefaultMutableTreeNode selectedNode = nodeMap.get(surface); + logger.debug("Handle selection from 3D {}", surface); + if (selectedNode != null) { + boolean alreadySelected = getTree().isAlreadySelected(selectedNode); + if(alreadySelected){ + logger.debug("Handle selection from 3D REM"); + getTree().removeSelectedNode(selectedNode); + } else { + if (keep) { + logger.debug("Handle selection from 3D ADD"); + getTree().addSelectedNode(selectedNode); + } else { + logger.debug("Handle selection from 3D SET"); + getTree().setSelectedNode(selectedNode); + } + } + + } + } + } + + @Override + public void process3DVisibilityEvent(boolean selected) { + logger.debug("handle selection from check box"); + if (getTree() != null) { + if (selected) { + // getTree().getCheckManager().selectNode(getRoot()); + } else { + getTree().getCheckManager().deselectNode(getRoot()); + } + } + } + + @Override + public void clear() { + currentSelection = null; + } + } + +} diff --git a/src/eu/engys/gui/mesh/panels/MaterialPointsPanel.java b/src/eu/engys/gui/mesh/panels/MaterialPointsPanel.java new file mode 100644 index 0000000..49e11fb --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/MaterialPointsPanel.java @@ -0,0 +1,124 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh.panels; + +import static eu.engys.core.project.system.SnappyHexMeshDict.CASTELLATED_MESH_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.LOCATION_IN_MESH; +import static eu.engys.core.project.system.SnappyHexMeshDict.REFINEMENTS_REGIONS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.REFINEMENTS_SURFACES_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.WRAPPER_KEY; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.PointInfo; +import eu.engys.core.dictionary.model.ShowLocationAdapter; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.PointEvent; +import eu.engys.util.ui.builder.PanelBuilder; + +public class MaterialPointsPanel extends DefaultGUIPanel { + + public static final String TITLE = "Material Point"; + + private DictionaryModel castellatedModel; + private ShowLocationAdapter locationPanel; + + @Inject + public MaterialPointsPanel(Model model) { + super(TITLE, model); + } + + @Override + public void start() { + super.start(); + locationPanel.turnMaterialPointsOn(); + } + + @Override + public void stop() { + super.stop(); + locationPanel.turnMaterialPointsOff(); + } + + @Override + protected JComponent layoutComponents() { + castellatedModel = new DictionaryModel(new Dictionary("")); + + PanelBuilder builder = new PanelBuilder(); + locationPanel = castellatedModel.bindLocation(LOCATION_IN_MESH, 4); + builder.addComponent(locationPanel); + locationPanel.addPropertyChangeListener(PointInfo.PROPERTY_NAME, new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(PointInfo.PROPERTY_NAME)) { + PointInfo pi = (PointInfo) evt.getNewValue(); + EventManager.triggerEvent(this, new PointEvent(pi.getPoint(), pi.getKey(), pi.getAction(), pi.getColor())); + } + } + }); + + return builder.removeMargins().getPanel(); + + } + + @Override + public void load() { + SnappyHexMeshDict snappyDict = model.getProject().getSystemFolder().getSnappyHexMeshDict(); + if (snappyDict != null) { + if (snappyDict.found(CASTELLATED_MESH_CONTROLS_KEY)) { + Dictionary castellated = snappyDict.subDict(CASTELLATED_MESH_CONTROLS_KEY); + + Dictionary castellatedCopy = new Dictionary(castellated); + castellatedCopy.remove(REFINEMENTS_SURFACES_KEY); + castellatedCopy.remove(REFINEMENTS_REGIONS_KEY); + castellatedCopy.remove(WRAPPER_KEY); + this.castellatedModel.setDictionary(castellatedCopy); + } + } + } + + @Override + public void save() { + SnappyHexMeshDict snappyDict = model.getProject().getSystemFolder().getSnappyHexMeshDict(); + if (snappyDict != null) { + Dictionary castellated = snappyDict.subDict(CASTELLATED_MESH_CONTROLS_KEY); + String locations = castellatedModel.getDictionary().lookup(LOCATION_IN_MESH); + castellated.add(LOCATION_IN_MESH, locations); + } + } + +} diff --git a/src/eu/engys/gui/mesh/panels/SolverBoundaryMeshPanel.java b/src/eu/engys/gui/mesh/panels/SolverBoundaryMeshPanel.java new file mode 100644 index 0000000..5d216e0 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/SolverBoundaryMeshPanel.java @@ -0,0 +1,207 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh.panels; + +import static eu.engys.util.ui.ComponentsFactory.labelField; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import javax.inject.Inject; +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JTextArea; + +import eu.engys.core.project.Model; +import eu.engys.gui.AbstractGUIPanel; +import eu.engys.gui.tree.TreeNodeManager; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.builder.PanelBuilder; + +public class SolverBoundaryMeshPanel extends AbstractGUIPanel { + + public static final String TITLE = "Mesh"; + private static final DecimalFormat formatter = new DecimalFormat("#.###", new DecimalFormatSymbols(Locale.US)); + + private BoundaryMeshTreeNodeManager treeNodeManager; + + private JLabel name; + private JLabel path; + private JLabel created; + private JLabel cells; + private JLabel points; + private JLabel faces; + private JTextArea cellsPerLevel; + private JLabel memory; + + private JLabel xBounds; + private JLabel yBounds; + private JLabel zBounds; + + private PanelBuilder dataArrays; + + @Inject + public SolverBoundaryMeshPanel(Model model) { + super(TITLE, model); + this.treeNodeManager = new BoundaryMeshTreeNodeManager(model, this); + model.addObserver(treeNodeManager); + } + + protected JComponent layoutComponents() { + name = labelField(""); + path = labelField(""); + created = labelField(""); + + cells = labelField(""); + points = labelField(""); + faces = labelField(""); + + cellsPerLevel = ComponentsFactory.labelArea(); + cellsPerLevel.setEditable(false); + + memory = labelField(""); + + xBounds = labelField(""); + yBounds = labelField(""); + zBounds = labelField(""); + + PanelBuilder properties = new PanelBuilder(); + properties.getPanel().setBorder(BorderFactory.createTitledBorder("Properties")); + properties.addComponent("Name", name); + properties.addComponent("Path", path); + properties.addComponent("Created", created); + + PanelBuilder statistics = new PanelBuilder(); + statistics.getPanel().setBorder(BorderFactory.createTitledBorder("Statistics")); + statistics.addComponent("Number of Cells", cells); + statistics.addComponent("Number of Faces", faces); + statistics.addComponent("Number of Points", points); + statistics.addComponent("Cells per Refinement Level", cellsPerLevel); + // statistics.addComponent("Memory [MB]", memory); + + dataArrays = new PanelBuilder(); + dataArrays.getPanel().setBorder(BorderFactory.createTitledBorder("Data Arrays")); + + PanelBuilder bounds = new PanelBuilder(); + bounds.getPanel().setBorder(BorderFactory.createTitledBorder("Bounds")); + bounds.addComponent("X Range", xBounds); + bounds.addComponent("Y Range", yBounds); + bounds.addComponent("Z Range", zBounds); + + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(properties.getPanel()); + builder.addComponent(statistics.getPanel()); + builder.addComponent(dataArrays.getPanel()); + builder.addComponent(bounds.getPanel()); + return builder.removeMargins().getPanel(); + } + + @Override + public void start() { + super.start(); + } + + @Override + public void load() { + name.setText(model.getProject().getBaseDir().getName()); + path.setText(model.getProject().getBaseDir().getParent()); + + try { + Path basePath = model.getProject().getBaseDir().toPath(); + long lastModify = Files.getLastModifiedTime(basePath).toMillis(); + created.setText(DateFormat.getDateInstance().format(new Date(lastModify))); + } catch (Exception e) { + created.setText("-"); + } + + if (model.getMesh() != null) { + cells.setText(formatter.format(model.getMesh().getNumberOfCells())); + points.setText(formatter.format(model.getMesh().getNumberOfPoints())); + faces.setText(formatter.format(model.getMesh().getNumberOfFaces())); + + List cellsPerRefinementLevel = model.getMesh().getCellsPerRefinementLevel(); + String text = ""; + for (int i = 0; i < cellsPerRefinementLevel.size(); i++) { + if (i > 0) + text += "\n"; + text += i + "\t" + cellsPerRefinementLevel.get(i); + } + cellsPerLevel.setText(text); + + // memory.setText(formatter.format(model.getMesh().getMemorySize()/1024D)); + + double[] bounds = model.getMesh().getBounds(); + + xBounds.setText(getTextForBounds(bounds[0], bounds[1])); + yBounds.setText(getTextForBounds(bounds[2], bounds[3])); + zBounds.setText(getTextForBounds(bounds[4], bounds[5])); + } else { + cells.setText("-"); + points.setText("-"); + faces.setText("-"); + cellsPerLevel.setText(" - "); + // memory.setText("-"); + xBounds.setText("[- , -]"); + yBounds.setText("[- , -]"); + zBounds.setText("[- , -]"); + } + } + + private String getTextForBounds(double min, double max) { + if (areValid(min, max)) { + return "[" + formatter.format(min) + " , " + formatter.format(max) + "] (Delta " + formatter.format(max - min) + ")"; + } else { + return "[0 , 0]"; + } + } + + private boolean areValid(double min, double max) { + return min < Double.MAX_VALUE && max > -Double.MAX_VALUE; + } + + @Override + public void save() { + } + + @Override + public void stop() { + super.stop(); + } + + @Override + public TreeNodeManager getTreeNodeManager() { + return treeNodeManager; + } + +} diff --git a/src/eu/engys/gui/mesh/panels/StandardBaseMeshPanel.java b/src/eu/engys/gui/mesh/panels/StandardBaseMeshPanel.java new file mode 100644 index 0000000..e911afd --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/StandardBaseMeshPanel.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import static eu.engys.core.project.system.BlockMeshDict.SPACING_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.AUTO_BLOCK_MESH_KEY; + +import com.google.inject.Inject; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.BlockMeshDict; +import eu.engys.core.project.system.SnappyHexMeshDict; + +public class StandardBaseMeshPanel extends AbstractBaseMeshPanel { + + @Inject + public StandardBaseMeshPanel(Model model, Controller controller) { + super(model, controller); + } + + @Override + protected void loadSpacing() { + BlockMeshDict blockMeshDict = model.getProject().getSystemFolder().getBlockMeshDict(); + if (blockMeshDict != null && blockMeshDict.found(SPACING_KEY)) { + setBaseMeshSpacing(blockMeshDict.lookupDouble(SPACING_KEY)); + } + } + + @Override + public void save() { + super.save(); + fixSpacing(); + fixAutoBlockMesh(); + } + + private void fixAutoBlockMesh() { + SnappyHexMeshDict snappyDict = model.getProject().getSystemFolder().getSnappyHexMeshDict(); + if (snappyDict != null) { + if (model.getGeometry().isAutoBoundingBox()) { + snappyDict.add(AUTO_BLOCK_MESH_KEY, String.valueOf(true)); + } else { + snappyDict.add(AUTO_BLOCK_MESH_KEY, String.valueOf(false)); + } + } + } + + private void fixSpacing() { + BlockMeshDict blockMeshDict = model.getProject().getSystemFolder().getBlockMeshDict(); + if (blockMeshDict != null) { + if (isUserDefined() || isFromFile()) { + blockMeshDict.remove(SPACING_KEY); + } else if (isAutomatic()) { + blockMeshDict.add(SPACING_KEY, Double.toString(getBaseMeshSpacing())); + } + } + } +} diff --git a/src/eu/engys/gui/mesh/panels/StandardFeatureLinesPanel.java b/src/eu/engys/gui/mesh/panels/StandardFeatureLinesPanel.java new file mode 100644 index 0000000..d851cd5 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/StandardFeatureLinesPanel.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import com.google.inject.Inject; + +import eu.engys.core.project.Model; + +public class StandardFeatureLinesPanel extends FeatureLinesPanel { + + @Inject + public StandardFeatureLinesPanel(Model model) { + super(model); + } + + @Override + protected boolean hasRefineOnly() { + return false; + } + +} diff --git a/src/eu/engys/gui/mesh/panels/StandardGeometryPanel.java b/src/eu/engys/gui/mesh/panels/StandardGeometryPanel.java new file mode 100644 index 0000000..f1a9d78 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/StandardGeometryPanel.java @@ -0,0 +1,169 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels; + +import static eu.engys.core.project.system.SnappyHexMeshDict.BAFFLE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.BOUNDARY_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.EXPANSION_RATIO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_TYPE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FACE_ZONE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FINAL_LAYER_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.GAP_LEVEL_INCREMENT_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.INTERNAL_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.IS_CELL_ZONE; +import static eu.engys.core.project.system.SnappyHexMeshDict.LEVEL_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.NONE_KEY; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JPanel; + +import com.google.inject.Inject; + +import eu.engys.core.controller.Controller; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.IntegerField; +import eu.engys.util.ui.textfields.StringField; + +public class StandardGeometryPanel extends AbstractGeometryPanel { + + private static final String LAYER_MIN_THICKNESS_LABEL = "Layer Min Thickness"; + + @Inject + public StandardGeometryPanel(Model model, Controller controller) { + super(model, controller); + } + + @Override + protected DefaultGeometryActions getGeometryActions(Controller controller) { + return new DefaultGeometryActions(this, controller); + } + + @Override + protected JPanel getSurfacesPanel() { + surfaceBuilder = new PanelBuilder(); + surfaceBuilder.addComponent(LEVEL_LABEL, surfaceModel.bindIntegerArray(LEVEL_KEY, 2)); + surfaceBuilder.addComponent(PROXIMITY_REFINEMENT_LABEL, surfaceModel.bindIntegerPositive(GAP_LEVEL_INCREMENT_KEY)); + surfaceBuilder.getPanel().setBorder(BorderFactory.createTitledBorder(SURFACE_LABEL)); + return surfaceBuilder.getPanel(); + } + + @Override + protected JPanel getLayersPanel() { + layersBuilder = new PanelBuilder(); + layersBuilder.addComponent(NUMBER_OF_LAYERS_LABEL, layerModel.bindIntegerPositive(SnappyHexMeshDict.N_SURFACE_LAYERS_KEY)); + layersBuilder.addComponent(FINAL_LAYER_THICKNESS_LABEL, layerModel.bindDouble(FINAL_LAYER_THICKNESS_KEY, (Double) null)); + layersBuilder.addComponent(LAYER_MIN_THICKNESS_LABEL, layerModel.bindDouble(MIN_THICKNESS_KEY, (Double) null)); + layersBuilder.addComponent(LAYER_STRETCHING_LABEL, layerModel.bindDouble(EXPANSION_RATIO_KEY, (Double) null)); + return layersBuilder.getPanel(); + } + + @Override + protected JPanel getZonesPanel() { + zonesBuilder = new PanelBuilder(); + String[] TYPE_KEYS = { NONE_KEY, INTERNAL_KEY, BOUNDARY_KEY, BAFFLE_KEY }; + String[] TYPE_LABELS = { NONE_LABEL, INTERNAL_LABEL, BOUNDARY_LABEL, BAFFLE_LABEL }; + final JComboBox zoneType = zoneModel.bindSelection(FACE_TYPE_KEY, TYPE_KEYS, TYPE_LABELS); + final StringField zoneName = zoneModel.bindLabel(FACE_ZONE_KEY, true); + final JCheckBox isCellZone = zoneModel.bindBoolean(IS_CELL_ZONE); + final IntegerField[] zoneLevel = zoneModel.bindIntegerArray(LEVEL_KEY, 2); + + zonesBuilder.addComponent(TYPE_LABEL, zoneType); + zonesBuilder.addComponent(NAME_LABEL, zoneName); + zonesBuilder.addComponent(CELL_ZONE_LABEL, isCellZone); + zonesBuilder.addComponent(LEVEL_LABEL, zoneLevel); + + zoneName.setEnabled(false); + isCellZone.setEnabled(false); + zoneLevel[0].setEnabled(false); + zoneLevel[1].setEnabled(false); + + zoneType.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + boolean enabled = zoneType.getSelectedIndex() > 0; + zoneName.setEnabled(enabled); + zoneLevel[0].setEnabled(enabled); + zoneLevel[1].setEnabled(enabled); + isCellZone.setEnabled(enabled); + } + }); + return zonesBuilder.getPanel(); + } + + // public static void main(String[] args) { + // SwingUtilities.invokeLater(new Runnable() { + // + // @Override + // public void run() { + // new HelyxOSLookAndFeel().init(); + // StandardGeometryPanel panel = new StandardGeometryPanel(new Model()); + // panel.layoutPanel(); + // UiUtil.show("Prova", panel); + // panel.layerModel.setDictionary(new Dictionary("pippo")); + // } + // }); + // } + + @Override + protected JButton[] getShapeButtons() { + JButton[] buttons = new JButton[5]; + + JButton stlButton = new JButton(ActionManager.getInstance().get("mesh.stl")); + stlButton.setName("add.stl.button"); + buttons[0] = stlButton; + + JButton boxButton = new JButton(ActionManager.getInstance().get("mesh.box")); + boxButton.setName("add.box.button"); + buttons[1] = boxButton; + + stlButton.setPreferredSize(boxButton.getPreferredSize()); + + JButton sphereButton = new JButton(ActionManager.getInstance().get("mesh.sphere")); + sphereButton.setName("add.sphere.button"); + buttons[2] = sphereButton; + + JButton cylinderButton = new JButton(ActionManager.getInstance().get("mesh.cylinder")); + cylinderButton.setName("add.cylinder.button"); + buttons[3] = cylinderButton; + + JButton planeButton = new JButton(ActionManager.getInstance().get("mesh.plane")); + planeButton.setName("add.plane.button"); + buttons[4] = planeButton; + + return buttons; + } + +} diff --git a/src/eu/engys/gui/mesh/panels/StandardMeshAdvancedOptionsPanel.java b/src/eu/engys/gui/mesh/panels/StandardMeshAdvancedOptionsPanel.java new file mode 100644 index 0000000..4e3e063 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/StandardMeshAdvancedOptionsPanel.java @@ -0,0 +1,199 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.mesh.panels; + +import static eu.engys.core.project.system.SnappyHexMeshDict.ADD_LAYERS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.ALLOW_FREE_STANDING_ZONE_FACES_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.CASTELLATED_MESH_CONTROLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.CASTELLATED_MESH_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.DEBUG_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.EXPANSION_RATIO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.EXPLICIT_FEATURE_SNAP_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FEATURE_ANGLE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FINAL_LAYER_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.IMPLICIT_FEATURE_SNAP_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_FACE_THICKNESS_RATIO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_GLOBAL_CELLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_LOAD_UNBALANCE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_LOCAL_CELLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_THICKNESS_TO_MEDIAL_RATIO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MERGE_TOLERANCE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_MEDIAL_AXIS_ANGLE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_REFINEMENT_CELLS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MIN_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MULTI_REGION_FEATURE_SNAP_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_BUFFER_CELLS_NO_EXTRUDE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_CELLS_BETWEEN_LEVELS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_FEATURE_SNAP_ITER_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_GROW_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_LAYER_ITER_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_RELAXED_ITER_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_RELAX_ITER_LAYERS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_RELAX_ITER_SNAP_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SMOOTH_NORMALS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SMOOTH_PATCH_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SMOOTH_SURFACE_NORMALS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SMOOTH_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SOLVER_ITER_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.PLANAR_ANGLE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.RESOLVE_FEATURE_ANGLE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.SLIP_FEATURE_ANGLE_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.SNAP_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.TOLERANCE_KEY; + +import javax.swing.JPanel; + +import com.google.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.SnappyHexMeshDict; +import eu.engys.util.ui.builder.PanelBuilder; + +public class StandardMeshAdvancedOptionsPanel extends DefaultMeshAdvancedOptionsPanel { + + + // CASTELLATED + public static final String PLANAR_ANGLE_LABEL = "Planar Angle"; + public static final String PLANAR_ANGLE_TOOLTIP = "Planar angle"; + + //SNAP + public static final String SNAP_FEATURE_ITERATIONS_LABEL = "Snap Feature Iterations"; + public static final String SNAP_FEATURE_ITERATIONS_TOOLTIP = "Number of feature edge snapping iterations"; + public static final String EXPLICIT_SNAP_FEATURE_LABEL = "Explicit Snap Feature"; + public static final String EXPLICIT_SNAP_FEATURE_TOOLTIP = "Use features in castellatedMeshControls"; + public static final String IMPLICIT_SNAP_FEATURE_LABEL = "Implicit Snap Feature"; + public static final String IMPLICIT_SNAP_FEATURE_TOOLTIP = "Detects (geometric only) features by sampling the surface"; + public static final String MULTI_REGION_FEATURE_LABEL = "Multi Region Feature"; + public static final String MULTI_REGION_FEATURE_TOOLTIP = "For explicitFeatureSnap, detect features between multiple surfaces"; + + //LAYERS + public static final String NUMBER_OF_LAYERS_NOT_GROWN_LABEL = "Layers Not Grown"; + public static final String NUMBER_OF_LAYERS_NOT_GROWN_TOOLTIP = "Number of layers of connected faces that are not grown if points get not extruded; helps convergence of layer addition close to features"; + public static final String LAYER_ADDITION_ITERATIONS_LABEL = "Layer Addition Iterations"; + public static final String LAYER_ADDITION_ITERATIONS_TOOLTIP = "Overall maximum number of layer addition iterations"; + public static final String NUMBER_OF_BUFFER_CELLS_LABEL = "Number of Buffer Cells"; + public static final String NUMBER_OF_BUFFER_CELLS_TOOLTIP = "Create buffer region for new layer terminations"; + public static final String SMOOTH_LAYER_THICKNESS_LABEL = "Smooth Layer Thickness"; + public static final String SMOOTH_LAYER_THICKNESS_TOOLTIP = "Smooth layer thickness over surface patches"; + public static final String SLIP_FEATURE_ANGLE_LABEL = "Slip Feature Angle"; + public static final String SLIP_FEATURE_ANGLE_TOOLTIP = "Sliding of vertices along a boundary will occur when the angle between the patch on which layers are added and its neighbouring patch is larger than that specified by this value"; + public static final String FEATURE_ANGLE_LABEL = "Feature Angle"; + public static final String FEATURE_ANGLE_TOOLTIP = "Angle above which surface is not extruded"; + + @Inject + public StandardMeshAdvancedOptionsPanel(Model model) { + super(model); + } + + @Override + protected JPanel createGeneralPanel() { + PanelBuilder builder = new PanelBuilder("options.general.panel"); + + builder.addComponent(CASTELLATED_MESH_LABEL, snappyHexMeshModel.bindBoolean(CASTELLATED_MESH_KEY), CASTELLATED_MESH_TOOLTIP); + builder.addComponent(SNAPPING_LABEL, snappyHexMeshModel.bindBoolean(SNAP_KEY), SNAPPING_TOOLTIP); + builder.addComponent(LAYERS_ADDITION_LABEL, snappyHexMeshModel.bindBoolean(ADD_LAYERS_KEY), LAYERS_ADDITION_TOOLTIP); + + builder.addComponent(DEBUG_LABEL, snappyHexMeshModel.bindInteger(DEBUG_KEY, 0, 2), DEBUG_TOOLTIP); + builder.addComponent(MERGE_TOLERANCE_LABEL, snappyHexMeshModel.bindDouble(MERGE_TOLERANCE_KEY), MERGE_TOLERANCE_TOOLTIP); + + return builder.getPanel(); + } + + @Override + protected JPanel createRefinementsPanel() { + PanelBuilder builder = new PanelBuilder("options.geometry.panel"); + builder.addComponent(MAX_LOCAL_CELLS_LABEL, castellatedMeshControlsModel.bindIntegerPositive(MAX_LOCAL_CELLS_KEY), MAX_LOCAL_CELLS_TOOLTIP); + builder.addComponent(MAX_GLOBAL_CELLS_LABEL, castellatedMeshControlsModel.bindIntegerPositive(MAX_GLOBAL_CELLS_KEY), MAX_GLOBAL_CELLS_TOOLTIP); + builder.addComponent(MIN_REFINEMENT_CELLS_LABEL, castellatedMeshControlsModel.bindIntegerPositive(MIN_REFINEMENT_CELLS_KEY), MIN_REFINEMENT_CELLS_TOOLTIP); + builder.addComponent(CELLS_BETWEEN_LEVELS_LABEL, castellatedMeshControlsModel.bindInteger(N_CELLS_BETWEEN_LEVELS_KEY, 1, Integer.MAX_VALUE), CELLS_BETWEEN_LEVELS_TOOLTIP); + builder.addComponent(RESOLVE_FEATURE_ANGLE_LABEL, castellatedMeshControlsModel.bindDoubleAngle_360(RESOLVE_FEATURE_ANGLE_KEY), RESOLVE_FEATURE_ANGLE_TOOLTIP); + builder.addComponent(ALLOW_FREE_STANDING_ZONE_FACES_LABEL, castellatedMeshControlsModel.bindBoolean(ALLOW_FREE_STANDING_ZONE_FACES_KEY), ALLOW_FREE_STANDING_ZONE_FACES_TOOLTIP); + builder.addComponent(PLANAR_ANGLE_LABEL, castellatedMeshControlsModel.bindDoubleAngle_360(PLANAR_ANGLE_KEY), PLANAR_ANGLE_TOOLTIP); + builder.addComponent(MAX_LOAD_UNBALANCE_LABEL, castellatedMeshControlsModel.bindDoublePositive(MAX_LOAD_UNBALANCE_KEY), MAX_LOAD_UNBALANCE_TOOLTIP); + return builder.getPanel(); + } + + @Override + protected JPanel createLayersPanel() { + PanelBuilder builder = new PanelBuilder("options.layers.panel"); + builder.addComponent(EXPANSION_RATIO_LABEL, layersControlsModel.bindDouble(EXPANSION_RATIO_KEY), EXPANSION_RATIO_TOOLTIP); + builder.addComponent(FINAL_LAYER_THICKNESS_LABEL, layersControlsModel.bindDouble(FINAL_LAYER_THICKNESS_KEY), FINAL_LAYER_THICKNESS_TOOLTIP); +// builder.addComponent(RELATIVE_SIZES_LABEL, layersControlsModel.bindBoolean(RELATIVE_SIZES_KEY), RELATIVE_SIZES_TOOLTIP); + builder.addComponent(MIN_THICKNESS_LABEL, layersControlsModel.bindDouble(MIN_THICKNESS_KEY), MIN_THICKNESS_TOOLTIP); + builder.addComponent(FEATURE_ANGLE_LABEL, layersControlsModel.bindDoubleAngle_360(FEATURE_ANGLE_KEY), FEATURE_ANGLE_TOOLTIP); + builder.addComponent(SLIP_FEATURE_ANGLE_LABEL, layersControlsModel.bindDoubleAngle_360(SLIP_FEATURE_ANGLE_KEY), SLIP_FEATURE_ANGLE_TOOLTIP); + builder.addComponent(RELAX_ITERATIONS_LAYERS_LABEL, layersControlsModel.bindIntegerPositive(N_RELAX_ITER_LAYERS_KEY), RELAX_ITERATIONS_LAYERS_TOOLTIP); + builder.addComponent(RELAXED_ITERATIONS_LABEL, layersControlsModel.bindIntegerPositive(N_RELAXED_ITER_KEY), RELAXED_ITERATIONS_TOOLTIP); + builder.addComponent(SURFACE_NORMALS_SMOOTHING_ITERATIONS_LABEL, layersControlsModel.bindIntegerPositive(N_SMOOTH_SURFACE_NORMALS_KEY), SURFACE_NORMALS_SMOOTHING_ITERATIONS_TOOLTIP); + builder.addComponent(INTERIOR_MESH_SMOOTHING_ITERATIONS_LABEL, layersControlsModel.bindIntegerPositive(N_SMOOTH_NORMALS_KEY), INTERIOR_MESH_SMOOTHING_ITERATIONS_TOOLTIP); + builder.addComponent(SMOOTH_LAYER_THICKNESS_LABEL, layersControlsModel.bindIntegerPositive(N_SMOOTH_THICKNESS_KEY), SMOOTH_LAYER_THICKNESS_TOOLTIP); + builder.addComponent(MAX_FACE_THICKNESS_RATIO_LABEL, layersControlsModel.bindDouble(MAX_FACE_THICKNESS_RATIO_KEY), MAX_FACE_THICKNESS_RATIO_TOOLTIP); + builder.addComponent(MAX_THICKNESS_TO_MEDIAL_RATIO_LABEL, layersControlsModel.bindDouble(MAX_THICKNESS_TO_MEDIAL_RATIO_KEY), MAX_THICKNESS_TO_MEDIAL_RATIO_TOOLTIP); + builder.addComponent(MIN_MEDIAL_AXIS_ANGLE_LABEL, layersControlsModel.bindIntegerAngle_360(MIN_MEDIAL_AXIS_ANGLE_KEY), MIN_MEDIAL_AXIS_ANGLE_TOOLTIP); + builder.addComponent(NUMBER_OF_BUFFER_CELLS_LABEL, layersControlsModel.bindIntegerPositive(N_BUFFER_CELLS_NO_EXTRUDE_KEY), NUMBER_OF_BUFFER_CELLS_TOOLTIP); + builder.addComponent(LAYER_ADDITION_ITERATIONS_LABEL, layersControlsModel.bindIntegerPositive(N_LAYER_ITER_KEY), LAYER_ADDITION_ITERATIONS_TOOLTIP); + builder.addComponent(NUMBER_OF_LAYERS_NOT_GROWN_LABEL, layersControlsModel.bindIntegerPositive(N_GROW_KEY), NUMBER_OF_LAYERS_NOT_GROWN_TOOLTIP); + return builder.getPanel(); + } + + @Override + protected JPanel createSnappingPanel() { + PanelBuilder builder = new PanelBuilder("options.snapping.panel"); + builder.addComponent(SOLVER_ITERATIONS_LABEL, snapControlsModel.bindIntegerPositive(N_SOLVER_ITER_KEY), SOLVER_ITERATIONS_TOOLTIP); + builder.addComponent(SMOOTH_PATCH_LABEL, snapControlsModel.bindIntegerPositive(N_SMOOTH_PATCH_KEY), SMOOTH_PATCH_TOOLTIP); + builder.addComponent(TOLERANCE_LABEL, snapControlsModel.bindDoublePositive(TOLERANCE_KEY), TOLERANCE_TOOLTIP); + builder.addComponent(RELAX_ITERATIONS_SNAP_LABEL, snapControlsModel.bindIntegerPositive(N_RELAX_ITER_SNAP_KEY), RELAX_ITERATIONS_SNAP_TOOLTIP); + builder.addComponent(SNAP_FEATURE_ITERATIONS_LABEL, snapControlsModel.bindIntegerPositive(N_FEATURE_SNAP_ITER_KEY), SNAP_FEATURE_ITERATIONS_TOOLTIP); + builder.addComponent(IMPLICIT_SNAP_FEATURE_LABEL, snapControlsModel.bindBoolean(IMPLICIT_FEATURE_SNAP_KEY), IMPLICIT_SNAP_FEATURE_TOOLTIP); + builder.addComponent(EXPLICIT_SNAP_FEATURE_LABEL, snapControlsModel.bindBoolean(EXPLICIT_FEATURE_SNAP_KEY), EXPLICIT_SNAP_FEATURE_TOOLTIP); + builder.addComponent(MULTI_REGION_FEATURE_LABEL, snapControlsModel.bindBoolean(MULTI_REGION_FEATURE_SNAP_KEY), MULTI_REGION_FEATURE_TOOLTIP); + return builder.getPanel(); + } + + @Override + public void load() { + SnappyHexMeshDict snappyDict = getSnappyDict(); + if (snappyDict != null) { + loadCastellated(snappyDict); + loadLayers(snappyDict); + loadQuality(snappyDict); + loadSnap(snappyDict); + this.snappyHexMeshModel.setDictionary(new SnappyHexMeshDict(snappyDict)); + } + } + + @Override + protected void loadCastellated(SnappyHexMeshDict snappyDict) { + if (snappyDict.found(CASTELLATED_MESH_CONTROLS_KEY)) { + Dictionary castellated = new Dictionary(snappyDict.subDict(CASTELLATED_MESH_CONTROLS_KEY)); + snappyDict.remove(CASTELLATED_MESH_CONTROLS_KEY); + this.castellatedMeshControlsModel.setDictionary(castellated); + } + } + +} diff --git a/src/eu/engys/gui/mesh/panels/lines/AutomaticBaseMeshPanel.java b/src/eu/engys/gui/mesh/panels/lines/AutomaticBaseMeshPanel.java new file mode 100644 index 0000000..b93b5d2 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/lines/AutomaticBaseMeshPanel.java @@ -0,0 +1,84 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels.lines; + +import static eu.engys.util.ui.ComponentsFactory.doubleField; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Geometry; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.RemoveSurfaceEvent; +import eu.engys.util.ui.textfields.DoubleField; + +public class AutomaticBaseMeshPanel { + + public static final String AUTOMATIC_LABEL = "Automatic"; + public static final String BASE_MESHSPACING_LABEL = "Base Mesh Spacing"; + + private DictionaryPanelBuilder builder; + + protected DoubleField meshSpacing; + + private Model model; + + public AutomaticBaseMeshPanel(Model model, DictionaryPanelBuilder builder) { + this.model = model; + this.builder = builder; + + builder.startGroup(AUTOMATIC_LABEL); + layoutComponents(); + builder.endGroup(); + } + + private void layoutComponents() { + meshSpacing = doubleField(1.0); + builder.addComponent(BASE_MESHSPACING_LABEL, meshSpacing); + } + + public void save() { + model.getProject().getSystemFolder().getBlockMeshDict().setFromFile(false); + model.getGeometry().setAutoBoundingBox(true); + model.getGeometry().setCellSize(new double[] { meshSpacing.getDoubleValue(), meshSpacing.getDoubleValue(), meshSpacing.getDoubleValue() }); + model.getGeometry().saveAutoBlock(model); + } + + public void updateBlock() { + if (model.getGeometry().hasBlock()) { + EventManager.triggerEvent(this, new RemoveSurfaceEvent(model.getGeometry().getBlock())); + model.getGeometry().setBlock(Geometry.FAKE_BLOCK); + model.blockChanged(); + } + } + + public void setBaseMeshSpacing(double baseMeshSpacing) { + meshSpacing.setDoubleValue(baseMeshSpacing); + } + + public double getBaseMeshSpacing() { + return meshSpacing.getDoubleValue(); + } + +} diff --git a/src/eu/engys/gui/mesh/panels/lines/BoundingBoxFacesPanel.java b/src/eu/engys/gui/mesh/panels/lines/BoundingBoxFacesPanel.java new file mode 100644 index 0000000..32d3770 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/lines/BoundingBoxFacesPanel.java @@ -0,0 +1,131 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels.lines; + +import static eu.engys.core.project.system.SnappyHexMeshDict.EXPANSION_RATIO_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FCH_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.FINAL_LAYER_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.MAX_LAYER_THICKNESS_KEY; +import static eu.engys.core.project.system.SnappyHexMeshDict.N_SURFACE_LAYERS_KEY; +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.beans.PropertyChangeListener; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.geometry.surface.PlaneRegion; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.StringField; + +public class BoundingBoxFacesPanel { + + public static final String NUMBER_OF_LAYERS_LABEL = "Number of Layers"; + public static final String FIRST_CELL_HEIGHT_LABEL = "First Cell Height"; + public static final String LAYER_STRETCHING_LABEL = "Layer Stretching"; + public static final String FINAL_LAYER_THICKNESS_LABEL = "Final Layer Thickness"; + public static final String TOTAL_LAYER_THICKNESS_LABEL = "Total Layer Thickness"; + public static final String FACE_NAME_LABEL = "Face Name"; + public static final String BOUNDING_BOX_FACES_LABEL = "Bounding Box Faces"; + + private PanelBuilder planeBuilder; + private DictionaryModel planeModel; + private StringField planeName; + private PropertyChangeListener listener; + + public BoundingBoxFacesPanel(PropertyChangeListener listener) { + this.listener = listener; + this.planeModel = new DictionaryModel(); + this.planeBuilder = new PanelBuilder(); + layoutComponents(); + addNameListener(); + } + + private void layoutComponents() { + planeModel = new DictionaryModel(); + + planeBuilder = new DictionaryPanelBuilder(); + planeBuilder.addComponent(FACE_NAME_LABEL, planeName = stringField()); + planeBuilder.addComponent(NUMBER_OF_LAYERS_LABEL, planeModel.bindIntegerPositive(N_SURFACE_LAYERS_KEY)); + planeBuilder.addComponent(TOTAL_LAYER_THICKNESS_LABEL, planeModel.bindDouble(MAX_LAYER_THICKNESS_KEY, (Double) null)); + planeBuilder.addComponent(FINAL_LAYER_THICKNESS_LABEL, planeModel.bindDouble(FINAL_LAYER_THICKNESS_KEY, (Double) null)); + planeBuilder.addComponent(LAYER_STRETCHING_LABEL, planeModel.bindDouble(EXPANSION_RATIO_KEY, (Double) null)); + planeBuilder.addComponent(FIRST_CELL_HEIGHT_LABEL, planeModel.bindDouble(FCH_KEY, (Double) null)); + planeBuilder.setEnabled(false); + } + + public JPanel getPanel() { + JPanel panel = planeBuilder.getPanel(); + panel.setBorder(BorderFactory.createTitledBorder(BOUNDING_BOX_FACES_LABEL)); + panel.setName("plane.panel"); + return panel; + } + + public void save(PlaneRegion... planes) { + for (PlaneRegion plane : planes) { + plane.setLayerDictionary(new Dictionary(planeModel.getDictionary())); + } + } + + public void selectPlane(PlaneRegion[] selection) { + setEnabled(true); + + PlaneRegion plane = selection[0]; + planeModel.setDictionary(plane.getLayerDictionary()); + setPlaneName(plane.getName()); + } + + public void setEnabled(boolean enabled) { + planeName.setEnabled(enabled); + planeBuilder.setEnabled(enabled); + } + + public void disableNameField() { + planeName.setEnabled(false); + } + + public void setPlaneName(String name) { + removeNameListener(); + planeName.setValue(name); + addNameListener(); + } + + public String getPlaneName() { + return planeName.getText(); + } + + public void addNameListener() { + planeName.addPropertyChangeListener(listener); + } + + public void removeNameListener() { + planeName.removePropertyChangeListener(listener); + } + +} diff --git a/src/eu/engys/gui/mesh/panels/lines/ColorFeatureLineAction.java b/src/eu/engys/gui/mesh/panels/lines/ColorFeatureLineAction.java new file mode 100644 index 0000000..fef37d4 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/lines/ColorFeatureLineAction.java @@ -0,0 +1,73 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels.lines; + +import java.awt.Color; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JColorChooser; +import javax.swing.SwingUtilities; + +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.ColorSurfaceEvent; +import eu.engys.gui.mesh.panels.FeatureLinesPanel; + +public class ColorFeatureLineAction extends AbstractAction { + + // private static final Icon PICK_ICON = ResourcesUtil.getIcon("color.pick.icon"); + + private Color currentColor = Color.WHITE; + private FeatureLinesPanel linesPanel; + + public ColorFeatureLineAction(FeatureLinesPanel engysLinesPanel) { + // super("", PICK_ICON); + super("Choose"); + this.linesPanel = engysLinesPanel; + } + + @Override + public void actionPerformed(ActionEvent e) { + this.currentColor = JColorChooser.showDialog(SwingUtilities.getWindowAncestor(linesPanel), "Select a color", currentColor); + changeColor(currentColor, (JButton) e.getSource()); + } + + private void changeColor(Color currentColor, JButton sourceButton) { + if (linesPanel.getSelectedLine() != null) { + FeatureLine selectedLine = linesPanel.getSelectedLine(); + selectedLine.setColor(currentColor); + sourceButton.setBackground(currentColor); + EventManager.triggerEvent(this, new ColorSurfaceEvent(selectedLine, currentColor)); + } + } + + public void setCurrentColor(Color currentColor) { + this.currentColor = currentColor; + } + +} diff --git a/src/eu/engys/gui/mesh/panels/lines/FeatureLinesRefinementTable.java b/src/eu/engys/gui/mesh/panels/lines/FeatureLinesRefinementTable.java new file mode 100644 index 0000000..22fee06 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/lines/FeatureLinesRefinementTable.java @@ -0,0 +1,176 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels.lines; + +import java.awt.BorderLayout; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; + +import eu.engys.core.dictionary.model.AbstractTableAdapter; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.FeatureLine.Refinement; +import eu.engys.gui.mesh.panels.AbstractGeometryPanel.Size; +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; + +public class FeatureLinesRefinementTable extends AbstractTableAdapter { + + public static final String REFINEMENTS_LEVELS_KEY = "feature.lines.refinements.levels"; + public static final String LEVEL_LABEL = "Level"; + public static final String DISTANCE_M_LABEL = "Distance [m]"; + public static final String CELL_SIZE_LABEL = "Cell Size [m]"; + + private static final String[] COLUMN_NAMES = { DISTANCE_M_LABEL, LEVEL_LABEL, CELL_SIZE_LABEL}; + + private List refinements; + private Model model; + + public FeatureLinesRefinementTable(Model model, List refinements) { + super(COLUMN_NAMES); + setName(REFINEMENTS_LEVELS_KEY); + this.model = model; + this.refinements = refinements; +// System.out.println("FeatureLinesRefinementTable.FeatureLinesRefinementTable() size: " + refinements.size()); +// fixOldStyleLevels(); + } + + public JButton getButton() { + JButton b = new JButton(new AbstractAction("Edit") { + @Override + public void actionPerformed(ActionEvent e) { + getDialog().setVisible(true); + } + + }); + return b; + } + + private JDialog getDialog() { + final JDialog dialog = new JDialog(UiUtil.getActiveWindow(), "Refinement Level", ModalityType.MODELESS); + dialog.setName("line.adapter.dialog"); + + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + JButton okButton = new JButton(new AbstractAction("OK") { + @Override + public void actionPerformed(ActionEvent e) { + save(); + dialog.setVisible(false); + } + }); + okButton.setName("OK"); + buttonsPanel.add(okButton); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(new JScrollPane(this), BorderLayout.CENTER); + mainPanel.add(buttonsPanel, BorderLayout.SOUTH); + + dialog.add(mainPanel); + dialog.setSize(600, 400); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.getRootPane().setDefaultButton(okButton); + return dialog; + } + +// private void fixOldStyleLevels() { +// if (lineDictionary.found(LEVEL)) { +// Dictionary clone = new Dictionary(lineDictionary); +// String levelValue = clone.lookup(LEVEL); +// clone.remove(LEVEL); +// clone.add(LEVELS, "( ( 0.0 " + levelValue + " ) )"); +// this.lineDictionary = clone; +// } +// } + + protected void addRow() { + DoubleField d = ComponentsFactory.doubleField(); + IntegerField i = ComponentsFactory.intField(); + Size s = new Size(model, i); + s.recalculate(); + JTextField[] row = new JTextField[] {d, i, s}; + addRow(row); + } + + @Override + public void load() { + clear(); + for (Refinement ref : refinements) { + + DoubleField d = ComponentsFactory.doubleField(); + d.setDoubleValue(ref.getDistance()); + + IntegerField i = ComponentsFactory.intField(); + i.setIntValue(ref.getLevel()); + + Size s = new Size(model, i); + s.recalculate(); + + JTextField[] row = new JTextField[] {d, i, s}; + addRow(row, false); + } + +// if (getRowsMap().isEmpty()) { +// addRow(); +// } + } + + @Override + protected void save() { + refinements.clear(); + if (getRowsMap().isEmpty()) { + return; + } + + for (Integer index : getRowsMap().keySet()) { + JComponent[] row = getRowsMap().get(index); + int level = ((IntegerField) row[1]).getIntValue(); + double distance = ((DoubleField) row[0]).getDoubleValue(); + + refinements.add(new Refinement(distance, level)); + } + } + + public List getRefinements() { + return refinements; + } + + public void setRefinements(List refinements) { + this.refinements = refinements; + } + +} diff --git a/src/eu/engys/gui/mesh/panels/lines/FromFileBaseMeshPanel.java b/src/eu/engys/gui/mesh/panels/lines/FromFileBaseMeshPanel.java new file mode 100644 index 0000000..8e318ba --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/lines/FromFileBaseMeshPanel.java @@ -0,0 +1,192 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels.lines; + +import java.awt.HeadlessException; +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.SwingUtilities; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.Controller; +import eu.engys.core.dictionary.FileEditor; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Geometry; +import eu.engys.core.project.system.BlockMeshDict; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.RemoveSurfaceEvent; +import eu.engys.gui.mesh.actions.RunBlockMeshAction; +import eu.engys.util.LineSeparator; +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.ResourcesUtil; + +public class FromFileBaseMeshPanel { + + private static final Logger logger = LoggerFactory.getLogger(FromFileBaseMeshPanel.class); + + public static final HelyxFileFilter BLOCKMESHDICT_FILE_FILTER = new HelyxFileFilter("Block Mesh Dictionary", BlockMeshDict.BLOCK_DICT); + + public static final String FROM_FILE_LABEL = "From File"; + + public static final String EDIT_LABEL = "Edit"; + public static final String IMPORT_LABEL = "Import"; + public static final String CREATE_LABEL = "Create"; + + private Model model; + private Controller controller; + private DictionaryPanelBuilder builder; + private JButton editButton, previewButton, importButton; + + public FromFileBaseMeshPanel(Model model, Controller controller, DictionaryPanelBuilder builder) { + this.model = model; + this.controller = controller; + this.builder = builder; + builder.startGroup(FROM_FILE_LABEL); + layoutComponents(); + builder.endGroup(); + } + + private void layoutComponents() { + previewButton = new JButton(new RunBlockMeshAction(model, controller)); + previewButton.setName(CREATE_LABEL); + + editButton = new JButton(new AbstractAction(EDIT_LABEL, ResourcesUtil.getIcon("mesh.create.edit.icon")) { + @Override + public void actionPerformed(ActionEvent e) { + try { + showEditor(); + } catch (IOException ex) { + logger.error("Unable to open blockMeshDict editor", ex.getMessage()); + } + } + }); + editButton.setName(EDIT_LABEL); + + importButton = new JButton(new AbstractAction(IMPORT_LABEL, ResourcesUtil.getIcon("mesh.import.icon")) { + @Override + public void actionPerformed(ActionEvent e) { + HelyxFileChooser fc = createFileChooser(); + fc.showOpenDialog(); + } + }); + importButton.setName(IMPORT_LABEL); + builder.addSeparator(""); + builder.addComponent(importButton, editButton, previewButton); + } + + public void save(){ + model.getProject().getSystemFolder().getBlockMeshDict().setFromFile(true); + model.getGeometry().setAutoBoundingBox(false); + } + + public void updateBlock(){ + if (model.getGeometry().hasBlock()) { + EventManager.triggerEvent(this, new RemoveSurfaceEvent(model.getGeometry().getBlock())); + model.getGeometry().setBlock(Geometry.FAKE_BLOCK); + model.blockChanged(); + } + } + + private HelyxFileChooser createFileChooser() { + String initialPath = PrefUtil.getWorkDir(PrefUtil.LAST_IMPORT_DIR).getAbsolutePath(); + HelyxFileChooser chooser = new HelyxFileChooser(initialPath) { + @Override + public ReturnValue showOpenDialog() throws HeadlessException { + ReturnValue retVal = super.showOpenDialog(BLOCKMESHDICT_FILE_FILTER); + if (retVal.isApprove()) { + File newBlockDictFile = getSelectedFile(); + PrefUtil.putFile(PrefUtil.LAST_IMPORT_DIR, newBlockDictFile.getParentFile()); + try { + importBlockMeshDict(newBlockDictFile); + } catch (IOException e) { + logger.error("Error importing blockMeshDict from file" + e.getMessage()); + } + } + return retVal; + } + + }; + chooser.setSelectionMode(SelectionMode.FILES_ONLY); + chooser.setTitle("Select " + BlockMeshDict.BLOCK_DICT + " File"); + chooser.setParent(SwingUtilities.getWindowAncestor(builder.getPanel())); + return chooser; + } + + private void importBlockMeshDict(File toImportBlockMeshDict) throws IOException { + List newBlockMeshDictContent = FileUtils.readLines(toImportBlockMeshDict); + File currentBlockMeshDict = new File(model.getProject().getSystemFolder().getFileManager().getFile(), BlockMeshDict.BLOCK_DICT); + newBlockMeshDictContent.add(BlockMeshDict.FROM_FILE_LINE); + + String lineEnding = Util.isWindowsScriptStyle() ? LineSeparator.DOS.getSeparator() : LineSeparator.UNIX.getSeparator(); + FileUtils.writeLines(currentBlockMeshDict, null, newBlockMeshDictContent, lineEnding); + + showEditor(); + } + + private void showEditor() throws IOException { + final File blockMeshDictFile = new File(model.getProject().getSystemFolder().getFileManager().getFile(), BlockMeshDict.BLOCK_DICT); + final List lines = FileUtils.readLines(blockMeshDictFile); + + Runnable onShowRunnable = new Runnable() { + @Override + public void run() { + importButton.setEnabled(false); + editButton.setEnabled(false); + previewButton.setEnabled(false); + } + }; + Runnable onDisposeRunnable = new Runnable() { + @Override + public void run() { + importButton.setEnabled(true); + editButton.setEnabled(true); + previewButton.setEnabled(true); + try { + String lineEnding = Util.isWindowsScriptStyle() ? LineSeparator.DOS.getSeparator() : LineSeparator.UNIX.getSeparator(); + FileUtils.writeLines(blockMeshDictFile, null, lines, lineEnding); + } catch (IOException e) { + logger.error("Error saving blockMeshDict" + e.getMessage()); + } + } + }; + + FileEditor.getInstance().show(SwingUtilities.getWindowAncestor(builder.getPanel()), lines, BlockMeshDict.BLOCK_DICT, onShowRunnable, onDisposeRunnable, null); + } + +} diff --git a/src/eu/engys/gui/mesh/panels/lines/ImportFeatureLineAction.java b/src/eu/engys/gui/mesh/panels/lines/ImportFeatureLineAction.java new file mode 100644 index 0000000..6fa7158 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/lines/ImportFeatureLineAction.java @@ -0,0 +1,117 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels.lines; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.io.File; + +import javax.swing.AbstractAction; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.AddSurfaceEvent; +import eu.engys.util.ColorUtil; +import eu.engys.util.PrefUtil; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.ExecUtil; + +public class ImportFeatureLineAction extends AbstractAction { + + private static final Logger logger = LoggerFactory.getLogger(ImportFeatureLineAction.class); + + public static final String FROM_FILE_LABEL = "Open"; + private Model model; + + public ImportFeatureLineAction(Model model) { + super(FROM_FILE_LABEL); + this.model = model; + } + + @Override + public void actionPerformed(ActionEvent e) { + HelyxFileChooser fc = getFeatureLinesFileChooser(); + HelyxFileFilter filter = new HelyxFileFilter("EMesh File (*.eMesh, *.eMesh.gz)", "eMesh", "eMesh.gz"); + fc.setSelectionMode(SelectionMode.FILES_ONLY); + fc.setMultiSelectionEnabled(true); + + ReturnValue returnedValue = fc.showOpenDialog(filter); + + if (returnedValue.isApprove()) { + importFiles(fc.getSelectedFiles()); + } + } + + private HelyxFileChooser getFeatureLinesFileChooser() { + File lastDir = PrefUtil.getWorkDir(PrefUtil.LAST_IMPORT_DIR); + HelyxFileChooser fc = new HelyxFileChooser(lastDir.getAbsolutePath()); + fc.setMultiSelectionEnabled(true); + fc.setSelectionMode(SelectionMode.FILES_ONLY); + return fc; + } + + private void importFiles(File[] files) { + if (files != null && files.length > 0) { + PrefUtil.putFile(PrefUtil.LAST_IMPORT_DIR, files[0].getParentFile()); + + for (File file : files) { + importFile(file); + } + } + } + + public void importFile(final File file) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + // if (!alreadyImported(file)) { + FeatureLine line = model.getGeometry().getFactory().readLine(file); + addLine(line); + // } + } + }); + } + + public void addLine(FeatureLine line) { + logger.debug("ADD LINE " + line); + line.setColor(nextColor()); + model.getGeometry().addLine(line); + model.geometryChanged(line); + + EventManager.triggerEvent(this, new AddSurfaceEvent(line)); + } + + private Color nextColor() { + return ColorUtil.getColor(model.getGeometry().getLines().size()); + } +} diff --git a/src/eu/engys/gui/mesh/panels/lines/UserDefinedBaseMeshPanel.java b/src/eu/engys/gui/mesh/panels/lines/UserDefinedBaseMeshPanel.java new file mode 100644 index 0000000..a0544b1 --- /dev/null +++ b/src/eu/engys/gui/mesh/panels/lines/UserDefinedBaseMeshPanel.java @@ -0,0 +1,240 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.mesh.panels.lines; + +import static eu.engys.core.project.geometry.Surface.MAX_KEY; +import static eu.engys.core.project.geometry.Surface.MIN_KEY; +import static eu.engys.core.project.system.BlockMeshDict.ELEMENTS_KEY; +import static eu.engys.util.ui.ComponentsFactory.doublePointField; +import static eu.engys.util.ui.ComponentsFactory.labelField; + +import java.awt.Dimension; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JToggleButton; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldChangeListener; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.dictionary.model.DictionaryPanelBuilder; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.geometry.surface.MultiPlane; +import eu.engys.core.project.system.SystemFolder; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.ChangeSurfaceEvent; +import eu.engys.gui.view3D.BoxEventButton; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; + +public class UserDefinedBaseMeshPanel { + + public static final String USER_DEFINED_LABEL = "User Defined"; + + public static final String CELL_SIZE_LABEL = "Cell Size [m]"; + public static final String N_ELEMENTS_LABEL = "Elements"; + public static final String MAX_LABEL = "Max"; + public static final String MIN_LABEL = "Min"; + + private final static Icon FIT_ICON = ResourcesUtil.getIcon("fit.boundingbox.icon"); + + private DictionaryPanelBuilder builder; + + private DoubleField[] boxMin; + private DoubleField[] boxMax; + private DoubleField[] cellSize; + private JToggleButton showBoxButton; + + private Model model; + + private DictionaryModel minMaxModel; + private UpdateBlockListener blockListener; + + public UserDefinedBaseMeshPanel(Model model, DictionaryPanelBuilder builder) { + this.model = model; + this.builder = builder; + + minMaxModel = new DictionaryModel(new Dictionary(defaultBoxModelDict)); + builder.startDictionary(USER_DEFINED_LABEL, minMaxModel); + layoutComponents(); + builder.endDictionary(); + } + + private void layoutComponents() { + blockListener = new UpdateBlockListener(); + + boxMin = minMaxModel.bindPoint(MIN_KEY, 4, blockListener); + boxMax = minMaxModel.bindPoint(MAX_KEY, 4, blockListener); + showBoxButton = new BoxEventButton(boxMin, boxMax); + + builder.addComponent("", labelField("X"), labelField("Y"), labelField("Z")); + builder.addComponent(MIN_LABEL, boxMin[0], boxMin[1], boxMin[2], showBoxButton); + builder.addComponentAndSpan(MAX_LABEL, boxMax); + + IntegerField[] elements = minMaxModel.bindIntegerArray(ELEMENTS_KEY, 3, blockListener); + JButton fitButton = new JButton(new FitBoundingBoxAction()); + fitButton.setPreferredSize(new Dimension(36, 48)); + + builder.addComponent(N_ELEMENTS_LABEL, elements[0], elements[1], elements[2], fitButton); + cellSize = doublePointField(3); + cellSize[0].setEnabled(false); + cellSize[1].setEnabled(false); + cellSize[2].setEnabled(false); + builder.addComponentAndSpan(CELL_SIZE_LABEL, cellSize); + } + + public void load() { + blockListener.setAdjusting(true); + + MultiPlane block = model.getGeometry().getBlock(); + minMaxModel.setDictionary(block.getGeometryDictionary()); + updateDelta(); + + blockListener.setAdjusting(false); + } + + public void save() { + model.getProject().getSystemFolder().getBlockMeshDict().setFromFile(false); + model.getGeometry().setAutoBoundingBox(false); + model.getGeometry().setCellSize(new double[] { cellSize[0].getDoubleValue(), cellSize[1].getDoubleValue(), cellSize[2].getDoubleValue() }); + model.getGeometry().saveUserDefinedBlock(model, minMaxModel.getDictionary()); + } + + public void updateBlock() { + if (model.getGeometry().hasBlock()) { + editBlock(); + } else { + addBlock(); + } + updateDelta(); + save(); + } + + private void editBlock() { + MultiPlane block = model.getGeometry().getBlock(); + block.setGeometryDictionary(minMaxModel.getDictionary()); + + EventManager.triggerEvent(this, new ChangeSurfaceEvent(block, false)); + } + + private void addBlock() { + SystemFolder systemFolder = model.getProject().getSystemFolder(); + model.getGeometry().loadBlock(systemFolder.getBlockMeshDict(), systemFolder.getSnappyHexMeshDict()); + model.blockChanged(); + minMaxModel.setDictionary(model.getGeometry().getBlock().getGeometryDictionary()); + EventManager.triggerEvent(this, new ChangeSurfaceEvent(model.getGeometry().getBlock(), true)); + } + + private void updateDelta() { + double[] d = model.getGeometry().getBlock().getDelta(); + for (int i = 0; i < d.length; i++) { + cellSize[i].setDoubleValue(d[i]); + } + } + + public void turnOffShowBoxButton() { + if (showBoxButton.isSelected()) { + showBoxButton.doClick(); + } + } + + public void resetToDefault() { + minMaxModel.setDictionary(new Dictionary(defaultBoxModelDict)); + } + + private Dictionary defaultBoxModelDict = new Dictionary("block") { + { + add(MIN_KEY, new String[] { "-1.0", "-1.0", "-1.0" }); + add(MAX_KEY, new String[] { "1.0", "1.0", "1.0" }); + add("patch0", "ffminx"); + add("patch1", "ffminx"); + add("patch2", "ffminx"); + add("patch3", "ffmaxx"); + add("patch4", "ffminz"); + add("patch5", "ffmaxz"); + add(ELEMENTS_KEY, new String[] { "10", "10", "10" }); + } + }; + + private class UpdateBlockListener implements FieldChangeListener { + + boolean adjusting = false; + + @Override + public void actionPerformed(ActionEvent e) { + } + + @Override + public void setAdjusting(boolean b) { + this.adjusting = b; + } + + @Override + public boolean isAdjusting() { + return adjusting; + } + + @Override + public void fieldChanged() { + if (!isAdjusting()) { + updateBlock(); + } + } + } + + private class FitBoundingBoxAction extends AbstractAction { + + public FitBoundingBoxAction() { + super("", FIT_ICON); + putValue(SHORT_DESCRIPTION, "Fit Bounding Box"); + } + + @Override + public void actionPerformed(ActionEvent e) { + BoundingBox bb = model.getGeometry().computeBoundingBox(); + + blockListener.setAdjusting(true); + + boxMin[0].setDoubleValue(bb.getXmin()); + boxMin[1].setDoubleValue(bb.getYmin()); + boxMin[2].setDoubleValue(bb.getZmin()); + + boxMax[0].setDoubleValue(bb.getXmax()); + boxMax[1].setDoubleValue(bb.getYmax()); + boxMax[2].setDoubleValue(bb.getZmax()); + + blockListener.setAdjusting(false); + + updateBlock(); + } + + } + +} diff --git a/src/eu/engys/gui/solver/DefaultRunOptionsPanel.java b/src/eu/engys/gui/solver/DefaultRunOptionsPanel.java new file mode 100644 index 0000000..4f0fae9 --- /dev/null +++ b/src/eu/engys/gui/solver/DefaultRunOptionsPanel.java @@ -0,0 +1,168 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver; + +import static eu.engys.util.ui.ComponentsFactory.labelField; +import static eu.engys.util.ui.ComponentsFactory.stringField; + +import java.awt.Dimension; +import java.io.File; +import java.nio.file.Paths; + +import javax.inject.Inject; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import net.java.dev.designgridlayout.Componentizer; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.StringField; + +public class DefaultRunOptionsPanel extends DefaultGUIPanel { + + private static final String RUN = "Run Options"; + public static final String SOLVER_LABEL = "Solver"; + public static final String LOG_FILE_LABEL = "Log File"; + public static final String PROPERTIES_LABEL = "Properties"; + + private JLabel solverName; + // private IntegerField nProcessors; + // private JCheckBox parallel; + private StringField log; + + @Inject + public DefaultRunOptionsPanel(Model model) { + super(RUN, model); + } + + protected JComponent layoutComponents() { + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(getActionsPanel()); + builder.addComponent(getPropertiesPanel()); + builder.addComponent(getServerPanel()); + builder.addComponent(getQueuePanel()); + return builder.removeMargins().getPanel(); + } + + protected JComponent getServerPanel() { + return new JPanel(); + } + + protected JComponent getQueuePanel() { + return new JPanel(); + } + + protected JComponent getPropertiesPanel() { + PanelBuilder properties = new PanelBuilder(); + properties.getPanel().setBorder(BorderFactory.createTitledBorder(PROPERTIES_LABEL)); + properties.addComponent(SOLVER_LABEL, solverName); + // properties.addComponent("Parallel Run", parallel); + // properties.addComponent("Number Of Processors", nProcessors); + properties.addComponent(LOG_FILE_LABEL, log); + return properties.getPanel(); + } + + protected JComponent getActionsPanel() { + solverName = labelField(""); + // parallel = checkField(); + // nProcessors = intField(); + log = stringField(); + + solverName.setEnabled(false); + // parallel.setEnabled(false); + // nProcessors.setEnabled(false); + + PanelBuilder actions = new PanelBuilder(); + actions.getPanel().setBorder(BorderFactory.createTitledBorder("Actions")); + + Action runSolverAction = ActionManager.getInstance().get("solver.run"); + Action editRunSolverAction = ActionManager.getInstance().get("solver.run.edit"); + + JButton runSolverButton = new JButton(runSolverAction); + JButton editRunSolverButton = new JButton(editRunSolverAction); + + runSolverButton.setPreferredSize(new Dimension(120, runSolverButton.getPreferredSize().height)); + + JComponent c1 = Componentizer.create().minToPref(runSolverButton).fixedPref(editRunSolverButton).minAndMore(new JLabel()).component(); + actions.addComponent(c1); + + JComponent[] cs = getExtraButtons(); + for (JComponent c : cs) { + actions.addComponent(c); + } + return actions.getPanel(); + } + + protected JComponent[] getExtraButtons() { + return new JComponent[0]; + } + + @Override + public void load() { + if (model.getSolverModel().getLogFile() != null) { + File logFile = Paths.get(model.getProject().getBaseDir().getAbsolutePath(), "log", model.getSolverModel().getLogFile()).toFile(); + if (logFile == null || !logFile.exists() || !logFile.isFile()) { + setDefaultLogName(); + } else { + log.setText(logFile.getName()); + solverName.setText(model.getState().getSolver().getName()); + } + } else { + setDefaultLogName(); + } + // parallel.setSelected(model.getProject().isParallel()); + // nProcessors.setValue(model.getProject().getProcessors()); + } + + @Override + public void save() { + super.save(); + model.getSolverModel().setLogFile(log.getText()); + } + + @Override + public void stateChanged() { + setDefaultLogName(); + } + + @Override + public void solverChanged() { + setDefaultLogName(); + } + + public void setDefaultLogName() { + String application = model.getState().getSolver().getName(); + solverName.setText(application); + log.setText(application + ".log"); + } + +} diff --git a/src/eu/engys/gui/solver/ReloadOnFinish.java b/src/eu/engys/gui/solver/ReloadOnFinish.java new file mode 100644 index 0000000..3ae8610 --- /dev/null +++ b/src/eu/engys/gui/solver/ReloadOnFinish.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver; + +import eu.engys.core.controller.Command; +import eu.engys.core.controller.Controller; +import eu.engys.core.project.state.ServerState; +import eu.engys.gui.solver.postprocessing.ServerListener; + +public class ReloadOnFinish implements ServerListener { + + private Controller controller; + + public ReloadOnFinish(Controller controller) { + this.controller = controller; + } + + @Override + public void serverChanged(ServerState serverState) { + if (serverState.getCommand().equals(Command.RUN_CASE) || serverState.getCommand().equals(Command.RUN_ALL)) { + if (serverState.getSolverState().isFinished() || serverState.getSolverState().isError()) { + if (controller.getListener() != null) { + controller.getListener().afterRunCase(); + } + } + } + } +} diff --git a/src/eu/engys/gui/solver/ReopenOnInitialised.java b/src/eu/engys/gui/solver/ReopenOnInitialised.java new file mode 100644 index 0000000..6565ef3 --- /dev/null +++ b/src/eu/engys/gui/solver/ReopenOnInitialised.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver; + +import eu.engys.core.controller.Command; +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.Controller.OpenOptions; +import eu.engys.core.project.state.ServerState; +import eu.engys.gui.solver.postprocessing.ServerListener; + +public class ReopenOnInitialised implements ServerListener { + + private Controller controller; + + public ReopenOnInitialised(Controller controller) { + this.controller = controller; + } + + @Override + public void serverChanged(ServerState serverState) { + if (serverState.getCommand().equals(Command.INITIALISE_FIELDS)) { + if (serverState.getSolverState().isInitialised()) { + if (controller.getListener() != null) { + controller.reopenCase(OpenOptions.MESH_ONLY); + } + } + } + } + +} diff --git a/src/eu/engys/gui/solver/ReopenOnMeshed.java b/src/eu/engys/gui/solver/ReopenOnMeshed.java new file mode 100644 index 0000000..04199e0 --- /dev/null +++ b/src/eu/engys/gui/solver/ReopenOnMeshed.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver; + +import eu.engys.core.controller.Command; +import eu.engys.core.controller.Controller; +import eu.engys.core.controller.Controller.OpenOptions; +import eu.engys.core.project.state.ServerState; +import eu.engys.gui.solver.postprocessing.ServerListener; + +public class ReopenOnMeshed implements ServerListener { + + private Controller controller; + + public ReopenOnMeshed(Controller controller) { + this.controller = controller; + } + + @Override + public void serverChanged(ServerState serverState) { + if (serverState.getCommand().equals(Command.CREATE_MESH)) { + if (serverState.getSolverState().isMeshed()) { + if (controller.getListener() != null) { + controller.reopenCase(OpenOptions.MESH_ONLY); + } + } + } + } + +} diff --git a/src/eu/engys/gui/solver/Solver.java b/src/eu/engys/gui/solver/Solver.java new file mode 100644 index 0000000..fe1cdcf --- /dev/null +++ b/src/eu/engys/gui/solver/Solver.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.solver; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +public @interface Solver { + +} diff --git a/src/eu/engys/gui/solver/Solver3DElement.java b/src/eu/engys/gui/solver/Solver3DElement.java new file mode 100644 index 0000000..1c29c4c --- /dev/null +++ b/src/eu/engys/gui/solver/Solver3DElement.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.solver; + +import java.util.Set; + +import javax.inject.Inject; + +import eu.engys.gui.GUIPanel; +import eu.engys.gui.view.AbstractView3DElement; +import eu.engys.gui.view3D.CanvasPanel; + +public class Solver3DElement extends AbstractView3DElement { + + @Inject + public Solver3DElement(@Solver Set panels) { + super(panels); + } + +// @Override +// public void start(CanvasPanel view3D) { +// view3D.applyContext(CaseSetup3DElement.class); +// } +// +// @Override +// public void save(CanvasPanel view3d) { +// view3d.dumpContext(CaseSetup3DElement.class); +// } + + @Override + public void load(CanvasPanel view3D) { + view3D.getMeshController().newContext(getClass()); + view3D.getGeometryController().newEmptyContext(getClass()); + } + +} diff --git a/src/eu/engys/gui/solver/SolverElement.java b/src/eu/engys/gui/solver/SolverElement.java new file mode 100644 index 0000000..170f83d --- /dev/null +++ b/src/eu/engys/gui/solver/SolverElement.java @@ -0,0 +1,114 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver; + +import java.util.Observable; +import java.util.Observer; +import java.util.Set; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.Model; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.gui.Actions; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.view.AbstractViewElement; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElementPanel; +import eu.engys.util.plaf.ILookAndFeel; + +public class SolverElement extends AbstractViewElement { + + private static final Logger logger = LoggerFactory.getLogger(SolverElement.class); + + private ViewElementPanel viewElementPanel; + private Model model; + + private Observer solverModelObserver; + + @Inject + public SolverElement(Model model, @Solver String title, @Solver Set panels, Set modules, @Solver View3DElement view3DElement, @Solver Actions actions, ILookAndFeel lookAndFeel) { + super(title, panels, modules, view3DElement, actions, lookAndFeel); + this.model = model; + } + + @Override + public void layoutComponents() { + viewElementPanel = new ViewElementPanel(this); + solverModelObserver = new Observer() { + @Override + public void update(Observable o, Object arg) { + //arg is null, see SolverModel.setState +// logger.debug("Observerd a change"); + actions.update(); + } + }; + super.layoutComponents(); + } + + @Override + public int getPreferredWidth() { + return 800; + } + + @Override + public ViewElementPanel getPanel() { + return viewElementPanel; + } + + @Override + public void start() { + super.start(); + model.getSolverModel().addObserver(solverModelObserver); + } + + @Override + public void stop() { + super.stop(); + model.getSolverModel().deleteObserver(solverModelObserver); + } + + @Override + public void load(Model model) { + super.load(model); + } + + @Override + public ProjectReader getReader() { + return null; + } + + @Override + public ProjectWriter getWriter() { + return null; + } + +} diff --git a/src/eu/engys/gui/solver/SolverRuntimeControlsPanel.java b/src/eu/engys/gui/solver/SolverRuntimeControlsPanel.java new file mode 100644 index 0000000..4ca6b13 --- /dev/null +++ b/src/eu/engys/gui/solver/SolverRuntimeControlsPanel.java @@ -0,0 +1,373 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver; + +import static eu.engys.core.project.system.ControlDict.ADJUSTABLE_RUN_TIME_KEY; +import static eu.engys.core.project.system.ControlDict.ADJUST_TIME_STEP_KEY; +import static eu.engys.core.project.system.ControlDict.DELTA_T_KEY; +import static eu.engys.core.project.system.ControlDict.END_TIME_KEY; +import static eu.engys.core.project.system.ControlDict.FUNCTIONS_KEY; +import static eu.engys.core.project.system.ControlDict.GRAPH_FORMAT_KEY; +import static eu.engys.core.project.system.ControlDict.GRAPH_FORMAT_VALUE; +import static eu.engys.core.project.system.ControlDict.MAX_ALPHA_CO_KEY; +import static eu.engys.core.project.system.ControlDict.MAX_CO_KEY; +import static eu.engys.core.project.system.ControlDict.MAX_DELTA_T_KEY; +import static eu.engys.core.project.system.ControlDict.PURGE_WRITE_KEY; +import static eu.engys.core.project.system.ControlDict.RUN_TIME_VALUE; +import static eu.engys.core.project.system.ControlDict.START_FROM_KEY; +import static eu.engys.core.project.system.ControlDict.START_FROM_VALUES; +import static eu.engys.core.project.system.ControlDict.START_TIME_KEY; +import static eu.engys.core.project.system.ControlDict.START_TIME_VALUE; +import static eu.engys.core.project.system.ControlDict.STOP_AT_KEY; +import static eu.engys.core.project.system.ControlDict.TIME_FORMAT_KEY; +import static eu.engys.core.project.system.ControlDict.TIME_FORMAT_VALUES; +import static eu.engys.core.project.system.ControlDict.TIME_PRECISION_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_COMPRESSION_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_COMPRESSION_VALUES; +import static eu.engys.core.project.system.ControlDict.WRITE_CONTROL_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_CONTROL_VALUES; +import static eu.engys.core.project.system.ControlDict.WRITE_FORMAT_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_FORMAT_VALUES; +import static eu.engys.core.project.system.ControlDict.WRITE_INTERVAL_KEY; +import static eu.engys.core.project.system.ControlDict.WRITE_PRECISION_KEY; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.ADJUSTABLE_TIME_STEP_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.DATA_WRITING_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.DELTA_T_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.END_TIME_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.GRAPH_FORMAT_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.GRAPH_FORMAT_LABELS; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.MAX_COURANT_ALPHA_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.MAX_COURANT_NUMBER_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.MAX_TIME_STEP_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.PURGE_WRITE_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.RUNTIME_CONTROLS; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.START_FROM_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.START_FROM_LABELS; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.TIME_FORMAT_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.TIME_FORMAT_LABELS; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.TIME_PRECISION_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.TIME_SETTINGS_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.WRITE_COMPRESSION_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.WRITE_COMPRESSION_LABELS; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.WRITE_CONTROL_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.WRITE_CONTROL_LABELS; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.WRITE_FORMAT_LABEL; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.WRITE_FORMAT_LABELS; +import static eu.engys.gui.casesetup.RuntimeControlsPanel.WRITE_PRECISION_LABEL; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JPanel; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.Time; +import eu.engys.core.project.system.ControlDict; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.util.progress.SilentMonitor; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.SelectionValueConfigurator; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.DoubleField; + +public class SolverRuntimeControlsPanel extends DefaultGUIPanel { + + private static final ImageIcon APPLY_ICON = new ImageIcon(SolverRuntimeControlsPanel.class.getClassLoader().getResource("eu/engys/resources/images/tick16.png")); + + private DictionaryModel dictionaryModel; + private JCheckBox adjustableTime; + private JComponent maxCourantNumber; + private JComponent maxAlphaCourant; + private JComponent maxTimeStep; + private DoubleField deltaT; + private Time time = null; + + private JComboBox startFrom; + private DoubleField startTime; + private PropertyChangeListener startFromListener; + + private boolean isSaving = false; + + private ActionListener adjustableTimeListener; + + @Inject + public SolverRuntimeControlsPanel(Model model) { + super(RUNTIME_CONTROLS, model); + } + + @Override + public String getName() { + return "Solver " + RUNTIME_CONTROLS; + } + + @Override + public void start() { + super.start(); + if (model.getSolverModel().getServerState().getSolverState().isRunning()) { + fixGUI(); + UiUtil.enable(this); + } else { + UiUtil.disable(this); + } + } + + protected JComponent layoutComponents() { + dictionaryModel = new DictionaryModel(new Dictionary("")); + PanelBuilder timeBuilder = new PanelBuilder(); + + startFrom = dictionaryModel.bindSelection(START_FROM_KEY, START_FROM_VALUES, START_FROM_LABELS); + startTime = dictionaryModel.bindDouble(START_TIME_KEY); + DoubleField endTime = dictionaryModel.bindDouble(END_TIME_KEY); + + timeBuilder.addComponent(START_FROM_LABEL, startFrom, startTime); + timeBuilder.addComponent(END_TIME_LABEL, endTime); + + startTime.setEnabled(false); + startFromListener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + startTime.setEnabled(START_TIME_VALUE.equals(evt.getNewValue())); + } + }; + startFrom.addPropertyChangeListener("value", startFromListener); + + timeBuilder.addComponent(DELTA_T_LABEL, deltaT = dictionaryModel.bindDouble(DELTA_T_KEY)); + + timeBuilder.addComponent(ADJUSTABLE_TIME_STEP_LABEL, adjustableTime = dictionaryModel.bindBoolean(ADJUST_TIME_STEP_KEY)); + timeBuilder.addComponent(MAX_COURANT_NUMBER_LABEL, maxCourantNumber = dictionaryModel.bindDouble(MAX_CO_KEY)); + timeBuilder.addComponent(MAX_COURANT_ALPHA_LABEL, maxAlphaCourant = dictionaryModel.bindDouble(MAX_ALPHA_CO_KEY)); + timeBuilder.addComponent(MAX_TIME_STEP_LABEL, maxTimeStep = dictionaryModel.bindDouble(MAX_DELTA_T_KEY)); + + adjustableTimeListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + maxCourantNumber.setEnabled(adjustableTime.isSelected()); + maxAlphaCourant.setEnabled(adjustableTime.isSelected() && model.getState().getMultiphaseModel().isMultiphase()); + maxTimeStep.setEnabled(adjustableTime.isSelected()); + } + }; + adjustableTime.setSelected(false); + adjustableTime.addActionListener(adjustableTimeListener); + + maxCourantNumber.setEnabled(false); + maxAlphaCourant.setEnabled(false); + maxTimeStep.setEnabled(false); + + PanelBuilder dataWriteBuilder = new PanelBuilder(); + SelectionValueConfigurator conf = new SelectionValueConfigurator() { + @Override + public String write(String value) { + if (value != null && value.equals(RUN_TIME_VALUE) && adjustableTime.isSelected()) + return ADJUSTABLE_RUN_TIME_KEY; + return value; + } + + @Override + public String read(String value) { + if (value != null && value.equals(ADJUSTABLE_RUN_TIME_KEY)) + return RUN_TIME_VALUE; + return value; + } + }; + dataWriteBuilder.addComponent(WRITE_CONTROL_LABEL, dictionaryModel.bindSelection(WRITE_CONTROL_KEY, WRITE_CONTROL_VALUES, WRITE_CONTROL_LABELS, conf), dictionaryModel.bindDouble(WRITE_INTERVAL_KEY)); + dataWriteBuilder.addComponent(PURGE_WRITE_LABEL, dictionaryModel.bindIntegerPositive(PURGE_WRITE_KEY)); + dataWriteBuilder.addComponent(WRITE_FORMAT_LABEL, dictionaryModel.bindSelection(WRITE_FORMAT_KEY, WRITE_FORMAT_VALUES, WRITE_FORMAT_LABELS)); + dataWriteBuilder.addComponent(WRITE_PRECISION_LABEL, dictionaryModel.bindIntegerPositive(WRITE_PRECISION_KEY)); + dataWriteBuilder.addComponent(WRITE_COMPRESSION_LABEL, dictionaryModel.bindSelection(WRITE_COMPRESSION_KEY, WRITE_COMPRESSION_VALUES, WRITE_COMPRESSION_LABELS)); + dataWriteBuilder.addComponent(TIME_FORMAT_LABEL, dictionaryModel.bindSelection(TIME_FORMAT_KEY, TIME_FORMAT_VALUES, TIME_FORMAT_LABELS)); + dataWriteBuilder.addComponent(TIME_PRECISION_LABEL, dictionaryModel.bindIntegerPositive(TIME_PRECISION_KEY)); + dataWriteBuilder.addComponent(GRAPH_FORMAT_LABEL, dictionaryModel.bindSelection(GRAPH_FORMAT_KEY, GRAPH_FORMAT_VALUE, GRAPH_FORMAT_LABELS)); + + JPanel timePanel = timeBuilder.margins(.5, .5, .5, .5).getPanel(); + timePanel.setBorder(BorderFactory.createTitledBorder(TIME_SETTINGS_LABEL)); + timePanel.setName(TIME_SETTINGS_LABEL); + + JPanel dataWritePanel = dataWriteBuilder.margins(.5, .5, .5, .5).getPanel(); + dataWritePanel.setBorder(BorderFactory.createTitledBorder(DATA_WRITING_LABEL)); + dataWritePanel.setName(DATA_WRITING_LABEL); + + PanelBuilder builder = new PanelBuilder(); + builder.addComponent(timePanel); + builder.addComponent(dataWritePanel); + + List actionsList = new ArrayList(); + JButton applyButton = new JButton(new WriteControlDictAction()); + applyButton.setName("Apply"); + actionsList.add(applyButton); + + JComponent buttonsPanel = UiUtil.getCommandRow(actionsList); + buttonsPanel.setBorder(BorderFactory.createEmptyBorder()); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(buttonsPanel, BorderLayout.NORTH); + mainPanel.add(builder.removeMargins().getPanel(), BorderLayout.CENTER); + + return mainPanel; + } + + @Override + public void load() { + this.time = model.getState().getTime(); + loadControlDict(); + fixGUI(); + } + + @Override + public void save() { + ControlDict controlDict = getModel().getProject().getSystemFolder().getControlDict(); + if (controlDict != null) { + boolean changed = hasControlDictChanged(controlDict); + controlDict.merge(dictionaryModel.getDictionary()); + controlDict.add(STOP_AT_KEY, END_TIME_KEY); + if (changed) { + isSaving = true; + model.projectChanged(); + isSaving = false; + } + } + } + + private boolean hasControlDictChanged(ControlDict controlDict) { + ControlDict d = new ControlDict(controlDict); + d.remove(ControlDict.FUNCTIONS_KEY); + return !d.toString().equals(dictionaryModel.getDictionary().toString()); + } + + @Override + public void stateChanged() { + super.stateChanged(); + State state = model.getState(); + if (this.time == null || state.getTime() != this.time) { + this.time = state.getTime(); + loadControlDict(); + } else { + /* + * Il file controlDict ora contiene i valori di default. Lo mergio con i valori della GUI per non perdere i cambiamenti fatti. Ovviamente questo significa che quello che ce nella GUI...rimane! + */ + Dictionary controlDict = model.getProject().getSystemFolder().getControlDict(); + if (controlDict != null) { + controlDict.merge(dictionaryModel.getDictionary()); + } + } + } + + @Override + public void projectChanged() { + if (!isSaving) { + loadControlDict(); + } + } + + private void loadControlDict() { + removeListeners(); + + ControlDict controlDict = getModel().getProject().getSystemFolder().getControlDict(); + if (controlDict != null) { + Dictionary dictionary = new Dictionary(controlDict); + dictionary.remove(FUNCTIONS_KEY); + dictionaryModel.setDictionary(dictionary); + } + + addListeners(); + } + + private void removeListeners() { + startFrom.removePropertyChangeListener("value", startFromListener); + adjustableTime.removeActionListener(adjustableTimeListener); + } + + private void addListeners() { + startFrom.addPropertyChangeListener("value", startFromListener); + adjustableTime.addActionListener(adjustableTimeListener); + } + + public void fixGUI() { + if (model.getSolverModel().getServerState().getSolverState().isRunning()) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + _fixGUI(); + } + }); + } + } + + private void _fixGUI() { + startTime.setEnabled(START_TIME_VALUE.equals(startFrom.getSelectedItem())); + + State state = model.getState(); + boolean isTransient = state.isTransient(); + boolean isSteadyMultiphase = state.isSteady() && state.getMultiphaseModel().isMultiphase(); + boolean isSteadyCoupled = state.isSteady() && state.getSolverType().isCoupled(); + + if (isTransient || isSteadyMultiphase || isSteadyCoupled) { + deltaT.setEnabled(true); + } else { + deltaT.setEnabled(false); + deltaT.setDoubleValue(1); + } + + adjustableTime.setEnabled((isTransient || isSteadyMultiphase) && !isSonic(state)); + maxCourantNumber.setEnabled((isTransient || isSteadyMultiphase) && adjustableTime.isSelected()); + maxAlphaCourant.setEnabled((isTransient || isSteadyMultiphase) && adjustableTime.isSelected() && state.getMultiphaseModel().isMultiphase()); + maxTimeStep.setEnabled((isTransient || isSteadyMultiphase) && adjustableTime.isSelected()); + } + + private boolean isSonic(State state) { + return state.isHighMach() && state.getSolverFamily().isPimple(); + } + + private class WriteControlDictAction extends AbstractAction { + + public WriteControlDictAction() { + super("Apply", APPLY_ICON); + } + + @Override + public void actionPerformed(ActionEvent e) { + // TODO check remote case + save(); + model.getProject().getSystemFolder().writeControlDict(new SilentMonitor()); + } + } +} diff --git a/src/eu/engys/gui/solver/UpdateClientState.java b/src/eu/engys/gui/solver/UpdateClientState.java new file mode 100644 index 0000000..84a88f6 --- /dev/null +++ b/src/eu/engys/gui/solver/UpdateClientState.java @@ -0,0 +1,45 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver; + +import eu.engys.core.project.Model; +import eu.engys.core.project.state.ServerState; +import eu.engys.gui.solver.postprocessing.ServerListener; + +public class UpdateClientState implements ServerListener { + + private Model model; + + public UpdateClientState(Model model) { + this.model = model; + } + + @Override + public void serverChanged(ServerState serverState) { + model.getSolverModel().setServerState(serverState); + } + +} diff --git a/src/eu/engys/gui/solver/actions/DefaultSolverActions.java b/src/eu/engys/gui/solver/actions/DefaultSolverActions.java new file mode 100644 index 0000000..640d140 --- /dev/null +++ b/src/eu/engys/gui/solver/actions/DefaultSolverActions.java @@ -0,0 +1,86 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.actions; + +import static eu.engys.util.ui.UiUtil.createToolBarButton; + +import javax.inject.Inject; +import javax.swing.Action; +import javax.swing.Box; +import javax.swing.JToolBar; + +import eu.engys.core.controller.Controller; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.gui.Actions; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public abstract class DefaultSolverActions implements Actions { + + private final Action launchAction; + + private JToolBar toolbar; + protected Model model; + + @Inject + public DefaultSolverActions(Model model, Controller controller) { + this.model = model; + this.launchAction = ActionManager.getInstance().get("solver.run"); + } + + @Override + public JToolBar toolbar() { + toolbar = UiUtil.getToolbar("view.element.toolbar"); + + toolbar.add(createToolBarButton(launchAction)); + toolbar.addSeparator(); + addExtraActions(); + toolbar.add(Box.createHorizontalGlue()); + return toolbar; + } + + public JToolBar getToolbar() { + return toolbar; + } + + protected abstract void addExtraActions(); + + @Override + public void update() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + boolean isRemote = model.getSolverModel().isRemote(); + boolean hasMesh = !model.getPatches().isEmpty(); + boolean isRunning = model.getSolverModel() != null && model.getSolverModel().getServerState() != null && model.getSolverModel().getServerState().getSolverState().isRunning(); + boolean isSolutionSet = model.getState().areTimeAndFlowAndTurbulenceChoosen(); + launchAction.setEnabled(hasMesh && !isRunning && isSolutionSet); + } + }); + } + +} diff --git a/src/eu/engys/gui/solver/actions/EditRunSolverAction.java b/src/eu/engys/gui/solver/actions/EditRunSolverAction.java new file mode 100644 index 0000000..dfe61de --- /dev/null +++ b/src/eu/engys/gui/solver/actions/EditRunSolverAction.java @@ -0,0 +1,46 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.solver.actions; + + +//public class EditRunSolverAction extends ViewAction { +// +// private static final String EDIT_RUN_SOLVER_LABEL = ResourcesUtil.getString("solver.run.edit.label"); +// private static final String EDIT_RUN_SOLVER_TOOLTIP = ResourcesUtil.getString("solver.run.edit.tooltip"); +// private static final Icon EDIT_RUN_SOLVER_ICON = ResourcesUtil.getIcon("solver.run.edit.icon"); +// +// private Controller controller; +// +// public EditRunSolverAction(Controller controller) { +// super(EDIT_RUN_SOLVER_LABEL, EDIT_RUN_SOLVER_ICON, EDIT_RUN_SOLVER_TOOLTIP); +// this.controller = controller; +// } +// +// public void actionPerformed(ActionEvent e) { +// controller.editRunCaseScript(); +// } +//} diff --git a/src/eu/engys/gui/solver/actions/OpenParaviewAction.java b/src/eu/engys/gui/solver/actions/OpenParaviewAction.java new file mode 100644 index 0000000..985e864 --- /dev/null +++ b/src/eu/engys/gui/solver/actions/OpenParaviewAction.java @@ -0,0 +1,108 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.actions; + +import static eu.engys.core.OpenFOAMEnvironment.getEnvironment; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.FilenameFilter; + +import javax.swing.Icon; +import javax.swing.JOptionPane; + +import eu.engys.core.OpenFOAMEnvironment; +import eu.engys.core.executor.Executor; +import eu.engys.core.project.Model; +import eu.engys.util.OpenFOAMCommands; +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class OpenParaviewAction extends ViewAction { + + private static final String FOAM_EXTENSION = ".foam"; + + private Model model; + + public OpenParaviewAction(Model model) { + super(PARAVIEW_LABEL, PARAVIEW_ICON, PARAVIEW_TOOLTIP); + this.model = model; + } + + @Override + public void actionPerformed(ActionEvent e) { + launchParaView(); + } + + private void launchParaView() { + File paraView = PrefUtil.getParaViewEntry(); + if (OpenFOAMEnvironment.isParaviewPathSet()) { + String foamFile = getCaseFoamFile(); + if (foamFile != null) { + Executor.command(paraView, "--data=" + foamFile).inFolder(model.getProject().getBaseDir()).description(PARAVIEW_LABEL).exec(); + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No .foam file found!", "Missing file", JOptionPane.ERROR_MESSAGE); + } + } else { + if(Util.isWindows()){ + UiUtil.showEnvironmentNotLoadedWarning(PARAVIEW_LABEL); + } else { + if(OpenFOAMEnvironment.isEnvironementLoaded()){ + Executor.command(OpenFOAMCommands.PARA_FOAM).inFolder(model.getProject().getBaseDir()).withOpenFoamEnv().env(getEnvironment(model)).description(PARAVIEW_LABEL).exec(); + } else { + UiUtil.showCoreEnvironmentNotLoadedWarning(); + } + } + } + } + + private String getCaseFoamFile() { + File baseDir = model.getProject().getBaseDir(); + String[] foamFiles = baseDir.list(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(FOAM_EXTENSION); + } + }); + if (foamFiles.length == 0) { + return null; + } else { + return baseDir.toPath().resolve(foamFiles[0]).toAbsolutePath().toString(); + } + } + + /** + * Resources + */ + + private static final Icon PARAVIEW_ICON = ResourcesUtil.getIcon("paraview.icon"); + + private static final String PARAVIEW_LABEL = ResourcesUtil.getString("paraview.label"); + private static final String PARAVIEW_TOOLTIP = ResourcesUtil.getString("paraview.tooltip"); +} diff --git a/src/eu/engys/gui/solver/actions/RunSolverAction.java b/src/eu/engys/gui/solver/actions/RunSolverAction.java new file mode 100644 index 0000000..b135eb0 --- /dev/null +++ b/src/eu/engys/gui/solver/actions/RunSolverAction.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.solver.actions; + + +//public class RunSolverAction extends ViewAction { +// +// private static final String RUN_SOLVER_LABEL = ResourcesUtil.getString("solver.run.label"); +// private static final String RUN_SOLVER_TOOLTIP = ResourcesUtil.getString("solver.run.tooltip"); +// private static final Icon RUN_SOLVER_ICON = ResourcesUtil.getIcon("solver.run.icon"); +// +// private Controller controller; +// +// public RunSolverAction(Controller controller) { +// super(RUN_SOLVER_LABEL, RUN_SOLVER_ICON, RUN_SOLVER_TOOLTIP); +// this.controller = controller; +// } +// +// @Override +// public void actionPerformed(ActionEvent e) { +// if (controller.isDemo()) { +// controller.showDemoMessage(); +// } else { +// if (PrefUtil.isEnvironementLoaded()) { +//// controller.launch(); +// } else { +// UiUtil.showCoreEnvironmentNotLoadedWarning(); +// } +// } +// } +//} diff --git a/src/eu/engys/gui/solver/actions/StandardSolverActions.java b/src/eu/engys/gui/solver/actions/StandardSolverActions.java new file mode 100644 index 0000000..8639c1f --- /dev/null +++ b/src/eu/engys/gui/solver/actions/StandardSolverActions.java @@ -0,0 +1,47 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.actions; + +import static eu.engys.util.ui.UiUtil.createToolBarButton; + +import javax.inject.Inject; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; + +public class StandardSolverActions extends DefaultSolverActions { + + @Inject + public StandardSolverActions(Model model, Controller controller) { + super(model, controller); + } + + @Override + protected void addExtraActions() { + getToolbar().add(createToolBarButton(new OpenParaviewAction(model))); + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/ParsersHandler.java b/src/eu/engys/gui/solver/postprocessing/ParsersHandler.java new file mode 100644 index 0000000..4f73861 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/ParsersHandler.java @@ -0,0 +1,182 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.Model; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObject; +import eu.engys.core.project.system.monitoringfunctionobjects.Parser; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.gui.solver.postprocessing.parsers.ResidualsParser; +import eu.engys.gui.solver.postprocessing.parsers.ResidualsUtils; + +public class ParsersHandler { + + private static final Logger logger = LoggerFactory.getLogger(ParsersHandler.class); + + private final Model model; + + private Map> parsersMap; + + public ParsersHandler(Model model) { + this.model = model; + this.parsersMap = Collections.synchronizedMap(new HashMap>()); + // this will syncro add/remove/indexof/size BUT iterating should be + // sync'd manually! + } + + public void deleteUselessLogFiles() { + ResidualsUtils.clearLogFile(model); + for (MonitoringFunctionObject fo : model.getMonitoringFunctionObjects()) { + fo.getType().getFactory().deleteUselessLogFiles(fo); + } + } + + /* + * Register + */ + private void registerParsersForFunctionObject(String foName) { + if (foName.equals(ResidualsParser.KEY)) { + ResidualsParser residualsParser = new ResidualsParser(ResidualsUtils.fileToParse(model)); + register(residualsParser); + } + for (MonitoringFunctionObject fo : model.getMonitoringFunctionObjects()) { + if (fo.getName().equals(foName)) { + List parsers = fo.getType().getFactory().createParsers(fo); + for (Parser parser : parsers) { + register(parser); + } + } + } + } + + private void register(Parser parser) { + if (parser != null && !isAlreadyRegistered(parser)) { + logger.debug("ADDING PARSER FOR {}", parser.getFile()); + if (!parsersMap.containsKey(parser.getKey())) { + parsersMap.put(parser.getKey(), new ArrayList()); + } + parsersMap.get(parser.getKey()).add(parser); + parser.init(); + parser.clear(); + } + } + + private boolean isAlreadyRegistered(Parser parser) { + if (parsersMap.containsKey(parser.getKey())) { + List parsersForKey = parsersMap.get(parser.getKey()); + for (Parser p : parsersForKey) { + if (p.getFile().getAbsolutePath().equals(parser.getFile().getAbsolutePath())) { + return true; + } + } + } + return false; + } + + /* + * Refresh + */ + + public List refreshOnceForFunctionObject(String foName) { + logger.info("REFRESH ONCE {}", foName); + List list = refreshParsersForFunctionObject(foName); + endParsersForFunctionObject(foName); + return list; + } + + public List refreshParsersForFunctionObject(String foName) { + // If new files are created at runtime + registerParsersForFunctionObject(foName); + + List blocks = new ArrayList<>(); + if (parsersMap.containsKey(foName)) { + for (Parser parser : parsersMap.get(foName)) { + try { + TimeBlocks newTimeBlocks = parser.updateParsing(); + if (!newTimeBlocks.isEmpty()) { + logger.debug("{} ADDED {} BLOCKS [{} - {}] FROM FILE {}", foName, newTimeBlocks.size(), newTimeBlocks.get(0).getTime(), newTimeBlocks.getLast().getTime(), parser.getFile()); + } else { + logger.debug("{} ADDED {} BLOCKS FROM FILE {}", foName, newTimeBlocks.size(), parser.getFile()); + } + blocks.add(newTimeBlocks); + } catch (Exception e) { + logger.error("ERROR WHILE PARSING", e); + } + } + + printTimeBlocksInfo(blocks, foName); + + } else { + logger.warn("CANNOT FIND PARSER {} AMONG {}", foName, parsersMap.keySet()); + } + + return blocks; + } + + private void printTimeBlocksInfo(List blocks, String functionObjectName) { + if (!blocks.isEmpty()) { + TimeBlocks allTimeBlocks = new TimeBlocks(); + for (TimeBlocks bs : blocks) { + allTimeBlocks.addAll(bs); + } + if (!allTimeBlocks.isEmpty()) { + logger.debug("{} TOTAL BLOCKS: [{} - {}]", functionObjectName, allTimeBlocks.get(0).getTime(), allTimeBlocks.getLast().getTime()); + } else { + logger.debug("{} PARSER BLOCKS: NO TIMES", functionObjectName); + } + } else { + logger.debug("{} PARSER BLOCKS: NO BLOCKS", functionObjectName); + } + } + + /* + * End + */ + + public void endParsers() { + for (String parserName : parsersMap.keySet()) { + endParsersForFunctionObject(parserName); + } + } + + private void endParsersForFunctionObject(String functionObjectName) { + if(parsersMap.containsKey(functionObjectName)){ + for (Parser parser : parsersMap.get(functionObjectName)) { + parser.end(); + } + } + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/ParsersViewHandler.java b/src/eu/engys/gui/solver/postprocessing/ParsersViewHandler.java new file mode 100644 index 0000000..21d7bc8 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/ParsersViewHandler.java @@ -0,0 +1,232 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing; + +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadPoolExecutor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.ParsersManager; +import eu.engys.core.executor.Executor; +import eu.engys.core.project.Model; +import eu.engys.core.project.state.ServerState; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObject; +import eu.engys.core.project.system.monitoringfunctionobjects.ParserView; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.gui.solver.postprocessing.panels.residuals.ResidualsView; +import eu.engys.util.ui.ExecUtil; + +public class ParsersViewHandler implements ServerListener { + + private static final Logger logger = LoggerFactory.getLogger(ParsersViewHandler.class); + + private final Model model; + + private List views; + private ResidualsView residualsView; + private ThreadPoolExecutor executor; + + private ParsersManager parserManager; + + public ParsersViewHandler(Model model, ParsersManager parserManager, ResidualsView residualsView) { + this.model = model; + this.parserManager = parserManager; + this.residualsView = residualsView; + this.views = Collections.synchronizedList(new ArrayList()); + this.executor = Executor.newExecutor("ParserViewHandler"); + registerViews(); + } + + private void registerViews() { + register(residualsView); + for (MonitoringFunctionObject fo : model.getMonitoringFunctionObjects()) { + ParserView view = fo.getView(); + register(view); + } + } + + private void register(ParserView view) { + if (view != null) { + logger.debug("REGISTERING {} VIEW", view.getKey()); + views.add(view); + } + } + + @Override + public void serverChanged(ServerState serverState) { + switch (serverState.getSolverState()) { + case STARTED: + started(); + break; + case RUNNING: + running(); + break; + case ERROR: + error(); + break; + case FINISHED: + running();// Needed by OS + finished(); + break; + + default: + break; + } + } + + private void started() { + logger.debug("STARTED"); + for (ParserView view : views) { + view.setParsingEnabled(true); + view.handleSolverStarted(); + } + } + + private void finished() { + logger.debug("FINISHED"); + executor.submit(new Runnable() { + @Override + public void run() { + try { + logger.debug("ENDING PARSERS"); + parserManager.endParsers(); + } catch (RemoteException e) { + logger.error("ERROR ENDING PARSERS", e); + } + } + }); + executor.shutdown(); + } + + private void running() { + for (final ParserView view : views) { + if (view.isParsingEnabled()) { + if (notInQueue(view)) { + executor.submit(new ParserUpdateTask(view)); + } + } + } + } + + private boolean notInQueue(ParserView view) { + for (Runnable r : executor.getQueue()) { + if (r instanceof ParserUpdateTask) { + ParserUpdateTask task = (ParserUpdateTask) r; + if (task.getView() == view) { + return false; + } + } + } + + return true; + } + + public void refreshOnce() { + logger.info("REFRESH ONCE"); + for (final ParserView view : views) { + if (view.isParsingEnabled()) { + executor.submit(new Runnable() { + @Override + public void run() { + view.showLoading(); + List timeBlocks = updateParserOnce(parserManager, view.getKey()); + logger.debug("RETRIVED {} TIME BLOCKS FOR {}", timeBlocks.size(), view.getKey()); + updateView(view, timeBlocks); + view.stopLoading(); + } + }); + } + } + executor.shutdown(); + } + + private List updateParser(ParsersManager parsersManager, String key) { + logger.debug("REFRESH PARSER {}", key); + try { + return parsersManager.updateParser(key); + } catch (RemoteException e) { + logger.error("ERROR ON REFRESH", e); + } + return Collections.emptyList(); + } + + private List updateParserOnce(ParsersManager parsersManager, String key) { + logger.debug("REFRESH PARSER ONCE {}", key); + try { + return parsersManager.updateParserOnce(key); + } catch (RemoteException e) { + logger.error("ERROR ON REFRESH ONCE", e); + } + return Collections.emptyList(); + } + + private void updateView(final ParserView view, final List newTimeBlocks) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + if (newTimeBlocks != null) { + view.updateParsing(newTimeBlocks); + } else { + logger.warn("EMPTY TIME BLOCK"); + } + } + }); + } + + private void error() { + logger.debug("ERROR"); + executor.shutdown(); + } + + class ParserUpdateTask implements Runnable { + + private ParserView view; + + public ParserUpdateTask(ParserView view) { + this.view = view; + } + + @Override + public void run() { + view.showLoading(); + List timeBlocks = updateParser(parserManager, view.getKey()); + logger.debug("RETRIVED {} TIME BLOCKS FOR {}", timeBlocks.size(), view.getKey()); + updateView(view, timeBlocks); + view.stopLoading(); + } + + public ParserView getView() { + return view; + } + + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/ServerListener.java b/src/eu/engys/gui/solver/postprocessing/ServerListener.java new file mode 100644 index 0000000..b9cf5c2 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/ServerListener.java @@ -0,0 +1,34 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing; + +import eu.engys.core.project.state.ServerState; + +public interface ServerListener { + + void serverChanged(ServerState serverState); + +} diff --git a/src/eu/engys/gui/solver/postprocessing/ServerStateMonitor.java b/src/eu/engys/gui/solver/postprocessing/ServerStateMonitor.java new file mode 100644 index 0000000..3b2beca --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/ServerStateMonitor.java @@ -0,0 +1,279 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing; + +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ThreadPoolExecutor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.Command; +import eu.engys.core.controller.Server; +import eu.engys.core.executor.Executor; +import eu.engys.core.executor.ExecutorError; +import eu.engys.core.project.SolverState; +import eu.engys.core.project.state.ServerState; +import eu.engys.util.PrefUtil; + +public class ServerStateMonitor { + + private static final Logger logger = LoggerFactory.getLogger(ServerStateMonitor.class); + + private static final long TIMER_INITIAL_DELAY = 500L; + private static final long TIMER_REFRESH_RATE = 1000L; + + private Timer timer; + private Server server; + + private Map> listeners = new HashMap<>(); + private Map>> hooks = new HashMap<>(); + + private ServerState endState; + + private ThreadPoolExecutor executor; + + public ServerStateMonitor() { + } + + public void startMonitor(Server server) { + logger.info(">>> START MONITOR"); + this.server = server; + startTimer(); + } + + public void waitForFinished() { + int wait_for_running_refresh_time = PrefUtil.getInt(PrefUtil.SERVER_WAIT_FOR_RUN_REFRESH_TIME, 2000); + while (timer != null) { + try { + Thread.sleep(wait_for_running_refresh_time); + } catch (InterruptedException e) { + } finally { + } + } + } + + private void startTimer() { + executor = Executor.newExecutor("ServerStateMonitor"); + if (timer == null) { + timer = new Timer("- Server Monitor -", true); + } + timer.schedule(new TimerTask() { + @Override + public void run() { + if (executor.getQueue().isEmpty()) { + executor.submit(new Runnable() { + @Override + public void run() { + runTimer(); + } + }); + } else { + logger.debug("Timer running..."); + } + } + }, TIMER_INITIAL_DELAY, TIMER_REFRESH_RATE); + } + + private void runTimer() { + if (server == null) { + handleNoServer(); + } else { + handleServerIsRunning(); + } + } + + private void handleNoServer() { + logger.info(">>> ERROR: NO SERVER"); + notifyServerStateChanged(new ServerState(Command.ANY, SolverState.ERROR)); + } + + private void handleServerIsRunning() { + try { + List remoteStates = server.getStates(); + if (remoteStates.isEmpty()) { + logger.info(">>> NO SERVER STATES"); + } + + for (ServerState remoteState : remoteStates) { + logger.info(">>> SERVER STATE: " + remoteState); + + if (remoteState.getSolverState().isStarted()) { + notifyServerStateChanged(remoteState); + } else if (remoteState.getSolverState().isMeshing()) { + notifyServerStateChanged(remoteState); + } else if (remoteState.getSolverState().isInitialising()) { + notifyServerStateChanged(remoteState); + } else if (remoteState.getSolverState().isRunning()) { + notifyServerStateChanged(remoteState); + } else if (remoteState.getSolverState().isFinished()) { + notifyServerStateChanged(remoteState); + } else if (remoteState.getSolverState().isMeshed()) { + notifyServerStateChanged(remoteState); + } else if (remoteState.getSolverState().isInitialised()) { + notifyServerStateChanged(remoteState); + } else if (remoteState.getSolverState().isError()) { + notifyServerStateChanged(remoteState); + } else { + logger.error(">>> UNKOWN STATE {]", remoteState.getSolverState()); + } + + // try { Thread.sleep(1000); } catch (InterruptedException e) {} + } + } catch (RemoteException e) { + logger.info(">>> SERVER: ERROR (SERVER EXITED)"); + ServerState errorState = new ServerState(Command.ANY, SolverState.ERROR, new ExecutorError(-1, "Server Exited")); + notifyServerStateChanged(errorState); + stopTimer(); + } + } + + private void notifyServerStateChanged(ServerState state) { + // logger.info(">>> NOTIFY: {} ", state); + Command command = state.getCommand(); + SolverState solverState = state.getSolverState(); + + if (listeners.containsKey(command)) { + for (ServerListener listener : listeners.get(command)) { + listener.serverChanged(state); + } + } else if (command.equals(Command.ANY)) { + for (Command c : listeners.keySet()) { + for (ServerListener listener : listeners.get(c)) { + listener.serverChanged(state); + } + } + } else if (listeners.containsKey(Command.ANY)) { + for (ServerListener listener : listeners.get(Command.ANY)) { + listener.serverChanged(state); + } + } + + if (hooks.containsKey(command)) { + if (hooks.get(command).containsKey(solverState)) { + for (ServerListener listener : hooks.get(command).get(solverState)) { + listener.serverChanged(state); + } + } + } else if (command.equals(Command.ANY)) { + for (Command c : hooks.keySet()) { + if (hooks.get(c).containsKey(solverState)) { + for (ServerListener listener : hooks.get(c).get(solverState)) { + listener.serverChanged(state); + } + } + } + } else if (hooks.containsKey(Command.ANY)) { + if (hooks.get(Command.ANY).containsKey(solverState)) { + for (ServerListener listener : hooks.get(Command.ANY).get(solverState)) { + listener.serverChanged(state); + } + } + } + + if (endState != null) { + if (endState.equals(state) || state.getSolverState().isError()) { + logger.info("STATE IS {}, END STATE IS {}", state.getSolverState(), endState); + stopTimer(); + } + } + } + + public void stopTimer() { + logger.debug("STOP TIMER"); + if (executor != null) { + executor.shutdown(); + executor = null; + } + if (timer != null) { + timer.cancel(); + timer.purge(); + timer = null; + } + } + + public CommandHook forCommand(Command command) { + return new CommandHook(command); + } + + /* + * For test purposes only + */ + public boolean isRunning() { + return timer != null; + } + + public class CommandHook { + private Command command; + + public CommandHook(Command command) { + this.command = command; + if (!hooks.containsKey(command)) { + hooks.put(command, new HashMap>()); + } + if (!listeners.containsKey(command)) { + listeners.put(command, new ArrayList()); + } + } + + public SolverHook when(SolverState state) { + return new SolverHook(command, state); + } + + public void forEachState(ServerListener listener) { + listeners.get(command).add(listener); + } + } + + public class SolverHook { + + private SolverState state; + private Command command; + + public SolverHook(Command command, SolverState state) { + this.command = command; + this.state = state; + if (!hooks.get(command).containsKey(state)) { + hooks.get(command).put(state, new ArrayList()); + } + } + + public void execute(ServerListener listener) { + hooks.get(command).get(state).add(listener); + } + + public void endTimer() { + ServerStateMonitor.this.endState = new ServerState(command, state); + } + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/data/DoubleListTimeBlockUnit.java b/src/eu/engys/gui/solver/postprocessing/data/DoubleListTimeBlockUnit.java new file mode 100644 index 0000000..cbe57dd --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/data/DoubleListTimeBlockUnit.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.data; + +import java.util.LinkedList; +import java.util.List; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlockUnit; + +public class DoubleListTimeBlockUnit extends TimeBlockUnit { + + /* + * Used for residuals parser where a variable can be resolved multiple times (orthogonal correctors) + */ + + private List values; + + public DoubleListTimeBlockUnit(String varName) { + super(varName); + this.values = new LinkedList(); + } + + public List getValues() { + return values; + } + + @Override + public String toString() { + return "[" + getVarName() + ", " + values + "]"; + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/data/DoubleTimeBlockUnit.java b/src/eu/engys/gui/solver/postprocessing/data/DoubleTimeBlockUnit.java new file mode 100644 index 0000000..3e3437b --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/data/DoubleTimeBlockUnit.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.data; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlockUnit; + + +public class DoubleTimeBlockUnit extends TimeBlockUnit { + + private Double value; + + public DoubleTimeBlockUnit(String varName, Double value) { + super(varName); + this.value = value; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } + + @Override + public String toString() { + return "[" + getVarName() + ", " + getValue() + "]"; + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/data/PointTimeBlockUnit.java b/src/eu/engys/gui/solver/postprocessing/data/PointTimeBlockUnit.java new file mode 100644 index 0000000..cdf20e9 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/data/PointTimeBlockUnit.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.data; + +import javax.vecmath.Point3d; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlockUnit; + +public class PointTimeBlockUnit extends TimeBlockUnit { + + private Point3d point; + + public PointTimeBlockUnit(String varName, double[] points) { + super(varName); + this.point = new Point3d(points); + } + + public PointTimeBlockUnit(String varName, Point3d point) { + super(varName); + this.point = point; + } + + public Point3d getPoint() { + return point; + } + + @Override + public String toString() { + return "[" + getVarName() + ", " + getPoint() + "]"; + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/AbstractChartPanel.java b/src/eu/engys/gui/solver/postprocessing/panels/AbstractChartPanel.java new file mode 100644 index 0000000..2b7dbd6 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/AbstractChartPanel.java @@ -0,0 +1,148 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels; + +import static org.jfree.chart.ChartPanel.DEFAULT_HEIGHT; +import static org.jfree.chart.ChartPanel.DEFAULT_MAXIMUM_DRAW_HEIGHT; +import static org.jfree.chart.ChartPanel.DEFAULT_MAXIMUM_DRAW_WIDTH; +import static org.jfree.chart.ChartPanel.DEFAULT_MINIMUM_DRAW_HEIGHT; +import static org.jfree.chart.ChartPanel.DEFAULT_MINIMUM_DRAW_WIDTH; +import static org.jfree.chart.ChartPanel.DEFAULT_WIDTH; + +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.text.DecimalFormat; + +import javax.swing.JPanel; + +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.block.BlockBorder; +import org.jfree.chart.labels.CrosshairLabelGenerator; +import org.jfree.chart.panel.CrosshairOverlay; +import org.jfree.chart.plot.Crosshair; +import org.jfree.chart.title.LegendTitle; +import org.jfree.ui.RectangleEdge; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; + +public abstract class AbstractChartPanel extends JPanel { + + protected static final String TIME_LABEL = "Time [s]"; + + protected String title; + protected String domainAxisLabel; + protected String rangeAxisLabel; + + protected ChartPanel chartPanel; + protected JFreeChart chart; + + protected CrosshairOverlay overlay; + + public AbstractChartPanel(String title, String domainAxisLabel, String rangeAxisLabel) { + super(new BorderLayout()); + this.title = title; + this.domainAxisLabel = domainAxisLabel; + this.rangeAxisLabel = rangeAxisLabel; + } + + public void layoutComponents() { + createChart(); + this.chart.setBackgroundPaint(new Color(0, 0, 0, 0)); + this.chartPanel = createChartPanel(); + layoutLegend(); + } + + protected abstract void createChart(); + + public abstract void stop(); + + public abstract void addToDataSet(TimeBlocks list); + + public abstract void clearData(); + + private ChartPanel createChartPanel() { + boolean useBuffer = true; + boolean showPropertiesMenu = true; + boolean showCopyMenu = true; + boolean showSaveMenu = false; + boolean showPrintMenu = true; + boolean showZoomMenu = true; + boolean showTooltipsMenu = true; + ChartPanel panel = new ChartPanel(chart, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_MINIMUM_DRAW_WIDTH, DEFAULT_MINIMUM_DRAW_HEIGHT, DEFAULT_MAXIMUM_DRAW_WIDTH, DEFAULT_MAXIMUM_DRAW_HEIGHT, useBuffer, showPropertiesMenu, showCopyMenu, showSaveMenu, showPrintMenu, showZoomMenu, showTooltipsMenu); + this.overlay = createOverlay(); + return panel; + } + + private CrosshairOverlay createOverlay() { + CrosshairOverlay crosshairOverlay = new CrosshairOverlay(); + Crosshair xCrosshair = new Crosshair(Double.NaN, Color.BLUE.brighter(), new BasicStroke(0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, new float[] { 1.0f }, 0.0f)); + xCrosshair.setLabelGenerator(new CrosshairLabelGenerator() { + @Override + public String generateLabel(Crosshair crosshair) { + DecimalFormat decimalFormat = new DecimalFormat("#.######"); + return decimalFormat.format(crosshair.getValue()); + } + }); + xCrosshair.setLabelBackgroundPaint(Color.WHITE); + xCrosshair.setLabelOutlineVisible(false); + xCrosshair.setLabelVisible(true); + + Crosshair yCrosshair = new Crosshair(Double.NaN, Color.BLUE.brighter(), new BasicStroke(0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, new float[] { 1.0f }, 0.0f)); + yCrosshair.setLabelGenerator(new CrosshairLabelGenerator() { + @Override + public String generateLabel(Crosshair crosshair) { + DecimalFormat decimalFormat = new DecimalFormat("#.######"); + return decimalFormat.format(crosshair.getValue()); + } + }); + yCrosshair.setLabelBackgroundPaint(Color.WHITE); + yCrosshair.setLabelOutlineVisible(false); + yCrosshair.setLabelVisible(true); + + crosshairOverlay.addDomainCrosshair(xCrosshair); + crosshairOverlay.addRangeCrosshair(yCrosshair); + return crosshairOverlay; + } + + private void layoutLegend() { + LegendTitle legend = chart.getLegend(); + if (legend != null) { + legend.setFrame(BlockBorder.NONE); + legend.setBackgroundPaint(null); + legend.setPosition(RectangleEdge.RIGHT); + legend.setVisible(false); + } + } + + public JFreeChart getChart() { + return chart; + } + + public void initSeries() { + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/AbstractParserView.java b/src/eu/engys/gui/solver/postprocessing/panels/AbstractParserView.java new file mode 100644 index 0000000..1f51633 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/AbstractParserView.java @@ -0,0 +1,266 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import javax.swing.JComponent; +import javax.swing.JLayer; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; + +import org.apache.commons.io.FilenameUtils; +import org.jfree.chart.ChartUtilities; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.executor.FileManagerSupport; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObject; +import eu.engys.core.project.system.monitoringfunctionobjects.Parser; +import eu.engys.core.project.system.monitoringfunctionobjects.ParserView; +import eu.engys.gui.solver.postprocessing.panels.utils.WaitLayerUI; +import eu.engys.util.Util; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.FileChooserUtils; + +public abstract class AbstractParserView extends JPanel implements ParserView { + + private static final Logger logger = LoggerFactory.getLogger(AbstractParserView.class); + protected Model model; + protected MonitoringFunctionObject functionObject; + protected ProgressMonitor monitor; + protected JTabbedPane tabbedPane; + private boolean parsingEnabled; + + private WaitLayerUI loadingPane; + + public AbstractParserView(Model model, MonitoringFunctionObject functionObject, ProgressMonitor monitor) { + super(new BorderLayout()); + this.model = model; + this.functionObject = functionObject; + this.monitor = monitor; + this.tabbedPane = new JTabbedPane(); + this.parsingEnabled = false; + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(tabbedPane, BorderLayout.CENTER); + + loadingPane = new WaitLayerUI(new EnableParsing()); + JLayer layer = new JLayer(mainPanel, loadingPane); + + add(layer, BorderLayout.CENTER); + } + + @Override + public void reset() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + clearData(); + loadingPane.init(); + setParsingEnabled(false); + } + }); + } + + @Override + public void handleSolverStarted() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + clearData(); + loadingPane.stop(); + } + }); + } + + @Override + public void showLoading() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + loadingPane.start(); + } + }); + } + + @Override + public void stopLoading() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + loadingPane.stop(); + } + }); + } + + @Override + public void setCrosshairVisibile(boolean visible) { + for (Component c : tabbedPane.getComponents()) { + if (c instanceof MovingAverageChartPanel) { + ((MovingAverageChartPanel) c).setCrosshairVisible(visible); + } + } + } + + @Override + public void showLogFile() { + try { + List parsersList = gerReportParsersList(); + for (Parser parser : parsersList) { + File logFile = parser.getFile(); + if (logFile != null && logFile.exists()) { + if (Util.isWindows() && FilenameUtils.getExtension(logFile.getName()).isEmpty()) { + FileManagerSupport.open(logFile.getParentFile()); + } else { + FileManagerSupport.open(logFile); + } + } + } + } catch (Exception e1) { + JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(AbstractParserView.this), e1.getMessage(), "Export Error", JOptionPane.ERROR_MESSAGE); + logger.error("Cannot open log file", e1.getMessage()); + } + } + + @Override + public void exportToExcel() { + final File excelFile = FileChooserUtils.getExcelFile(); + if (excelFile != null) { + monitor.setIndeterminate(true); + monitor.start("Export to Excel", false, new Runnable() { + @Override + public void run() { + try { + getExporter().exportToExcel(excelFile, monitor); + } catch (Exception e) { + showErrorMessage(e); + } finally { + monitor.end(); + } + } + + }); + } + } + + @Override + public void exportToCSV() { + final File csvFile = FileChooserUtils.getCSVFile(); + if (csvFile != null) { + monitor.start("Export to CSV", false, new Runnable() { + @Override + public void run() { + try { + getExporter().exportToCSV(csvFile, monitor); + } catch (Exception e) { + showErrorMessage(e); + } finally { + monitor.end(); + } + } + }); + } + } + + @Override + public void exportToPNG() { + AbstractChartPanel chartPanel = (AbstractChartPanel) tabbedPane.getSelectedComponent(); + File pngFile = FileChooserUtils.getPNGFile(); + if (pngFile != null && chartPanel != null) { + // PRE-SAVE + chartPanel.getChart().setBackgroundPaint(Color.WHITE); + if (chartPanel.getChart().getLegend() != null) { + chartPanel.getChart().getLegend().setBackgroundPaint(Color.WHITE); + chartPanel.getChart().getLegend().setVisible(true); + } + // SAVE + try { + ChartUtilities.saveChartAsPNG(pngFile, chartPanel.getChart(), chartPanel.getSize().width, chartPanel.getSize().height); + } catch (IOException e1) { + e1.printStackTrace(); + } + + // POST-SAVE + chartPanel.getChart().setBackgroundPaint(new Color(0, 0, 0, 0)); + if (chartPanel.getChart().getLegend() != null) { + chartPanel.getChart().getLegend().setBackgroundPaint(new Color(0, 0, 0, 0)); + chartPanel.getChart().getLegend().setVisible(false); + } + FileManagerSupport.open(pngFile); + } else { + logger.error("Problem saving chart to PNG"); + } + } + + private void showErrorMessage(final Exception e) { + ExecUtil.invokeLater(new Runnable() { + + @Override + public void run() { + JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(AbstractParserView.this), e.getMessage(), "Export Error", JOptionPane.ERROR_MESSAGE); + logger.error("Cannot export", e.getMessage()); + } + }); + } + + @Override + public boolean isParsingEnabled() { + return parsingEnabled; + } + + @Override + public void setParsingEnabled(boolean parsingEnabled) { + this.parsingEnabled = parsingEnabled; + } + + @Override + public JComponent getPanel() { + return this; + } + + protected class EnableParsing implements Runnable { + @Override + public void run() { + setParsingEnabled(true); + ActionManager.getInstance().invoke("solver.refresh.once"); + if (!model.getSolverModel().getServerState().getSolverState().isDoingSomething()) { + setParsingEnabled(false); + } + } + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/HistoryChartPanel.java b/src/eu/engys/gui/solver/postprocessing/panels/HistoryChartPanel.java new file mode 100644 index 0000000..0031cf6 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/HistoryChartPanel.java @@ -0,0 +1,87 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels; + +import java.util.List; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.labels.StandardXYToolTipGenerator; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.renderer.xy.StandardXYItemRenderer; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +import eu.engys.util.ui.textfields.DoubleField; + +public abstract class HistoryChartPanel extends MovingAverageChartPanel { + + private static final long serialVersionUID = 1L; + + protected List seriesNames; + + public HistoryChartPanel(String title, List seriesNames, String domainAxisLabel, String rangeAxisLabel, boolean showMovingAverage) { + super(title, domainAxisLabel, rangeAxisLabel, showMovingAverage); + this.seriesNames = seriesNames; + this.dataset = new XYSeriesCollection(); + } + + @Override + public void initSeries() { + for (String serieName : seriesNames) { + XYSeries series = new XYSeries(serieName); + dataset.addSeries(series); + populateSeriesPanel(dataset.getSeriesIndex(series.getKey()), series.getKey().toString()); + } + } + + @Override + protected void createChart() { + this.chart = ChartFactory.createXYLineChart("", "", "", dataset, PlotOrientation.VERTICAL, true, true, false); + + NumberAxis domainAxis = new NumberAxis(domainAxisLabel); + domainAxis.setAutoRangeIncludesZero(false); + + NumberAxis rangeAxis = new NumberAxis(rangeAxisLabel); + rangeAxis.setNumberFormatOverride(DoubleField.getFormatForDISPLAY(10)); + + chart.getXYPlot().setDomainAxis(domainAxis); + chart.getXYPlot().setRangeAxis(rangeAxis); + chart.getXYPlot().setDataset(1, movingAverageDataSet); + + StandardXYItemRenderer movingAverageRenderer = new StandardXYItemRenderer(); + movingAverageRenderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator()); + chart.getXYPlot().setRenderer(1, movingAverageRenderer); + } + + @Override + protected void clearDataset() { + for (int i = 0; i < dataset.getSeriesCount(); i++) { + dataset.getSeries(i).clear(); + } + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/MovingAverageChartPanel.java b/src/eu/engys/gui/solver/postprocessing/panels/MovingAverageChartPanel.java new file mode 100644 index 0000000..e54469e --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/MovingAverageChartPanel.java @@ -0,0 +1,235 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels; + +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; + +import org.jfree.chart.ChartMouseEvent; +import org.jfree.chart.ChartMouseListener; +import org.jfree.chart.plot.Crosshair; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.data.general.DatasetUtilities; +import org.jfree.data.xy.AbstractIntervalXYDataset; +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.ui.RectangleEdge; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlock; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.gui.solver.postprocessing.panels.utils.MovingAveragePanel; +import eu.engys.gui.solver.postprocessing.panels.utils.SeriesPanel; +import eu.engys.util.ui.ExecUtil; + +public abstract class MovingAverageChartPanel extends AbstractChartPanel { + + private static final long serialVersionUID = 1L; + + protected SeriesPanel seriesPanel; + protected MovingAveragePanel movingAveragePanel; + + protected D dataset; + protected XYSeriesCollection movingAverageDataSet; + private boolean showMovingAverage; + + private CrosshairListener crosshairListener; + + public MovingAverageChartPanel(String title, String domainAxisLabel, String rangeAxisLabel, boolean showMovingAverage) { + super(title, domainAxisLabel, rangeAxisLabel); + setName(title + ".chart.panel"); + this.showMovingAverage = showMovingAverage; + this.movingAverageDataSet = new XYSeriesCollection(); + this.crosshairListener = new CrosshairListener(); + } + + @Override + public void layoutComponents() { + super.layoutComponents(); + chartPanel.addOverlay(overlay); + + this.seriesPanel = new SeriesPanel(showMovingAverage ? movingAveragePanel = new MovingAveragePanel(dataset, movingAverageDataSet) : null); + + JScrollPane seriesScrollPane = new JScrollPane(seriesPanel); + seriesScrollPane.setBorder(BorderFactory.createEmptyBorder()); + + JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + splitPane.setOneTouchExpandable(false); + splitPane.setLeftComponent(chartPanel); + splitPane.setRightComponent(seriesScrollPane); + + double scrollPaneWidth = splitPane.getPreferredSize().getWidth(); + double seriesPanelWidth = seriesPanel.getPreferredSize().getWidth(); + if (seriesPanelWidth != 0 && scrollPaneWidth != 0) { + double value = 1 - (seriesPanelWidth / scrollPaneWidth) - 0.07; + splitPane.setResizeWeight(value); + } else { + splitPane.setResizeWeight(0.9); + } + add(splitPane, BorderLayout.CENTER); + } + + public void setCrosshairVisible(boolean visible) { + if (visible) { + chartPanel.addChartMouseListener(crosshairListener); + chartPanel.addMouseListener(crosshairListener); + } else { + chartPanel.removeChartMouseListener(crosshairListener); + chartPanel.removeMouseListener(crosshairListener); + removeCrosshair(); + } + } + + @Override + public void addToDataSet(final TimeBlocks list) { + synchronized (list) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + notifySeries(false); + for (final TimeBlock block : list) { + addTimeBlock(block); + } + if(showMovingAverage){ + movingAveragePanel.updateMovingAverageDataset(); + } + notifySeries(true); + refreshGUI(); + } + }); + } + } + + protected abstract void addTimeBlock(final TimeBlock block); + + protected void populateSeriesPanel(int seriesIndex, String seriesTitle) { + XYItemRenderer baseRenderer = chart.getXYPlot().getRenderer(); + seriesPanel.addSeries(baseRenderer, seriesIndex, seriesTitle); + + if (showMovingAverage) { + XYItemRenderer renderer = chart.getXYPlot().getRenderer(1); + renderer.setSeriesPaint(seriesIndex, ((Color) baseRenderer.getItemPaint(seriesIndex, 0)).darker().darker()); + renderer.setSeriesStroke(seriesIndex, new BasicStroke(1)); + seriesPanel.addMovingAverageSeries(renderer, seriesIndex, seriesTitle); + } + } + + @Override + public void clearData() { + notifySeries(false); + clearDataset(); + clearMovingAverageDataset(); + notifySeries(true); + removeCrosshair(); + chartPanel.restoreAutoDomainBounds(); + } + + protected abstract void clearDataset(); + + private void clearMovingAverageDataset() { + for (int i = 0; i < movingAverageDataSet.getSeriesCount(); i++) { + movingAverageDataSet.getSeries(i).clear(); + } + } + + protected void notifySeries(boolean notify) { + dataset.setNotify(notify); + movingAverageDataSet.setNotify(notify); + } + + protected void refreshGUI() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + seriesPanel.revalidate(); + chartPanel.revalidate(); + chartPanel.repaint(); + } + }); + } + + private void removeCrosshair() { + ((Crosshair) overlay.getDomainCrosshairs().get(0)).setValue(Double.NaN); + ((Crosshair) overlay.getRangeCrosshairs().get(0)).setValue(Double.NaN); + } + + @Override + public void stop() { + } + + private class CrosshairListener extends MouseAdapter implements ChartMouseListener { + + @Override + public void chartMouseClicked(ChartMouseEvent arg0) { + } + + @Override + public void chartMouseMoved(ChartMouseEvent event) { + if (chart.getPlot() instanceof XYPlot) { + XYPlot plot = (XYPlot) chart.getPlot(); + double x = plot.getDomainAxis().java2DToValue(event.getTrigger().getX(), chartPanel.getScreenDataArea(), RectangleEdge.BOTTOM); + // make the crosshairs disappear if the mouse is out of range + if (!plot.getDomainAxis().getRange().contains(x)) { + x = Double.NaN; + } + ((Crosshair) overlay.getDomainCrosshairs().get(0)).setValue(x); + + double y = DatasetUtilities.findYValue(dataset, getClosestSeriesIndex(x, event.getTrigger().getY()), x); + ((Crosshair) overlay.getRangeCrosshairs().get(0)).setValue(y); + } + + } + + private int getClosestSeriesIndex(double x, int compare) { + int series = 0; + double distance = Double.MAX_VALUE; + for (int i = 0; i < dataset.getSeriesCount(); i++) { + double y = DatasetUtilities.findYValue(dataset, i, x); + double toCompare = ((XYPlot) chart.getPlot()).getRangeAxis().java2DToValue(compare, chartPanel.getScreenDataArea(), ((XYPlot) chart.getPlot()).getRangeAxisEdge()); + + if (Math.abs(y - toCompare) < distance) { + distance = Math.abs(y - toCompare); + series = i; + } + } + + return series; + } + + @Override + public void mouseExited(MouseEvent e) { + removeCrosshair(); + } + + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToCSVAction.java b/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToCSVAction.java new file mode 100644 index 0000000..9415791 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToCSVAction.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; + +import eu.engys.gui.solver.postprocessing.panels.utils.SelectedViewProvider; +import eu.engys.util.ui.ResourcesUtil; + +public class ExportToCSVAction extends AbstractAction { + + private static final Icon CSV_ICON = ResourcesUtil.getIcon("file"); + private SelectedViewProvider selector; + + public ExportToCSVAction(SelectedViewProvider selector) { + super("", CSV_ICON); + this.selector = selector; + putValue(SHORT_DESCRIPTION, "Export chart data in CSV format"); + } + + @Override + public void actionPerformed(ActionEvent e) { + selector.getSelectedView().exportToCSV(); + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToExcelAction.java b/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToExcelAction.java new file mode 100644 index 0000000..ab6ec01 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToExcelAction.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; + +import eu.engys.gui.solver.postprocessing.panels.utils.SelectedViewProvider; +import eu.engys.util.ui.ResourcesUtil; + +public class ExportToExcelAction extends AbstractAction { + + private SelectedViewProvider selector; + private static final Icon EXCEL_ICON = ResourcesUtil.getIcon("file.excel"); + + public ExportToExcelAction(SelectedViewProvider selector) { + super("", EXCEL_ICON); + this.selector = selector; + putValue(SHORT_DESCRIPTION, "Export chart data in Excel format"); + } + + @Override + public void actionPerformed(ActionEvent e) { + selector.getSelectedView().exportToExcel(); + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToPNGAction.java b/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToPNGAction.java new file mode 100644 index 0000000..d36d294 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/actions/ExportToPNGAction.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; + +import eu.engys.gui.solver.postprocessing.panels.utils.SelectedViewProvider; +import eu.engys.util.ui.ResourcesUtil; + +public class ExportToPNGAction extends AbstractAction { + + private static final Icon PNG_ICON = ResourcesUtil.getIcon("file.png"); + private SelectedViewProvider selector; + + public ExportToPNGAction(SelectedViewProvider selector) { + super("", PNG_ICON); + this.selector = selector; + putValue(SHORT_DESCRIPTION, "Export chart in PNG format"); + } + + @Override + public void actionPerformed(ActionEvent e) { + selector.getSelectedView().exportToPNG(); + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowCrosshairAction.java b/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowCrosshairAction.java new file mode 100644 index 0000000..4581e64 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowCrosshairAction.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.Icon; + +import eu.engys.core.project.Model; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObject; +import eu.engys.util.ui.ResourcesUtil; + +public class ShowCrosshairAction extends AbstractAction { + + private static final Icon CROSSHAIR_ICON = ResourcesUtil.getIcon("crosshair.icon"); + private Model model; + + public ShowCrosshairAction(Model model) { + super("", CROSSHAIR_ICON); + this.model = model; + putValue(SHORT_DESCRIPTION, "Show a crosshair over the chart"); + } + + @Override + public void actionPerformed(ActionEvent e) { + boolean visible = ((AbstractButton) e.getSource()).isSelected(); + for (MonitoringFunctionObject fo : model.getMonitoringFunctionObjects()) { + fo.getView().setCrosshairVisibile(visible); + } + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowCrosshairForResidualsAction.java b/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowCrosshairForResidualsAction.java new file mode 100644 index 0000000..bf89aec --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowCrosshairForResidualsAction.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.Icon; + +import eu.engys.gui.solver.postprocessing.panels.residuals.ResidualsView; +import eu.engys.util.ui.ResourcesUtil; + +public class ShowCrosshairForResidualsAction extends AbstractAction { + + private static final Icon CROSSHAIR_ICON = ResourcesUtil.getIcon("crosshair.icon"); + private ResidualsView residualsView; + + public ShowCrosshairForResidualsAction(ResidualsView residualsView) { + super("", CROSSHAIR_ICON); + this.residualsView = residualsView; + putValue(SHORT_DESCRIPTION, "Show a crosshair over the chart"); + } + + @Override + public void actionPerformed(ActionEvent e) { + boolean visible = ((AbstractButton) e.getSource()).isSelected(); + residualsView.setCrosshairVisibile(visible); + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowLogFileAction.java b/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowLogFileAction.java new file mode 100644 index 0000000..54d50be --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/actions/ShowLogFileAction.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.actions; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; + +import eu.engys.gui.solver.postprocessing.panels.utils.SelectedViewProvider; +import eu.engys.util.ui.ResourcesUtil; + +public class ShowLogFileAction extends AbstractAction { + + private static final Icon LOG_FILE_ICON = ResourcesUtil.getIcon("browse.file"); + private SelectedViewProvider selector; + + public ShowLogFileAction(SelectedViewProvider selector) { + super("", LOG_FILE_ICON); + this.selector = selector; + putValue(SHORT_DESCRIPTION, "Open log file"); + } + + @Override + public void actionPerformed(ActionEvent e) { + selector.getSelectedView().showLogFile(); + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsChartPanel.java b/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsChartPanel.java new file mode 100644 index 0000000..d99d9fe --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsChartPanel.java @@ -0,0 +1,94 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.residuals; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.axis.LogarithmicAxis; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.xy.XYSeries; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlock; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlockUnit; +import eu.engys.gui.solver.postprocessing.data.DoubleListTimeBlockUnit; +import eu.engys.gui.solver.postprocessing.panels.HistoryChartPanel; + +public class ResidualsChartPanel extends HistoryChartPanel { + + public ResidualsChartPanel() { + super("Residuals", null, TIME_LABEL, "", false); + } + + @Override + protected void createChart() { + this.chart = ChartFactory.createXYLineChart("", "", "", dataset, PlotOrientation.VERTICAL, true, true, false); + NumberAxis domainAxis = new NumberAxis(domainAxisLabel); + domainAxis.setAutoRangeIncludesZero(false); + + LogarithmicAxis rangeAxis = new LogarithmicAxis(rangeAxisLabel); + rangeAxis.setExpTickLabelsFlag(true); + + XYPlot xyPlot = chart.getXYPlot(); + xyPlot.setDomainAxis(domainAxis); + xyPlot.setRangeAxis(rangeAxis); + } + + @Override + protected void addTimeBlock(TimeBlock block) { + for (TimeBlockUnit unit : block.getUnitsMap().values()) { + if (unit instanceof DoubleListTimeBlockUnit) { + addTimeUnit(block.getTime(), (DoubleListTimeBlockUnit) unit); + } + } + } + + private void addTimeUnit(double time, DoubleListTimeBlockUnit unit) { + String varName = unit.getVarName(); + if (dataset.getSeriesIndex(varName) == -1) { + XYSeries series = new XYSeries(varName); + dataset.addSeries(series); + populateSeriesPanel(dataset.getSeriesIndex(series.getKey()), series.getKey().toString()); + } + XYSeries xyserie = dataset.getSeries(varName); + DoubleListTimeBlockUnit doubleListUnit = (DoubleListTimeBlockUnit) unit; + for (Double value : doubleListUnit.getValues()) { + if (value > 0) { + xyserie.add(time, value); + } + } + } + + @Override + public void clearData() { + // Chart is recreated everytime so we remove all + dataset.removeAllSeries(); + chartPanel.restoreAutoDomainBounds(); + seriesPanel.clear(); + refreshGUI(); + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsExporter.java b/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsExporter.java new file mode 100644 index 0000000..80dd5a5 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsExporter.java @@ -0,0 +1,193 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.residuals; + +import static eu.engys.core.report.excel.ExcelUtils.addDoubleCell; +import static eu.engys.core.report.excel.ExcelUtils.addHeaderCell; +import static eu.engys.core.report.excel.ExcelUtils.autoSizeColumns; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +import au.com.bytecode.opencsv.CSVWriter; +import eu.engys.core.project.system.monitoringfunctionobjects.Parser; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlock; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlockUnit; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.core.report.Exporter; +import eu.engys.gui.solver.postprocessing.data.DoubleListTimeBlockUnit; +import eu.engys.util.progress.ProgressMonitor; + +public class ResidualsExporter extends Exporter { + + public ResidualsExporter(List parsers, ProgressMonitor monitor) { + super(parsers, monitor); + } + + @Override + protected void populateExcelFile(Workbook workbook) throws Exception { + monitor.setIndeterminate(false); + + Parser parser = parsers.get(0); + monitor.info(PARSING_LOG_FILE + parser.getFile(), 1); + parser.init(); + TimeBlocks blocks = parser.updateParsing(); + parser.end(); + + monitor.setTotal(blocks.size()); + monitor.info(POPULATING_SHEET + "Residuals" + DOTS, 1); + addExcelSheet(workbook, blocks); + } + + @Override + protected void populateCSVFile(CSVWriter writer) throws Exception { + monitor.setIndeterminate(false); + + Parser parser = parsers.get(0); + monitor.info(PARSING_LOG_FILE + parser.getFile(), 1); + parser.init(); + TimeBlocks blocks = parser.updateParsing(); + parser.end(); + + monitor.setTotal(blocks.size()); + monitor.info(POPULATING_SHEET + "Residuals" + DOTS, 1); + addCSVSheet(writer, blocks); + } + + /* + * CSV + */ + + private void addCSVSheet(CSVWriter writer, TimeBlocks blocks) { + if (!blocks.isEmpty()) { + addCSVHeaderRow(writer, blocks.get(0)); + addCSVTableRows(writer, blocks); + } + } + + private void addCSVHeaderRow(CSVWriter writer, TimeBlock firstTimeBlock) { + List headerRow = new LinkedList<>(); + headerRow.add("Time"); + + Map unitsMap = firstTimeBlock.getUnitsMap(); + for (String var : unitsMap.keySet()) { + DoubleListTimeBlockUnit unit = (DoubleListTimeBlockUnit) unitsMap.get(var); + if (unit.getValues().size() == 1) { + headerRow.add(var); + } else { + for (int i = 0; i < unit.getValues().size(); i++) { + headerRow.add(var + i); + } + } + } + + writer.writeNext(headerRow.toArray(new String[0])); + } + + private void addCSVTableRows(CSVWriter writer, TimeBlocks blocks) { + List tableRows = new LinkedList<>(); + + for (int i = 0; i < blocks.size(); i++) { + TimeBlock block = blocks.get(i); + + List row = new LinkedList<>(); + row.add(String.valueOf(block.getTime())); + + Map unitsMap = block.getUnitsMap(); + for (String var : unitsMap.keySet()) { + DoubleListTimeBlockUnit unit = (DoubleListTimeBlockUnit) unitsMap.get(var); + for (int j = 0; j < unit.getValues().size(); j++) { + row.add(String.valueOf(unit.getValues().get(j))); + } + } + tableRows.add(row.toArray(new String[0])); + + monitor.setCurrent(null, monitor.getCurrent() + 1); + } + writer.writeAll(tableRows); + } + + /* + * Excel + */ + + private void addExcelSheet(Workbook workbook, TimeBlocks blocks) { + Sheet sheet = workbook.createSheet("Residuals"); + if (!blocks.isEmpty()) { + addExcelHeaderRow(workbook, sheet, blocks.get(0)); + addExcelTableRows(sheet, blocks); + autoSizeColumns(sheet); + } + } + + private void addExcelHeaderRow(Workbook workbook, Sheet sheet, TimeBlock firstTimeBlock) { + Row headerRow = sheet.createRow(0); + addHeaderCell(workbook, headerRow, 0, "Time"); + + Map unitsMap = firstTimeBlock.getUnitsMap(); + int counter = 1; + for (String var : unitsMap.keySet()) { + DoubleListTimeBlockUnit unit = (DoubleListTimeBlockUnit) unitsMap.get(var); + if (unit.getValues().size() == 1) { + addHeaderCell(workbook, headerRow, counter, var); + counter++; + } else { + for (int i = 0; i < unit.getValues().size(); i++) { + addHeaderCell(workbook, headerRow, counter, var + i); + counter++; + } + } + } + } + + private void addExcelTableRows(Sheet sheet, TimeBlocks blocks) { + for (int i = 0; i < blocks.size(); i++) { + TimeBlock block = blocks.get(i); + + // i+1 because row 0 is for the header + Row row = sheet.createRow(i + 1); + row.createCell(0).setCellValue(block.getTime()); + + Map unitsMap = block.getUnitsMap(); + int counter = 0; + for (String var : unitsMap.keySet()) { + DoubleListTimeBlockUnit unit = (DoubleListTimeBlockUnit) unitsMap.get(var); + for (int j = 0; j < unit.getValues().size(); j++) { + addDoubleCell(sheet, i, counter, unit.getValues().get(j)); + counter++; + } + } + + monitor.setCurrent(null, monitor.getCurrent() + 1); + } + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsPanel.java b/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsPanel.java new file mode 100644 index 0000000..b7db9fd --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsPanel.java @@ -0,0 +1,99 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.residuals; + +import javax.inject.Inject; +import javax.swing.JComponent; +import javax.swing.JToggleButton; + +import eu.engys.core.controller.Controller; +import eu.engys.core.project.Model; +import eu.engys.core.project.system.monitoringfunctionobjects.ParserView; +import eu.engys.gui.DefaultGUIPanel; +import eu.engys.gui.solver.postprocessing.panels.actions.ExportToCSVAction; +import eu.engys.gui.solver.postprocessing.panels.actions.ExportToExcelAction; +import eu.engys.gui.solver.postprocessing.panels.actions.ExportToPNGAction; +import eu.engys.gui.solver.postprocessing.panels.actions.ShowCrosshairForResidualsAction; +import eu.engys.gui.solver.postprocessing.panels.actions.ShowLogFileAction; +import eu.engys.gui.solver.postprocessing.panels.utils.SelectedViewProvider; +import eu.engys.util.ui.UiUtil; + +public class ResidualsPanel extends DefaultGUIPanel implements SelectedViewProvider { + + private static final String TITLE = "Residuals"; + private ResidualsView residualsView; + private JToggleButton showCrosshairButton; + + @Inject + public ResidualsPanel(Model model, Controller controller) throws Exception { + super(TITLE, model); + this.residualsView = (ResidualsView) controller.getResidualView(); + } + + @Override + protected JComponent layoutComponents() { + populateToolbar(); + return residualsView.getPanel(); + } + + @Override + public void stop() { + super.stop(); + stopCrosshair(); + } + + private void stopCrosshair() { + if (showCrosshairButton.isSelected()) { + showCrosshairButton.doClick(); + } + } + + private void populateToolbar() { + titleToolbar.add(showCrosshairButton = UiUtil.createToolBarToggleButton(new ShowCrosshairForResidualsAction(residualsView), true)); + titleToolbar.addSeparator(); + titleToolbar.add(UiUtil.createToolBarButton(new ShowLogFileAction(this))); + titleToolbar.add(UiUtil.createToolBarButton(new ExportToExcelAction(this))); + titleToolbar.add(UiUtil.createToolBarButton(new ExportToCSVAction(this))); + titleToolbar.add(UiUtil.createToolBarButton(new ExportToPNGAction(this))); + + } + + @Override + public ParserView getSelectedView() { + return residualsView; + } + + @Override + public JComponent getPanel() { + return this; + } + + @Override + public void load() { + residualsView.reset(); + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsView.java b/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsView.java new file mode 100644 index 0000000..cf8deff --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/residuals/ResidualsView.java @@ -0,0 +1,101 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.residuals; + +import java.util.ArrayList; +import java.util.List; + +import eu.engys.core.project.Model; +import eu.engys.core.project.system.monitoringfunctionobjects.Parser; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.core.report.Exporter; +import eu.engys.gui.solver.postprocessing.panels.AbstractParserView; +import eu.engys.gui.solver.postprocessing.parsers.ResidualsParser; +import eu.engys.gui.solver.postprocessing.parsers.ResidualsUtils; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.UiUtil; + +public class ResidualsView extends AbstractParserView { + + private ResidualsChartPanel chartPanel; + + // public static void main(String[] args) { + // new HelyxLookAndFeel().init(); + // Model model = new Model(); + // model.init(); + // ResidualsView panel = new ResidualsView(model, null); + // JFrame f = UiUtil.defaultTestFrame("a", panel); + // f.setSize(600, 500); + // f.setVisible(true); + // } + + public ResidualsView(Model model, ProgressMonitor monitor) { + super(model, null, monitor); + this.chartPanel = new ResidualsChartPanel(); + chartPanel.layoutComponents(); + + tabbedPane.addTab("Residuals", chartPanel); + UiUtil.setOneTabHide(tabbedPane); + } + + @Override + public List gerReportParsersList() { + List reportParsersList = new ArrayList<>(); + reportParsersList.add(new ResidualsParser(ResidualsUtils.fileToParse(model))); + return reportParsersList; + } + + @Override + public Exporter getExporter() { + return new ResidualsExporter(gerReportParsersList(), monitor); + } + + @Override + public String getKey() { + return ResidualsParser.KEY; + } + + @Override + public void clearData() { + chartPanel.clearData(); + } + + @Override + public void handleFunctionObjectChanged() { + } + + @Override + public void stop() { + } + + @Override + public void updateParsing(List newTimeBlocks) { + if (!newTimeBlocks.isEmpty()) { + chartPanel.addToDataSet(newTimeBlocks.get(0)); + } + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAverageCalculator.java b/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAverageCalculator.java new file mode 100644 index 0000000..b8d963d --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAverageCalculator.java @@ -0,0 +1,161 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.utils; + +import org.jfree.data.xy.AbstractIntervalXYDataset; +import org.jfree.data.xy.XYDataItem; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.data.xy.YIntervalDataItem; +import org.jfree.data.xy.YIntervalSeries; +import org.jfree.data.xy.YIntervalSeriesCollection; + +public class MovingAverageCalculator { + + public static void calculate(AbstractIntervalXYDataset sourceDataset, AbstractIntervalXYDataset movingAverageDataSet, MovingAverageType type, int period) { + if (type.isTrailing()) { + if(sourceDataset instanceof XYSeriesCollection){ + calculateTrailing((XYSeriesCollection)sourceDataset, (XYSeriesCollection)movingAverageDataSet, period); + } else if(sourceDataset instanceof YIntervalSeriesCollection){ + calculateTrailing((YIntervalSeriesCollection)sourceDataset, (XYSeriesCollection)movingAverageDataSet, period); + } + } else { + if(sourceDataset instanceof XYSeriesCollection){ + calculateCentral((XYSeriesCollection)sourceDataset, (XYSeriesCollection)movingAverageDataSet, period); + } else if(sourceDataset instanceof YIntervalSeriesCollection){ + calculateCentral((YIntervalSeriesCollection)sourceDataset, (XYSeriesCollection)movingAverageDataSet, period); + } + } + } + + /* + * XY SERIES + */ + + // Sum of the left N-values, divided by N + private static void calculateTrailing(XYSeriesCollection sourceDataset, XYSeriesCollection movingAverageDataSet, int period) { + movingAverageDataSet.removeAllSeries(); + + for (int i = 0; i < sourceDataset.getSeriesCount(); i++) { + XYSeries origSeries = sourceDataset.getSeries(i); + XYSeries maSeries = new XYSeries(origSeries.getKey() + "-MAVG"); + + for (int j = 0; j < origSeries.getItemCount(); j++) { + XYDataItem origItem = origSeries.getDataItem(j); + if (j - (period - 1) < 0) { + // do nothing + } else { + double yValue = 0; + for (int k = (j - (period - 1)); k <= j; k++) { + yValue += origSeries.getDataItem(k).getYValue(); + } + maSeries.add(origItem.getXValue(), (yValue / period)); + } + } + movingAverageDataSet.addSeries(maSeries); + } + } + + // Sum of the N/2 left-values and of the N/2 right-values, divided by N + private static void calculateCentral(XYSeriesCollection sourceDataset, XYSeriesCollection movingAverageDataSet, int period) { + movingAverageDataSet.removeAllSeries(); + for (int i = 0; i < sourceDataset.getSeriesCount(); i++) { + XYSeries origSeries = sourceDataset.getSeries(i); + XYSeries maSeries = new XYSeries(origSeries.getKey() + "-MAVG"); + + int limit = (int) Math.floor(period / 2); + + for (int j = 0; j < origSeries.getItemCount(); j++) { + XYDataItem origItem = origSeries.getDataItem(j); + if (j - limit < 0) { + // do nothing + } else if (j + limit >= origSeries.getItemCount()) { + // do nothing + } else { + double yValue = 0; + for (int k = (j - limit); k <= (j + limit); k++) { + yValue += origSeries.getDataItem(k).getYValue(); + } + maSeries.add(origItem.getXValue(), (yValue / period)); + } + } + movingAverageDataSet.addSeries(maSeries); + } + } + + /* + * YSERIES + */ + + private static void calculateTrailing(YIntervalSeriesCollection sourceDataset, XYSeriesCollection movingAverageDataSet, int period) { + movingAverageDataSet.removeAllSeries(); + + for (int i = 0; i < sourceDataset.getSeriesCount(); i++) { + YIntervalSeries origSeries = sourceDataset.getSeries(i); + XYSeries maSeries = new XYSeries(origSeries.getKey() + "-MAVG"); + + for (int j = 0; j < origSeries.getItemCount(); j++) { + YIntervalDataItem origItem = (YIntervalDataItem) origSeries.getDataItem(j); + if (j - (period - 1) < 0) { + // do nothing + } else { + double yValue = 0; + for (int k = (j - (period - 1)); k <= j; k++) { + yValue += ((YIntervalDataItem) origSeries.getDataItem(k)).getYValue(); + } + maSeries.add(origItem.getX().doubleValue(), (yValue / period)); + } + } + movingAverageDataSet.addSeries(maSeries); + } + } + + private static void calculateCentral(YIntervalSeriesCollection sourceDataset, XYSeriesCollection movingAverageDataSet, int period) { + movingAverageDataSet.removeAllSeries(); + for (int i = 0; i < sourceDataset.getSeriesCount(); i++) { + YIntervalSeries origSeries = sourceDataset.getSeries(i); + XYSeries maSeries = new XYSeries(origSeries.getKey() + "-MAVG"); + + int limit = (int) Math.floor(period / 2); + + for (int j = 0; j < origSeries.getItemCount(); j++) { + YIntervalDataItem origItem = (YIntervalDataItem) origSeries.getDataItem(j); + if (j - limit < 0) { + // do nothing + } else if (j + limit >= origSeries.getItemCount()) { + // do nothing + } else { + double yValue = 0; + for (int k = (j - limit); k <= (j + limit); k++) { + yValue += ((YIntervalDataItem) origSeries.getDataItem(k)).getYValue(); + } + maSeries.add(origItem.getX().doubleValue(), (yValue / period)); + } + } + movingAverageDataSet.addSeries(maSeries); + } + } +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAveragePanel.java b/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAveragePanel.java new file mode 100644 index 0000000..2934ed8 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAveragePanel.java @@ -0,0 +1,105 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.utils; + +import java.awt.BorderLayout; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JComboBox; +import javax.swing.JPanel; + +import org.jfree.data.xy.AbstractIntervalXYDataset; + +import eu.engys.util.ui.ComponentsFactory; +import eu.engys.util.ui.builder.PanelBuilder; +import eu.engys.util.ui.textfields.IntegerField; + +public class MovingAveragePanel extends JPanel { + + private JComboBox type; + private IntegerField periodField; + + private AbstractIntervalXYDataset sourceDataSet; + private AbstractIntervalXYDataset movingAverageDataset; + + private MovingAverageType movingAverageType = MovingAverageType.TRAILING; + private int movingAveragePeriod = 1; + + public MovingAveragePanel(AbstractIntervalXYDataset sourceDataSet, AbstractIntervalXYDataset movingAverageDataSet) { + super(new BorderLayout()); + this.sourceDataSet = sourceDataSet; + this.movingAverageDataset = movingAverageDataSet; + layoutComponents(); + } + + private void layoutComponents() { + PanelBuilder builder = new PanelBuilder(); + + type = ComponentsFactory.selectField(new String[] { MovingAverageType.TRAILING.getLabel(), MovingAverageType.CENTERED.getLabel() }); + type.setPrototypeDisplayValue(MovingAverageType.CENTERED.getLabel()); + type.addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + updateMovingAverageType((String) type.getSelectedItem()); + } + } + }); + type.setSelectedItem(movingAverageType.getLabel()); + builder.addComponent("Type", type); + + periodField = ComponentsFactory.intField(1, Integer.MAX_VALUE); + periodField.addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + updateMovingAveragePeriod(periodField.getIntValue()); + } + } + }); + builder.addComponent("Period", periodField); + + add(builder.removeMargins().getPanel(), BorderLayout.CENTER); + } + + private void updateMovingAveragePeriod(int period) { + this.movingAveragePeriod = period; + updateMovingAverageDataset(); + } + + private void updateMovingAverageType(String label) { + this.movingAverageType = MovingAverageType.getTypeByLabel(label); + updateMovingAverageDataset(); + } + + public void updateMovingAverageDataset() { + MovingAverageCalculator.calculate(sourceDataSet, movingAverageDataset, movingAverageType, movingAveragePeriod); + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAverageType.java b/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAverageType.java new file mode 100644 index 0000000..52eef9b --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/utils/MovingAverageType.java @@ -0,0 +1,57 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.utils; + +public enum MovingAverageType { + + TRAILING("Trailing"), CENTERED("Centered"); + + private String label; + + private MovingAverageType(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } + + public boolean isTrailing() { + return equals(TRAILING); + } + + public static MovingAverageType getTypeByLabel(String label) { + MovingAverageType[] all = values(); + for (MovingAverageType type : all) { + if (type.getLabel().equals(label)) { + return type; + } + } + return null; + + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/utils/SelectedViewProvider.java b/src/eu/engys/gui/solver/postprocessing/panels/utils/SelectedViewProvider.java new file mode 100644 index 0000000..434bb7d --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/utils/SelectedViewProvider.java @@ -0,0 +1,32 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.utils; + +import eu.engys.core.project.system.monitoringfunctionobjects.ParserView; + +public interface SelectedViewProvider { + ParserView getSelectedView(); +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/utils/SeriesPanel.java b/src/eu/engys/gui/solver/postprocessing/panels/utils/SeriesPanel.java new file mode 100644 index 0000000..b8b05a8 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/utils/SeriesPanel.java @@ -0,0 +1,136 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.utils; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JPanel; + +import org.jfree.chart.renderer.xy.XYItemRenderer; + +import eu.engys.util.ui.ComponentsFactory; + +public class SeriesPanel extends JPanel { + + private Map seriesVisibility = new HashMap<>(); + private Map movingAverageSeriesVisibility = new HashMap<>(); + private JPanel seriesPanel; + private JPanel seriesAveragePanel; + + public SeriesPanel(JPanel movingAveragePanel) { + super(); + seriesPanel = new JPanel(new GridBagLayout()); + seriesAveragePanel = new JPanel(new GridBagLayout()); + + if (movingAveragePanel != null) { + setLayout(new GridLayout(2, 1)); + + JPanel movingAveragepanel = new JPanel(new BorderLayout()); + movingAveragepanel.setBorder(BorderFactory.createTitledBorder("Moving Average")); + movingAveragepanel.add(movingAveragePanel, BorderLayout.NORTH); + movingAveragepanel.add(seriesAveragePanel, BorderLayout.CENTER); + + seriesPanel.setBorder(BorderFactory.createTitledBorder("Series")); + add(seriesPanel); + add(movingAveragepanel); + } else { + setLayout(new BorderLayout()); + add(seriesPanel, BorderLayout.CENTER); + } + } + + public void clear() { + // do not clear visibility maps + seriesPanel.removeAll(); + seriesAveragePanel.removeAll(); + } + + public void addSeries(final XYItemRenderer renderer, final int seriesIndex, final String label) { + boolean visible = true; + if (seriesVisibility.containsKey(label)) { + visible = seriesVisibility.get(label); + } else { + seriesVisibility.put(label, visible); + } + final JCheckBox checkBox = ComponentsFactory.checkField(label, visible, getColorOfSeries(renderer, seriesIndex)); + checkBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (checkBox.isSelected()) { + seriesVisibility.put(label, true); + renderer.setSeriesVisible(seriesIndex, true, true); + } else { + seriesVisibility.put(label, false); + renderer.setSeriesVisible(seriesIndex, false, true); + } + } + }); + seriesPanel.add(checkBox, new GridBagConstraints(0, seriesIndex, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + } + + public void addMovingAverageSeries(final XYItemRenderer renderer, final int seriesIndex, final String label) { + boolean visible = false; + if (movingAverageSeriesVisibility.containsKey(label)) { + visible = movingAverageSeriesVisibility.get(label); + } else { + movingAverageSeriesVisibility.put(label, visible); + } + final JCheckBox checkBox = ComponentsFactory.checkField(label, visible, getColorOfSeries(renderer, seriesIndex)); + checkBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (checkBox.isSelected()) { + seriesVisibility.put(label, true); + renderer.setSeriesVisible(seriesIndex, true, true); + } else { + seriesVisibility.put(label, false); + renderer.setSeriesVisible(seriesIndex, false, true); + } + } + }); + + seriesAveragePanel.add(checkBox, new GridBagConstraints(0, seriesIndex, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + renderer.setSeriesVisible(seriesIndex, visible, true); + } + + // Used to colour points in the 3D + public static Color getColorOfSeries(XYItemRenderer renderer, int seriesIndex) { + Color colorWithTransparency = (Color) renderer.getItemPaint(seriesIndex, 0); + return new Color(colorWithTransparency.getRed(), colorWithTransparency.getGreen(), colorWithTransparency.getBlue()); + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/panels/utils/WaitLayerUI.java b/src/eu/engys/gui/solver/postprocessing/panels/utils/WaitLayerUI.java new file mode 100644 index 0000000..a8f1875 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/panels/utils/WaitLayerUI.java @@ -0,0 +1,288 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.panels.utils; + +import static java.awt.AlphaComposite.SRC_OVER; +import static java.awt.BasicStroke.CAP_ROUND; +import static java.awt.BasicStroke.JOIN_ROUND; +import static java.awt.RenderingHints.KEY_ANTIALIASING; +import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON; + +import java.awt.AWTEvent; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Composite; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.geom.Rectangle2D; +import java.beans.PropertyChangeEvent; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JLayer; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.plaf.LayerUI; + +import eu.engys.util.ui.ResourcesUtil; + +public class WaitLayerUI extends LayerUI implements ActionListener { + + private Timer timer; + private int angle; + private UiState state; + private Runnable runnable; + private boolean mouseOver; + + private static final int FPS = 24; + private static final int TICK = 1000 / FPS; + private static final String PROPERTY_NAME = "tick"; + + private static final Icon REFRESH_ICON_GRAY = ResourcesUtil.getIcon("chart.refresh.gray.icon"); + private static final Icon REFRESH_ICON_WHITE = ResourcesUtil.getIcon("chart.refresh.white.icon"); + + public WaitLayerUI(Runnable runnable) { + this.runnable = runnable; + init(); + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + JLayer jlayer = (JLayer) c; + jlayer.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); + } + + @Override + public void uninstallUI(JComponent c) { + JLayer jlayer = (JLayer) c; + jlayer.setLayerEventMask(0); + super.uninstallUI(c); + } + + public void init() { + changeState(UiState.SHOW_REFRESH); + } + + public void start() { + if (state.isShowingRefreshIcon()) { + timer = new Timer(TICK, this); + timer.start(); + changeState(UiState.SHOW_WHEEL); + } + } + + public void stop() { + if (state.isShowingRefreshIcon() || state.isShowingWheel()) { + changeState(UiState.SHOW_NOTHING); + if (timer != null) { + timer.stop(); + } + } + } + + @Override + public void paint(Graphics g, JComponent c) { + super.paint(g, c); + switch (state) { + case SHOW_REFRESH: + paintRefreshIcon(g, c); + break; + case SHOW_WHEEL: + paintLoadingWheel(g, c); + break; + case SHOW_NOTHING: + break; + default: + break; + } + } + + private void paintRefreshIcon(Graphics g, JComponent c) { + Graphics2D g2 = (Graphics2D) g.create(); + paintBackgroundPanel(g2, c); + paintBackgroundButton(g2, c); + paintRefreshIcon(g2, c); + g2.dispose(); + } + + private void paintLoadingWheel(Graphics g, JComponent c) { + Graphics2D g2 = (Graphics2D) g.create(); + paintBackgroundPanel(g2, c); + paintWheel(g2, c); + g2.dispose(); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (state.isShowingWheel()) { + repaintLayer(); + angle += 3; + if (angle >= 360) { + angle = 0; + } + } + } + + @Override + protected void processMouseEvent(MouseEvent event, JLayer layer) { + if (event.getID() == MouseEvent.MOUSE_RELEASED && isOnRefreshButton(layer, event)) { + if (state.isShowingRefreshIcon()) { + runnable.run(); + } + } + } + + @Override + protected void processMouseMotionEvent(MouseEvent event, JLayer layer) { + if (event.getID() == MouseEvent.MOUSE_MOVED) { + if (isOnRefreshButton(layer, event)) { + mouseOver = true; + } else { + mouseOver = false; + } + repaintLayer(); + } + } + + public boolean isOnRefreshButton(JLayer layer, MouseEvent event) { + ImageIcon imageIcon = (ImageIcon) REFRESH_ICON_GRAY; + int x = (layer.getWidth() - imageIcon.getIconWidth()) / 2; + int y = (layer.getHeight() - imageIcon.getIconHeight()) / 2; + int w = imageIcon.getIconWidth(); + int h = imageIcon.getIconHeight(); + Rectangle2D refreshIconBounds = new Rectangle2D.Double(x, y, w, h); + Point mousePoint = SwingUtilities.convertPoint((Component) event.getSource(), event.getPoint(), layer); + return refreshIconBounds.contains(mousePoint); + } + + private void changeState(UiState state) { + this.state = state; + repaintLayer(); + } + + private void repaintLayer() { + firePropertyChange(PROPERTY_NAME, 0, 1); + } + + @Override + public void applyPropertyChange(PropertyChangeEvent event, JLayer layer) { + if (PROPERTY_NAME.equals(event.getPropertyName())) { + layer.repaint(); + } + } + + /* + * Paint + */ + private void paintRefreshIcon(Graphics2D g2, JComponent c) { + ImageIcon imageGray = (ImageIcon) REFRESH_ICON_GRAY; + ImageIcon imageWhite = (ImageIcon) REFRESH_ICON_WHITE; + int x = ((c.getWidth() - imageGray.getIconWidth()) / 2); + int y = ((c.getHeight() - imageGray.getIconHeight()) / 2); + + if (mouseOver) { + g2.drawImage(imageWhite.getImage(), x, y, null); + } else { + g2.drawImage(imageGray.getImage(), x, y, null); + } + } + + private void paintWheel(Graphics2D g2, JComponent c) { + int cx = c.getWidth() / 2; + int cy = c.getHeight() / 2; + int stroke = 3; + int linesSize = 9; + + g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON); + g2.setStroke(new BasicStroke(stroke, CAP_ROUND, JOIN_ROUND)); + g2.setPaint(Color.GRAY.darker()); + g2.rotate(Math.PI * angle / 180, cx, cy); + for (int i = 0; i < 12; i++) { + float scale = (11.0f - (float) i) / 11.0f; + g2.drawLine(cx + linesSize, cy, cx + linesSize * 2, cy); + g2.rotate(-Math.PI / 6, cx, cy); + g2.setComposite(AlphaComposite.getInstance(SRC_OVER, scale)); + } + } + + private void paintBackgroundButton(Graphics2D g2, JComponent c) { + ImageIcon image = (ImageIcon) REFRESH_ICON_GRAY; + int padding = 8; + int x = ((c.getWidth() - image.getIconWidth()) / 2); + int y = ((c.getHeight() - image.getIconHeight()) / 2); + int w = image.getIconWidth(); + int h = image.getIconHeight(); + int roundAngle = image.getIconWidth() / 2; + int grayIntensity = 100; + + g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON); + g2.setColor(new Color(grayIntensity, grayIntensity, grayIntensity)); + g2.fillRoundRect(x - padding, y - padding, w + (padding * 2), h + (padding * 2), roundAngle, roundAngle); + } + + private void paintBackgroundPanel(Graphics2D g2, JComponent c) { + int w = c.getWidth(); + int h = c.getHeight(); + + // float alpha = 1.0f; + float alpha = 0.6f; + Color color = new JPanel().getBackground(); + + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Composite backupComposite = g2.getComposite(); + g2.setColor(color); + g2.setComposite(AlphaComposite.getInstance(SRC_OVER, alpha)); + g2.fillRect(0, 0, w, h); + g2.setComposite(backupComposite); + } + + private enum UiState { + SHOW_REFRESH, SHOW_WHEEL, SHOW_NOTHING; + + public boolean isShowingRefreshIcon() { + return this == SHOW_REFRESH; + } + + public boolean isShowingWheel() { + return this == SHOW_WHEEL; + } + + public boolean isShowingNothing() { + return this == SHOW_NOTHING; + } + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/parsers/AbstractParser.java b/src/eu/engys/gui/solver/postprocessing/parsers/AbstractParser.java new file mode 100644 index 0000000..90da429 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/parsers/AbstractParser.java @@ -0,0 +1,169 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.parsers; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObject; +import eu.engys.core.project.system.monitoringfunctionobjects.Parser; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.util.Util; + +public abstract class AbstractParser implements Parser { + + private static final int MAX_LINES_PARSED_AT_A_TIME = 100_000; + + private static final Logger logger = LoggerFactory.getLogger(AbstractParser.class); + + private boolean isParserInitialised; + private BufferedReader in; + + protected MonitoringFunctionObject functionObject; + + protected File file; + + protected String blockKey; + + private boolean needUpdate; + + public AbstractParser(MonitoringFunctionObject functionObject, File file, String blockKey) { + this.functionObject = functionObject; + this.file = file; + this.blockKey = blockKey; + } + + public AbstractParser(MonitoringFunctionObject functionObject, File file) { + this(functionObject, file, file.getName()); + } + + @Override + public void clear() { + } + + @Override + public void init() { + logger.debug("INIT: {} [{}]", getClass().getSimpleName(), getFile()); + try { + File file = getFile(); + if (file.exists()) { + in = new BufferedReader(new FileReader(file), 2048); + logger.info("{} Parsing file {}", getClass().getCanonicalName(), file); + } + } catch (Exception e) { + logger.warn("INIT PROBLEM: {}", e.getMessage()); + } finally { + isParserInitialised = true; + } + } + + @Override + public TimeBlocks updateParsing() throws Exception { + logger.debug("UPDATE: {} [{}] ", getClass().getSimpleName(), getFile()); + if (in == null && isParserInitialised) { + init(); + } + + if (in != null) { + return parse(); + } + + return new TimeBlocks(blockKey); + } + + @Override + public void end() { + if (in != null) { + logger.debug("END: {} [{}]", getClass().getSimpleName(), getFile()); + try { + in.close(); + } catch (Exception e) { + logger.warn("END PROBLEM: {}", e.getMessage()); + } finally { + in = null; + isParserInitialised = false; + } + } + } + + private TimeBlocks parse() throws IOException { + needUpdate = false; + List newFileLines = updateNewFileLines(); + if (newFileLines.size() > 0) { + TimeBlocks timeBlocks = updateNewTimeBlocks(newFileLines); + removeInconsistentBlocks(timeBlocks); + checkTimeBlockConsistency(timeBlocks); + newFileLines = null; + System.gc(); + + if (needUpdate) { + timeBlocks.addAll(parse()); + } + + return timeBlocks; + } + + return new TimeBlocks(blockKey); + } + + public List updateNewFileLines() throws IOException { + List newFileLines = new ArrayList<>(); + String s = null; + int i = 0; + while ((s = in.readLine()) != null) { + String line = Util.getTrimmedSingleSpaceLine(s); + if (!line.isEmpty()) { + newFileLines.add(line); + i++; + } + if (i == MAX_LINES_PARSED_AT_A_TIME) { + needUpdate = true; + break; + } + } + return newFileLines; + } + + protected void removeInconsistentBlocks(TimeBlocks newTimeBlocks) { + } + + protected abstract TimeBlocks updateNewTimeBlocks(List newFileLines); + + public abstract boolean checkTimeBlockConsistency(TimeBlocks newTimeBlocks); + + @Override + public File getFile() { + return file; + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/parsers/ParserUtils.java b/src/eu/engys/gui/solver/postprocessing/parsers/ParserUtils.java new file mode 100644 index 0000000..185e7f1 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/parsers/ParserUtils.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.parsers; + +import org.slf4j.Logger; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlock; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; + +public class ParserUtils { + + public static boolean checkTimeBlockConsistency(TimeBlocks newTimeBlocks, int variablesSize, Logger logger) { + if(newTimeBlocks.isEmpty() || variablesSize < 0){ + return true; + } + for (TimeBlock timeBlock : newTimeBlocks) { + if(timeBlock.getSize() < variablesSize){ + logger.error("The number of units is smaller than the number of variables : {} < {}", timeBlock.getSize(), variablesSize); + return false; + } + if(timeBlock.getSize() > variablesSize){ + logger.error("The number of units is bigger than the number of variables : {} > {}", timeBlock.getSize(), variablesSize); + return false; + } + } + return true; + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/parsers/ResidualsParser.java b/src/eu/engys/gui/solver/postprocessing/parsers/ResidualsParser.java new file mode 100644 index 0000000..3bd9109 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/parsers/ResidualsParser.java @@ -0,0 +1,234 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.parsers; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlock; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlockUnit; +import eu.engys.core.project.system.monitoringfunctionobjects.TimeBlocks; +import eu.engys.gui.solver.postprocessing.data.DoubleListTimeBlockUnit; + +public class ResidualsParser extends AbstractParser { + + private static final Logger logger = LoggerFactory.getLogger(ResidualsParser.class); + public static final String KEY = "residuals"; + + private static final String CHECK_STRING1 = ", Initial residual = "; + private static final String CHECK_STRING2 = ", Final residual"; + private static final String CHECK_STRING3 = "Solving for "; + private static final String ILAMBDA = "ILambda"; + public static final String TIME_PREFIX = "Time = "; + + // COUPLED + private static final String TIME_PREFIX_COUPLED = "PHYSICAL TIME = "; + private static final String U_MOM = "U-Mom"; + private static final String V_MOM = "V-Mom"; + private static final String W_MOM = "W-Mom"; + private static final String P_MASS = "p-Mass"; + private static final String K_EQN = "K-Eqn"; + private static final String OMEGA_EQN = "Omega-Eqn"; + private static final String EPSILON_EQN = "Epsilon-Eqn"; + + private TimeBlock incompleteBlock;// from previous parsing + + private int timeBlockSize = -1; + + public ResidualsParser(File file) { + super(null, file); + this.incompleteBlock = null; + this.timeBlockSize = -1; + } + + @Override + public String getKey() { + return KEY; + } + + @Override + public void clear() { + super.clear(); + this.timeBlockSize = -1; + this.incompleteBlock = null; + } + + @Override + public TimeBlocks updateNewTimeBlocks(List newFileLines) { + // newTimeBlocks.clear(); + TimeBlocks newTimeBlocks = new TimeBlocks(blockKey); + + if (incompleteBlock != null) { + newTimeBlocks.add(incompleteBlock); + incompleteBlock = null; + } + for (String row : newFileLines) { + if (isValidTimeRow(row)) { + TimeBlock timeBlock = new TimeBlock(Double.parseDouble(extractTimeValue(row))); + newTimeBlocks.add(timeBlock); + } else if (newTimeBlocks.size() > 0 && isValidDataRow(row)) { + String extractVarName = extractVarName(row); + TimeBlock lastTimeBlock = newTimeBlocks.getLast(); + Map unitsMap = lastTimeBlock.getUnitsMap(); + if (!unitsMap.containsKey(extractVarName)) { + unitsMap.put(extractVarName, new DoubleListTimeBlockUnit(extractVarName)); + } + DoubleListTimeBlockUnit unit = (DoubleListTimeBlockUnit) unitsMap.get(extractVarName); + unit.getValues().add(extractInitialResidual(row)); + } + } + + return newTimeBlocks; + } + + public boolean checkTimeBlockConsistency(TimeBlocks newTimeBlocks) { + return ParserUtils.checkTimeBlockConsistency(newTimeBlocks, timeBlockSize, logger); + } + + @Override + public void removeInconsistentBlocks(TimeBlocks newTimeBlocks) { + boolean timeBlockSizeNotSet = timeBlockSize == -1; + if (newTimeBlocks.size() == 0) { + return; + } else { + if (newTimeBlocks.size() == 1 && timeBlockSizeNotSet) { + // E' il primo blocco in assoluto e non so se e' completo + this.incompleteBlock = newTimeBlocks.removeLast(); + return; + } else { + // Ho piu' di un blocco (quindi almeno il primo e' completo) + // Oppure ho un blocco solo ma non e' il primo (lo capisco dal + // fatto che timeBlockSize e' settata) + + if (timeBlockSizeNotSet) { + timeBlockSize = newTimeBlocks.get(0).getUnitsMap().size(); + } + + if (lastBlockIsIncomplete(newTimeBlocks)) { + this.incompleteBlock = newTimeBlocks.removeLast(); + logger.debug("Block {} is smaller than it should: {} < {} and will be reprocessed", incompleteBlock.getTime(), incompleteBlock.getUnitsMap().size(), timeBlockSize); + } else if (lastBlockIsOK(newTimeBlocks)) { + /* is OK */ + } else { + logger.debug("Block {} is bigger than it should: {} > {}", newTimeBlocks.getLast().getTime(), newTimeBlocks.getLast().getUnitsMap().size(), timeBlockSize); + } + } + } + } + + private boolean lastBlockIsIncomplete(TimeBlocks newTimeBlocks) { + TimeBlock lastBlock = newTimeBlocks.getLast(); + return lastBlock.getUnitsMap().size() < timeBlockSize; + } + + private boolean lastBlockIsOK(TimeBlocks newTimeBlocks) { + TimeBlock lastBlock = newTimeBlocks.getLast(); + return lastBlock.getUnitsMap().size() == timeBlockSize; + } + + @Override + public boolean isValidTimeRow(String row) { + boolean isResidualsTimeRow = row.startsWith(TIME_PREFIX); + boolean isCoupledResidualsTimeRow = row.startsWith(TIME_PREFIX_COUPLED); + return isResidualsTimeRow || isCoupledResidualsTimeRow; + } + + @Override + public boolean isValidDataRow(String row) { + return isValidResidualsDataRow(row) || isValidCoupledResidualsDataRow(row); + } + + private boolean isValidResidualsDataRow(String row) { + return row.contains(CHECK_STRING1) && row.contains(CHECK_STRING2) && row.contains(CHECK_STRING3) && !row.contains(ILAMBDA); + } + + private boolean isValidCoupledResidualsDataRow(String row) { + return row.contains(U_MOM) || row.contains(V_MOM) || row.contains(W_MOM) || row.contains(P_MASS) || row.contains(K_EQN) || row.contains(OMEGA_EQN) || row.contains(EPSILON_EQN); + } + + public String extractTimeValue(String row) { + if (row.startsWith(TIME_PREFIX)) { + return row.substring(row.indexOf(TIME_PREFIX) + TIME_PREFIX.length()); + } else if (row.startsWith(TIME_PREFIX_COUPLED)) { + return row.substring(row.indexOf(TIME_PREFIX_COUPLED) + TIME_PREFIX_COUPLED.length()); + } + return ""; + } + + public String extractVarName(String row) { + if (isValidResidualsDataRow(row)) { + return row.substring(row.indexOf(CHECK_STRING3) + CHECK_STRING3.length(), row.indexOf(CHECK_STRING1)); + } else if (isValidCoupledResidualsDataRow(row)) { + if (row.contains(U_MOM)) { + return "Ux"; + } else if (row.contains(V_MOM)) { + return "Uy"; + } else if (row.contains(W_MOM)) { + return "Uz"; + } else if (row.contains(P_MASS)) { + return "p"; + } else if (row.contains(K_EQN)) { + return "k"; + } else if (row.contains(OMEGA_EQN)) { + return "omega"; + } else if (row.contains(EPSILON_EQN)) { + return "epsilon"; + } else { + return ""; + } + } else { + return ""; + } + } + + public Double extractInitialResidual(String row) { + if (isValidResidualsDataRow(row)) { + return Double.parseDouble(row.substring(row.indexOf(CHECK_STRING1) + CHECK_STRING1.length(), row.indexOf(CHECK_STRING2))); + } else if (isValidCoupledResidualsDataRow(row)) { + // the value is beetween the 4th and 5th "|" + int initialDelimiter = StringUtils.ordinalIndexOf(row, "|", 4); + int finalDelimiter = StringUtils.ordinalIndexOf(row, "|", 5); + String stringValue = row.substring(initialDelimiter + 1, finalDelimiter).trim(); + return Double.parseDouble(stringValue); + } + return 0.0; + } + + // For test purpose only + public void setIncompleteBlock(TimeBlock incompleteBlock) { + this.incompleteBlock = incompleteBlock; + } + + public void setTimeBlockSize(int timeBlockSize) { + this.timeBlockSize = timeBlockSize; + } + +} diff --git a/src/eu/engys/gui/solver/postprocessing/parsers/ResidualsUtils.java b/src/eu/engys/gui/solver/postprocessing/parsers/ResidualsUtils.java new file mode 100644 index 0000000..5a05f60 --- /dev/null +++ b/src/eu/engys/gui/solver/postprocessing/parsers/ResidualsUtils.java @@ -0,0 +1,61 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.solver.postprocessing.parsers; + +import java.io.File; +import java.nio.file.Paths; + +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.util.IOUtils; + +public class ResidualsUtils { + + public static void clearLogFile(Model model) { + File logFile = fileToParse(model); + if (logFile != null && logFile.exists()) { + IOUtils.clearFile(logFile); + } + } + + public static File fileToParse(Model model) { + String logFile = model.getSolverModel().getLogFile(); + if (logFile.isEmpty()) { + logFile = guessLogFile(model); + } + return Paths.get(model.getProject().getBaseDir().getAbsolutePath(), openFOAMProject.LOG, logFile).toFile(); + + } + + private static String guessLogFile(Model model) { + String application = model.getState().getSolver().getName(); + if (application != null && !application.isEmpty()) { + return application + ".log"; + } + return "none.log"; + } + +} diff --git a/src/eu/engys/gui/tree/AbstractSelectionHandler.java b/src/eu/engys/gui/tree/AbstractSelectionHandler.java new file mode 100644 index 0000000..fcb7859 --- /dev/null +++ b/src/eu/engys/gui/tree/AbstractSelectionHandler.java @@ -0,0 +1,47 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.tree; + + +public abstract class AbstractSelectionHandler implements SelectionHandler { + + private boolean enabled = true; + @Override + public void enable() { + this.enabled = true; + } + + @Override + public void disable() { + this.enabled = false; + } + + @Override + public boolean isEnabled() { + return enabled; + } + +} diff --git a/src/eu/engys/gui/tree/DefaultTreeNodeManager.java b/src/eu/engys/gui/tree/DefaultTreeNodeManager.java new file mode 100644 index 0000000..bb59bb3 --- /dev/null +++ b/src/eu/engys/gui/tree/DefaultTreeNodeManager.java @@ -0,0 +1,118 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.tree; + +import java.util.HashMap; +import java.util.Map; +import java.util.Observable; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.MutableTreeNode; + +import eu.engys.core.project.Model; +import eu.engys.gui.GUIPanel; + +public class DefaultTreeNodeManager implements TreeNodeManager { + + protected DefaultMutableTreeNode root; + protected Model model; + private Tree tree; + protected Map nodeMap; + + public DefaultTreeNodeManager(Model model, GUIPanel guiPanel) { + this.model = model; + this.nodeMap = new HashMap(); + this.root = new DefaultMutableTreeNode(guiPanel); + } + + @Override + public void update(Observable o, Object arg) { + } + + @Override + public void clear() { + } + + @Override + public DefaultMutableTreeNode getRoot() { + return root; + } + + @Override + public void setTree(Tree tree) { + this.tree = tree; + } + + @Override + public Tree getTree() { + return tree; + } + + @Override + public DefaultTreeCellRenderer getRenderer() { + return null; + } + + @Override + public SelectionHandler getSelectionHandler() { + return null; + } + + @Override + public PopUpBuilder getPopUpBuilder() { + return null; + } + + @Override + public Class getRendererClass() { + return null; + } + + protected void treeChanged(DefaultMutableTreeNode node) { + if (tree != null) { + int[] childIndices = new int[node.getChildCount()]; + for (int i = 0; i < childIndices.length; i++) { + childIndices[i] = node.getIndex(node.getChildAt(i)); + } + getTree().getModel().reload(node); + } + } + + public void refreshNode(K key) { + getTree().getModel().nodeChanged(nodeMap.get(key)); + } + + protected void clearNode(DefaultMutableTreeNode node) { + if (tree != null) { + for (int i = node.getChildCount() - 1; i >= 0; i--) { + getTree().getModel().removeNodeFromParent((MutableTreeNode) node.getChildAt(i)); + } + getTree().getModel().reload(node); + } + } +} diff --git a/src/eu/engys/gui/tree/GUIPanelHandler.java b/src/eu/engys/gui/tree/GUIPanelHandler.java new file mode 100644 index 0000000..ad964d4 --- /dev/null +++ b/src/eu/engys/gui/tree/GUIPanelHandler.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.tree; + +import java.util.Set; + +import eu.engys.gui.GUIPanel; + +public interface GUIPanelHandler { + + Set getPanels(); + + void selectPanel(String key); + void selectAndClearPanel(String key); + + +} diff --git a/src/eu/engys/gui/tree/SelectionHandler.java b/src/eu/engys/gui/tree/SelectionHandler.java new file mode 100644 index 0000000..c3e0ab4 --- /dev/null +++ b/src/eu/engys/gui/tree/SelectionHandler.java @@ -0,0 +1,48 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.tree; + +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public interface SelectionHandler { + + void enable(); + void disable(); + boolean isEnabled(); + + void handleSelection(boolean fire3DEvent, Object... selection); + void handleVisibility(VisibleItem item); + + void process3DSelectionEvent(Picker picker, Actor actor, boolean keep); + void process3DVisibilityEvent(boolean selected); + + void clear(); + + +} diff --git a/src/eu/engys/gui/tree/Tree.java b/src/eu/engys/gui/tree/Tree.java new file mode 100644 index 0000000..63cc198 --- /dev/null +++ b/src/eu/engys/gui/tree/Tree.java @@ -0,0 +1,581 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.tree; + +import java.awt.Component; +import java.awt.Font; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import eu.engys.core.modules.ModulePanel; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.EventManager.Event; +import eu.engys.gui.events.EventManager.GenericEventListener; +import eu.engys.gui.events.view3D.ActorPopUpEvent; +import eu.engys.gui.events.view3D.ActorSelectionEvent; +import eu.engys.gui.events.view3D.ActorVisibilityEvent; +import eu.engys.gui.events.view3D.VisibleItemEvent; +import eu.engys.gui.tree.TreeNodeManager.PopUpBuilder; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.TreeUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.checkboxtree.AddCheckBoxToTree; +import eu.engys.util.ui.checkboxtree.AddCheckBoxToTree.CheckBoxSelectionListener; +import eu.engys.util.ui.checkboxtree.AddCheckBoxToTree.CheckTreeManager; +import eu.engys.util.ui.checkboxtree.RootVisibleItem; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class Tree extends JScrollPane { + + private final GUIPanelHandler panelsHandler; + + private DefaultTreeModel treeModel; + private Map nodesMap = new HashMap(); + private Map, DefaultTreeCellRenderer> renderersMap = new HashMap<>(); + private Map selectionHandlersMap = new HashMap<>(); + private Map, PopUpBuilder> popupBuildersMap = new HashMap<>(); + private JTree tree; + private DefaultMutableTreeNode root; + private CheckTreeManager checkManager; + + private boolean fire3DEvent = true; + + private PopUpMenuListener popUp; + + public Tree(GUIPanelHandler panelsHandler) { + super(); + this.panelsHandler = panelsHandler; + layoutComponents(); + } + + private void layoutComponents() { + root = new DefaultMutableTreeNode(); + treeModel = new DefaultTreeModel(root); + tree = new JTree(treeModel); + tree.setToggleClickCount(0); + tree.setSelectionModel(new TreeSelectionModel()); + tree.setRootVisible(false); + tree.setCellRenderer(new TreeRenderer()); + tree.setRowHeight(20); + tree.setLargeModel(true); + + setViewportView(tree); + + Set panels = panelsHandler.getPanels(); + for (GUIPanel guiPanel : panels) { + addPanel(guiPanel); + } + + treeModel.nodeStructureChanged(root); + + checkManager = AddCheckBoxToTree.toTree(tree).withListener(new CheckBoxTreeToPanels()); + tree.getSelectionModel().addTreeSelectionListener(new TreeToPanels()); + + popUp = new PopUpMenuListener(); + tree.addMouseListener(popUp); + } + + public CheckTreeManager getCheckManager() { + return checkManager; + } + + public void addListener() { + EventManager.registerEventListener(new ActorPopUpListener(), ActorPopUpEvent.class); + EventManager.registerEventListener(new ActorSelectionListener(), ActorSelectionEvent.class); + EventManager.registerEventListener(new ActorVisibilityListener(), ActorVisibilityEvent.class); + } + + public void removeListener() { + EventManager.unregisterEventSubscriptions(ActorPopUpEvent.class); + EventManager.unregisterEventSubscriptions(ActorSelectionEvent.class); + EventManager.unregisterEventSubscriptions(ActorVisibilityEvent.class); + } + + public void addPanel(GUIPanel guiPanel) { + TreeNodeManager treeNodeManager = guiPanel.getTreeNodeManager(); + treeNodeManager.setTree(this); + DefaultMutableTreeNode node = treeNodeManager.getRoot(); + + installRenderer(treeNodeManager); + installListener(treeNodeManager); + installPopUpActions(treeNodeManager); + + nodesMap.put(guiPanel, node); + + int childIndex = guiPanel.getIndex(); + if (childIndex >= 0 && childIndex <= root.getChildCount()) { + root.insert(node, childIndex); + } else { + root.add(node); + } + + getModel().reload(); + expandNode(); + } + + public void removePanel(GUIPanel guiPanel) { + if (nodesMap.containsKey(guiPanel)) { + DefaultMutableTreeNode node = nodesMap.remove(guiPanel); + + TreeNodeManager treeNodeManager = guiPanel.getTreeNodeManager(); + removeRenderer(treeNodeManager); + removeListener(treeNodeManager); + removePopUpActions(treeNodeManager); + + root.remove(node); + getModel().reload(); + expandNode(); + } + } + + private void installRenderer(TreeNodeManager treeNodeManager) { + DefaultTreeCellRenderer renderer = treeNodeManager.getRenderer(); + Class rendererClass = treeNodeManager.getRendererClass(); + if (renderer != null) { + renderersMap.put(rendererClass, renderer); + } + } + + private void removeRenderer(TreeNodeManager treeNodeManager) { + Class rendererClass = treeNodeManager.getRendererClass(); + if (renderersMap.containsKey(rendererClass)) { + renderersMap.remove(rendererClass); + } + } + + private void installListener(TreeNodeManager treeNodeManager) { + SelectionHandler handler = treeNodeManager.getSelectionHandler(); + DefaultMutableTreeNode root = treeNodeManager.getRoot(); + if (handler != null) { + selectionHandlersMap.put(root, handler); + } + } + + private void removeListener(TreeNodeManager treeNodeManager) { + DefaultMutableTreeNode root = treeNodeManager.getRoot(); + if (selectionHandlersMap.containsKey(root)) { + selectionHandlersMap.remove(root); + } + } + + private void installPopUpActions(TreeNodeManager treeNodeManager) { + PopUpBuilder builder = treeNodeManager.getPopUpBuilder(); + Class rendererClass = treeNodeManager.getRendererClass(); + if (builder != null) { + popupBuildersMap.put(rendererClass, builder); + } + } + + private void removePopUpActions(TreeNodeManager treeNodeManager) { + Class rendererClass = treeNodeManager.getRendererClass(); + if (popupBuildersMap.containsKey(rendererClass)) { + popupBuildersMap.remove(rendererClass); + } + } + + public void selectPanel(GUIPanel panel) { + if (nodesMap.containsKey(panel)) { + TreeNode node = nodesMap.get(panel); + tree.setSelectionPath(new TreePath(getModel().getPathToRoot(node))); + } + } + + private final class ActorSelectionListener implements GenericEventListener { + @Override + public void eventTriggered(Object obj, Event event) { + ActorSelectionEvent selectionEvent = ActorSelectionEvent.class.cast(event); + final Actor selection = selectionEvent.getActor(); + final boolean keep = selectionEvent.isKeep(); + final Picker picker = selectionEvent.getPicker(); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + processSelectionEvent(picker, selection, keep); + } + }); + } + + private void processSelectionEvent(Picker picker, Actor actor, boolean keep) { + if (actor == null) { + TreePath[] selectionPath = tree.getSelectionPaths(); + if (selectionPath != null) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPath[0].getLastPathComponent(); + DefaultMutableTreeNode parent = TreeUtil.getFirstLevelParent(node); + tree.setSelectionPath(new TreePath(getModel().getPathToRoot(parent))); + } + } else { + for (SelectionHandler handler : selectionHandlersMap.values()) { + if (handler.isEnabled()) { + handler.process3DSelectionEvent(picker, actor, keep); + } + } + } + } + + } + + private final class ActorPopUpListener implements GenericEventListener { + @Override + public void eventTriggered(Object obj, Event event) { + ActorPopUpEvent popUpEvent = ActorPopUpEvent.class.cast(event); + Actor selection = popUpEvent.getActor(); + Picker picker = popUpEvent.getPicker(); + if (selection != null) { + popUp.mouseReleased(popUpEvent.getMouseEvent()); + } + } + } + + private final class ActorVisibilityListener implements GenericEventListener { + @Override + public void eventTriggered(Object obj, Event event) { + ActorVisibilityEvent selectionEvent = ActorVisibilityEvent.class.cast(event); + final boolean select = selectionEvent.isSelect(); + + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + processTreeCheckBoxSelectionEvent(select); + } + }); + } + + private void processTreeCheckBoxSelectionEvent(boolean selected) { + for (SelectionHandler handler : selectionHandlersMap.values()) { + if (handler.isEnabled()) { + handler.process3DVisibilityEvent(selected); + } + } + tree.repaint(); + } + + } + + private final class TreeToPanels implements TreeSelectionListener { + @Override + public void valueChanged(TreeSelectionEvent e) { + TreePath[] selectionPath = tree.getSelectionPaths(); + if (selectionPath != null) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPath[0].getLastPathComponent(); + List selection = TreeUtil.toUserObjects(selectionPath); + + if (node.getLevel() != 1) { + DefaultMutableTreeNode firstLevelParent = TreeUtil.getFirstLevelParent(node); + selectPanelByNode(firstLevelParent); + + SelectionHandler selectionHandler = selectionHandlersMap.get(firstLevelParent); + if (selectionHandler.isEnabled()) { + selectionHandler.handleSelection(fire3DEvent, selection.toArray()); + } + } else { + selectAndClerPanelByNode(node); + } + } else { + for (SelectionHandler handler : selectionHandlersMap.values()) { + if (handler.isEnabled()) { + handler.handleSelection(fire3DEvent, new Object[0]); + } + } + } + } + + private void selectAndClerPanelByNode(DefaultMutableTreeNode node) { + if (node.getLevel() == 1) { + selectAndClearPanelByNode(node); + } else { + selectAndClearPanelByFirstLevelParent(node); + } + } + + private void selectAndClearPanelByNode(DefaultMutableTreeNode node) { + panelsHandler.selectAndClearPanel(getNodeLabel(node)); + } + + private void selectAndClearPanelByFirstLevelParent(DefaultMutableTreeNode node) { + DefaultMutableTreeNode firstLevelParent = TreeUtil.getFirstLevelParent(node); + selectAndClearPanelByNode(firstLevelParent); + } + + private void selectPanelByNode(DefaultMutableTreeNode node) { + panelsHandler.selectPanel(getNodeLabel(node)); + } + + private String getNodeLabel(DefaultMutableTreeNode node) { + Object userObject = node.getUserObject(); + if (userObject instanceof String) { + return (String) userObject; + } else if (userObject instanceof ModulePanel) { + return ((ModulePanel) userObject).getKey(); + } else if (userObject instanceof RootVisibleItem) { + return ((RootVisibleItem) userObject).getName(); + } else { + return ""; + } + } + + } + + private final class CheckBoxTreeToPanels implements CheckBoxSelectionListener { + + @Override + public void selectionAdded(DefaultMutableTreeNode node) { + // System.out.println("Tree.CheckBoxTreeToPanels.selectionAdded()"); + Object userObject = node.getUserObject(); + if (userObject instanceof RootVisibleItem) { + if (node.getChildCount() > 0) { + for (int i = 0; i < node.getChildCount(); i++) { + DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i); + selectionAdded(child); + } + } + } else if (userObject instanceof VisibleItem) { + selectNode(node, true); + } + } + + private void selectNode(DefaultMutableTreeNode node, boolean selected) { + Object userObject = node.getUserObject(); + VisibleItem item = (VisibleItem) userObject; + item.setVisible(selected); + + if (node.getLevel() != 1) { + DefaultMutableTreeNode firstLevelParent = TreeUtil.getFirstLevelParent(node); + SelectionHandler handler = selectionHandlersMap.get(firstLevelParent); + if (handler.isEnabled()) { + handler.handleVisibility(item); + EventManager.triggerEvent(this, new VisibleItemEvent(this, (VisibleItem) userObject)); + } + } + } + + @Override + public void selectionRemoved(DefaultMutableTreeNode node) { + // System.out.println("Tree.CheckBoxTreeToPanels.selectionRemoved() "+node); + Object userObject = node.getUserObject(); + if (userObject instanceof RootVisibleItem) { + if (node.getChildCount() > 0) { + for (int i = 0; i < node.getChildCount(); i++) { + DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i); + selectionRemoved(child); + } + } + } else if (userObject instanceof VisibleItem) { + selectNode(node, false); + } + } + } + + public class TreeRenderer extends DefaultTreeCellRenderer { + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + + Object userObject = node.getUserObject(); + if (userObject != null) { + Class klass = containsClass(userObject.getClass()); + if (klass != Object.class) { + return renderersMap.get(klass).getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + } + } + super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + if (userObject instanceof ModulePanel) { + setText(((ModulePanel) userObject).getTitle()); + } + if (node.getLevel() == 1) { + setFont(tree.getFont().deriveFont(Font.BOLD)); + } else { + setFont(tree.getFont().deriveFont(Font.PLAIN)); + } + setIcon(null); + return this; + } + } + + private Class containsClass(Class klass) { + if (klass == null) { + return Object.class; + } + if (renderersMap.containsKey(klass)) { + return klass; + } + + if (klass.getSuperclass() != null && klass.getSuperclass() != Object.class) { + return containsClass(klass.getSuperclass()); + } + + if (klass.getInterfaces().length != 0) { + for (Class c : klass.getInterfaces()) { + Class k = containsClass(c); + if (k != Object.class) { + return k; + } + } + } + return Object.class; + } + + public void clearAllSelections() { + tree.clearSelection(); + checkManager.clearSelection(); + } + + public void clearSelection() { + tree.clearSelection(); + } + + public void clearCheckSelection() { + checkManager.clearSelection(); + } + + public boolean isAlreadySelected(DefaultMutableTreeNode selectedNode) { + TreePath treePath = new TreePath(getPathToRoot(selectedNode)); + return tree.getSelectionModel().isPathSelected(treePath); + } + + public void addSelectedNode(DefaultMutableTreeNode selectedNode) { + this.fire3DEvent = false; + TreePath treePath = new TreePath(getPathToRoot(selectedNode)); + tree.getSelectionModel().addSelectionPath(treePath); + tree.repaint(); + this.fire3DEvent = true; + } + + public void removeSelectedNode(DefaultMutableTreeNode selectedNode) { + this.fire3DEvent = false; + TreePath treePath = new TreePath(getPathToRoot(selectedNode)); + tree.getSelectionModel().removeSelectionPath(treePath); + tree.repaint(); + this.fire3DEvent = true; + } + + public void setSelectedNode(DefaultMutableTreeNode selectedNode) { + this.fire3DEvent = false; + TreePath treePath = new TreePath(getPathToRoot(selectedNode)); + tree.getSelectionModel().setSelectionPath(treePath); + tree.scrollPathToVisible(treePath); + tree.repaint(); + this.fire3DEvent = true; + } + + public Object[] getPathToRoot(DefaultMutableTreeNode selectedNode) { + return ((DefaultTreeModel) tree.getModel()).getPathToRoot(selectedNode); + } + + public TreePath[] getSelectedDescendantOf(DefaultMutableTreeNode parentNode) { + TreePath parentPath = new TreePath(getPathToRoot(parentNode)); + List selection = new ArrayList<>(); + TreePath[] selectionPaths = getSelectionPaths(); + if (selectionPaths != null) { + for (TreePath path : selectionPaths) { + if (path != parentPath && parentPath.isDescendant(path)) { + selection.add(path); + } + } + } + return selection.toArray(new TreePath[0]); + } + + public TreePath[] getSelectionPaths() { + return tree.getSelectionPaths(); + } + + public void expandNode() { + UiUtil.expandAll(tree, true); + } + + public void expandNode(DefaultMutableTreeNode node) { + TreePath treePath = new TreePath(node.getPath()); + UiUtil.expandAll(tree, treePath, true); + } + + public void setSelectionPaths(TreePath[] selPaths) { + tree.setSelectionPaths(selPaths); + } + + public DefaultTreeModel getModel() { + return (DefaultTreeModel) tree.getModel(); + } + + private final class PopUpMenuListener extends MouseAdapter { + private JPopupMenu popUp; + + public PopUpMenuListener() { + popUp = new JPopupMenu(); + } + + @Override + public void mouseReleased(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e)) { + + // Select row if not selected + // tree.setSelectionRow(tree.getClosestRowForLocation(e.getX(), e.getY())); + + TreePath[] selectionPath = tree.getSelectionPaths(); + if (selectionPath != null) { + List selection = TreeUtil.toUserObjects(selectionPath); + Class klass = containsClass(selection.get(0).getClass()); + if (klass != Object.class) { + if (popupBuildersMap.containsKey(klass)) { + popUp.removeAll(); + + PopUpBuilder builder = popupBuildersMap.get(klass); + builder.populate(popUp); + popUp.show(e.getComponent(), e.getX(), e.getY()); + } + } + } + } + } + } + + public void selectPanelIfNeeded() { + if (tree.getSelectionCount() == 0) { + tree.setSelectionRow(0); + } + } +} diff --git a/src/eu/engys/gui/tree/TreeNodeManager.java b/src/eu/engys/gui/tree/TreeNodeManager.java new file mode 100644 index 0000000..c48f0c5 --- /dev/null +++ b/src/eu/engys/gui/tree/TreeNodeManager.java @@ -0,0 +1,57 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.tree; + +import java.util.Observer; + +import javax.swing.JPopupMenu; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; + + +public interface TreeNodeManager extends Observer { + + public void clear(); + + public DefaultMutableTreeNode getRoot(); + + public void setTree(Tree tree); + + public Tree getTree(); + + public DefaultTreeCellRenderer getRenderer(); + + public Class getRendererClass(); + + public SelectionHandler getSelectionHandler(); + + public PopUpBuilder getPopUpBuilder(); + + public interface PopUpBuilder { + void populate(JPopupMenu popUp); + } +} diff --git a/src/eu/engys/gui/tree/TreeSelectionModel.java b/src/eu/engys/gui/tree/TreeSelectionModel.java new file mode 100644 index 0000000..2a2fca5 --- /dev/null +++ b/src/eu/engys/gui/tree/TreeSelectionModel.java @@ -0,0 +1,78 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.tree; + +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.TreePath; + +import eu.engys.util.ui.TreeUtil; + +public class TreeSelectionModel extends DefaultTreeSelectionModel { + + public TreeSelectionModel() { + super(); + } + + @Override + public void setSelectionPaths(TreePath[] selectionPath) { + if ((selectionPath != null) && (selectionPath.length > 0)) { + TreePath firstPathParent = selectionPath[0].getParentPath(); + + if (firstPathParent == null) { + TreePath[] paths = new TreePath[] {selectionPath[0]}; + super.setSelectionPaths(paths); + return; + } + + if (TreeUtil.areSiblings(selectionPath, firstPathParent)) { + TreePath[] consistentPath = TreeUtil.getAConsistentSelection(selectionPath); + if (consistentPath.length > 0) { + super.setSelectionPaths(consistentPath); + } +// } + } + } + } + + @Override + public void addSelectionPaths(TreePath[] selectionPath) { + if (getSelectionPath() != null) { + TreePath firstPathParent = getSelectionPath().getParentPath(); + if (TreeUtil.areSiblings(selectionPath, firstPathParent)) { + Class leadSelectionClass = ((DefaultMutableTreeNode) getSelectionPath().getLastPathComponent()).getUserObject().getClass(); + List selection = TreeUtil.toUserObjects(selectionPath); + + if (TreeUtil.isConsistent(selection.toArray(), leadSelectionClass)) { + super.addSelectionPaths(selectionPath); + } + } + } + } +} diff --git a/src/eu/engys/gui/view/AbstractView3DElement.java b/src/eu/engys/gui/view/AbstractView3DElement.java new file mode 100644 index 0000000..c1ecff9 --- /dev/null +++ b/src/eu/engys/gui/view/AbstractView3DElement.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view; + +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.gui.GUIPanel; +import eu.engys.gui.view3D.CanvasPanel; + +public abstract class AbstractView3DElement implements View3DElement { + + private static final Logger logger = LoggerFactory.getLogger(View3DElement.class); + + private Set panels; + + public AbstractView3DElement(Set panels) { + this.panels = panels; + } + + @Override + public void install(CanvasPanel view3D) { + for (GUIPanel panel : panels) { + panel.install(view3D); + } + } + + @Override + public void start(CanvasPanel view3D) { + logger.info("[START 3D] {}", getClass().getSimpleName()); + view3D.applyContext(getClass()); + } + + @Override + public void stop(CanvasPanel view3D) { + logger.info("[STOP 3D] {}", getClass().getSimpleName()); + } + + @Override + public void save(CanvasPanel view3D) { + view3D.dumpContext(getClass()); + } + +} diff --git a/src/eu/engys/gui/view/AbstractViewElement.java b/src/eu/engys/gui/view/AbstractViewElement.java new file mode 100644 index 0000000..a73874a --- /dev/null +++ b/src/eu/engys/gui/view/AbstractViewElement.java @@ -0,0 +1,225 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import java.util.HashSet; +import java.util.Set; + +import javax.swing.ImageIcon; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.materials.Materials; +import eu.engys.core.project.runtimefields.RuntimeFields; +import eu.engys.core.project.state.Solver; +import eu.engys.core.project.state.State; +import eu.engys.core.project.system.fieldmanipulationfunctionobjects.FieldManipulationFunctionObjects; +import eu.engys.core.project.system.monitoringfunctionobjects.MonitoringFunctionObjects; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.gui.Actions; +import eu.engys.gui.GUIError; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.ModelObserver; +import eu.engys.gui.tree.Tree; +import eu.engys.launcher.StartUpMonitor; +import eu.engys.util.plaf.ILookAndFeel; + +public abstract class AbstractViewElement implements ViewElement { + + private static final Logger logger = LoggerFactory.getLogger(ViewElement.class); + + protected final String title; + protected final View3DElement view3DElement; + protected final Set panels; + protected final Set modulePanels; + protected final Set modules; + protected final ILookAndFeel lookAndFeel; + protected final Actions actions; + + public AbstractViewElement(String title, Set panels, Set modules, View3DElement view3DElement, Actions actions, ILookAndFeel lookAndFeel) { + this.title = title; + this.panels = panels; + this.modules = modules; + this.actions = actions; + this.lookAndFeel = lookAndFeel; + this.view3DElement = view3DElement; + this.modulePanels = getModulePanels(); + logger.info("-> {}", getTitle()); + } + + protected Set getModulePanels() { + Set allPanels = new HashSet(); + return allPanels; + } + + @Override + public void layoutComponents() { + for (GUIPanel guiPanel : panels) { + StartUpMonitor.info("Layout " + guiPanel.getTitle()); + logger.info("Layout " + guiPanel.getTitle()); + guiPanel.layoutPanel(); + } + for (GUIPanel guiPanel : modulePanels) { + StartUpMonitor.info("Layout " + guiPanel.getTitle()); + logger.info("Layout " + guiPanel.getTitle()); + guiPanel.layoutPanel(); + } + } + + @Override + public int getPreferredWidth() { + return 0; + } + + @Override + public Actions getActions() { + return actions; + } + + @Override + public String getTitle() { + return title; + } + + @Override + public ImageIcon getIcon() { + return null; + } + + @Override + public Set getPanels() { + // do not add module panels. The module is responsible to add/remove the panel because it contains the logic (module on/off) + return panels; + + } + + @Override + public Set getModules() { + return modules; + } + + @Override + public Tree getTree() { + return getPanel().getTree(); + } + + @Override + public View3DElement getView3D() { + return view3DElement; + } + + @Override + public void start() { + logger.info("[START] {}", getTitle()); + getPanel().start(); + } + + @Override + public void stop() { + logger.info("[STOP] {}", getTitle()); + getPanel().stop(); + } + + @Override + public void clear() { + getPanel().clear(); + logger.info("[CLEAR] {}", getTitle()); + } + + @Override + public void load(Model model) { + logger.info("[LOAD] {}", getTitle()); + for (GUIPanel guiPanel : panels) { + try { + guiPanel.load(); + logger.info("[LOAD] -> {} LOADED", guiPanel.getKey()); + } catch (GUIError error) { + logger.error("[LOAD ERROR] {}", error); + } + } + for (GUIPanel guiPanel : modulePanels) { + try { + guiPanel.load(); + logger.info("[LOAD] -> {} LOADED", guiPanel.getKey()); + } catch (GUIError error) { + logger.error("[LOAD ERROR] {}", error); + } + } + } + + @Override + public void save(Model model) { + logger.info("[SAVE] {}", getTitle()); + for (GUIPanel guiPanel : panels) { + try { + guiPanel.save(); + } catch (GUIError error) { + logger.error("[SAVE ERROR] {}", error); + } + } + for (GUIPanel guiPanel : modulePanels) { + try { + guiPanel.save(); + } catch (GUIError error) { + logger.error("[SAVE ERROR] {}", error); + } + } + } + + @Override + public void changeObserved(Object arg) { + for (ModelObserver observer : getPanel().getObservers()) { + logger.trace("[CHANGE OBSERVED] [{}] -> Panel: {}", arg.getClass().getSimpleName(), observer.getTitle()); + + if (arg instanceof State) { + observer.stateChanged(); + } else if (arg instanceof Solver) { + observer.solverChanged(); + } else if (arg instanceof Materials) { + observer.materialsChanged(); + } else if (arg instanceof Fields) { + observer.fieldsChanged(); + } else if (arg instanceof RuntimeFields) { + observer.runtimeFieldsChanged(); + } else if (arg instanceof openFOAMProject) { + observer.projectChanged(); + } else if (arg instanceof FieldManipulationFunctionObjects) { + observer.fieldManipulationFunctionObjectsChanged(); + } else if (arg instanceof MonitoringFunctionObjects) { + observer.monitoringFunctionObjectsChanged(); + } + } + } + + @Override + public boolean isEnabled(Model model) { + return true; + } +} diff --git a/src/eu/engys/gui/view/ApplicationToolBar.java b/src/eu/engys/gui/view/ApplicationToolBar.java new file mode 100644 index 0000000..17e6467 --- /dev/null +++ b/src/eu/engys/gui/view/ApplicationToolBar.java @@ -0,0 +1,102 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import static eu.engys.util.ui.UiUtil.createToolBarButton; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; + +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.launcher.StartUpMonitor; +import eu.engys.util.ui.ViewAction; + +public class ApplicationToolBar extends JToolBar { + + private Model model; + + public ApplicationToolBar(Model model) { + super(JToolBar.HORIZONTAL); + this.model = model; + StartUpMonitor.info("Loading Toolbar"); + setFloatable(false); + setRollover(true); + setOpaque(false); + setBorder(BorderFactory.createEmptyBorder()); + + layoutComponents(); + } + + private void layoutComponents() { + add(createToolBarButton(ActionManager.getInstance().get("application.create"))); + add(createToolBarButton(ActionManager.getInstance().get("application.open"))); + add(createToolBarButton(ActionManager.getInstance().get("application.recent"))); + add(createToolBarButton(ActionManager.getInstance().get("application.save"))); + add(createToolBarButton(ActionManager.getInstance().get("application.saveAs"))); + addSeparator(); + add(createToolBarButton(ActionManager.getInstance().get("application.open.terminal"))); + add(createToolBarButton(ActionManager.getInstance().get("application.browse.case"))); + + if (ActionManager.getInstance().contains("application.support.window")) { + addSeparator(); + add(createToolBarButton(ActionManager.getInstance().get("application.support.window"))); + } + + ViewAction connectionAction = ActionManager.getInstance().get("application.connection.window"); + if (ActionManager.getInstance().contains("application.connection.window")) { + addSeparator(); + add(createToolBarButton(connectionAction)); + connectionAction.setEnabled(false); + } + + add(Box.createHorizontalGlue()); + add(createToolBarButton(ActionManager.getInstance().get("application.exit"))); + + ActionManager.getInstance().get("application.save").setEnabled(false); + ActionManager.getInstance().get("application.saveAs").setEnabled(false); + ActionManager.getInstance().get("application.open.terminal").setEnabled(false); + ActionManager.getInstance().get("application.browse.case").setEnabled(false); + } + + public void refresh() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + ActionManager.getInstance().get("application.save").setEnabled(model.getProject() != null); + ActionManager.getInstance().get("application.saveAs").setEnabled(model.getProject() != null); + ActionManager.getInstance().get("application.open.terminal").setEnabled(model.getProject() != null); + ActionManager.getInstance().get("application.browse.case").setEnabled(model.getProject() != null); + if (ActionManager.getInstance().contains("application.connection.window")) { + ActionManager.getInstance().get("application.connection.window").setEnabled(model.getProject() != null); + } + } + }); + } + +} diff --git a/src/eu/engys/gui/view/DefaultControllerListener.java b/src/eu/engys/gui/view/DefaultControllerListener.java new file mode 100644 index 0000000..01c003a --- /dev/null +++ b/src/eu/engys/gui/view/DefaultControllerListener.java @@ -0,0 +1,174 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.ControllerListener; +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.executor.TerminalManager; +import eu.engys.core.project.Model; + +public class DefaultControllerListener implements ControllerListener { + + private static final Logger logger = LoggerFactory.getLogger(DefaultControllerListener.class); + private View view; + private ElementSelector selector; + + public DefaultControllerListener(Model model, View view) { + this.view = view; + this.selector = new ElementSelector(model, view); + } + + @Override + public void saveLocation() { + selector.saveLocation(); + } + + @Override + public void goToLocation() { + selector.goToLocation(); + } + + @Override + public void selectDestinationAndGo() { + selector.selectDestinationAndGo(); + } + + /* + * Case + */ + @Override + public void beforeNewCase() { + logger.debug("BEFORE NEW CASE"); + TerminalManager.getInstance().clear(); + view.clear(); + if (view.getController().getClient() != null) { + view.getController().getClient().reset(); + } + } + + @Override + public void afterNewCase() { + logger.debug("AFTER NEW CASE"); + view.loadView(); + selector.goToFirstElement(); + } + + @Override + public void beforeLoadCase() { + logger.debug("BEFORE LOAD CASE"); + view.clear(); + TerminalManager.getInstance().clear(); + } + + @Override + public void afterLoadCase() { + logger.debug("AFTER LOAD CASE"); + view.loadView(); + } + + @Override + public void beforeReopenCase() { + logger.debug("BEFORE REOPEN CASE"); + view.clear(); + } + + @Override + public void afterReopenCase() { + logger.debug("AFTER REOPEN CASE"); + afterLoadCase(); + } + + @Override + public void beforeSaveCase() { + logger.debug("BEFORE SAVE CASE"); + view.saveView(); + } + + @Override + public void afterSaveCase() { + logger.debug("AFTER SAVE CASE"); + view.loadToolbars(); + } + + /* + * Base mesh from file + */ + @Override + public void afterBlockMesh() { + view.getCanvasPanel().resetZoom(); + } + + /* + * Check + */ + + @Override + public void beforeCheckMesh() { + } + + @Override + public void afterCheckMesh() { + view.getCanvasPanel().getMeshController().readTimeSteps(); + view.getCanvasPanel().loadWidgets(); + selector.goToBoundaryMesh(); + } + + /* + * Virtualise + */ + + @Override + public void beforeVirtualise() { + logger.debug("BEFORE VIRTUALISE"); + view.saveView(); + selector.saveLocation(); + } + + @Override + public void afterVirtualise(GeometryToMesh g2m) { + view.getCanvasPanel().geometryToMesh(g2m); + selector.goToLocation(); + } + + /* + * Solver + */ + + @Override + public void beforeRunCase() { + selector.goToResiduals(); + } + + @Override + public void afterRunCase() { + view.getCanvasPanel().getMeshController().readTimeSteps(); + view.getCanvasPanel().loadWidgets(); + } + +} diff --git a/src/eu/engys/gui/view/ElementSelector.java b/src/eu/engys/gui/view/ElementSelector.java new file mode 100644 index 0000000..37505b1 --- /dev/null +++ b/src/eu/engys/gui/view/ElementSelector.java @@ -0,0 +1,154 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.Model; +import eu.engys.core.project.SolverState; +import eu.engys.util.ui.ExecUtil; + +public class ElementSelector { + + private static final Logger logger = LoggerFactory.getLogger(ElementSelector.class); + + public static final String MESH = "Mesh"; + private static final String MESH_ELEMENT = "eu.engys.gui.mesh.MeshElement"; + + private static final String CASE_SETUP_ELEMENT = "eu.engys.gui.casesetup.CaseSetupElement"; + public static final String FIELDS_INITIALISATION = "Fields Initialisation"; + + private static final String SOLVER_ELEMENT = "eu.engys.gui.solver.SolverElement"; + public static final String RESIDUALS = "Residuals"; + + private Model model; + private View view; + + private Class currentTab; + private String currentNode; + + public ElementSelector(Model model, View view) { + this.model = model; + this.view = view; + } + + public void selectDestinationAndGo() { + if(model.hasProject()){ + if (model.getSolverModel() != null && model.getSolverModel().getServerState() != null && model.getSolverModel().getServerState().getSolverState().isDoingSomething()) { + SolverState solverState = model.getSolverModel().getServerState().getSolverState(); + if(solverState.isMeshing()){ + goToTabAndPanel(getMeshElementClass(), null); + } else if (solverState.isInitialising()){ + goToFieldsInitialisation(); + } else if (solverState.isRunning()){ + goToResiduals(); + } else { + goToFirstElement(); + } + } else { + goToFirstElement(); + } + } + } + + public void saveLocation() { + if(view.getMainPanel().getCurrentElement() != null){ + this.currentTab = view.getMainPanel().getCurrentElement().getClass(); + this.currentNode = view.getMainPanel().getElement(currentTab).getPanel().getSelectedNode(); + } else { + this.currentTab = null; + this.currentNode = null; + } + logger.debug("Location saved: {} - {}", currentTab, currentNode); + } + + public void goToLocation() { + goToTabAndPanel(currentTab, currentNode); + } + + public void goToFirstElement() { + goToTabAndPanel((Class)null, null); + } + + public void goToBoundaryMesh() { + goToTabAndPanel(getMeshElementClass(), MESH); + view.getMainPanel().getElement(getMeshElementClass()).getPanel().getNode(MESH).start(); + } + + private void goToFieldsInitialisation() { + goToTabAndPanel(getCaseSetupElementClass(), FIELDS_INITIALISATION); + } + + public void goToResiduals() { + goToTabAndPanel(getSolverElementClass(), RESIDUALS); + } + + private void goToTabAndPanel(final Class klass, final String panel) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + view.getMainPanel().stop(null); + view.getMainPanel().start(klass); + view.getCanvasPanel().start(klass); + + if(panel != null){ + view.getMainPanel().getElement(klass).getPanel().selectNode(panel); + } + + logger.debug("Location selected: {} - {}", klass, panel); + } + }); + } + + @SuppressWarnings("unchecked") + private Class getCaseSetupElementClass() { + try { + return (Class) Class.forName(CASE_SETUP_ELEMENT); + } catch (ClassNotFoundException e) { + } + return null; + } + + @SuppressWarnings("unchecked") + private Class getSolverElementClass() { + try { + return (Class) Class.forName(SOLVER_ELEMENT); + } catch (ClassNotFoundException e) { + } + return null; + } + + @SuppressWarnings("unchecked") + private Class getMeshElementClass() { + try { + return (Class) Class.forName(MESH_ELEMENT); + } catch (ClassNotFoundException e) { + } + return null; + } + +} diff --git a/src/eu/engys/gui/view/MainPanel.java b/src/eu/engys/gui/view/MainPanel.java new file mode 100644 index 0000000..4c0abfa --- /dev/null +++ b/src/eu/engys/gui/view/MainPanel.java @@ -0,0 +1,271 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import java.awt.BorderLayout; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.executor.TerminalManager; +import eu.engys.core.project.Model; +import eu.engys.gui.GUIPanel; +import eu.engys.launcher.StartUpMonitor; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public class MainPanel extends JPanel { + + private class TabChangeListener implements ChangeListener { + private ViewElement elementByIndex(int index) { + String title = tabbedPane.getTitleAt(index); + ViewElement element = elementsByTitle.get(title); + return element; + } + + public void stateChanged(ChangeEvent changeEvent) { + int index = tabbedPane.getSelectedIndex(); + ViewElement newElement = elementByIndex(index); + MainPanel.this.firePropertyChange("element", currentElement== null ? null : currentElement.getClass(), newElement.getClass()); + } + } + + private static final Logger logger = LoggerFactory.getLogger(MainPanel.class); + + private final Model model; + private final ProgressMonitor monitor; + private final Set viewElements; + + private Map, ViewElement> elementsByClass = new HashMap, ViewElement>(); + private Map elementsByTitle = new HashMap(); + + private JTabbedPane tabbedPane; + private ViewElement currentElement; + + private TabChangeListener tabChangeListener; + + public MainPanel(Model model, Set viewElements, ProgressMonitor monitor) { + this.model = model; + this.viewElements = viewElements; + this.monitor = monitor; + } + + public void layoutComponents() { + setLayout(new BorderLayout()); + + tabbedPane = new JTabbedPane(); + tabbedPane.putClientProperty("Synthetica.tabbedPane.tabIndex", 0); + tabbedPane.setName("view.tab"); + + for (ViewElement element : viewElements) { + layoutElements(element); + } + + JSplitPane terminalSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + terminalSplitPane.setTopComponent(tabbedPane); + terminalSplitPane.setBottomComponent(TerminalManager.getInstance().getComponent()); + terminalSplitPane.setResizeWeight(1); + terminalSplitPane.setOneTouchExpandable(false); + + add(terminalSplitPane); + + tabChangeListener = new TabChangeListener(); + tabbedPane.addChangeListener(tabChangeListener); + + disableAll(); + } + + private void layoutElements(ViewElement element) { + StartUpMonitor.info("Layout " + element.getTitle()); + logger.info("Layout {}", element.getTitle()); + + element.layoutComponents(); + elementsByClass.put(element.getClass(), element); + elementsByTitle.put(element.getTitle(), element); + + JPanel panel = element.getPanel(); + tabbedPane.addTab(element.getTitle(), panel); + } + + public ViewElement getElement(Class klass) { + return elementsByClass.get(klass); + } + + public ViewElement getElement(String title) { + return elementsByTitle.get(title); + } + + public void clear() { + currentElement = null; + for (ViewElement element : viewElements) { + clear(element.getClass()); + } + } + + private void clear(Class klass) { + if (elementsByClass.containsKey(klass)) { + final ViewElement viewElement = elementsByClass.get(klass); + ExecUtil.invokeAndWait(new Runnable() { + + @Override + public void run() { + viewElement.clear(); + // viewElement.getView3D().clear(); + for (final GUIPanel panel : viewElement.getPanels()) { + panel.clear(); + } + } + }); + + } + } + + public void load() { + for (ViewElement element : viewElements) { + _load(element); + } + } + + private void _load(final ViewElement viewElement) { + logger.debug("LOAD: {}", viewElement.getTitle()); + if (viewElement.isEnabled(model)) { + monitor.setIndeterminate(true); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + viewElement.load(model); + _enable(viewElement, true); + } + }); + monitor.setIndeterminate(false); + } else { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + _enable(viewElement, false); + } + }); + } + } + + public void save() { + for (final ViewElement viewElement : viewElements) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + if (viewElement.isEnabled(model)) { + viewElement.save(model); + } + } + }); + } + } + + public ViewElement getCurrentElement() { + return currentElement; + } + + private void _enable(final ViewElement element, final boolean enable) { + int index = tabbedPane.indexOfTab(element.getTitle()); + if (index >= 0) { + tabbedPane.setEnabledAt(index, enable); + } + if (enable) + UiUtil.enable(element.getPanel()); + else + UiUtil.disable(element.getPanel()); + } + + public void disableAll() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + for (ViewElement element : viewElements) { + _enable(element, false); + } + } + }); + } + + public void stop(Class klass) { + if (klass == null) { + if (currentElement != null) { + _stop(currentElement); + } else { + _stop(viewElements.iterator().next()); + } + } else if (elementsByClass.containsKey(klass)) { + _stop(elementsByClass.get(klass)); + } + } + + private void _stop(final ViewElement viewElement) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + viewElement.stop(); + viewElement.save(model); + } + }); + } + + public void start(Class klass) { + if (klass == null) { + _start(viewElements.iterator().next()); + } else if (elementsByClass.containsKey(klass)) { + _start(elementsByClass.get(klass)); + } + } + + private void _start(final ViewElement viewElement) { + this.currentElement = viewElement; + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + + viewElement.start(); + viewElement.getActions().update(); + + int index = tabbedPane.indexOfTab(viewElement.getTitle()); + if (index >= 0 && index != tabbedPane.getSelectedIndex()) { + tabbedPane.removeChangeListener(tabChangeListener); + tabbedPane.setSelectedIndex(index); + tabbedPane.addChangeListener(tabChangeListener); + } + } + }); + } +} diff --git a/src/eu/engys/gui/view/StatusBar.java b/src/eu/engys/gui/view/StatusBar.java new file mode 100644 index 0000000..321ed81 --- /dev/null +++ b/src/eu/engys/gui/view/StatusBar.java @@ -0,0 +1,184 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ +package eu.engys.gui.view; + +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JToolBar; +import javax.swing.JToolBar.Separator; +import javax.swing.SwingConstants; + +import org.apache.commons.lang.StringUtils; + +import eu.engys.core.executor.TerminalManager; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.application.OpenMonitorEvent; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.MemoryWidget; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; + +public class StatusBar extends JPanel { + + private static final Icon consoleIcon = ResourcesUtil.getIcon("console.tab.icon"); + private static final Icon monitorIcon = ResourcesUtil.getIcon("console.tab.icon"); + + private static final String DEFAULT_TEXT = StringUtils.repeat(" ", 10); + + private JButton terminalButton; + private JLabel nameLabel; + private JLabel versionLabel; + private JLabel caseLabel; + private JLabel typeLabel; + private JLabel licenseLabel; + private JButton monitorButton; + private MemoryWidget memoryWidget; + + public StatusBar() { + super(); + layoutComponents(); + } + + private void layoutComponents() { + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + + terminalButton = createTerminalButton(); + nameLabel = createLabel(ApplicationInfo.getName()); + versionLabel = createLabel(ApplicationInfo.getVersion() + " " + "[" + ApplicationInfo.getBuildDate() + "]"); + caseLabel = createLabel(DEFAULT_TEXT); + typeLabel = createLabel(DEFAULT_TEXT); + licenseLabel = createLabel(DEFAULT_TEXT); + + monitorButton = createMonitorButton(); + memoryWidget = createMemoryWidget(); + + add(terminalButton); + addSeparator(); + add(nameLabel); + addSeparator(); + add(versionLabel); + addSeparator(); + add(caseLabel); + addSeparator(); + add(typeLabel); + addSeparator(); + add(licenseLabel); + add(Box.createHorizontalGlue()); + add(monitorButton); + addSeparator(); + add(memoryWidget); + } + + private void addSeparator() { + Separator separator = new JToolBar.Separator(); + separator.setOrientation(SwingConstants.VERTICAL); + add(separator); + } + + private MemoryWidget createMemoryWidget() { + MemoryWidget mem = new MemoryWidget(); + setupDimensions(mem, MemoryWidget.PROTOTYPE_STRING); + return mem; + } + + private JButton createMonitorButton() { + JButton button = new JButton(monitorIcon); + button.setFocusable(false); + button.setBorder(BorderFactory.createEmptyBorder()); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + EventManager.triggerEvent(this, new OpenMonitorEvent()); + } + }); + return button; + } + + private JLabel createLabel(String text) { + JLabel label = new JLabel(text); + label.setBorder(BorderFactory.createEmptyBorder()); + + setupDimensions(label, label.getText()); + + return label; + } + + private void setupDimensions(JComponent c, String text) { + Dimension d = new Dimension(c.getFontMetrics(c.getFont()).stringWidth(text), 20); + c.setPreferredSize(d); + c.setMaximumSize(d); + } + + private JButton createTerminalButton() { + JButton button = new JButton(consoleIcon); + button.setFocusable(false); + button.setBorder(BorderFactory.createEmptyBorder()); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + TerminalManager.getInstance().toggleVisibility(); + } + }); + return button; + } + + public void load(final Model model) { + ExecUtil.invokeLater(new Runnable() { + public void run() { + openFOAMProject project = model.getProject(); + if (project != null) { + caseLabel.setText(project.getBaseDir().getAbsolutePath()); + typeLabel.setText(project.isParallel() ? "Parallel" : "Serial"); + } else { + caseLabel.setText(""); + typeLabel.setText(""); + } + + setupDimensions(caseLabel, caseLabel.getText()); + setupDimensions(typeLabel, typeLabel.getText()); + + revalidate(); + repaint(); + } + }); + + } + + public void updateLicenseField() { + } + +} diff --git a/src/eu/engys/gui/view/SurfacesCombo.java b/src/eu/engys/gui/view/SurfacesCombo.java new file mode 100644 index 0000000..287ab7a --- /dev/null +++ b/src/eu/engys/gui/view/SurfacesCombo.java @@ -0,0 +1,102 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import java.awt.Component; + +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.Surface; + +public class SurfacesCombo extends JComboBox { + + public SurfacesCombo() { + super(); + setRenderer(new SurfacesComboRenderer(getRenderer())); + } + + public void loadAll(Model model) { + for (Surface surface : model.getGeometry().getSurfaces()) { + if (surface.getType().isStl()) { + if (surface.isSingleton()) { + addItem(surface); + } else { + addItem(surface); + for (Surface region : surface.getRegions()) { + addItem(region); + } + } + } else { + addItem(surface); + } + } + } + + public void loadSTLs(Model model) { + for (Surface surface : model.getGeometry().getSurfaces()) { + if (surface.getType().isStl()) { + addItem(surface); + } + } + } + + public void loadParents(Model model) { + for (Surface surface : model.getGeometry().getSurfaces()) { + if (surface.getType().isStl() || surface.getType().isBaseShape()) { + addItem(surface); + } + } + } + + public Surface getSelectedSurface() { + return (Surface) getSelectedItem(); + } + + class SurfacesComboRenderer implements ListCellRenderer { + + private ListCellRenderer renderer; + + public SurfacesComboRenderer(ListCellRenderer renderer) { + this.renderer = renderer; + } + + @Override + public Component getListCellRendererComponent(JList list, Surface value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (c instanceof JLabel) { + ((JLabel) c).setText(value.getName()); + } + return c; + } + + + } + +} diff --git a/src/eu/engys/gui/view/View.java b/src/eu/engys/gui/view/View.java new file mode 100644 index 0000000..5024561 --- /dev/null +++ b/src/eu/engys/gui/view/View.java @@ -0,0 +1,430 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import java.awt.BorderLayout; +import java.awt.MouseInfo; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.List; +import java.util.Observable; +import java.util.Observer; +import java.util.Set; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Inject; + +import eu.engys.application.AbstractApplication; +import eu.engys.core.Arguments; +import eu.engys.core.controller.Controller; +import eu.engys.core.executor.FileManagerSupport; +import eu.engys.core.executor.TerminalSupport; +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.modules.ModulesUtil; +import eu.engys.core.presentation.Action; +import eu.engys.core.presentation.ActionContainer; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.gui.CreateCaseDialog; +import eu.engys.gui.MenuBar; +import eu.engys.gui.RecentItems; +import eu.engys.gui.StartPanel; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.AddSurfaceEvent; +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.launcher.StartUpMonitor; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.plaf.ILookAndFeel; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; + +public class View extends JPanel implements Observer, ActionContainer { + + private static final Logger logger = LoggerFactory.getLogger(View.class); + + private final Model model; + private final Controller controller; + + private MainPanel mainPanel; + private final CanvasPanel canvasPanel; + + private final ILookAndFeel lookAndFeel; + private final Set viewElements; + private final Set modules; + private final ProgressMonitor monitor; + + private JSplitPane splitPane; + private MenuBar menuBar; + private StatusBar statusBar; + private ApplicationToolBar applicationToolBar; + + private JDialog startupDialog; + + @Override + public boolean isDemo() { + return controller.isDemo(); + } + + @Inject + public View(Model model, Controller controller, CanvasPanel canvasPanel, ILookAndFeel lookAndFeel, Set vElements, Set modules, ProgressMonitor monitor) { + super(); + this.model = model; + this.controller = controller; + this.viewElements = vElements; + this.canvasPanel = canvasPanel; + this.lookAndFeel = lookAndFeel; + this.modules = modules; + this.monitor = monitor; + + for (ViewElement element : viewElements) { + controller.getReader().registerReader(element.getReader()); + controller.getWriter().registerWriter(element.getWriter()); + } + + controller.addListener(new DefaultControllerListener(model, this)); + model.addObserver(this); + + StartUpMonitor.info("Loading View"); + logger.info("Loading View"); + + ActionManager.getInstance().parseActions(this); + } + + public void setProgressMonitorParent(JFrame frame) { + this.monitor.setParent(frame); + } + + public void layoutComponents() { + menuBar = new MenuBar(this); + statusBar = new StatusBar(); + applicationToolBar = new ApplicationToolBar(model); + + mainPanel = new MainPanel(model, viewElements, monitor); + + mainPanel.layoutComponents(); + canvasPanel.layoutComponents(); + + setLayout(new BorderLayout()); + setName("view"); + + splitPane = new JSplitPane(); + splitPane.setName("split.pane.3d"); + splitPane.setLeftComponent(mainPanel); + splitPane.setRightComponent(canvasPanel.getPanel()); + splitPane.setDividerLocation(lookAndFeel.getMainWidth()); + splitPane.setOneTouchExpandable(false); + + add(applicationToolBar, BorderLayout.NORTH); + add(splitPane, BorderLayout.CENTER); + + // updateSplitPosition(elementByIndex(0)); + + mainPanel.addPropertyChangeListener("element", new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + Class oldKlass = (Class) evt.getOldValue(); + Class newKlass = (Class) evt.getNewValue(); + + // System.out.println("oldKlass = " + oldKlass); + // System.out.println("newKlass = " + newKlass); + + if (oldKlass != null && oldKlass != newKlass) { + _stop(oldKlass); + } + _start(newKlass); + } + }); + } + + public StatusBar getStatusBar() { + return statusBar; + } + + public MenuBar getMenuBar() { + return menuBar; + } + + public ApplicationToolBar getToolBar() { + return applicationToolBar; + } + + public MainPanel getMainPanel() { + return mainPanel; + } + + public CanvasPanel getCanvasPanel() { + return canvasPanel; + } + + public void clear() { + canvasPanel.clear(); + mainPanel.clear(); + } + + public void saveView() { + monitor.info("Saving GUI"); + + mainPanel.save(); + canvasPanel.save(); + + ModulesUtil.save(modules); + } + + public void loadView() { + loadToolbars(); + + if (model.hasProject()) { + monitor.info(""); + monitor.info("Loading 3D"); + canvasPanel.load(); + + monitor.info(""); + monitor.info("Loading GUI"); + mainPanel.load(); + } else { + canvasPanel.clear(); + mainPanel.disableAll(); + } + } + + public void loadToolbars() { + if (model.hasProject()) { + RecentItems.getInstance().push(model.getProject().getBaseDir()); + } + menuBar.updateDictionariesList(model); + statusBar.load(model); + applicationToolBar.refresh(); + } + + private void _stop(Class klass) { + logger.debug("STOP: {}", klass.getSimpleName()); + mainPanel.stop(klass); + canvasPanel.stop(klass); + } + + private void _start(Class klass) { + logger.debug("START: {}", klass.getSimpleName()); + mainPanel.start(klass); + canvasPanel.start(klass); + } + + @Override + public void update(Observable o, Object arg) { + if (o instanceof Model) { + if (arg != null) { + for (ViewElement element : viewElements) { + logger.debug("[CHANGE OBSERVERD] {}", element.getClass().getName()); + element.changeObserved(arg); + } + } + } + } + + @Action(key = "application.create") + public void createCase() { + if (controller.allowActionsOnRunning(false)) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + final CreateCaseDialog createCaseDialog = new CreateCaseDialog(); + createCaseDialog.showDialog(); + if (createCaseDialog.isOK()) { + hideStartupDialog(); + controller.createCase(createCaseDialog.getParameters()); + } + importFiles(); + } + }); + } + } + + @Action(key = "application.open") + public void openCase() { + if (controller.allowActionsOnRunning(false)) { + if (Arguments.baseDir != null) { + controller.openCase(Arguments.baseDir); + Arguments.baseDir = null; + } else { + controller.openCase(null); + } + importFiles(); + } + } + + public void importFiles() { + if (Arguments.stlFiles != null) { + monitor.setIndeterminate(false); + monitor.start("Loading STL Files", false, new Runnable() { + @Override + public void run() { + for (File file : Arguments.stlFiles) { + Stl stl = model.getGeometry().getFactory().readSTL(file, monitor); + model.getGeometry().addSurface(stl); + model.geometryChanged(stl); + + EventManager.triggerEvent(this, new AddSurfaceEvent(stl)); + } + Arguments.stlFiles = null; + monitor.end(); + } + }); + } + } + + @Action(key = "application.recent") + public void open() { + try { + Point location = MouseInfo.getPointerInfo().getLocation(); + SwingUtilities.convertPointFromScreen(location, UiUtil.getActiveWindow()); + createRecentProjectsPopUp().show(this, location.x, (location.y / 2)); + } catch (Exception e) { + // convertPointFromScreen can throw a Nullpointer exception + // no need to do anything + } + + } + + private JPopupMenu createRecentProjectsPopUp() { + final JPopupMenu popup = new JPopupMenu(); + List items = RecentItems.getInstance().getItems(); + if (items.isEmpty()) { + JMenuItem menuItem = new JMenuItem(RecentItems.NO_ITEMS); + menuItem.setEnabled(false); + popup.add(menuItem); + } else { + Icon CASE_ICON = ResourcesUtil.getIcon(ApplicationInfo.getVendor().toLowerCase() + ".case"); + for (final String item : items) { + popup.add(new AbstractAction(item, CASE_ICON) { + @Override + public void actionPerformed(ActionEvent e) { + if (controller.allowActionsOnRunning(false)) { + controller.openCase(new File(item)); + } + } + }); + } + popup.addSeparator(); + popup.add(new AbstractAction("Clear") { + @Override + public void actionPerformed(ActionEvent e) { + RecentItems.getInstance().clear(); + } + }); + } + return popup; + } + + @Action(key = "application.save", checkLicense = true) + public void save() { + File baseDir = model.getProject().getBaseDir(); + if (baseDir.exists()) { + int retVal = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "Overwrite existing case?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (retVal == JOptionPane.YES_OPTION) { + controller.saveCase(baseDir); + } + } + } + + @Action(key = "application.saveAs", checkLicense = true) + public void saveAs() { + controller.saveCase(null); + } + + @Action(key = "application.exit") + public void exit() { + if (controller.allowActionsOnRunning(true)) { + _exit(); + } + } + + @Action(key = "application.browse.case") + public void browseCase() { + if (model.getProject() != null && model.getProject().getBaseDir() != null) { + FileManagerSupport.open(model.getProject().getBaseDir()); + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No project directory", "File System error", JOptionPane.ERROR_MESSAGE); + } + } + + @Action(key = "application.open.terminal", checkEnv = true, checkLicense = true) + public void openTerminal() { + if (model.getProject() != null && model.getProject().getBaseDir() != null) { + TerminalSupport.openTerminal(model); + } + } + + private void _exit() { + System.exit(0); + } + + public void showStartupDialog(AbstractApplication abstractApplication) { + startupDialog = new JDialog(abstractApplication.getFrame(), JDialog.DEFAULT_MODALITY_TYPE); + startupDialog.getContentPane().setLayout(new BorderLayout()); + startupDialog.setName("engys.cfd.dialog"); + startupDialog.getContentPane().add(new StartPanel(abstractApplication, this), BorderLayout.CENTER); + startupDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + startupDialog.setResizable(false); + startupDialog.setTitle(controller.isDemo() ? "(Demo mode)" : ""); + abstractApplication.checkVersion(); + // dialog.getRootPane().setWindowDecorationStyle(JRootPane.NONE); + // dialog.getRootPane().setBorder(BorderFactory.createLineBorder(Color.BLACK)); + UiUtil.centerAndShow(startupDialog); + } + + @Action(key = "application.startup.hide") + public void hideStartupDialog() { + if (startupDialog != null) { + startupDialog.dispose(); + } + } + + public void dump() { + model.getPatches().print(); + } + + public Controller getController() { + return controller; + } + +} diff --git a/src/eu/engys/gui/view/View3DElement.java b/src/eu/engys/gui/view/View3DElement.java new file mode 100644 index 0000000..81f4916 --- /dev/null +++ b/src/eu/engys/gui/view/View3DElement.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view; + +import eu.engys.gui.view3D.CanvasPanel; + + +public interface View3DElement { + + public void start(CanvasPanel view3d); + public void stop(CanvasPanel view3d); + public void load(CanvasPanel view3d); + public void save(CanvasPanel view3d); + + public void install(CanvasPanel view3d); + +} diff --git a/src/eu/engys/gui/view/ViewElement.java b/src/eu/engys/gui/view/ViewElement.java new file mode 100644 index 0000000..1a56d6d --- /dev/null +++ b/src/eu/engys/gui/view/ViewElement.java @@ -0,0 +1,80 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import java.util.Set; + +import javax.swing.ImageIcon; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.Model; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.gui.Actions; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.tree.Tree; + +public interface ViewElement { + + public String getTitle(); + + public ImageIcon getIcon(); + + public ViewElementPanel getPanel(); + + public Tree getTree(); + + public void start(); + + public void stop(); + + public void clear(); + + public void load(Model model); + + public void save(Model model); + + public void layoutComponents(); + + public Set getPanels(); + + public Set getModules(); + + public boolean isEnabled(Model model); + + public View3DElement getView3D(); + + public Actions getActions(); + + public ProjectReader getReader(); + + public ProjectWriter getWriter(); + + public int getPreferredWidth(); + + public void changeObserved(Object arg); + +} diff --git a/src/eu/engys/gui/view/ViewElementNavigator.java b/src/eu/engys/gui/view/ViewElementNavigator.java new file mode 100644 index 0000000..222a81e --- /dev/null +++ b/src/eu/engys/gui/view/ViewElementNavigator.java @@ -0,0 +1,106 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view; + +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; +import javax.swing.ButtonModel; +import javax.swing.JPanel; +import javax.swing.JToggleButton; + +import eu.engys.gui.GUIPanel; +import eu.engys.util.ui.stepcomponent.FlatButtonUI; + +public class ViewElementNavigator extends JPanel { + + private ViewElementPanel viewElementPanel; + private ButtonGroup bg; + private Map buttonsMap = new HashMap(); + + public ViewElementNavigator(ViewElementPanel viewElementPanel) { + super(); + setName("view.element.navigator"); + this.viewElementPanel = viewElementPanel; + layoutComponents(); + } + + private void layoutComponents() { + setLayout(new GridLayout(0, 1, 4, 4)); + bg = new ButtonGroup() { + public void setSelected(ButtonModel m, boolean b) { + if (b) { + super.setSelected(m, b); + } else { + clearSelection(); + } + } + }; + Set panels = viewElementPanel.getPanels(); + GUIPanel[] panelsArray = panels.toArray(new GUIPanel[panels.size()]); + for (int i=0; i panels; + protected Map panelsMap = new HashMap(); + protected Map modulePanelsMap = new HashMap(); + + private JSplitPane splitPane; + private Tree tree; + private ViewElement element; + + public ViewElementPanel(ViewElement element) { + super(); + this.element = element; + this.panels = element.getPanels(); + setName(element.getTitle()); + layoutPanel(); + } + + protected void layoutPanel() { + mainLayout = new CardLayout(); + guiPanelContainer = new JPanel(mainLayout); + + tree = new Tree(this); + + for (GUIPanel guiPanel : panels) { + String title = guiPanel.getKey(); + JComponent panel = guiPanel.getPanel(); + + guiPanelContainer.add(panel, title); + panelsMap.put(title, guiPanel); + } + + splitPane = new JSplitPane(); + splitPane.setOneTouchExpandable(false); + splitPane.setLeftComponent(tree); + splitPane.setRightComponent(guiPanelContainer); + splitPane.setDividerLocation(200); + + setLayout(new BorderLayout()); + setBorder(UiUtil.getStandardBorder()); + + if (element.getActions() != null) { + add(element.getActions().toolbar(), BorderLayout.NORTH); + } + + add(splitPane, BorderLayout.CENTER); + } + + private GUIPanel selectedPanel; + + @Override + public void selectAndClearPanel(String key) { + selectPanel(key); + selectedPanel.clear(); + } + + @Override + public void selectPanel(final String key) { + if (selectedPanel != null) { + if (selectedPanel.getKey().equals(key)) + return; + if (selectedPanel.canStop()) { + selectedPanel.stop(); + } else { + return; + } + } + + if (panelsMap.containsKey(key)) { + this.selectedPanel = panelsMap.get(key); + } else if (modulePanelsMap.containsKey(key)) { + this.selectedPanel = (GUIPanel) modulePanelsMap.get(key); + } + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + selectedPanel.start(); + mainLayout.show(guiPanelContainer, key); + } + }); + } + + public void selectNode(String key) { + selectPanel(key); + tree.selectPanel(selectedPanel); + } + + public GUIPanel getNode(String key) { + return panelsMap.get(key); + } + + @Override + public Set getPanels() { + return panels; + } + + public List getObservers() { + List list = new ArrayList(); + for (GUIPanel guiPanel : panelsMap.values()) { + if (guiPanel instanceof ModelObserver) { + list.add((ModelObserver) guiPanel); + } + } + for (ModulePanel modulePanel : modulePanelsMap.values()) { + if (modulePanel instanceof ModelObserver) { + list.add((ModelObserver) modulePanel); + } + } + return list; + } + + public void start() { + if (tree != null) { + tree.selectPanelIfNeeded(); + if (selectedPanel != null) { + selectedPanel.start(); + } + tree.addListener(); + } + } + + public void stop() { + if (tree != null) { + tree.removeListener(); + } + if (selectedPanel != null) { + selectedPanel.stop(); + } + } + + public String getSelectedNode() { + return selectedPanel.getKey(); + } + + public void clear() { + getTree().clearAllSelections(); + } + + public Tree getTree() { + return tree; + } + + @Override + public void addPanel(ModulePanel modulePanel) { + String key = modulePanel.getKey(); + + if (!modulePanelsMap.containsKey(key)) { + JComponent panel = modulePanel.getPanel(); + guiPanelContainer.add(panel, key); + modulePanelsMap.put(key, modulePanel); + } + + if (modulePanel instanceof GUIPanel) { + tree.addPanel((GUIPanel) modulePanel); + } + + } + + @Override + public void removePanel(ModulePanel modulePanel) { + if (modulePanel instanceof GUIPanel) { + tree.removePanel((GUIPanel) modulePanel); + } + } + + /* + * For test purposes only + */ + public Map getModulePanelsMap() { + return modulePanelsMap; + } +} diff --git a/src/eu/engys/gui/view/ViewElementPanelTopNavigator.java b/src/eu/engys/gui/view/ViewElementPanelTopNavigator.java new file mode 100644 index 0000000..ae81547 --- /dev/null +++ b/src/eu/engys/gui/view/ViewElementPanelTopNavigator.java @@ -0,0 +1,132 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.util.Set; + +import javax.swing.JComponent; +import javax.swing.JPanel; + +import eu.engys.gui.GUIPanel; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public class ViewElementPanelTopNavigator extends ViewElementPanel { + + private CardLayout mainLayout; + private JPanel mainPanel; + private ViewElementTopNavigator navigator; + + private GUIPanel selectedPanel; + + public ViewElementPanelTopNavigator(ViewElement element) { + super(element); + } + + protected void layoutPanel() { + mainLayout = new CardLayout(); + mainPanel = new JPanel(mainLayout); + + navigator = new ViewElementTopNavigator(this); + + for (GUIPanel guiPanel : panels) { + String title = guiPanel.getKey(); + JComponent panel = guiPanel.getPanel(); + + mainPanel.add(panel, title); + panelsMap.put(title, guiPanel); + } + + setLayout(new BorderLayout()); + setBorder(UiUtil.getStandardBorder()); + add(navigator, BorderLayout.NORTH); + add(mainPanel, BorderLayout.CENTER); + + if (panels.iterator().hasNext()) { + String key = panels.iterator().next().getKey(); + navigator.selectPanel(key); + selectPanel(key); + } + } + + GUIPanel getSelectedPanel() { + return selectedPanel; + } + + public boolean canStop(final String key) { + return selectedPanel != null && selectedPanel.canStop(); + } + + @Override + public void selectPanel(final String key) { + if (key == null) + return; + if (selectedPanel != null) { + if (selectedPanel.getKey().equals(key)) + return; + if (selectedPanel.canStop()) { + selectedPanel.stop(); + } else { + return; + } + } + final GUIPanel panel = panelsMap.get(key); + this.selectedPanel = panel; + panel.start(); + + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + mainLayout.show(mainPanel, key); + navigator.selectPanel(key); + } + }); + } + + public void panelChanged(GUIPanel panel) { + selectPanel(panel.getKey()); + } + + public Set getPanels() { + return panels; + } + + @Override + public void clear() { + navigator.clear(); + selectedPanel = null; + } + + @Override + public void start() { + super.start(); + if (selectedPanel == null) { + navigator.setSelectedIndex(0); + } + } +} diff --git a/src/eu/engys/gui/view/ViewElementTopNavigator.java b/src/eu/engys/gui/view/ViewElementTopNavigator.java new file mode 100644 index 0000000..4e4db9b --- /dev/null +++ b/src/eu/engys/gui/view/ViewElementTopNavigator.java @@ -0,0 +1,83 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view; + +import java.util.Set; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import eu.engys.gui.GUIPanel; +import eu.engys.util.ui.stepcomponent.StepComponent; + +public class ViewElementTopNavigator extends StepComponent { + + private ViewElementPanelTopNavigator viewElementPanel; + + public ViewElementTopNavigator(ViewElementPanelTopNavigator viewElementPanel) { + super(15, 2, 60); + this.viewElementPanel = viewElementPanel; + load(); + } + + private void load() { + Set panels = viewElementPanel.getPanels(); + GUIPanel[] panelsArray = panels.toArray(new GUIPanel[panels.size()]); + for (int i = 0; i < panelsArray.length; i++) { + GUIPanel guiPanel = panelsArray[i]; + String title = guiPanel.getKey(); + if (i == 0) { + addFirst(title, null); + } else if (i == panelsArray.length - 1) { + addLast(title, null); + } else { + addStep(title, null); + } + } + getSelectionModel().addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + GUIPanel selectedPanel = viewElementPanel.getSelectedPanel(); + if (selectedPanel != null && !selectedPanel.getKey().equals(getSelectedStep())) { + viewElementPanel.selectPanel(getSelectedStep()); + if (!viewElementPanel.getSelectedPanel().getKey().equals(getSelectedStep())) { + selectPanel(selectedPanel.getKey()); + } + } else { + viewElementPanel.selectPanel(getSelectedStep()); + } + } + }); + } + + public void selectPanel(String key) { + setSelectedStep(key); + } + + public void clear() { + getSelectionModel().clearSelection(); + } +} diff --git a/src/eu/engys/gui/view/fallback/FallbackViewElement.java b/src/eu/engys/gui/view/fallback/FallbackViewElement.java new file mode 100644 index 0000000..47015c2 --- /dev/null +++ b/src/eu/engys/gui/view/fallback/FallbackViewElement.java @@ -0,0 +1,134 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view.fallback; + +import java.util.Collections; +import java.util.Set; + +import javax.swing.ImageIcon; + +import eu.engys.core.modules.ApplicationModule; +import eu.engys.core.project.Model; +import eu.engys.core.project.ProjectReader; +import eu.engys.core.project.ProjectWriter; +import eu.engys.gui.Actions; +import eu.engys.gui.GUIPanel; +import eu.engys.gui.tree.Tree; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElement; +import eu.engys.gui.view.ViewElementPanel; + +public class FallbackViewElement implements ViewElement { + + @Override + public String getTitle() { + return null; + } + + @Override + public ImageIcon getIcon() { + return null; + } + + @Override + public ViewElementPanel getPanel() { + return null; + } + + @Override + public Tree getTree() { + return null; + } + + @Override + public void start() { + } + + @Override + public void stop() { + } + + @Override + public void clear() { + } + + @Override + public void load(Model model) { + } + + @Override + public void save(Model model) { + } + + @Override + public void layoutComponents() { + } + + @Override + public Set getPanels() { + return Collections.emptySet(); + } + + @Override + public Set getModules() { + return Collections.emptySet(); + } + + @Override + public boolean isEnabled(Model model) { + return false; + } + + @Override + public View3DElement getView3D() { + return null; + } + + @Override + public Actions getActions() { + return null; + } + + @Override + public ProjectReader getReader() { + return null; + } + + @Override + public ProjectWriter getWriter() { + return null; + } + + @Override + public int getPreferredWidth() { + return 0; + } + + @Override + public void changeObserved(Object arg) { + } + +} diff --git a/src/eu/engys/gui/view3D/Actor.java b/src/eu/engys/gui/view3D/Actor.java new file mode 100644 index 0000000..797a14d --- /dev/null +++ b/src/eu/engys/gui/view3D/Actor.java @@ -0,0 +1,86 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + +import vtk.vtkActor; +import vtk.vtkLookupTable; +import vtk.vtkMapper; +import vtk.vtkPolyData; +import vtk.vtkTransform; +import vtk.vtkUnstructuredGrid; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public interface Actor { + + String getName(); + VisibleItem getVisibleItem(); + + boolean getVisibility(); + void setVisibility(boolean onoff); + + vtkMapper getMapper(); + +// vtkProperty getProperty(); +// void setProperty(vtkProperty vtkProperty); + + vtkActor getActor(); + vtkActor getSelectionActor(); + + void rename(String name); + + void deleteActor(); + + void transformActor(boolean save, AffineTransform t); + + void interactiveOn(); + void interactiveOff(); + + double[] getBounds(); + + void setSolidColor(double[] color, double opacity); + void setScalarColors(vtkLookupTable lut, FieldItem field); + + vtkTransform getUserTransform(); + + void setInput(vtkPolyData input); + void setInput(vtkUnstructuredGrid input); + + void setRepresentation(Representation representation); + + void restoreFromSelection(); + void selectActor(); + void deselectActor(); + + void deselectedStateOn(); + void deselectedStateOff(); + + int getMemorySize(); + + + +} diff --git a/src/eu/engys/gui/view3D/Axis.java b/src/eu/engys/gui/view3D/Axis.java new file mode 100644 index 0000000..c8c5c2a --- /dev/null +++ b/src/eu/engys/gui/view3D/Axis.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +public enum Axis { + X_AXE, Y_AXE, Z_AXE; + + public boolean isX() { + return this == X_AXE; + } + + public boolean isY() { + return this == Y_AXE; + } + + public boolean isZ() { + return this == Z_AXE; + } +} diff --git a/src/eu/engys/gui/view3D/BoxEventButton.java b/src/eu/engys/gui/view3D/BoxEventButton.java new file mode 100644 index 0000000..73d0529 --- /dev/null +++ b/src/eu/engys/gui/view3D/BoxEventButton.java @@ -0,0 +1,66 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + +import java.awt.Dimension; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JToggleButton; +import javax.swing.SwingConstants; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.BoxEvent; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.textfields.DoubleField; + +public class BoxEventButton extends JToggleButton { + + private static final Icon ICON_ON = ResourcesUtil.getResourceIcon("eu/engys/resources/images/lightbulb16.png"); + private static final Icon ICON_OFF = ResourcesUtil.getResourceIcon("eu/engys/resources/images/lightbulb_off16.png"); + + public BoxEventButton(final DoubleField[] boxMin, final DoubleField[] boxMax) { + super(); + setAction(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (isSelected()) { + EventManager.triggerEvent(this, new BoxEvent(boxMin, boxMax, EventActionType.SHOW)); + } else { + EventManager.triggerEvent(this, new BoxEvent(boxMin, boxMax, EventActionType.HIDE)); + } + } + }); + setPreferredSize(new Dimension(36, 48)); + setIcon(ICON_OFF); + setSelectedIcon(ICON_ON); + setPressedIcon(ICON_ON); +// setVerticalAlignment(SwingConstants.TOP); + setVerticalTextPosition(SwingConstants.CENTER); + } +} diff --git a/src/eu/engys/gui/view3D/CameraManager.java b/src/eu/engys/gui/view3D/CameraManager.java new file mode 100644 index 0000000..0862568 --- /dev/null +++ b/src/eu/engys/gui/view3D/CameraManager.java @@ -0,0 +1,35 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + + +public interface CameraManager { + public enum Position { + X_POS, X_NEG, Y_POS, Y_NEG, Z_POS, Z_NEG + } + + void setCameraPosition(Position pos); +} diff --git a/src/eu/engys/gui/view3D/CanvasPanel.java b/src/eu/engys/gui/view3D/CanvasPanel.java new file mode 100644 index 0000000..fc67a43 --- /dev/null +++ b/src/eu/engys/gui/view3D/CanvasPanel.java @@ -0,0 +1,92 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +import java.awt.Color; + +import javax.swing.JPanel; +import javax.vecmath.Point3d; + +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.gui.events.view3D.VolumeReportVisibilityEvent.Kind; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElement; +import eu.engys.gui.view3D.widget.Widget; +import eu.engys.util.ui.textfields.DoubleField; + +public interface CanvasPanel { + +// public void start(); +// public void stop(); +// public void load(); + public void start(Class klass); + public void stop(Class klass); + public void load(); + public void save(); + public void clear(); + + public void geometryToMesh(GeometryToMesh g2m); + + public JPanel getPanel(); + + public void showBox(DoubleField[] min, DoubleField[] max, EventActionType actions); + public void showPoint(DoubleField[] point, String key, EventActionType action, Color color); + public void showPlane(DoubleField[] origin, DoubleField[] normal, EventActionType actions); + public void showPlaneDisplay(DoubleField[] origin, DoubleField[] normal, EventActionType actions); + public void showAxis(DoubleField[] origin, DoubleField[] normal, EventActionType actions); + public void activateSelection(Selection selection, EventActionType action); + public void showQualityFields(QualityInfo qualityInfo, EventActionType action); + public void showLayersCoverage(LayerInfo layerInfo, JPanel colorBar, EventActionType action); + + public void layoutComponents(); + + public void updateMinAndMaxForFields(String varName, Point3d min, Point3d max); + public void showMinMaxFieldPoints(String key, Kind kind, boolean visible); + + public Geometry3DController getGeometryController(); + public Mesh3DController getMeshController(); + + public T getController(Class klass); + + public BoundingBox computeBoundingBox(boolean visibleOnly); + + public void showWidgetPanel(Widget widget); + public void hideWidgetPanel(Widget widget); + + public boolean showWidget(Widget widget); + public void hideWidget(Widget widget); + public void resetZoom(); + public void loadWidgets(); + + void registerController(Controller3D context); + + public void applyContext(Class klass); + public void dumpContext(Class klass); + +} diff --git a/src/eu/engys/gui/view3D/CellPicker.java b/src/eu/engys/gui/view3D/CellPicker.java new file mode 100644 index 0000000..6792a0e --- /dev/null +++ b/src/eu/engys/gui/view3D/CellPicker.java @@ -0,0 +1,33 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + + +public interface CellPicker { + + void pick(PickInfo pi); + +} diff --git a/src/eu/engys/gui/view3D/Context.java b/src/eu/engys/gui/view3D/Context.java new file mode 100644 index 0000000..9f59cef --- /dev/null +++ b/src/eu/engys/gui/view3D/Context.java @@ -0,0 +1,45 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + + +public class Context { + + protected Representation representation; + + public Context(Representation representation) { + this.representation = representation; + } + + public Representation getRepresentation() { + return representation; + } + + public boolean isEmpty() { + return false; + } +} diff --git a/src/eu/engys/gui/view3D/Controller3D.java b/src/eu/engys/gui/view3D/Controller3D.java new file mode 100644 index 0000000..cae00ef --- /dev/null +++ b/src/eu/engys/gui/view3D/Controller3D.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +import java.util.Collection; + +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.gui.view.View3DElement; + +public interface Controller3D { + + void clearContext(); + void newContext(Class klass); + void newEmptyContext(Class klass); + void dumpContext(Class klass); + void applyContext(Class klass); + + Context getCurrentContext(); + + void loadActors(); + void clear(); + + Collection getActorsList(); + + void geometryToMesh(GeometryToMesh g2m); + + void zoomReset(); + void render(); + + void setRenderPanel(RenderPanel renderPanel); +} diff --git a/src/eu/engys/gui/view3D/Geometry3DController.java b/src/eu/engys/gui/view3D/Geometry3DController.java new file mode 100644 index 0000000..33b3a11 --- /dev/null +++ b/src/eu/engys/gui/view3D/Geometry3DController.java @@ -0,0 +1,69 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +import java.awt.Color; +import java.util.Collection; +import java.util.Map; + +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.mesh.FieldItem; + +public interface Geometry3DController extends Controller3D { + + public void updateSurfacesSelection(Surface... selection); + + void updateSurfaceVisibility(Surface... selection); + + void updateSurfaceColor(Color color, Surface... selection); + + void addSurfaces(Surface... surface); + + void transformSurfaces(AffineTransform t, boolean save, Surface... surfaces); + + void changeSurface(Surface... surface); + + void removeSurfaces(Surface... surfaces); + + public BoundingBox computeBoundingBox(Surface... surfaces); + + void clear(); + + Collection getActorsList(); + + public Map getActorsMap(); + + public void showInternalMesh(); + + public void hideInternalMesh(); + + public void showField(FieldItem fieldItem); + + +} diff --git a/src/eu/engys/gui/view3D/Geometry3DEventListener.java b/src/eu/engys/gui/view3D/Geometry3DEventListener.java new file mode 100644 index 0000000..652566a --- /dev/null +++ b/src/eu/engys/gui/view3D/Geometry3DEventListener.java @@ -0,0 +1,136 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +import java.awt.Color; + +import javax.swing.SwingUtilities; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.gui.events.EventManager.Event; +import eu.engys.gui.events.view3D.AddSurfaceEvent; +import eu.engys.gui.events.view3D.ChangeSurfaceEvent; +import eu.engys.gui.events.view3D.ColorSurfaceEvent; +import eu.engys.gui.events.view3D.RemoveSurfaceEvent; +import eu.engys.gui.events.view3D.RenameSurfaceEvent; +import eu.engys.gui.events.view3D.SelectSurfaceEvent; +import eu.engys.gui.events.view3D.TransformSurfaceEvent; +import eu.engys.gui.events.view3D.VisibleItemEvent; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class Geometry3DEventListener implements View3DEventListener { + + private Geometry3DController controller; + + public Geometry3DEventListener(Geometry3DController geometryActors) { + this.controller = geometryActors; + } + + @Override + public void eventTriggered(final Object obj, final Event event) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (event instanceof RemoveSurfaceEvent) { + handleRemoveSurface((RemoveSurfaceEvent) event); + } else if (event instanceof RenameSurfaceEvent) { + handleRenameSurface((RenameSurfaceEvent) event); + } else if (event instanceof ChangeSurfaceEvent) { + handleChangeSurface((ChangeSurfaceEvent) event); + } else if (event instanceof AddSurfaceEvent) { + handleAddSurface((AddSurfaceEvent) event); + } else if (event instanceof TransformSurfaceEvent) { + handleTransformSurface((TransformSurfaceEvent) event); + } else if (event instanceof SelectSurfaceEvent) { + handleSelectSurface((SelectSurfaceEvent) event); + } else if (event instanceof VisibleItemEvent) { + handleVisibleItem((VisibleItemEvent) event); + } else if (event instanceof ColorSurfaceEvent) { + handleColorSurface((ColorSurfaceEvent) event); + } + } + + }); + } + + private void handleColorSurface(ColorSurfaceEvent event) { + Surface selection = event.getSelection(); + Color c = event.getColor(); + controller.updateSurfaceColor(c, selection); + } + + private void handleVisibleItem(VisibleItemEvent event) { + VisibleItem selection = event.getSelection(); + if (selection instanceof Surface) { + controller.updateSurfaceVisibility((Surface) selection); + } + } + + private void handleSelectSurface(SelectSurfaceEvent event) { + Surface selection[] = event.getSelection(); + controller.updateSurfacesSelection(selection); + } + + private void handleAddSurface(AddSurfaceEvent e) { + Surface[] surfaces = e.getSurfaces(); + controller.addSurfaces(surfaces); + if (e.isResetZoom()) { + controller.zoomReset(); + } else { + controller.render(); + } + } + + private void handleTransformSurface(TransformSurfaceEvent e) { + Surface[] surfaces = e.getSurfaces(); + AffineTransform t = e.getTransformation(); + boolean save = e.shouldSave(); + controller.transformSurfaces(t, save, surfaces); + controller.render(); + } + + private void handleChangeSurface(ChangeSurfaceEvent e) { + Surface surface = e.getSurface(); + boolean resetZoom = e.isResetZoom(); + controller.changeSurface(surface); + controller.render(); + if (resetZoom) { + controller.zoomReset(); + } + } + + private void handleRemoveSurface(RemoveSurfaceEvent e) { + Surface[] surfaces = e.getSurfaces(); + controller.removeSurfaces(surfaces); + } + + private void handleRenameSurface(RenameSurfaceEvent e) { + /* DO NOTHING */ + } + +} diff --git a/src/eu/engys/gui/view3D/Interactor.java b/src/eu/engys/gui/view3D/Interactor.java new file mode 100644 index 0000000..234a00a --- /dev/null +++ b/src/eu/engys/gui/view3D/Interactor.java @@ -0,0 +1,48 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + +import vtk.vtkInteractorObserver; + +public interface Interactor { + + void setStyleToDefault(); + void setStyleToArea(); + void setStyleToZoom(); + + void start(); + + void dispose(); + + void updateSize(int w, int h); + + void wheelForwardEvent(); + void wheelBackwardEvent(); + + void addObserver(vtkInteractorObserver widget); + + +} diff --git a/src/eu/engys/gui/view3D/LayerInfo.java b/src/eu/engys/gui/view3D/LayerInfo.java new file mode 100644 index 0000000..a4faea5 --- /dev/null +++ b/src/eu/engys/gui/view3D/LayerInfo.java @@ -0,0 +1,46 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + +public enum LayerInfo { + NUM_LAYERS("numLayers", true), FCH("fch", false), LEVEL("level", true); + + private String key; + private boolean discrete; + + private LayerInfo(String key, boolean discrete) { + this.key = key; + this.discrete = discrete; + } + + public String getKey() { + return key; + } + + public boolean isDiscrete() { + return discrete; + } +} diff --git a/src/eu/engys/gui/view3D/Mesh3DController.java b/src/eu/engys/gui/view3D/Mesh3DController.java new file mode 100644 index 0000000..887e80a --- /dev/null +++ b/src/eu/engys/gui/view3D/Mesh3DController.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +import java.util.Collection; + +import vtk.vtkPlane; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.core.project.mesh.ScalarBarType; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.patches.Patch; + +public interface Mesh3DController extends Controller3D { + + void updatePatchesSelection(Patch[] selection); + void updatePatchesVisibility(Patch... selection); + + void updateCellZonesSelection(CellZone[] selection); + void updateCellZonesVisibility(CellZone... selection); + + void clear(); + + BoundingBox computeBoundingBox(); + + void showTimeStep(double value); + void showField(FieldItem fieldItem); + + void clip(vtkPlane plane); + void slice(vtkPlane plane); + void crinkle(vtkPlane plane); + void disconnectFiltersFromInternalMesh(); + + void insideOut(boolean selected); + + void showExternalMesh(); + + void showInternalMesh(); + void hideInternalMesh(); + boolean isInternalMeshLoaded(); + + void readTimeSteps(); + FieldItem getCurrentFieldItem(); + double getCurrentTimeStep(); + + Collection getActorsList(); + + + void setAutomaticRangeCalculation(boolean autoRange); + void setManualRangeCalculation(double[] rangeField); + + void setScalarsActorsResolution(int resolution); + + void resetScalarsActorsRangeAndResolutionAndHue(); + void setScalarsBarType(ScalarBarType hueRangeType); + +} diff --git a/src/eu/engys/gui/view3D/Mesh3DEventListener.java b/src/eu/engys/gui/view3D/Mesh3DEventListener.java new file mode 100644 index 0000000..cc7c094 --- /dev/null +++ b/src/eu/engys/gui/view3D/Mesh3DEventListener.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +import javax.swing.SwingUtilities; + +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.events.EventManager.Event; +import eu.engys.gui.events.view3D.SelectCellZonesEvent; +import eu.engys.gui.events.view3D.SelectPatchesEvent; +import eu.engys.gui.events.view3D.VisibleItemEvent; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class Mesh3DEventListener implements View3DEventListener { + + private Mesh3DController mesh3DController; + + public Mesh3DEventListener(Mesh3DController mesh3DController) { + this.mesh3DController = mesh3DController; + } + + @Override + public void eventTriggered(Object obj, final Event event) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (event instanceof SelectPatchesEvent) { + handleSelectPatches((SelectPatchesEvent) event); + } else if (event instanceof SelectCellZonesEvent) { + handleSelectZones((SelectCellZonesEvent) event); + } else if (event instanceof VisibleItemEvent) { + handleVisibility((VisibleItemEvent) event); + } + } + }); + } + + private void handleSelectPatches(SelectPatchesEvent event) { + Patch selection[] = ((SelectPatchesEvent) event).getSelection(); + mesh3DController.updatePatchesSelection(selection); + } + + private void handleSelectZones(SelectCellZonesEvent event) { + CellZone selection[] = ((SelectCellZonesEvent) event).getSelection(); + mesh3DController.updateCellZonesSelection(selection); + } + + private void handleVisibility(VisibleItemEvent event) { + VisibleItem selection = event.getSelection(); + if (selection instanceof Patch) { + mesh3DController.updatePatchesVisibility((Patch) selection); + } else if (selection instanceof CellZone) { + mesh3DController.updateCellZonesVisibility((CellZone) selection); + } + } +} diff --git a/src/eu/engys/gui/view3D/PickInfo.java b/src/eu/engys/gui/view3D/PickInfo.java new file mode 100644 index 0000000..ec0e7fb --- /dev/null +++ b/src/eu/engys/gui/view3D/PickInfo.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + +import vtk.vtkDataSet; +import vtk.vtkPlanes; + +public class PickInfo { + + public Actor actor; + public vtkDataSet dataSet; + public int cellId; + public int[] cellIJK; + public double[] normal; + public double[] position; + public boolean shift; + public boolean control; + public vtkPlanes frustum; + +} diff --git a/src/eu/engys/gui/view3D/PickManager.java b/src/eu/engys/gui/view3D/PickManager.java new file mode 100644 index 0000000..0ec9352 --- /dev/null +++ b/src/eu/engys/gui/view3D/PickManager.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + + +public interface PickManager { + + void registerPickerForActors(Picker picker); + + void registerPickerForCells(CellPicker picker); + void unregisterPickerForCells(CellPicker picker); + + void pickForCells(); + + void pickForActors(); + + double[] pickPoint(); + + +} diff --git a/src/eu/engys/gui/view3D/Picker.java b/src/eu/engys/gui/view3D/Picker.java new file mode 100644 index 0000000..9546249 --- /dev/null +++ b/src/eu/engys/gui/view3D/Picker.java @@ -0,0 +1,35 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + + +public interface Picker { + public boolean containsActor(Actor actor); +// public String getActorName(Actor pickedActor); + public boolean canPickCells(Actor pickedActor); + public boolean canPickMesh(); +} diff --git a/src/eu/engys/gui/view3D/QualityInfo.java b/src/eu/engys/gui/view3D/QualityInfo.java new file mode 100644 index 0000000..3d4920f --- /dev/null +++ b/src/eu/engys/gui/view3D/QualityInfo.java @@ -0,0 +1,102 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + +import static eu.engys.gui.view3D.QualityInfo.Test.LESS_THAN; +import static eu.engys.gui.view3D.QualityInfo.Test.MORE_THAN; + +import java.awt.Color; + +import eu.engys.util.bean.AbstractBean; + + +public class QualityInfo extends AbstractBean { + +// metrics[0] = "nonOrthogonality"; +// metrics[1] = "pyramids"; +// metrics[2] = "skewness" ; +// metrics[3] = "weights"; +// metrics[4] = "volumeRatio"; +// metrics[5] = "determinant"; + public enum Test { + MORE_THAN, LESS_THAN; + } + + public enum QualityMeasure { + NON_ORTHOGONALITY("nonOrthogonality", MORE_THAN), + PYRAMIDS("pyramids", MORE_THAN), + SKEWNESS("skewness", LESS_THAN), + WEIGHTS("weights", MORE_THAN), + VOLUME_RATIO("volumeRatio", MORE_THAN), + DETERMINANT("determinant", MORE_THAN); + + private String fieldName; + private Test test; + + private QualityMeasure(String fieldName, Test test) { + this.fieldName = fieldName; + this.test = test; + } + + public String getFieldName() { + return fieldName; + } + + public Test getTest() { + return test; + } + } + + private QualityInfo.QualityMeasure measure; + private double threshold; + private Color color; + + public QualityInfo.QualityMeasure getMeasure() { + return measure; + } + public void setMeasure(QualityInfo.QualityMeasure measure) { + this.measure = measure; + } + public double getThreshold() { + return threshold; + } + public void setThreshold(double threshold) { + firePropertyChange("threshold", this.threshold, this.threshold = threshold); + } + + public Color getColor() { + return color; + } + public void setColor(Color color) { + this.color = color; + } + + @Override + public String toString() { + return "fieldName: " + getMeasure().getFieldName() + ", test: " + getMeasure().getTest() + ", threshold: " + getThreshold(); + } + +} diff --git a/src/eu/engys/gui/view3D/RenderPanel.java b/src/eu/engys/gui/view3D/RenderPanel.java new file mode 100644 index 0000000..b486ebd --- /dev/null +++ b/src/eu/engys/gui/view3D/RenderPanel.java @@ -0,0 +1,94 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + +import java.awt.Color; +import java.awt.event.KeyListener; + +import vtk.vtkAssembly; +import vtk.vtkImageData; +import eu.engys.gui.view3D.CameraManager.Position; + +public interface RenderPanel { + + void lock(); + + void Render(); + + void unlock(); + + void clear(); + + void setCameraPosition(Position xPos); + void resetCamera(); + + void wheelForward(); + void wheelBackward(); + + void zoomReset(); + void resetZoomLater(); + void resetZoomAndWait(); + + void clearSelection(); + + void setRepresentation(Representation r); + Representation getRepresentation(); + + void changeRepresentation(Representation r); + + void renderLater(); + void renderAndWait(); + + void addActor(vtkAssembly cor); + void addActor(Actor actor); + + void removeActor(Actor actor); + + void selectActors(boolean keepSelected, Actor... pickedActor); + + void setLowRendering(); + void setHighRendering(); + + void setActorColor(Color c, Actor... actor); + + void addKeyListener(KeyListener listener); + + void removeKeyListener(KeyListener listener); + + void dispose(); + + void ParallelProjectionOn(); + void ParallelProjectionOff(); + + PickManager getPickManager(); + + Interactor getInteractor(); + + vtkImageData toImageData(); + + void lowRenderingOff(); + void lowRenderingOn(); +} diff --git a/src/eu/engys/gui/view3D/Representation.java b/src/eu/engys/gui/view3D/Representation.java new file mode 100644 index 0000000..28ade97 --- /dev/null +++ b/src/eu/engys/gui/view3D/Representation.java @@ -0,0 +1,31 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +public enum Representation { + SURFACE, SURFACE_WITH_EDGES, WIREFRAME, OUTLINE, PROFILE +} diff --git a/src/eu/engys/gui/view3D/Selection.java b/src/eu/engys/gui/view3D/Selection.java new file mode 100644 index 0000000..caeb094 --- /dev/null +++ b/src/eu/engys/gui/view3D/Selection.java @@ -0,0 +1,120 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D; + +import vtk.vtkIdTypeArray; +import vtk.vtkPolyData; +import eu.engys.util.bean.AbstractBean; + +public class Selection extends AbstractBean { + + public enum SelectionType { + CELL, AREA, FEATURE + } + + public enum SelectionTarget { + POINT, LINE, CELL + } + + public enum SelectionMode { + SELECT, DESELECT + } + + private Selection.SelectionType type = SelectionType.FEATURE; + private Selection.SelectionMode mode = SelectionMode.SELECT; + private Selection.SelectionTarget target = SelectionTarget.CELL; + + private double featureAngle = 30.0; + private boolean keepSelection = true; + + private vtkPolyData selectionData; + private vtkPolyData inverseSelectionData; + private vtkIdTypeArray idList; + private vtkPolyData dataSet; + + public void setType(Selection.SelectionType type) { + firePropertyChange("type", this.type, this.type = type); + } + public Selection.SelectionType getType() { + return type; + } + + public void setMode(Selection.SelectionMode mode) { + this.mode = mode; + } + public Selection.SelectionMode getMode() { + return mode; + } + + public void setTarget(Selection.SelectionTarget target) { + this.target = target; + } + public Selection.SelectionTarget getTarget() { + return target; + } + + public void setFeatureAngle(double featureAngle) { + this.featureAngle = featureAngle; + } + public double getFeatureAngle() { + return featureAngle; + } + + public void setKeepSelection(boolean keepSelection) { + this.keepSelection = keepSelection; + } + public boolean isKeepSelection() { + return keepSelection; + } + + public void setSelectionData(vtkPolyData selectionData) { + this.selectionData = selectionData; + } + public vtkPolyData getSelectionData() { + return selectionData; + } + + public void setInverseSelectionData(vtkPolyData inverseSelectionData) { + this.inverseSelectionData = inverseSelectionData; + } + public vtkPolyData getInverseSelectionData() { + return inverseSelectionData; + } + + public void setIdList(vtkIdTypeArray list) { + this.idList = list; + } + public vtkIdTypeArray getIdList() { + return idList; + } + + public void setDataSet(vtkPolyData dataSet) { + firePropertyChange("dataSet", this.dataSet, this.dataSet = dataSet); + } + public vtkPolyData getDataSet() { + return dataSet; + } +} diff --git a/src/eu/engys/gui/view3D/View3DEventListener.java b/src/eu/engys/gui/view3D/View3DEventListener.java new file mode 100644 index 0000000..5d85152 --- /dev/null +++ b/src/eu/engys/gui/view3D/View3DEventListener.java @@ -0,0 +1,33 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D; + +import eu.engys.gui.events.EventManager.GenericEventListener; + +public interface View3DEventListener extends GenericEventListener { + +} diff --git a/src/eu/engys/gui/view3D/fallback/Fallback3DElement.java b/src/eu/engys/gui/view3D/fallback/Fallback3DElement.java new file mode 100644 index 0000000..3fc3dd9 --- /dev/null +++ b/src/eu/engys/gui/view3D/fallback/Fallback3DElement.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D.fallback; + +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view3D.CanvasPanel; + +public class Fallback3DElement implements View3DElement { + + @Override + public void install(CanvasPanel view3d) { + } + + @Override + public void start(CanvasPanel view3D) { + } + + @Override + public void stop(CanvasPanel view3D) { + } + + @Override + public void load(CanvasPanel view3D) { + } + + @Override + public void save(CanvasPanel view3D) { + } + +// @Override +// public View3D getView3D() { +// return FALLBACK3D_PANEL; +// } + +} diff --git a/src/eu/engys/gui/view3D/fallback/FallbackGeometry3DController.java b/src/eu/engys/gui/view3D/fallback/FallbackGeometry3DController.java new file mode 100644 index 0000000..91f20fc --- /dev/null +++ b/src/eu/engys/gui/view3D/fallback/FallbackGeometry3DController.java @@ -0,0 +1,149 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D.fallback; + +import java.awt.Color; +import java.util.Collection; +import java.util.Map; + +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Context; +import eu.engys.gui.view3D.Geometry3DController; +import eu.engys.gui.view3D.RenderPanel; + +public class FallbackGeometry3DController implements Geometry3DController { + + @Override + public Context getCurrentContext() { + return null; + } + + @Override + public void setRenderPanel(RenderPanel renderPanel) { + } + + @Override + public void clearContext() { + } + + @Override + public void geometryToMesh(GeometryToMesh g2m) { + } + + @Override + public void updateSurfacesSelection(Surface... selection) { + } + + @Override + public void updateSurfaceVisibility(Surface... selection) { + } + + @Override + public void updateSurfaceColor(Color color, Surface... selection) { + } + + @Override + public void addSurfaces(Surface... surface) { + } + + @Override + public void transformSurfaces(AffineTransform t, boolean save, Surface... surfaces) { + } + + @Override + public void removeSurfaces(Surface... surfaces) { + } + + @Override + public BoundingBox computeBoundingBox(Surface... surfaces) { + return new BoundingBox(0, 0, 0, 0, 0, 0); + } + + @Override + public void clear() { + } + + @Override + public void dumpContext(Class klass) { + } + + @Override + public void applyContext(Class klass) { + } + + @Override + public Collection getActorsList() { + return null; + } + + @Override + public Map getActorsMap() { + return null; + } + + @Override + public void loadActors() { + } + + @Override + public void newContext(Class klass) { + } + + @Override + public void newEmptyContext(Class klass) { + } + + @Override + public void showInternalMesh() { + } + + @Override + public void hideInternalMesh() { + } + + @Override + public void changeSurface(Surface... surface) { + } + + @Override + public void render() { + } + + @Override + public void zoomReset() { + } + + @Override + public void showField(FieldItem fieldItem) { + } +} diff --git a/src/eu/engys/gui/view3D/fallback/FallbackMesh3DController.java b/src/eu/engys/gui/view3D/fallback/FallbackMesh3DController.java new file mode 100644 index 0000000..2175962 --- /dev/null +++ b/src/eu/engys/gui/view3D/fallback/FallbackMesh3DController.java @@ -0,0 +1,198 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.gui.view3D.fallback; + +import java.util.Collection; + +import vtk.vtkPlane; +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.core.project.mesh.ScalarBarType; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Context; +import eu.engys.gui.view3D.Mesh3DController; +import eu.engys.gui.view3D.RenderPanel; + +public class FallbackMesh3DController implements Mesh3DController { + + @Override + public void setRenderPanel(RenderPanel renderPanel) { + } + + @Override + public void updatePatchesSelection(Patch[] selection) { + } + + @Override + public void updateCellZonesVisibility(CellZone... selection) { + } + + @Override + public void updatePatchesVisibility(Patch... selection) { + } + + @Override + public void updateCellZonesSelection(CellZone[] selection) { + } + + @Override + public void loadActors() { + } + + @Override + public Context getCurrentContext() { + return null; + } + + @Override + public void clearContext() { + } + + @Override + public void clear() { + } + + @Override + public BoundingBox computeBoundingBox() { + return null; + } + + @Override + public void setManualRangeCalculation(double[] rangeField) { + } + + @Override + public void setScalarsActorsResolution(int resolution) { + } + + @Override + public void setScalarsBarType(ScalarBarType hueRangeType) { + } + + @Override + public void resetScalarsActorsRangeAndResolutionAndHue() { + } + + @Override + public void setAutomaticRangeCalculation(boolean autoRange) { + } + + @Override + public void dumpContext(Class klass) { + } + + @Override + public void applyContext(Class klass) { + } + + @Override + public void newContext(Class klass) { + } + + @Override + public void newEmptyContext(Class klass) { + } + + @Override + public void geometryToMesh(GeometryToMesh g2m) { + } + + @Override + public void showTimeStep(double value) { + } + + @Override + public FieldItem getCurrentFieldItem() { + return null; + } + + @Override + public double getCurrentTimeStep() { + return 0; + } + + @Override + public void showField(FieldItem fieldItem) { + } + + @Override + public void clip(vtkPlane plane) { + } + + @Override + public void slice(vtkPlane plane) { + } + + @Override + public void crinkle(vtkPlane plane) { + } + + @Override + public void insideOut(boolean selected) { + } + + @Override + public void showInternalMesh() { + } + + @Override + public void hideInternalMesh() { + } + + @Override + public void readTimeSteps() { + } + + @Override + public void showExternalMesh() { + } + + @Override + public Collection getActorsList() { + return null; + } + + @Override + public boolean isInternalMeshLoaded() { + return false; + } + + @Override + public void render() { + } + + @Override + public void zoomReset() { + } + + @Override + public void disconnectFiltersFromInternalMesh() { + } +} diff --git a/src/eu/engys/gui/view3D/fallback/FallbackView3D.java b/src/eu/engys/gui/view3D/fallback/FallbackView3D.java new file mode 100644 index 0000000..fe88214 --- /dev/null +++ b/src/eu/engys/gui/view3D/fallback/FallbackView3D.java @@ -0,0 +1,251 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D.fallback; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.vecmath.Point3d; + +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.events.view3D.VolumeReportVisibilityEvent.Kind; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElement; +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.gui.view3D.Controller3D; +import eu.engys.gui.view3D.Geometry3DController; +import eu.engys.gui.view3D.LayerInfo; +import eu.engys.gui.view3D.Mesh3DController; +import eu.engys.gui.view3D.QualityInfo; +import eu.engys.gui.view3D.Selection; +import eu.engys.gui.view3D.widget.Widget; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.textfields.DoubleField; + +public class FallbackView3D implements CanvasPanel { + + private JPanel panel; + private Icon engysLogo = ResourcesUtil.getIcon(ApplicationInfo.getVendor().toLowerCase() + ".logo.full"); + + private Runnable r = new Runnable() { + @Override + public void run() { + final ImageIcon image = (ImageIcon) engysLogo; + panel = new JPanel() { + @Override + public void paintComponent(final Graphics g) { + super.paintComponent(g); + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + if (image != null) { + // int xCoord = 30; + // int yCoord = getHeight() - image.getIconHeight() - + // 30; + int xCoord = (getWidth() / 2) - (image.getIconWidth() / 2); + int yCoord = (getHeight() / 2) - (image.getIconHeight() / 2); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f)); + g.drawImage(image.getImage(), xCoord, yCoord, null); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); + } + } + }; + panel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); + panel.add(new JLabel("3D graphics not available")); + } + }; + + @Override + public void registerController(Controller3D context) { + } + + @Override + public void layoutComponents() { + } + + @Override + public void load() { + } + + @Override + public void save() { + } + + @Override + public void start(Class klass) { + } + + @Override + public void stop(Class klass) { + } + + @Override + public void loadWidgets() { + } + + @Override + public BoundingBox computeBoundingBox(boolean visibleOnly) { + return new BoundingBox(); + } + + public void updatePatchesSelection(Patch[] selection) { + } + + public void updatePatchVisibility(Patch selection, boolean b) { + } + + public void updateCellZonesSelection(CellZone[] selection) { + } + + public void updateCellZoneVisibility(CellZone selection, boolean b) { + } + + @Override + public void clear() { + } + + public Dimension getMinimumSize() { + return new Dimension(50, 50); + } + + @Override + public JPanel getPanel() { + if (SwingUtilities.isEventDispatchThread()) { + r.run(); + } else { + try { + SwingUtilities.invokeAndWait(r); + } catch (Exception e) { + e.printStackTrace(); + } + } + return panel; + } + + @Override + public void showPoint(DoubleField[] point, String key, EventActionType action, Color color) { + } + + @Override + public void showBox(DoubleField[] min, DoubleField[] max, EventActionType actions) { + } + + @Override + public void updateMinAndMaxForFields(String varName, Point3d min, Point3d max) { + } + + @Override + public void showMinMaxFieldPoints(String key, Kind kind, boolean visible) { + } + + @Override + public void activateSelection(Selection selection, EventActionType action) { + } + + @Override + public void showQualityFields(QualityInfo qualityInfo, EventActionType action) { + } + + @Override + public void showLayersCoverage(LayerInfo layerInfo, JPanel colorBar, EventActionType action) { + } + + @Override + public void geometryToMesh(GeometryToMesh g2m) { + } + + @Override + public boolean showWidget(Widget widget) { + return false; + } + + @Override + public void showWidgetPanel(Widget widget) { + } + + @Override + public void hideWidgetPanel(Widget widget) { + } + + @Override + public void hideWidget(Widget widget) { + } + + @Override + public Geometry3DController getGeometryController() { + return new FallbackGeometry3DController(); + } + + @Override + public Mesh3DController getMeshController() { + return new FallbackMesh3DController(); + } + + @Override + public T getController(Class klass) { + return null; + } + + @Override + public void resetZoom() { + } + + @Override + public void showPlane(DoubleField[] origin, DoubleField[] normal, EventActionType action) { + } + + @Override + public void showPlaneDisplay(DoubleField[] origin, DoubleField[] normal, EventActionType actions) { + } + + @Override + public void showAxis(DoubleField[] origin, DoubleField[] normal, EventActionType actions) { + } + + @Override + public void applyContext(Class klass) { + } + + @Override + public void dumpContext(Class klass) { + } + +} diff --git a/src/eu/engys/gui/view3D/widget/Widget.java b/src/eu/engys/gui/view3D/widget/Widget.java new file mode 100644 index 0000000..d59bbee --- /dev/null +++ b/src/eu/engys/gui/view3D/widget/Widget.java @@ -0,0 +1,57 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D.widget; + +import javax.swing.JToolBar; + +import eu.engys.gui.view3D.CanvasPanel; + +public interface Widget { + + void populate(CanvasPanel view3D); + void populate(JToolBar toolbar); + + boolean canShow(); + + void show(); + void hide(); + + void clear(); + + void stop(); + + WidgetComponent getWidgetComponent(); + void load(); + + void applyContext(); + + void handleFieldChanged(); + void handleTimeStepChanged(); + void handleNewTimeStepsRead(); +// void handleInitializeFieldsStarted(); +// void handleInitializeFieldsFinished(); +} diff --git a/src/eu/engys/gui/view3D/widget/WidgetComponent.java b/src/eu/engys/gui/view3D/widget/WidgetComponent.java new file mode 100644 index 0000000..8a43a1c --- /dev/null +++ b/src/eu/engys/gui/view3D/widget/WidgetComponent.java @@ -0,0 +1,41 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.gui.view3D.widget; + +import javax.swing.JPanel; + +public interface WidgetComponent { + + void handleShow(); + + JPanel getPanel(); + + String getKey(); + + void clear(); + +} diff --git a/src/eu/engys/launcher/AbstractApplicationLauncher.java b/src/eu/engys/launcher/AbstractApplicationLauncher.java new file mode 100644 index 0000000..ee2d33a --- /dev/null +++ b/src/eu/engys/launcher/AbstractApplicationLauncher.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.launcher; + +import static eu.engys.launcher.StartUpMonitor.info; + +import java.net.URL; + +import javax.inject.Inject; +import javax.swing.Icon; +import javax.swing.SwingUtilities; + +import com.google.inject.Injector; +import com.google.inject.Module; + +import eu.engys.application.Application; +import eu.engys.application.Batch; +import eu.engys.launcher.modules.Modules; + +public abstract class AbstractApplicationLauncher implements ApplicationLauncher { + + private Injector injector; + + @Inject + public AbstractApplicationLauncher(Injector injector) { + this.injector = injector; + } + + @Override + public String getTitle() { + return ""; + } + + @Override + public Icon getIcon() { + return null; + } + + @Override + public abstract void checkLicense(); + + @Override + public void launch() throws Exception { + info("Loading application modules"); + URL url = getClass().getProtectionDomain().getCodeSource().getLocation(); + Iterable modules = Modules.loadApplicationModules(url); + + info("Starting Modules"); + Injector appInjector = injector.createChildInjector(modules); + + info("Loading Application"); + Application application = appInjector.getInstance(Application.class); + + info("Layout Application"); + SwingUtilities.invokeLater(application); + } + + @Override + public void batch() throws Exception { + info("Loading modules"); + URL url = getClass().getProtectionDomain().getCodeSource().getLocation(); + Iterable modules = Modules.loadBatchModules(url); + + info("Starting modules"); + Injector appInjector = injector.createChildInjector(modules); + + info("Loading application"); + Batch batch = appInjector.getInstance(Batch.class); + + info("Launch Batch"); + batch.run(); + } +} diff --git a/src/eu/engys/launcher/ApplicationLauncher.java b/src/eu/engys/launcher/ApplicationLauncher.java new file mode 100644 index 0000000..87f2d7f --- /dev/null +++ b/src/eu/engys/launcher/ApplicationLauncher.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.launcher; + +import javax.swing.Icon; + + +public interface ApplicationLauncher { + + + public void checkLicense() throws Exception; + public void launch() throws Exception; + public void batch() throws Exception; + + public String getTitle(); + + public Icon getIcon(); + +} + diff --git a/src/eu/engys/launcher/HELYXOSLauncher.java b/src/eu/engys/launcher/HELYXOSLauncher.java new file mode 100644 index 0000000..db9ca29 --- /dev/null +++ b/src/eu/engys/launcher/HELYXOSLauncher.java @@ -0,0 +1,50 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.launcher; + +import javax.inject.Inject; + +import com.google.inject.Injector; + +public class HELYXOSLauncher extends AbstractApplicationLauncher { + + @Inject + public HELYXOSLauncher(Injector injector) { + super(injector); + } + + @Override + public void checkLicense() { + /* do not remove this method*/ + } + + @Override + public void batch() throws Exception { + /* do not remove this method*/ + } + +} diff --git a/src/eu/engys/launcher/Launcher.java b/src/eu/engys/launcher/Launcher.java new file mode 100644 index 0000000..576c30b --- /dev/null +++ b/src/eu/engys/launcher/Launcher.java @@ -0,0 +1,138 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.launcher; + +import static eu.engys.launcher.StartUpMonitor.info; + +import java.util.List; + +import javax.swing.SwingUtilities; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; + +import eu.engys.application.Application; +import eu.engys.application.Batch; +import eu.engys.core.Arguments; +import eu.engys.core.LoggerUtil; +import eu.engys.launcher.modules.Modules; +import eu.engys.suite.Suite; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.Util; +import eu.engys.util.plaf.ILookAndFeel; +import eu.engys.util.ui.UiUtil; + +public class Launcher { + + public static void main(String[] args) throws Exception { + + info("Set Application Info"); + ApplicationInfo.init(); + + printOut(ApplicationInfo.getHeaderInfo()); + + info("Initialize Arguments"); + Arguments.init(args); + + info("Initialize Logger"); + if (Arguments.isBatch()) + LoggerUtil.initFlatLogger(); + else + LoggerUtil.initLogger(); + + info("Initialize Locale"); + LocaleUtil.initLocale(); + + Util.initScriptStyle(); + + info("Loading modules"); + List modules = Modules.loadSuiteModules(); + + if (modules.isEmpty()) { + if (Arguments.isBatch() ) { + modules = Modules.loadBatchModules(null); + + info("Starting modules"); + Injector injector = Guice.createInjector(modules); + + info("Go to Batch"); + Batch batch = injector.getInstance(Batch.class); + + info("Launch Batch"); + batch.run(); + } else { + modules = Modules.loadApplicationModules(null); + + info("Starting modules"); + Injector injector = Guice.createInjector(modules); + + info("Loading LookAndFeel"); + ILookAndFeel laf = injector.getInstance(ILookAndFeel.class); + laf.init(); + + info("Check License"); + ApplicationLauncher launcher = injector.getInstance(ApplicationLauncher.class); + launcher.checkLicense(); + + info("Loading Application"); + Application application = injector.getInstance(Application.class); + + UiUtil.renameUIThread(); + + info("Layout Application"); + SwingUtilities.invokeLater(application); + } + } else { + info("Starting modules"); + Injector injector = Guice.createInjector(modules); + + info("Loading LookAndFeel"); + ILookAndFeel laf = injector.getInstance(ILookAndFeel.class); + laf.init(); + + info("Loading Suite"); + Suite suite = injector.getInstance(Suite.class); + + if (Arguments.isBatch() ) { + info("Go to Batch"); + suite.batch(); + } else { + info("Start Suite"); + UiUtil.installExceptionHandler(); + UiUtil.renameUIThread(); + suite.launch(); + } + } + } + + private static void printOut(String msg) { + System.out.println(msg); + } + +} + diff --git a/src/eu/engys/launcher/LocaleUtil.java b/src/eu/engys/launcher/LocaleUtil.java new file mode 100644 index 0000000..9e1b57d --- /dev/null +++ b/src/eu/engys/launcher/LocaleUtil.java @@ -0,0 +1,37 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.launcher; + +import java.util.Locale; + +public class LocaleUtil { + + public static void initLocale() { + Locale.setDefault(Locale.US); + } + +} diff --git a/src/eu/engys/launcher/StartUpMonitor.java b/src/eu/engys/launcher/StartUpMonitor.java new file mode 100644 index 0000000..2069cad --- /dev/null +++ b/src/eu/engys/launcher/StartUpMonitor.java @@ -0,0 +1,224 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.launcher; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.RenderingHints; +import java.awt.SplashScreen; +import java.awt.Window; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.net.URLDecoder; +import java.util.concurrent.atomic.AtomicBoolean; + +public class StartUpMonitor { + + private static StartUpMonitor instance; + private static int counter = 0; + private static boolean isElements = false; + private static boolean isHelyxOS = false; + + public static void info(final String msg) { + if (GraphicsEnvironment.isHeadless()) { + System.out.println("+++ " + msg + " +++"); + } else { + if (instance == null) { + instance = new StartUpMonitor(); + pwnSplashScreen(); + setApplicationType(); + } + instance.render(msg); + } + } + + private static void setApplicationType() { + try { + URL coreGuiJarURL = StartUpMonitor.class.getProtectionDomain().getCodeSource().getLocation(); + String decodedCoreGuiJarURL = URLDecoder.decode(coreGuiJarURL.getFile(), "UTF-8"); + File libDir = new File(decodedCoreGuiJarURL).getParentFile(); + isElements = new File(libDir, "ELEMENTS.jar").exists(); + isHelyxOS = new File(libDir, "HELYX-OS.jar").exists(); + } catch (UnsupportedEncodingException e) { + isElements = false; + isHelyxOS = false; + } + } + + private static void pwnSplashScreen() { + try { + Field field = Window.class.getDeclaredField("beforeFirstWindowShown"); + field.setAccessible(true); + + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + + field.set(null, new AtomicBoolean(false)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void close() { + SplashScreen splash = getSplashScreen(); + if (splash != null) { + splash.close(); + } + } + + private static SplashScreen getSplashScreen() { + try { + return SplashScreen.getSplashScreen(); + } catch (HeadlessException e) { + } + return null; + } + + private void render(final String string) { + SplashScreen splash = getSplashScreen(); + if (splash == null) { + return; + } + Graphics2D g = splash.createGraphics(); + if (g == null) { + return; + } + + if (isElements) { + paintElementsProgress(g, string); + } else { + paintHelyxProgress(g, string); + } + + splash.update(); + counter++; + } + + /* + * HELYX + */ + private void paintHelyxProgress(Graphics g, String string) { + paintHelyxProgressBar(g); + paintHelyxProgressText(g, string); + } + + private void paintHelyxProgressBar(Graphics g) { + int leftPadding = 15; + int topPadding = 205; + int splashWidth = getSplashScreen().getSize().width; + int width = Math.min(10 * counter, splashWidth - (leftPadding * 2)); + + g.setColor(isHelyxOS ? Color.BLUE.darker() : Color.RED.darker()); + g.fillRect(leftPadding, topPadding, width, 2); + g.setColor(isHelyxOS ? Color.BLUE.brighter() : Color.RED.brighter()); + g.fillRect(leftPadding, topPadding, width, 1); + } + + private void paintHelyxProgressText(Graphics g, String string) { + int leftPadding = 15; + int topPadding = 175; + + Color bgColor = Color.WHITE; + Color textColor = Color.BLACK; + + // background + int background_width = 210; + int background_height = 30; + g.setPaintMode(); + g.setColor(bgColor); + g.fillRect(leftPadding, topPadding, background_width, background_height); + + // foreground + int text_height = background_height - 5; + g.setColor(textColor); + enableAntialias(g); + g.drawString(string, leftPadding, topPadding + text_height); + disableAntialias(g); + } + + /* + * ELEMENTS + */ + private void paintElementsProgress(Graphics g, String string) { + paintElementsProgressBar(g); + paintElementsProgressText(g, string); + } + + private void paintElementsProgressBar(Graphics g) { + int leftPadding = 20; + int topPadding = 56; + int splashWidth = getSplashScreen().getSize().width; + int width = Math.min(10 * counter, splashWidth - (leftPadding * 2 + 2)); + + g.setColor(Color.GREEN.darker()); + g.fillRect(leftPadding, topPadding, width, 3); + g.setColor(Color.GREEN.brighter()); + g.fillRect(leftPadding, topPadding, width, 1); + } + + private void paintElementsProgressText(Graphics g, String string) { + int leftPadding = 15; + int topPadding = getSplashScreen().getSize().height - 35; + + Color bgColor = Color.WHITE; + Color textColor = Color.BLACK; + + // background + int background_width = 210; + int background_height = 30; + g.setPaintMode(); + g.setColor(bgColor); + g.fillRect(leftPadding, topPadding, background_width, background_height); + + // foreground + int text_height = background_height - 5; + g.setColor(textColor); + enableAntialias(g); + g.drawString(string, leftPadding, topPadding + text_height); + disableAntialias(g); + } + + /* + * Utils + */ + + private void enableAntialias(Graphics g) { + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + } + + private void disableAntialias(Graphics g) { + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + } + +} diff --git a/src/eu/engys/launcher/modules/Modules.java b/src/eu/engys/launcher/modules/Modules.java new file mode 100644 index 0000000..458acd3 --- /dev/null +++ b/src/eu/engys/launcher/modules/Modules.java @@ -0,0 +1,188 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.launcher.modules; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Module; + +public class Modules { + + private static final Logger logger = LoggerFactory.getLogger(Modules.class); + + private static ClassLoader classLoader; + private static String packageName; + private static Class interfase; + + private static URL url; + + public static List loadSuiteModules() { + return loadModules("eu.engys.suite.modules", Module.class, null); + } + + public static List loadApplicationModules(URL url) { + return loadModules("eu.engys.application.modules", Module.class, url); + } + + public static List loadBatchModules(URL url) { + return loadModules("eu.engys.batch.modules", Module.class, url); + } + + static List loadModules(String pkgName, Class interfaceClass, URL classURL) { + List modules = new ArrayList(); + + interfase = interfaceClass; + packageName = pkgName; + classLoader = Thread.currentThread().getContextClassLoader(); + url = classURL; + + try { + List> classes = findAllImplementationsInPackage(); + + for(Class clazz : classes) { + try { + M newInstance = clazz.newInstance(); + logger.info("[Modules] {} loaded", clazz.getName()); + modules.add(newInstance); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } + } catch (Exception e) { + logger.error(e.getMessage()); + } + + return modules; + } + + public static List> findAllImplementationsInPackage() throws IOException, ClassNotFoundException { + List> implementations = new ArrayList>(); + + List> classes = getClassesFromPackage(packageName); + for (Class klass : classes) { + if (interfase.isAssignableFrom(klass) && !klass.isInterface()){ + implementations.add(klass); + } else { + logger.info("[Modules] {} is not valid.", klass.getName()); + } + } + return implementations; + } + + @SuppressWarnings("unchecked") + private static List> getClassesFromPackage(String packageName) throws ClassNotFoundException, IOException { + List classNames = getClassNamesFromPackage(packageName); + + List> classes = new ArrayList>(); + for (String className : classNames) { + try { + classes.add((Class) Class.forName(className)); + } catch (ClassNotFoundException e) { + logger.error("[Modules] Error Loading class {}", className); + } + } + return classes; + } + + + public static List getClassNamesFromPackage(String packageName) throws IOException { + assert classLoader != null; + + List names = new ArrayList(); + + packageName = packageName.replace(".", "/"); + Enumeration packageURLs = classLoader.getResources(packageName); + + for(URL packageURL : Collections.list(packageURLs)) { + if (packageURL.getProtocol().equals("jar")) { + // build jar file name + String jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8"); + jarFileName = jarFileName.substring(5, jarFileName.indexOf("!")); + if (url == null ){ + names.addAll(extractClassName(packageName, jarFileName)); + } else { + String parentJarFileName = URLDecoder.decode(url.getFile(), "UTF-8"); + + if (jarFileName.startsWith(parentJarFileName)){ + names.addAll(extractClassName(packageName, jarFileName)); + } else { + //logger.error("[Modules] Jar {} is not a child of {}. Not loaded.", jarFileName, parentJarFileName); + } + } + } else { + if (url == null ) { + File folder = new File(packageURL.getFile()); + File[] contenuti = folder.listFiles(); + String entryName; + for (File actual : contenuti) { + entryName = actual.getName(); + entryName = entryName.substring(0, entryName.lastIndexOf('.')); + entryName = packageName+"/"+entryName; + entryName = entryName.replace("/", "."); + names.add(entryName); + } + } + } + } + return names; + } + + static List extractClassName(String packageName, String jarFileName) throws IOException { + List entryNames = new ArrayList(); + Enumeration jarEntries; + String entryName = ""; + logger.info("[Modules] Looking for Modules in file {}", jarFileName); + + JarFile jf = new JarFile(jarFileName); + jarEntries = jf.entries(); + while (jarEntries.hasMoreElements()) { + entryName = jarEntries.nextElement().getName(); + if (entryName.startsWith(packageName) && entryName.length() > packageName.length() + 5) { + entryName = entryName.substring(0, entryName.lastIndexOf('.')); + entryName = entryName.replace("/", "."); + logger.info("[Modules] Module {} found.", entryName); + entryNames.add(entryName); + } + } + jf.close(); + return entryNames; + } + +} + diff --git a/src/eu/engys/resources/application.properties b/src/eu/engys/resources/application.properties new file mode 100644 index 0000000..3a0606a --- /dev/null +++ b/src/eu/engys/resources/application.properties @@ -0,0 +1,34 @@ +################################################# +# # +# PROPERTIES FILE # +# # +################################################# + +# Solver Batch Run +batch.connection.max.tries 60 +batch.connection.wait.time 1000 +batch.stopped.wait.time 2000 +batch.running.wait.time 2000 + +batch.script.refresh.time 1000 +batch.script.kill.wait.time 5000 + +batch.monitor.dialog.max.row 10000 + +batch.log.wait.time 1000 + +# 3D rendering +3d.lock.intractive.time 2000 +3d.lock.intractive.memory 4096 +3d.transparency.memory 10240 + +# LOG FILES +max.log.rows 100000 + +# PATCHES +hide.empty.patches true + +# DEFAULT HOST FILE +default.hostfile.none false + +################################################# \ No newline at end of file diff --git a/src/eu/engys/resources/bundle.properties b/src/eu/engys/resources/bundle.properties new file mode 100644 index 0000000..dd7a143 --- /dev/null +++ b/src/eu/engys/resources/bundle.properties @@ -0,0 +1,604 @@ +# +# MESH +# + +mesh.create.label Create +mesh.create.tooltip Start mesher execution +mesh.create.icon eu/engys/resources/images/start16.png + +mesh.create.edit.label Edit Script +mesh.create.edit.tooltip Edit Create Mesh Script +mesh.create.edit.icon eu/engys/resources/images/pencil16.png + +mesh.check.label Check +mesh.check.tooltip Check Mesh +mesh.check.icon eu/engys/resources/images/tick16.png + +mesh.delete.label Delete +mesh.delete.tooltip Delete Mesh +mesh.delete.icon eu/engys/resources/images/erase16.png + +block.mesh.create.label Create +block.mesh.create.tooltip Create a Preview of The Block Mesh +block.mesh.create.icon eu/engys/resources/images/start16.png + +mesh.check.edit.label Edit Script +mesh.check.edit.tooltip Edit Check Mesh Script +mesh.check.edit.icon eu/engys/resources/images/pencil16.png + +mesh.batch.label Virtualise +mesh.batch.tooltip Use Geometry Objects To Simulate The Mesh +mesh.batch.icon eu/engys/resources/images/lightning.png + +mesh.options.label Options +mesh.options.tooltip Open Advanced Options Dialog +mesh.options.icon eu/engys/resources/images/cog16.png + +mesh.import.label Import +mesh.import.tooltip Import Mesh From 3rd Party +mesh.import.icon eu/engys/resources/images/import16.png + +mesh.export.label Export +mesh.export.tooltip Export Mesh For 3rd Party +mesh.export.icon eu/engys/resources/images/export16.png + +mesh.operations.label Operate +mesh.operations.tooltip Operate on 3D geometry items +mesh.operations.icon eu/engys/resources/images/toolbox16.png + +mesh.merge.label Merge +mesh.merge.tooltip Merge Mesh From 3rd Party + +mesh.stl.label +mesh.stl.icon eu/engys/resources/images/stl24.png +mesh.stl.tooltip STL +mesh.igs.label +mesh.igs.icon eu/engys/resources/images/igs24.png +mesh.igs.tooltip IGES/STEP +mesh.box.label +mesh.box.icon eu/engys/resources/images/cube24.png +mesh.box.tooltip Box +mesh.sphere.label +mesh.sphere.icon eu/engys/resources/images/sphere24.png +mesh.sphere.tooltip Sphere +mesh.cylinder.label +mesh.cylinder.icon eu/engys/resources/images/cylinder24.png +mesh.cylinder.tooltip Cylinder +mesh.plane.label +mesh.plane.icon eu/engys/resources/images/plane24.png +mesh.plane.tooltip Plane +mesh.ring.label +mesh.ring.icon eu/engys/resources/images/ring24.png +mesh.ring.tooltip Ring + +# +# CASE_SETUP +# + +best.practices.mesh.label Setup Mesh +best.practices.mesh.icon eu/engys/resources/images/tick16.png +best.practices.mesh.tooltip Setup Mesh + +best.practices.case.label Setup Case +best.practices.case.icon eu/engys/resources/images/tick16.png +best.practices.case.tooltip Setup Case + +best.practices.all.label Apply Defaults +best.practices.all.icon eu/engys/resources/images/tick16.png +best.practices.all.tooltip Setup Case + +casesetup.decompose.label Decompose +casesetup.decompose.tooltip Decompose Case + +calculate.frontal.area.label Calculate +calculate.frontal.area.tooltip Calculate frontal area from available vehicle geometry +calculate.frontal.area.icon eu/engys/resources/images/calculator16.png + +initialise.fields.icon eu/engys/resources/images/tick16.png +initialise.fields.label Initialise +initialise.fields.tooltip Initialise Fields + +parmap.fields.icon eu/engys/resources/images/parMap16.png +parmap.fields.label Map Fields +parmap.fields.tooltip Map Fields From External Case + +initialise.fields.edit.icon eu/engys/resources/images/pencil16.png +initialise.fields.edit.label Edit Script +initialise.fields.edit.tooltip Edit Script + +extrude.to.region.icon eu/engys/resources/images/extrude16.png +extrude.to.region.label Extrude To Region +extrude.to.region.tooltip Extrude To Region + +# +# RESULTS +# +results.export.label Create Report +results.export.icon eu/engys/resources/images/exportResults16.png +results.export.tooltip Create Report + +results.export.edit.label Edit Script +results.export.edit.icon eu/engys/resources/images/pencil16.png +results.export.edit.tooltip Edit Script + +results.export.edit.python.label Edit Results +results.export.edit.python.icon eu/engys/resources/images/pencil16.png +results.export.edit.python.tooltip Edit Results + +results.show.label Show Report +results.show.icon eu/engys/resources/images/showResults16.png +results.show.tooltip Show Report + +# +# SOLVER +# +solver.run.label Run +solver.run.tooltip Run +solver.run.icon eu/engys/resources/images/start16.png + +solver.run.edit.label Edit Script +solver.run.edit.tooltip Edit Solver Launcher Script +solver.run.edit.icon eu/engys/resources/images/pencil16.png + +solver.stop.label Stop +solver.stop.tooltip Try to gracefully stop solver execution. If not possible kills the solver process. +solver.stop.icon eu/engys/resources/images/stop16.png + +solver.run.all.label Run All +solver.run.all.tooltip Run All +solver.run.all.icon eu/engys/resources/images/startAll16.png + +solver.run.all.edit.label Edit Script +solver.run.all.edit.tooltip Edit Script +solver.run.all.edit.icon eu/engys/resources/images/pencil16.png + +solver.refresh.label Refresh Now +solver.refresh.tooltip Refresh Now + +solver.refresh.rate.tooltip Refresh Rate + +solver.show.log.terminal.label Terminal +solver.show.log.terminal.tooltip Display Log Terminal Window +solver.show.log.terminal.icon eu/engys/resources/images/console16.png + +# +# UPLOAD/DOWNLOAD +# +project.download.label Download +project.download.icon eu/engys/resources/images/download16.png +project.download.tooltip Download + +project.upload.label Upload +project.upload.icon eu/engys/resources/images/upload16.png +project.upload.tooltip Upload + +project.download.results.label Download +project.download.results.icon eu/engys/resources/images/download16.png +project.download.results.tooltip Download + +project.download.zip.label Download +project.download.zip.icon eu/engys/resources/images/download16.png +project.download.zip.tooltip Download + +project.upload.zip.label Upload +project.upload.zip.icon eu/engys/resources/images/upload16.png +project.upload.zip.tooltip Upload + +project.monitor.label Monitor +project.monitor.icon eu/engys/resources/images/upload16.png +project.monitor.tooltip Upload + +remote.edit.label Properties +remote.edit.icon eu/engys/resources/images/pencil16.png +remote.edit.tooltip Properties + +queue.edit.label Properties +queue.edit.icon eu/engys/resources/images/pencil16.png +queue.edit.tooltip Properties + + +# +# APPLICATION +# +application.create.label New +application.create.tooltip Create New Case +application.create.icon eu/engys/resources/images/new16.png + +application.save.label Save +application.save.tooltip Save Case +application.save.icon eu/engys/resources/images/save16.png + +application.saveAs.label Save As... +application.saveAs.tooltip Save Case With Different Name +application.saveAs.icon eu/engys/resources/images/saveAs16.png + +application.open.label Open +application.open.tooltip Open Case +application.open.icon eu/engys/resources/images/open16.png + +application.recent.label +application.recent.tooltip Open Recent Case +application.recent.icon eu/engys/resources/images/arrow_down16.png + +application.exit.label Exit +application.exit.tooltip Exit Application +application.exit.icon eu/engys/resources/images/exit16.png + +# +# 3D +# +3d.zoom.in.tooltip Zoom In +3d.zoom.in.icon eu/engys/resources/images/zoomIn16.png + +3d.zoom.out.tooltip Zoom Out +3d.zoom.out.icon eu/engys/resources/images/zoomOut16.png + +3d.zoom.reset.tooltip Reset Zoom +3d.zoom.reset.icon eu/engys/resources/images/zoomReset16.png + +3d.zoom.tobox.tooltip Zoom To Area +3d.zoom.tobox.icon eu/engys/resources/images/zoomToArea16.png + +3d.axis.xpos.tooltip +X +3d.axis.xpos.icon eu/engys/resources/images/XPos16.png + +3d.axis.xneg.tooltip -X +3d.axis.xneg.icon eu/engys/resources/images/XNeg16.png + +3d.axis.ypos.tooltip +Y +3d.axis.ypos.icon eu/engys/resources/images/YPos16.png + +3d.axis.yneg.tooltip -Y +3d.axis.yneg.icon eu/engys/resources/images/YNeg16.png + +3d.axis.zpos.tooltip +Z +3d.axis.zpos.icon eu/engys/resources/images/ZPos16.png + +3d.axis.zneg.tooltip -Z +3d.axis.zneg.icon eu/engys/resources/images/ZNeg16.png + +3d.view.surface.tooltip Surface +3d.view.surface.icon eu/engys/resources/images/shape_surface16.png + +3d.view.edges.tooltip Surface With Edges +3d.view.edges.icon eu/engys/resources/images/shape_surface_edges16.png + +3d.view.profile.tooltip Boundary Edges +3d.view.profile.icon eu/engys/resources/images/shape_boundary_edges16.png + +3d.view.wireframe.tooltip Wireframe +3d.view.wireframe.icon eu/engys/resources/images/shape_wireframe16.png + +3d.view.outline.tooltip Outline +3d.view.outline.icon eu/engys/resources/images/shape_outline16.png + +3d.load.mesh.tooltip Load External Mesh +3d.load.mesh.icon eu/engys/resources/images/externalMesh16.png + +3d.view.projections.perspective.tooltip Parallel Projection +3d.view.projections.perspective.icon eu/engys/resources/images/transform_perspective16.png +3d.view.projections.parallel.tooltip Perspective Projection +3d.view.projections.parallel.icon eu/engys/resources/images/transform_parallel16.png + +# +# WIDGETS +# +3d.widget.plane.tooltip Plane Widget +3d.widget.plane.icon eu/engys/resources/images/planeWidget16.png + +3d.widget.ruler.icon eu/engys/resources/images/rulerWidget16.png +3d.widget.ruler.tooltip Ruler Widget + +3d.widget.times.refresh.tooltip Reload Time Steps +3d.widget.times.tooltip Time Steps + +3d.widget.times.prev.icon eu/engys/resources/images/prev_grey16.png +3d.widget.times.prev.tooltip Display PREVIOUS Time + +3d.widget.times.next.icon eu/engys/resources/images/next_grey16.png +3d.widget.times.next.tooltip Display NEXT Time + +3d.widget.times.first.icon eu/engys/resources/images/first_grey16.png +3d.widget.times.first.tooltip Display FIRST Time + +3d.widget.times.last.icon eu/engys/resources/images/last_grey16.png +3d.widget.times.last.tooltip Display LAST Time + +3d.widget.times.refresh.icon eu/engys/resources/images/refresh_grey16.png +3d.widget.times.refresh.tooltip Rescan Times + +3d.widget.export.icon eu/engys/resources/images/exportImage16.png +3d.widget.export.tooltip Export PNG + +3d.widget.scalarbar.icon eu/engys/resources/images/scalarbar16.png +3d.widget.scalarbar.tooltip Scalar Bar + +3d.widget.editscalarbar.icon eu/engys/resources/images/scalarbarEdit16.png +3d.widget.editscalarbar.tooltip Edit Scalar Bar + +3d.widget.fields.tooltip Fields +3d.widget.fields.point.icon eu/engys/resources/images/pointField16.png +3d.widget.fields.cell.icon eu/engys/resources/images/cellField16.png + +3d.widget.feature.tooltip Split Surface Widget +3d.widget.feature.icon eu/engys/resources/images/table_select_big.png + +scalarbar.rainbow.icon eu/engys/resources/images/scalarbar/rainbow16.png +scalarbar.rainbow.inverted.icon eu/engys/resources/images/scalarbar/rainbowInverted16.png + +scalarbar.bluetored.hsv.icon eu/engys/resources/images/scalarbar/HSVBlueToRed16.png +scalarbar.redtoblue.hsv.icon eu/engys/resources/images/scalarbar/HSVRedToBlue16.png +scalarbar.bluetored.rgb.icon eu/engys/resources/images/scalarbar/RGBBlueToRed16.png +scalarbar.redtoblue.rgb.icon eu/engys/resources/images/scalarbar/RGBRedToBlue16.png +scalarbar.bluetored.div.icon eu/engys/resources/images/scalarbar/DIVBlueToRed16.png +scalarbar.redtoblue.div.icon eu/engys/resources/images/scalarbar/DIVRedToBlue16.png + +scalarbar.bluetoyellow.hsv.icon eu/engys/resources/images/scalarbar/HSVBlueToYellow16.png +scalarbar.yellowtoblue.hsv.icon eu/engys/resources/images/scalarbar/HSVYellowToBlue16.png +scalarbar.bluetoyellow.rgb.icon eu/engys/resources/images/scalarbar/RGBBlueToYellow16.png +scalarbar.yellowtoblue.rgb.icon eu/engys/resources/images/scalarbar/RGBYellowToBlue16.png +scalarbar.bluetoyellow.div.icon eu/engys/resources/images/scalarbar/DIVBlueToYellow16.png +scalarbar.yellowtoblue.div.icon eu/engys/resources/images/scalarbar/DIVYellowToBlue16.png + +scalarbar.blacktowhite.icon eu/engys/resources/images/scalarbar/blackToWhite16.png +scalarbar.whitetoblack.icon eu/engys/resources/images/scalarbar/whiteToBlack16.png + +scalarbar.lock.opened.icon eu/engys/resources/images/lockOpen16.png +scalarbar.lock.closed.icon eu/engys/resources/images/lockClose16.png + +slider.locked.icon eu/engys/resources/images/sliderLock16.png +slider.unlocked.icon eu/engys/resources/images/sliderUnlock16.png + +# +# CASE MANAGER +# + +case.manager.start.label Start +case.manager.start.icon eu/engys/resources/images/file16.png + +case.manager.stop.label Stop +case.manager.stop.icon eu/engys/resources/images/file16.png + + +case.manager.start.case.label Start +case.manager.start.case.icon eu/engys/resources/images/file16.png +case.manager.stop.case.label Stop +case.manager.stop.case.icon eu/engys/resources/images/file16.png +case.manager.open.case.label Open +case.manager.open.case.icon eu/engys/resources/images/file16.png +case.manager.view.case.label View +case.manager.view.case.icon eu/engys/resources/images/file16.png +case.manager.add.label Add +case.manager.add.icon eu/engys/resources/images/file16.png +case.manager.remove.label Remove +case.manager.remove.icon eu/engys/resources/images/file16.png +case.manager.clone.label Clone +case.manager.clone.icon eu/engys/resources/images/file16.png + +# +# EXTERNAL APPLICATIONS +# + +paraview.label ParaView +paraview.icon eu/engys/resources/images/paraview16.png +paraview.tooltip Open ParaView + +fieldview.label FieldView +fieldview.icon eu/engys/resources/images/fieldview16.png +fieldview.tooltip Open FieldView + +ensight.label EnSight +ensight.icon eu/engys/resources/images/ensight16.png +ensight.tooltip Open EnSight + +fluent.label Fluent +fluent.icon eu/engys/resources/images/fluent16.png +fluent.import.tooltip Import From Fluent +fluent.merge.tooltip Merge From Fluent +fluent.export.tooltip Export To Fluent + +starcd.label STAR-CD +starcd.icon eu/engys/resources/images/starcd16.png +starcd.tooltip Export To STAR-CD + +pointwise.label PointWise +pointwise.icon eu/engys/resources/images/gridgen16.png +pointwise.import.tooltip Import From PointWise +pointwise.merge.tooltip Merge From PointWise + +openfoam.label OpenFOAM +openfoam.icon eu/engys/resources/images/openFoam16.png +openfoam.import.tooltip Import From OpenFOAM +openfoam.merge.tooltip Merge From OpenFOAM + +# +# ICONS +# + +fit.boundingbox.icon eu/engys/resources/images/fit16.png +script.edit.icon eu/engys/resources/images/edit16.png +browse.file eu/engys/resources/images/browseFile16.png +save.log.file eu/engys/resources/images/fileSave16.png + +general.options.icon eu/engys/resources/images/cog16.png +import.icon eu/engys/resources/images/import16.png +merge.icon eu/engys/resources/images/merge16.png +decompose.icon eu/engys/resources/images/decompose16.png + +solver.start.icon eu/engys/resources/images/start16.png +solver.stop.icon eu/engys/resources/images/stop16.png +solver.refresh.icon eu/engys/resources/images/refresh16.png + +application.exit.big.icon eu/engys/resources/images/exit32.png + +console.stop.icon eu/engys/resources/images/stop16.png +console.copy.icon eu/engys/resources/images/copy16.png +console.email.icon eu/engys/resources/images/email16.png +console.browse.icon eu/engys/resources/images/browseFile16.png +console.scroll.icon eu/engys/resources/images/scroll_pane16.png +console.scroll.lock.icon eu/engys/resources/images/scroll_pane_lock16.png +console.tab.icon eu/engys/resources/images/console16.png +console.tab.close.icon eu/engys/resources/images/win_close16.png +console.tab.closeall.icon eu/engys/resources/images/win_closeAll16.png +console.tab.max.icon eu/engys/resources/images/win_maximize16.png +console.tab.restore.icon eu/engys/resources/images/win_restore16.png + +application.open.terminal.label Terminal +application.open.terminal.tooltip Open Terminal in case folder +application.open.terminal.icon eu/engys/resources/images/terminal16.png + +application.browse.case.label Browse +application.browse.case.tooltip Browse Case Folder +application.browse.case.icon eu/engys/resources/images/browseFolder16.png + +engys.logo eu/engys/resources/engys_logo.png +engys.logo.medium eu/engys/resources/engys_logo_medium.png +engys.logo.big eu/engys/resources/engys_logo_big.png +engys.logo.full eu/engys/resources/engys_logo_full.png +engys.terminal.icon eu/engys/resources/engys_terminal_logo.png + +helyx.banner eu/engys/resources/helyx_banner.png +helyx.startup eu/engys/resources/helyx_startup.png + +helyxsas.banner eu/engys/resources/helyxsas_banner.png +helyxsas.startup eu/engys/resources/helyxsas_startup.png + +helyxmesh.banner eu/engys/resources/helyxmesh_banner.png +helyxmesh.startup eu/engys/resources/helyxmesh_startup.png + +helyxos.banner eu/engys/resources/helyxos_banner.png +helyxos.startup eu/engys/resources/helyxos_startup.png +helyxos.faq eu/engys/resources/helyxos_faq.png +helyxos.products eu/engys/resources/helyxos_products.png +helyxos.helyx.box eu/engys/resources/helyxBox.png +helyxos.helyxos.box eu/engys/resources/helyxosBox.png +helyxos.elements.box eu/engys/resources/elementsBox.png + +streamlinesolutions.logo eu/engys/resources/elements_logo.png +streamlinesolutions.logo.medium eu/engys/resources/elements_logo_medium.png +streamlinesolutions.logo.big eu/engys/resources/elements_logo_big.png +streamlinesolutions.logo.full eu/engys/resources/elements_logo_full.png +elements.logo.full eu/engys/resources/elements_logo_full.png +streamlinesolutions.terminal.icon eu/engys/resources/streamlinesolutions_terminal_logo.png + +elements.banner eu/engys/resources/elements_banner.png +elements.background.image eu/engys/resources/elements_startup.png + +file.pdf eu/engys/resources/images/pdf16.png +file.excel eu/engys/resources/images/excel16.png +file.png eu/engys/resources/images/png16.png +info.icon eu/engys/resources/images/info16.png +license.icon eu/engys/resources/images/license16.png +preferences.icon eu/engys/resources/images/preferences16.png +monitoring.functions eu/engys/resources/images/monitoringFunction16.png +crosshair.icon eu/engys/resources/images/crosshair16.png + +chart.refresh.gray.icon eu/engys/resources/images/refreshChartGray32.png +chart.refresh.white.icon eu/engys/resources/images/refreshChartWhite32.png +search.table.icon eu/engys/resources/images/searchTable16.png + +helyx.gui.label HELYX GUI +helyxsas.gui.label HELYX-SAS GUI +helyxmesh.gui.label HELYX-MESH GUI + +helyx.core.label HELYX Core + +doc.helyx.gui.tooltip Open HELYX GUI Documentation +doc.helyx.core.tooltip Open HELYX Core Documentation +doc.helyxsas.gui.tooltip Open HELYX-SAS GUI Documentation +doc.helyxmesh.gui.tooltip Open HELYX-MESH GUI Documentation + +relnotes.helyx.gui.tooltip Open HELYX GUI Release Notes +relnotes.helyx.core.tooltip Open HELYX Core Release Notes +relnotes.helyxsas.gui.tooltip Open HELYX-SAS GUI Release Notes +relnotes.helyxmesh.gui.tooltip Open HELYX-MESH GUI Release Notes + +# +# FILE CHOOSER +# + +new.folder.label New Folder +new.folder.icon eu/engys/resources/images/folder_add16.png + +delete.file.label Delete File +delete.file.icon eu/engys/resources/images/folder_delete16.png + +extract.archive.label Extract +extract.archive.icon eu/engys/resources/images/extract16.png + +authenticator.browse Browse +authenticator.domain Domain +authenticator.enterCredentials Enter credentials +authenticator.enterCredentialsForUrl Enter credentials for URL {0} +authenticator.password Password: +authenticator.selectSshKey Select SSH key file +authenticator.sshKeyFile SSH key file: +authenticator.sshKeyFileDescription Your key has to be without paraphrase +authenticator.username User name: +browser.checkingSFtpLinksTask Checking for symbolic links +favorites.favorites Favorites +browser.folderContainsXElements Folder contains {0} elements +preview.loadedX Loaded {0}{1} +preview.loadedXOf Loaded {0} of {1} {2} +browser.loading Loading +browser.loading... Loading... +model.dateLastMod Last modification +model.name Name +model.size Size +model.type Type +preview.n/a N/A +nav.AddToFavorites Add current location to favorites +nav.goFolderUp Go folder up +nav.pathTooltip Path +nav.refreshActionLabelText Refresh +nav.ToolBarName Navigation tool bar +preview.enable Enable preview +preview.errorLoadingFile Error loading file +preview.fileContent File content: +preview.label Preview +authenticator.savePassword Save password +browser.skipCheckingLinks Skip checking links +favorites.systemLocations System locations +favorites.action Edit/rename +favorites.name Name: +favorites.url URL: +favorites.title Edit favorite +favorites.tooltip Edit selected favorite location + +arrowCircleDouble eu/engys/resources/images/update16.png +arrowTurn90 eu/engys/resources/images/arrow-turn16.png +computer eu/engys/resources/images/computer16.png +drive eu/engys/resources/images/drive16.png +sambaShare eu/engys/resources/images/share16.png +favorites.edit eu/engys/resources/images/edit16.png +file eu/engys/resources/images/file16.png +folderOpen eu/engys/resources/images/folder-open16.png +folderNew eu/engys/resources/images/folder_add16.png +folderZipper eu/engys/resources/images/zip16.png +minusButton eu/engys/resources/images/folder_delete16.png +jarIcon eu/engys/resources/images/jar16.png +networkCloud eu/engys/resources/images/network-cloud16.png +shortCut eu/engys/resources/images/shortcut16.png +star eu/engys/resources/images/favourites16.png +starPlus eu/engys/resources/images/favouritesAdd16.png +home eu/engys/resources/images/homeFolder16.png +desktop eu/engys/resources/images/desktop16.png +documents eu/engys/resources/images/documents16.png +engys.case eu/engys/resources/images/engys16.png +streamlinesolutions.case eu/engys/resources/images/streamlinesolutions16.png + +application.support.window.label Support +application.support.window.icon eu/engys/resources/images/info16.png +application.support.window.tooltip Obtain support for HELYX-OS + +application.connection.window.label Run Mode +application.connection.window.icon eu/engys/resources/images/runMode16.png +application.connection.window.tooltip Edit Connection Parameters + +# +# REPORT +# + +elements.report.watermark eu/engys/resources/report/elementsWatermark.png +elements.report.frontpage.watermark eu/engys/resources/report/elementsFrontPageWatermark.png +elements.report.logo.full eu/engys/resources/report/elements_logo_full.png diff --git a/src/eu/engys/resources/driver.pbs b/src/eu/engys/resources/driver.pbs new file mode 100644 index 0000000..13a3c83 --- /dev/null +++ b/src/eu/engys/resources/driver.pbs @@ -0,0 +1,12 @@ + +#module add openmpi/1.4.5 +#module load paraview + +#Initialize Environments +source $ENV_LOADER +source $PY_LOADER + +### Set OpenFOAM Environment +export WM_64=ON +export MPI_OPTIONS="-mca btl openib,sm,self" + \ No newline at end of file diff --git a/src/eu/engys/resources/elementsBox.png b/src/eu/engys/resources/elementsBox.png new file mode 100644 index 0000000000000000000000000000000000000000..c25dd877229d22dbc5621f213196c0dad43c7c5f GIT binary patch literal 9180 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 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/engys_logo_big.png b/src/eu/engys/resources/engys_logo_big.png new file mode 100644 index 0000000000000000000000000000000000000000..044bb262a74a291ad37e8d2916e85735009a27cf GIT binary patch literal 6030 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 IM6N<$f>FbL2><{9 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/engys_logo_full.png b/src/eu/engys/resources/engys_logo_full.png new file mode 100644 index 0000000000000000000000000000000000000000..12555c575d37518d86cec04cc9e9568563788385 GIT binary patch literal 2956 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 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/helyxBox.png b/src/eu/engys/resources/helyxBox.png new file mode 100644 index 0000000000000000000000000000000000000000..5645eabb845293f2f529c65251c96b17e07cc6ee GIT binary patch literal 9067 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 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/helyxos_faq.png b/src/eu/engys/resources/helyxos_faq.png new file mode 100644 index 0000000000000000000000000000000000000000..3f4c4e49e47f710ba0d53f379636c938803365fe GIT binary patch literal 245357 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

tcEeV&jqsCE-R1`wg>7q#F*dFRlJO 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ⅅ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

Qh6yUJ8 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 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/helyxos_startup.png b/src/eu/engys/resources/helyxos_startup.png new file mode 100644 index 0000000000000000000000000000000000000000..85c2428fb9a78aae2ddad5afd1873363201a9cea GIT binary patch literal 26532 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 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/XNeg16.png b/src/eu/engys/resources/images/XNeg16.png new file mode 100644 index 0000000000000000000000000000000000000000..17957b86a6082ebbdb7f0cd3fe7d51cd6654c38e GIT binary patch literal 594 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 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/ZPos16.png b/src/eu/engys/resources/images/ZPos16.png new file mode 100644 index 0000000000000000000000000000000000000000..8dd664d00d6897c2b5768ca718ab9f8891fc6dc7 GIT binary patch literal 612 zcmV-q0-ODbP)N2bPDNB8 zb~7$DE-^4L^m3s900H1hL_t(IPnD8iNRv?*#-Go~(S-2Ac@qTHRTo_>k)fNPO}!Yw z^1=}Rd{DcPRQ8E(U9|quZa%6Zm0h%xR~cSdq-n&~7ziOKSVE*$c5lIOE_NjZPv=_` zG?#q7@NhWiecs=B&*25EhoX%jZcMo|=kDN)^|HTCrTa1Bi4Sd@nXl#W%;}6bY8|2k zp5W=!LJdb#DCou9ao(M--trkxt#o2juVU151E12LTPf1u!(=P#bd1#panTB(Oq%TO z2p*(Y{1mg`qm-ZW%pp~71yJy)HxWy%`Y7JZ4&M1pK!xSvZ9sChiDC{MPBtAJ&?q~2 z`?Y~$0gNRZN&=L1K$o|fZ{8Co;LSG|#Ugkw;o1XGepXh-f4K??`~Lv1*PIkfppkIy z0w_PKs^aYLXWlTl(b2(d3Eip{?7os^XHS-A)pceyjo*PNz5qiEg~+b1ePu|%WnEf& z$(rU(G7#WLAchg3Iq&i0*w@E`g29q98lN+Co7At9p7S{}9OjYf2?T@`Nn;l|IPeZ_1j~TMAqc7M1pkFp35SqIF$tQS8mvPIM6eR!&T40N zXM8i7^(3HY-tgF6cD`@E@4Ywd!sE_HH4#hBdxXXC_wbaA7H16otk{&J1YTQCVT&Se z7=|E(5(29mdrQ(34wIuAPhNkC;9&?tw&yP)V2QwEu{J_^1^*iXD}(nCC&xz+g2OXT zUmT1)g8iw-(_ZHse4gWSt%iV=r$0w36I-^V&2#mzYaaFfQ;@1S?PX&J%Ht++=47v`R3wdVo&7f_L4IFg7Ozh5#nE zOzQ-S6fn-wY}5w`e)UC2fv?X}I3_Tg-lUUx1P+Gt4tZ2y%9hB}z9vdz;^7WnwZ^gA zeGil6u-1^0pnyXK1zJInwFk{c+0xPil*G5^3-R^F%*;QA!JVxEnLxF*g}p}?vHiA7 z)u$TR3|W@N$|qV=4Rmbv{nowT1bo0||HbY2ymozhs6h%?t^~(LI{vZ3j^we5M)3VVxgsijZ8=x8JHO8f)E1(OkE<;0R#&|DiWPw06Me`rB%z+ zua$pe$L@>$xX*D=(}pV@+xI=6<9pA2W(2mW`BBp-GOa$Y-~7~%JjEHXunIfEdddc?@tV-cXvH7 zCg3=nb^=(Ii^pzWqz~Jh%IO zc}r83rem1c*GyO}jxAw?C@=#}YE`1+B>L70+%HezEx%i^clKV}A3v?7tgUJS+>dJv zhDxOn1dUPtSl+@+>uku`(`==XK}g7>P76up%&k$JzH$v}Vu12^$FVQ2tp(qnKPK*< qwg8L#&?4wj&hYQL70(Y)*K0-AbW|YuPggq4jBPK9n&|jOn^csJY5_^EKa|j zWa!tDAkb?6$=`JkV^{@?<_CjqB3IT;53oL()F`|o?2aS%{{X$ciY(TmD`%u~_Zq5o zx1J2EIXgSWNMB!{+4%o4#*W875+&LKLM4xXEPiMqkt{IrxQeG=nIuQUs{y2xdj3?`G=9D=8%Dkd#b zzMsCB`TJ_?O*Z@t)>9qo&X}Fv|?aciI2| literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/browseFile16.png b/src/eu/engys/resources/images/browseFile16.png new file mode 100644 index 0000000000000000000000000000000000000000..ef8c5e2eb73836f4e626dfcae2b245d8440a540a GIT binary patch literal 672 zcmV;R0$=@!P)eR^WIC+XbmNw zqMPCegtQf02sWY%_Yzw{qhJ@h6vS=ah`1<-4q8AQx@0+=I&bjXni_Xoh*BcFoq3bZvZZcxvjDay$829_#=w(kM z5#wK$%jJyl>};r4KBxVrvzkZ}Qb;6I%~i(If}s%HZZ{5$jRnGy$fNE8rlTkVs=5Ig zOA|uiOR)%#$Ag1D--$>x8g4J3z*Nq;LSS7KN4#FdRSA3m7d1TsF%r z#-IoViysydpP$FqQVCM(olFh`&Vfz|za1`2C{Ps*$wUGVA3s56_c3faJ_XmQizx4z z!1Br`Oiy1u+$Le82d&#Jnu-^(=P-O{F}dFZ8(owB4lHRdlq{22kKK;ZQOjQ$C_+Uc zU%43Ffbp!vi^$GG+!wMn`es{5jmadkt@Mc`(UNv%%`vim81w zfNK{Pn8i?}=9cz9%{x4d8#ixte7k>UCy=MJypQD4LwgVmzOvixhvcNeXnT+H6*d=U zh7=18#d75ti(fth#fq2jvZv+l4uS*!Z=VTH(|`X{fB^vH(Af1*&6cnL0000m@A! literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/browseFolder16.png b/src/eu/engys/resources/images/browseFolder16.png new file mode 100644 index 0000000000000000000000000000000000000000..c830338d89ee2befb52c0cb2a6fd72df21b55218 GIT binary patch literal 815 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 Hu0mjflC)gi literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/computer16.png b/src/eu/engys/resources/images/computer16.png new file mode 100644 index 0000000000000000000000000000000000000000..d07d5fde68c0b3681e67d220a7d11d72a64da487 GIT binary patch literal 715 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 Rk^;J&!PC{xWt~$(69E3WWrqL& literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/cube24.png b/src/eu/engys/resources/images/cube24.png new file mode 100644 index 0000000000000000000000000000000000000000..5329b953ebc3149c0973efac2a4d57b2aea939ea GIT binary patch literal 961 zcmV;y13vtTP)7yvLdna@0Uz7LQ(Tc~XzCM(zB%(qhYT9$4+`4Pu z5wXwq$dQzuDMbs{oj&flbfzNzo70W=(=r#$5B5wnq|xd|^@gM|0C4=?yF_nH84v_< zJW_aM#GT-N`NDXj_HuiE!3NzkN1v+ngS^E`BGPZ#TI!G2XjK5fW%*BHOavfCir;E8 zC+ZRnPx1>k=n!lf0D?2$R8scRn6khR0DCtsUvcPIl|Ap>_dJo}!_F5fdyi!tfDk;H zhEGqm>4sH^)5wv+{}%SBX9Dw`R9XI=5D1Vgev796415{3`jZQ}UrQAJEPX2Dg0AW!X)SQCcplT#&?T8If( zFyff0^CzA6G-D&~n8p%f!||dIx4Dwi7DT2ME%Ln@b}3bAK^8<&c0M0cWn|}g2m5Sd zATX);@nW@M^X>yqbL02=zrPX6;DAkiaL4+${F0AaerYiHeG;{|nsqMc^EsXO+UNe! zZ&&yBSVVjG!?>Y=UUiS9BYwo~QVu(xsbo38EFHJB0MKlzQvh%gV@#@R?y_{=y*W2I zEz_5^c!^g#FCh@k6l%XMPq+72o_=@MEL42?sr%Z`^=|`sUkLzS?*#Ksc$g&lShVo; zoGkxDYWvl+62N-Sxs@1WeyvU~S2eU+1tIP~t=hV(00000NkvXXu0mjfJU z+)T*0k=$=0LUN(GS4i$$DJ8}7ku+wTk4V~lT!_f-+(?Sqt}(OBJGtNjvv;q($9XT* zXq)Y+|HbJ!&+q)7=bQsV2!6D_vB@Kah^=8_6VYf?wy|j^%d2ZeNHKl^c%DalTPu`G zWx!%vF{BUp`a*Vg7FwE{P*_;tShOxV(gFxk0pZV2+~51r)Tl?9Mq`*aTLQ@dvR?o? z6poAF?fnDSH(qG9Rbo3ubEX9%m&=O>`g6OZwfwVhaG)>I3zJsHC)sqqcVE{VtTmsE&s7 zLLQu!KLB=d_Y`P@WykBNY^i7ZZH%vDDG(B*prk3Eie?kOmlMpqnhbexS`0uAfFSe2 zR9?!is#;#(oMkZ)MZu4b#s+ej4wVypqtbAGKk-1U*cNbK1G)he03C8Gn-1ddUm`c5 zqA*U7@f+`X-u8(h2aKU4QUso+*xT3$XqS!c<*clUk%56i!<@m_`HTm>KoZD1OS`Fz zZCx^cn1w(AK;9aF7st^o7=Ry$t<(!ksDqMJmn1_pu!ta^^$8{n!;V|(Fzdy!)9{KZ ztCMUZjY@JZgCw;IP_m|C$0g4_zQFd1EjtXagIgDi%tiOBTAPTICdm&nDC+tI*m22| zuG926gQ#H>Hm*yBjg%bP$JW{!h8{%$K|VghgnEp=m3MGkHn+Dj+OMO>7HGM;2Td0U zA(#)T3_pypd|Q4bzKEC3S}A3CO@id-CCpj@X>u995<{RMP*6}PB*Q!(&lVKFcKhOJG7cH~ag_W};gCHoCRul>SZYd6mU3AfZ5JX*w&5I~wv}z8z z>mr2crmG+Z<~Bnw91*7EA`$Tih;Jjcy}Ic#*1MiA+B>(k&@Vjj@SO8}&X;qJAWu#| z7DLjN$#5+rK}rw;RKZVGrL(7%yA(;7mli*_(gshD*bZ`~-bJ-_A0Pq2tUkk=k=K0I z#$(|-RQ&^R`f;QUf|u*g(Oh?tuZt1%)F%W2iNtDYplU}WZ=<~gqkXYZ9z+E=aEY-) z)%#WF@nek6KVx#?3j<@zjB3kF%`YQ2Pq32tNJGtOzAfqH))Px*6TS5395nlow_Prh zyd$=dARK}CG!NsGM9X(mJ*V3`wYUbUY*`D~cG}Panh*djJ`x$pw%-yI0r3gkgU{&# zQk>#P?qjhmYfY>J%JM?fz#;(kNV8(TOh@LYs2OPTAr-+~cPqP!3wk^nstWDxYcM50 z;k*~=yZ(a8irUJOmRBM1z3?dqxZp+Jzv^XNYh%y$Db9G1j>pLS==jEbznk5ZtRf{Izkvp nU^sgyxk#!1Lyu+`YeV`2huO+Bf;?6^26<0> zvivO}TW#_=s@LzRzGeylpq1~iTBXEk^JT6yo9BPOHZDv}ruahcmXG838Ot<227nWY zs1pE)vn-bkMISO>>wdTL+{;~Mo);F6b)T_qi(D8w?d$J5;>~CO5Gi%G5;ZF@VOtpEi#sABoL8bO*jAmBJ!4LBnSYY>{4h;C~9=>dMp2Y=gyKO zD~**vjk?a9A3WtB{O+sJY(6X1YdT8+0FMnOQ^||x)uI05pzoUBn4gi2wDREk*#8tHlTbj-DH?B`8nd!8W&t{}>bY1Gaj5rN7+UB1-a8fEYqVPlHmALmdSGfMYqG nVc7*j$N~TAp>Bp&!eO zgVbU_k?uhh_dj0i8s9K(=2v0jlgtO%LXIgwfzUU^^z-Pk&>GWSpt zF>}05XCbjX%z?&VT<*9O5|N~W@&k>(NiIj3%euK075!MJt2jEqdk%Blx0j|3Z<64? z7J~lPhPGhHe{g@n`0(vH3sM}5GxlbXD^mA;Q$U#tyt+wTR_2J5>QWT+S;I7DjkQ9G z`6VfS$5`wRS7mSM$_SeRWsx;UBtT1pk0ZW4GNUXqvk2qkjK+qz_II)KTeHnn!plCw zMm=-EW;Zr5C9e+=-dc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHn2Hy2}b7iVKrQ%hGvLsvr!CqoNoCvyu! z7dID6b7v=*UYGpj(%jU%5}4i;gkBSzdO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPri z(>$o&6x?nx!l_pu=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6T05_KIs*gKDo+>3 zkcwMNCdYb+1d1H5H@2Rgw{m8im~BR@Mk1?P(u6NbUoITB6A_dUabZmj5p!H%>muMG zGR2WawD$Kj`9|9>6FP+0Y9li^Yjb{vuCv;G>)o3(=iZ*lx>6kXtZ1h7^YU}H|9{5& zY96g=3oI*LaI`G+f?w0i7kgIzJGEuay6NHGwm)jD+;;W-g|d3d3%_Rk-?Lz@rAt@(RC7eR|I?SftjL>lV4nb!EKx zqTgRt{w`dxL2B0d{_K7ue}1bs_KROi;_OKezFp&ZdYaW} z>VeB|?gl%nsIf;d$oowX*twYD-j$7;EBJla%7%pIHqG#Lop*AsuHcuGlH4-vlNQZ- zHc7xx`F_<)`^Xc=66`$Ax2V6&+Ua}wshdzIi;Bv=2P0~YP4h!~L)ILx zSQA$8bF)?W+@tSQV{Pj5FWS$VVy~WQBH#DgOVQge=dop&@U9Y9si{j}-kH5-(Z5U< zWp%rAlLPGRk9Dn#Hg-tu{8Rm9e_Uwhk|Q%~1(PjfWHg>F6;)9G$C(^x<5Z*MQ>`Pc zzHL%)s-oq+{dx0^r<#9J>D3RvXgJ9;Pr=6_qIu=Rb04gWi-X?W{*%bq`0jXwm(LgW zS<<^g{4eLsdaEG$EB(+er~dOLRe`Hh)BZnCopb3~_1t=H1BQwO+Y6_HS*t-Mxu>h2 J%Q~loCIG_dT}%J~ literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/documents16.png b/src/eu/engys/resources/images/documents16.png new file mode 100644 index 0000000000000000000000000000000000000000..502122ae4703fd47afca7db9aa49ac1ae2ae0485 GIT binary patch literal 711 zcmV;&0yzDNP)(=*ERBp;%l*SKW!UHY(Uw35p3x zYDv>34b4mPu5;f@(iCim_nkX)&di))U!I(px2mR3Sv6>5T!0CgVvL`nzc%ec!z?iI}^2PzcGK5P5=wD*g z<%$aWKZG%oi{O8Dd3zD}v$rlv8(Nt7H9mv6MADffvxvpS2nMha-MuRD#drz>hx{1* zQN)GG!K7rIqnu8_EEdpn_cgUiaxz^$sWRjwy`9d|fECV#x)B{K;`FX%oZ0Ed_0Hn~ zNqS>3{Ttpu2q-0B&BYu6Tw2zfHh{NHz)}v_F;5Pm=fK0>jm{qE77CdZy7wI>In%T{ z9%uY6vst#=B?-Vm7#%#)^xqkqhSU-jGFb%AZ>3r0X^y_S-sNVXrw;Iaw&1J=k%qe5 z^-WZ4kxS`~KOKf%DrJ|Y;Nd0uI%@}YXn@vjZ26Yq$ot-VSNDV~)mlw8yp~m)&li`_ zM?#QwZZPZ$>ib9?u0Y7I&rZho-iZCIpS4=e+t-+Zz*@!#V3mVYv2I>QFf)XXOnex@ tqqo;eZqI&>F|2Q!>E5!=dG4P80{|?p%(?`Q6_@}3002ovPDHLkV1j}&MpFO) literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/download16.png b/src/eu/engys/resources/images/download16.png new file mode 100644 index 0000000000000000000000000000000000000000..9553b2d0a84a1bb82b3bcfdd38d9420a61efa1b8 GIT binary patch literal 761 zcmV{v;`wH zL?enQU>%`=*5F3hQtqyVnR3&geYkd z6OmYy@=;pp*M9H%_LY_oIXKDedoyq5x09Lo7;KR0n=g=G(U39gI-A_iP{hFC_;Q@s zxgFS6`>1t(J=$dBgxypTx>feiE>CeTui`ZkPU$N$b+gk%E z@(b$f0@(dGhO)GHGzwV|vBTvu%|=PmJc)z^Ne}|W?n}jDkVFAYK^clJ^wJy_TSSp% zBnXJL*-Bzb(KENO1TmQsRN~i21zTkkz%YznUDpm1g`&s^i5h~84MK9sJbtql^OY>u zvjA0AHUh>uC*Rz9zTT5i42*_Vgq*uj*;G_l$T1ij7!9a`pPbQ+P zv8n0#^1P};ZhtBVQN|7j&m!>rLqLqK_OLALV=R_z4%2n9Grgf|;In)X6GBP5HP3mw z(tGyEya=p3dl}GU@t$M+tgpuQokW?DYk;@jbQ>&$z*^IwNv#}DlV{rfxyNsrfmO** z_d9c6`Hot@(L|N>Qa82-G?Q&pro12OZaU8c?0jrPuip{CU^b|5Epr!Fz-=(?PSp;Whz;PT^Q$$guT3lKR^9Mr@FWa(!i4fo^ zq;YmWKObeawNwZC`(d}+>479kXz5s=mZ*XrOf3^Y_j?W9CoQNb03Q#B$yFB8<#@fD zN?!>E>1yM70xUj3N}7+QYz(bv8o z_x<$T0&O*DyvfPA=iYNZ_nULBaOLSX{<0?SPGyu@J;LkqZj<8jNlCK4-317ufYWO7 zI4rs>7_Qfu;4!v&3^0ubqA=>Pv=2T;fa7KiXMewFhT~;b5U~wYzT4K<_^Dp zb(Hgo+)M}HyIwD#+^6(kyK!r>(DEWI?fIxFX^c$`O$_!4c)zfu`8F#Fg3zgv)X6(t zKp3vH^oCLST+JoNvzb*Z23<(tOur26#aqqM8*{QOmjqGl0`mDh6sHQ6)!GNGAhBW- zWTUc{8@Zg%h%}kn^Ou@i*XJZEPGcW~)>o?8Y}X0X)6<6&AS%(JON00lUc{EG+!mAS zeLk?LVLTj)H%mG3J5s?eeBVbHh9^&fCrn}&ds3>j(@4JKXBnxnelF610RNnVLQTBR zJrB}C9cj7V)8NjQ|H_3U5BXRM`J1z|vkz2N%{ug1Y}+DpNG^YtcRfZHhhqLrWtECo9#T_gMQj5g+d{*yu7?du=BaxrM3#j z+}{+~Zvw3R_^@UeMxs)wWOyI=%~`TxQZN>a#m4a;%k#XCq+pe{)n5V(09KY!`^#Ai QPXGV_07*qoM6N<$f`MLDGXMYp literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/drive16.png b/src/eu/engys/resources/images/drive16.png new file mode 100644 index 0000000000000000000000000000000000000000..e3979a83d4f080ff2e75f836e97065cde5a87a74 GIT binary patch literal 430 zcmV;f0a5;mP)YOW36Z*}C?aTQL3in(b?nlh9n!nx%y&kIs@Au{1 zy?a7yjZwnFh~ez+?ITSySeD>gmrA99K$0Z6c7Ljhxht%#u7E5vK+;R#`5u;+7IR(~8qo*pH}CxKmsi(@A!`g|Pr~*=LVeEj)Ncw%osMvm@;;|-A28BwD8-WV5a%2Y%pIIf9#K~&=LRMjjsX> Y00BI)n_shN)Bpeg07*qoM6N<$f-RN5#Q*>R literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/edit16.png b/src/eu/engys/resources/images/edit16.png new file mode 100644 index 0000000000000000000000000000000000000000..bca343308097abd2e281666ac6deb453d4c2e565 GIT binary patch literal 1185 zcmaJ>O>EOv9Cv|Ls4E+XA=V0krfN4-G;v{?7-AYi;{avS)-h4>B~4-z5{GruG{Gh=gN8nyOH(+IS+d`U ze!t)U>nBh3XLfIBX>Xw@YD2nD%93@X|E_N)-);A?N|rVx51^b~L}k^5R9v?QA)PkW zA((}#UOoI1?4hW&jFBHe1IinsW}B?)W7vx65H>~i#43)ejX*>X!Xd+oGWX73U}!^+ zG6g{aij#!HM&FnVb7PsjHa4O~bSBnI_f$k8U_zwQ6|-b{VkOEf>xyLWUvmt-3_&AN z=1EcmNnT}TTo2xuV8)8S5*?*x&~$WA&4c);;N4s->0APQX~;OUizA<Wwsn*ZFh*{BasLPf?O~dAc%lhwUAl~SYAh6L4uy<8V)jSi}n@O zL3`R*78=`L>k6bREOhP;FnYfD$4&uO>-6Pp)7ow?{kH{eAR(m7JBxm ztC7JKJN!_Nm~^3vY&UP)rFs|phizng!?r^wa{|lL1;f(qvbT&^6ftdiNVPPWmZA(% zU=2eTQ}I+dE+v7`DGNL=^Kl^&iU?h)ZW(~?R9LQaC0iRcp@r&P{VA7k$n~vYIwZ0L zUE>|7r(D~lmrE9nhPfo*QhU9~MatQsF$#O*Gz z^{E&BT}M$(o6=G|U%53{!#K8f`}EE*a{R!;T;G`& z+i(4fy|?E=M;7j=-G%daW9jDnx60DY=bz1={%0Zh(aU>phicXPA5Sz*zjRtf&YAiD z@Q?2vSn5KVr3)IK#Z}>VTK++5bH2L$7sk1*7=QiN!}0gDpYf&3W0S>=w0`m0{yoQw z_b~qD&qp{`sNpY4$)m+Y^Olof3FD(Xt`?7B{6`wk92@!Y%eI-OZQ%zP<0F?aF0^Aj z6KJ_v`s8HW!NmUYeV?j}6MJ9ZRBQF-ckm}Ny`?p;^zK24?-pyDzrV5jwO6MP9tI~e tyQba@bgjnO$$OSu5+~ z?GnX?h=lA4Aw)tUQAmVFq0y*l{09woYO#CvJPuUx9E=pyT_#!F+yaE_A#~L~0z7#IZ8fe)ldA+)52({5L z7I&}FQv-y8c`#;c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHmlXG2pbXHz3nOG^VoLsugUR|_X6M`trf zV;2Jh3ujZ9UYGpj(%jU%5}4i;gkEEudO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPra z(>$o&6x?nx#Hm*w=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6I#=us69WUIfTxRN zNX4xq!Pa?9h61(8vzK~^7cuxv2wt-A5!*>mr4|+cJ^ z(`PHJz`9~elqiQ6N8i@=v^5jop4fT*{d);Hd9MK~FFalST-G@yGywp~ZIA^3 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/engys16.png b/src/eu/engys/resources/images/engys16.png new file mode 100644 index 0000000000000000000000000000000000000000..3d364a0854d595fb892931cf5ccf11b24ff33ab3 GIT binary patch literal 1774 zcmV4Tx065EyRo!pfR1`mnZ(O7nKcKOW4i$^9Ra0BJ8yc;~21%2p=|UR0&DbiW z$#rfTQ`a`O(`{9s_5yDV_yd5l2Of}kLK+Oj_Ok5(v`JGz71bo9J#^YYXp{DWs&KBa zQ@dTpxRI}aIp=pi@6k0t$5)!;m`NF6-tt{FpOKHBn3g+MAqmexC-gw4rh87hTrL7G z#)U`L!(So6-Zux@>;H3gR;i~0B%VTSS3P|m@o9jRsXML@Al^p#@G0Lx-0?i(9WEw_ zSYddU<1E8793KxjQ|c&UmW!mTC>k>?{om1c9S zUx<6_jj_!T&^M{wWM#>IBbOSf*xP<^F{$j$aOQ5Y{cT zROCL1M7^NKKL z&(yA}mSw#iM0^;IB{ZO5!wl{^Sg-*ysE~&Yz8!E;Qv(A`lu*=Clo*MpVGd>OdF6n^ zam1Jntk;<}MrqIC5$=Q>n{*R}?8oOIDUw5En2dl--Xw34!z7E+5pr-OgyQ-soSab)C%saskMla`aQLVzg0+MZf20tJU&K{hZoBrUc+U4e9&3o zw|KmGEe4#xz17wBu{f`SS_4i66?j31EjY7n{zGfhONK~c+td!TS#B}JoR}5UAd7p& z5phTyXSkK0xCeD3xaYP^o&J~#Xp9xFb0C;HHml5fA<%h1eR|qw7wxF+oNL9T1Aits?sKNIwvGaN)^WO$I^cUV)HzL_| z1K?{9p!>B*)`xfEv!4N6IG{J&h49W#Bz^(#YWw%`e_a{8n{G9m5AeR~_yl0%<7V@p z5R@HO^{O-Vrn2?EY5Y~5>v-J}`e=5=Bv8HuR> zGtxy}JND{6IxW{XBeycjbBeDWRZ3sB`gm(LrufEA#g|}2Vc?K8>E}vI`&~2B(qvjq z5H3}uB4H6;#Cr3)z92kHxTujiH01Rwn;+6V!NUsuuw4`y5Ocl5@;xo>)4E3X=$?FB zVcoDeg7AXa>uUBjh(;Oed6K54^Npt_9{Nm zIl4h|s82?UbC#S@esHb7j-8Ywx9Rv}m5@8DIv5Sf-?~-%P@n9FSP)$rPzxQ}77}5kBC5@**JsqCS+&t= z<+=Bif7&S9|BL!Rzo|YI;9bJcn8n*oraN?PD~iUk^r!ms@3{EsD}?=5nfpevf=TO5 zm0=4`G>6-8yWqIaO&!8xzba46x?H)bAHi=f2Wg z9n<~Riob9J=^1TvMWK69IP$&A<+CU$4h2cicgp8rQ2TZB(!t*?jcrlA@NFx>1oku? zcL|I}K$TCcJoBUKFw~Y^8eZ1_3oK~D<8%=N QegFUf07*qoM6N<$g2>}zvj6}9 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/ensight16.png b/src/eu/engys/resources/images/ensight16.png new file mode 100644 index 0000000000000000000000000000000000000000..74a0d9f42159002a9a4472291f6476613ca19a31 GIT binary patch literal 867 zcmV-p1DyPcP)s0`N&h zK~y-)ZIfYWlyw-ufB*mgz4vx^^LFdqVmCd;jn;YUW{Z_3GD5;wpt1R>%`d@(29|_M z^r3-%k%5y43W0s!hX4& zIx?NBL)SL=ES(;FrcgMM4u!Cdfp8c$Y~Vp8PTMV;Kg$p(pVrpq*Qch=UtI0etBK=z z#~ov^wFcXU+62>1isZE_mb-IUJ+o|1r;krfoxgbI%;%NjMh6C3t|t=msG&h5l@i&K zm8(1V3cM)WFL%mDNlM~!jdTy~%dVHM0rF#G%`wZuCELL}+P zmiRkT6MtWvttaJ$N4sUSWTas!DYX+3iNsFGj-3~J|KGcIg|8bM3+=vNEjmWC`xZ7H zL7=b)zeS$Dg?FkGetHgL3G?%ZqsNYYvph2L%71{-Oy=aag@yOhp%A~RdfMH7B9sx| zK+%S18B{1I(n4X?%o~zMeE!H5z_LI>F5Xn22234BB@%J1?tb!#$;m6J zayjc*7WK+w)NkjM_Yx0@6UHNCL2mJFt&|e89#A(k;|{v+*=N(~o4HacdLL6$6Z{cA tU|lJ;gyw!OhQgn;>}cE9+t<1b@Hh0i5|#2wsu2JH002ovPDHLkV1i;0o9X}n literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/erase16.png b/src/eu/engys/resources/images/erase16.png new file mode 100644 index 0000000000000000000000000000000000000000..f2eca21b7fb553d3ad2f8766b8622fd2dbf2354b GIT binary patch literal 718 zcmV;<0x|uGP)9l3$dhY}psRT}PGOzplzBA|EBae=bqB<;MqiI`nt|DyPhE=xSFq^eWM4F~9 zdY2FaMV2Asj1X|KP-4-+b}-9=L}}a9&}5riRU|=^Q(@~69_m15_8T&DE6B_&Av$=U zzb`Vz#mT9#$>C=YkbQ4}C<-V~iMmiSix3rA2iC%g0?cA!5sStjV(-J615%d^N+@b> z-@xwdS3n{t6iY4Sq<Eq~n+1ptWuy}_B+|%2OmDP2qZa0_&Y-u(w zG&W&(W)Yr106w163!l+G_9*i9$#|Ol3-|T)V`F0z9$ucx(?uz+H#g(gqQRX5jEi$3geF!#N6-a!|(G&R8^g$l!nEJ zd_F%PkH`B3eA>K7RnIqhx(@Gu^Gu&Lt$zg=0L@z>aCD4s@c;k-07*qoM6N<$f|61^ AI{*Lx literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/excel16.png b/src/eu/engys/resources/images/excel16.png new file mode 100644 index 0000000000000000000000000000000000000000..3cf3f34b5f8be6b8ff62908267ccd77fc42d1fd6 GIT binary patch literal 725 zcmV;`0xJE9P)mLV}j1ElL-yv?w=1snA5Zh)@zT>Bk5+x(Xsk z$C+__@4nNS`{qZ>=sdo6&pns(bH8)0sP5b`l3b6UlCA^Fe1L$)FmwakOk>2SCr*Es zlh6_8GZ!009BjAf{f!j2aV>J~;d090A`89FDU8Vfxs`IM9RlrK;&^a5U zKv!zMjaA{&327w)jcA@IhIeq2slc@7Q;IkxzM!dQTm+SX~IZ#3NG7h9+ zg{KucYm6krW;}Ymz)d8IGag31QjFIn=@IO^{(_89SLwWt70lQl5Ka8dmzExswBjaV zWo#xJeY`qa{tAYHWz5PMzSnYQ(tyENU(~c1%%sU)LlfVW-QwvPd@~2>x@ZoTdjUT2 zjHiQ0b{3hTY7Uj>G7L@3;X;i+r(dk~Z>rMp9tbICQx|_tTT_jHOI=-wSr%oTk?a`2 zww;x@L&fPqammY|ezYMaW!?fi7a1b{{uW>WPI4oTieDgJ00000NkvXX Hu0mjf7#vS4 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/exit16.png b/src/eu/engys/resources/images/exit16.png new file mode 100644 index 0000000000000000000000000000000000000000..1903e23b9e959b8eda4d77887e0e8ec57fb4f246 GIT binary patch literal 773 zcmV+g1N!`lP);^?(Xf6qwzRfEc{Te| zRsM~8SB^``=(weaRel~xNpy1dcL9d7J45SCNJOP?5G;n20#X?X%?zwtVCd`{D6Cz>QB3R-h{6)2 z;54=c6fL~=KH#OA$JN{*Y;G8gPzkQ+kegE^-HeW*jYXsx!k`32dz`9&jUw2noFpb* z_26P|0Aa^nFyqmjX$VQISxXpag<2FuRx?L}D=R4ed&E|001!|2bQ z!&!9(+3^DeQ$tB7rA^>-l1sZ090v)_8II|X`D9k+Au&QB`a<%7x+_p!2x2ITH8o+l z`EVnecPv)MBk2}T=JQ$ivxC>$1=QLe^p9S~%E?3E=`vzsT~Se^Lu$fMmrWxq6)OlH zoWM@F1{CcV@VG{F;?l?<)=V7%_lXoiMzfrxBiP0yDmX>TVF77}pu6kfQ%e|Yw+$gK z3S1i-MdOoWV18Kfb>dV;CL{TX0Hd9Z7NueV)hP~XRX|>4`21`SI%?lQzi$E0M9#DL zWk>5?h7%G)91t2JCoB~p$z&2NPA&o?!`%PgNS||*6$3533z~BLT{X7Wm*A0k!XlAa zzaqIq+wqTas=KAVY3=g9)=iCq;s2tJa-AdShX4Zr4YwL(uI>`{00000NkvXXu0mjf DqjypN literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/exit32.png b/src/eu/engys/resources/images/exit32.png new file mode 100644 index 0000000000000000000000000000000000000000..a65ed5884e371fad9d3c82212ec646eb7bda8cf5 GIT binary patch literal 1382 zcmV-s1)2JZP)GW zK}?BFU#gJwMGZm?Q7EP?eGp$1g7%@{yU+(geDF!AivK{d#3;pw`Vnih6as3sUsTaV z4AnHGX;VyMQ)-jAGjs3toI7_nyRyyBB4(45$nN}e=2>lySr<8ZRxk(xwFS$q6k6= zzLsvrKD7C{i8yJsJ|9(xMm>Mh)u_zuzPGCD*&ub z+G5dlOuhr+stuK=)~fl3G( zrD5jad$7+P#YqMzHHSbEWwK?{1i)zPG*M?wM3~nkl>S|K{;xN&BFf64Rm4D25pt|0 z(PeD|2IxnJq0`m97)S>ic%kogJll(*vBEhho23OQ+Elh+%H_M$fj7-Z&H^e#s)m7d z@f|FN8r$4OLc3O`BXSt*eGw&f0>3YR13NhYnF$H9P9g!P8SVEoE&&8NCss&Pkqg0k z7UbFa@mG)GR{3+ToV1W`u=itP{sa#6z6_Zj#(DWQ)GyD_#sTea5`@6UA~bOb*m?Iu zGw9elkGW{D(hD4b3_tmu@&dlS^2K_&6{F-BnEYcHgFS~RZI0uj97o&K0PP;dUN!*0 zS)h$^Pp_?T)IWIN5{65UVxXw23{*9+qUR|Xa3(Tjd?a|5HoEfX$9Q7T9z>lt-ASi% z+00ap2z@OepZQ!GCJdZTs#(BTR_zU_EUFAxQ&Uh<0WM8XAv53UY66%(VK**B!WSZ2 z(SdO+Y{{k(QX%pYh#BBbLv<6`JjG)Rk&vScnb=Zo!0aM$q0~k6?93D!|mWoj83ykG`kNb(+DK-7i6p`zW}^QpKQ`Ch<(SIB0_CdnrFe^&6!98fxmuLhPLhs_$!&IH0+Hx`*O zHL2(=Ppv&75!UtssxG)qw%~1<1dKDIID7GZysN43@OP<1Yn70m!kGF>$d*Y_kDwS! zdGB@{j=qMy{{JYFv0`~a;%3N&$TsK&eq3V)avL-w4#_OvOIFZyaI^}G7J3nBK)Twm z8vqD(u;Dxqcylu$FIE%-W=y~)9S113DsIKv)~#~=h8Pg3gcA|xu!}!LYYcD$;u+BX z3pO(lQXR;*Fp{~_>-w2ZJQ8sT;x35wk<5>VCMr`{bIAatMMQ58inFkV_X1uQ>n4_x zsDj{wW1vQanW3Sfa>I>i;n*^(ddYuF9s+G8&de0BBNw5w5F(#4h=*g&f^u~tas$c8 z$jEM<3mOsN&u9MY``H8Aa=F9Bo`Vl}wD)ZYJNw^WPW}GvWLwFo<>3xj oU4hN}DF3io4~D0jm45^n0OJvI9sH?~iU0rr07*qoM6N<$f?2tFk^lez literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/export16.png b/src/eu/engys/resources/images/export16.png new file mode 100644 index 0000000000000000000000000000000000000000..e0df9e635b3d610dc56c7b3e0427ebb2161bc883 GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)mmH6}O#GcLAqECUc~2L|5R21GCmVVn4iIVG|GlQ9 zT=2Mp;^O9?oc~(?aVa{Bi<<{>1Ql!ucCT+pp4i|VzL2kPt4HC=9UQuCQ90`lXD?dj z+4AK;^Y3@IGUsgfEO%+SAK>*j<_@>DjBNT@8+pN>#YPqjOMWN6{C2!a*h_PNzyZ#u zpT2o=C@FU2>=ios*|c&;uI1jWORszt3@1oL?d43LtF|NeR~} zOwvZn5QlKy^zNz6yO=KXCuBNIn#GsITGcGNZ2p1kZrT|ESNTpYcQf{vnwD6?+n8G8 uUQ#>bs%n7f{Yw5De)mN_#C(~%pK*J_7O_{pMasa?WAJqKb6Mw<&;$UL_o9ga literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/exportImage16.png b/src/eu/engys/resources/images/exportImage16.png new file mode 100644 index 0000000000000000000000000000000000000000..07af88bec14d133e36b591b0daa3b68e2aca3ee9 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP~D=({&?(U$OKp{pUPZ!4!i_=RlZ}f@@6kvOhzy3D^ z7nc~@L2-eLbr;+^1Pt;O%ov4Pa$8(o1QQ)MY%*EmZ_qJI@92b6N1Qtm|bbn0oAmum5lpRpKah0_GJ{N(Rbn>uD3W=!*b zqugh_IX?KBGk?8S*STFgj*0x6-YIX9A8_qByU(#lSj`HrfB1I) f)9g)UHr0#@9$s%GuZENZ1B}7b)z4*}Q$iB}sFjxX literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/exportResults16.png b/src/eu/engys/resources/images/exportResults16.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc236a47c917ddb411ae5bbc1d48f217886d826 GIT binary patch literal 625 zcmV-%0*?KOP)EeVDv^p1KR_rXo9wJh7cT6^b-`^Rlz=Xz;16((_k>?*}MSGW}A@ zRIXmnRMP3%9U(r!#~^QH}9i2YpJIi;FNuMzBwT9^LivaWBbhj7Fn?>wW)mCq;geVIs->N-oOXqjMBMcb~BNmHcX=R0%&hO{7{Q6k@q* zSr2U6#=j7WL~ujbpM92cnXV@P3-KO}drjA$<3I6}^jyaVzXTWn+Z`(U1wCkS00000 LNkvXXu0mjf{QVGC literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/externalMesh16.png b/src/eu/engys/resources/images/externalMesh16.png new file mode 100644 index 0000000000000000000000000000000000000000..650396f1bb72a798baedcd4971f790cc1a111d6b GIT binary patch literal 534 zcmV+x0_pvUP)A^gic( zBQyO)L~Ouu9K}iWm!k!|#B0oD=ITEWhH(l**n}Yv6u-WAT5 zz00^+)3=*Ck@%9C7fPs)ATy7Y^$2#?4b8&(1yNgnw-)ttO&p4dCwQPrIeM7tXhp;* zE@5v2Z*c|Na025IG1T#7g<;&lD7NA%zJ@Bq^F{a&<2Z+7*j&n5#tVGJ{>;2x^y`Lr zt90cw7Bll&F^u3qcLv=T1Z3uFM11R!K}SXntVF~_L=0H_3%w8#F%S_GSZQYF#fUgu z0vc2e)66>NgE)&_xR;slqiY)baa}byQ>w0nIn}q#Vlp!q{uf=^vQD&A!}FnV46R<; YKU?{yB;&ePH2?qr07*qoM6N<$f|?5BivR!s literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/extract16.png b/src/eu/engys/resources/images/extract16.png new file mode 100644 index 0000000000000000000000000000000000000000..672b4a493c326e9ca532bfeacc4185959f993a11 GIT binary patch literal 609 zcmV-n0-pVeP){~B6<@E z+|K1NkjbE0t6^?_z7vZ@+U4@s`|5Q@P7QVmg1Z}#IJm-ULsv!C=qO&!yuzag4>2`8 zEpAyBUwpsVNvBddRY24we{DtKU#Cl^oO%p}LIJ<)yKqsj|8izu&!WFSqgShyv<3;M z)k3S)l$7du^)H=_qP)2Vq9!7Sn&l24&Z$+YeA@%Cr3zH&5SuvO(?F^(iR6)97^)zE zJaYoDpfSdRkmGF;Fy?$moc#fa5HU?GeOQ8F>I4rflFu1{xOMgP6V90l|M7qWWg6E` vW-pzK^$iTg;)x!BZ+3)uK}0iS_IUFzbBjwI@+GT700000NkvXXu0mjf9S{_6 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/extrude16.png b/src/eu/engys/resources/images/extrude16.png new file mode 100644 index 0000000000000000000000000000000000000000..94dbad738e35d3dae8a3bb82a204f455744f51d9 GIT binary patch literal 874 zcmV-w1C{)VP)JT z0AZYw$x8qL010qNS#tmY0CoTX0CoXRdnO0~000McNliru-V6i^AQ4>AEH3~60{2No zK~y-)Ws^@#n{^n+KfkyC(x#3ubrc%k7jYTGtZU*p7^l(G7B4U_BxZC;eT&4zkhs$h z9!PfFNn-dD+LJ7f>VhmiEtt)d`(scBOVQS*zp#`#24$>ttZ&<&2Wi9Vb9v8e**|VxMnS6;nu(Fb&R4Qpo zwLe~5RE12&_4}18uQUt(qw61usIE6kczk9_ks^zkHno8|>{r=M7K)`OZ*$(Y( zZ#$oFY^+sVTYvm!aPY&w{LzvcX)Z(-ZeAhdFSFqX-b*?_}aDY^3KlD zN4IYu1+oD38SI%-Mu7f(<#WJB%rLsO(b0T394-J}dGltQRV;4axqP|sVr$C=bldNo zIWs>!J$)`_7&$sWX#OBp%;m`6yNBj-HDV$XiTogh$ZMK5HaR(&0*G~X^6CBi%q9}+s#+EAI-S1d zi3y79>+I(9ES*2!ZC7d)Kq#e%L?S1E5g|mYQfl(l+}zJ6!eLU!k1K%6rAwl)x!IC3 z&0brrwg6Dov_Lc(T@eSrad>$6H7sib;7B?x-n?)@{d)KAgi`7^TdfuYz~Oj(YHF%6 zmzM+%ytT8{>wQtP*^*kd+5=E17G3dpyxh$F7jAM_3Dq6hCjbBd07*qoM6N<$f`kX2 ATmS$7 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/eye16.png b/src/eu/engys/resources/images/eye16.png new file mode 100644 index 0000000000000000000000000000000000000000..973a4a0d3e1c583fe4aa63ef24770ee2cbeab419 GIT binary patch literal 493 zcmVPx#=TJ;kMe_Ch^!EJm^!p@R$R}ONDPGD%a?eP0(MosHOL);rcF;_D(@c2MOnK5y zd(%yL(NBBRPI=N#dD2jN(o}!cR)Ex3fz?@p)n<*^X^+}&lG|;O+HjQHa+Tb3mfUrh z-F27TcbVOGnA~}q-Flnde4XEbpWlO`;F7H4lC9&HvE`k$=El_V#nbT0*z?KP^2^xr z@ALcf_Wbho`#NsWJa5o{px=q97Qp|K<4q_x=Cn`TzO;|NsC0O$!NO00001bW%=J06^y0W&i*H z0b)x>L;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000McNliru-2)2>1ukCWB-{W1 z0CGu0K~xCWV_+Z=7%20ZnhGfELwNG+ntBe7cIF&%AfC9ap^uL?o3)p*f*1pXw5pG{ zi-s19kgKPUnk0jynUA|07c;9ckgG1iz#yt<}+qrBLy*9 jM~T&101=n#H)Hw~+>|6(9k+<9++d0Ro3G1jmNoI1lglCnMq9Uo?hp5!t$ieJaaY8c zXY+&Hlz+2yPM7SBdpzgy#|nmowMW0#-g;~1C@^FCgA%K&haWm@zPTi9^~V}JLBYK3 z(&sG8cFXR2FYG$;CuiUBWL>fDmc)*&VhvA=PG)Ugbo;Fk3nRnlpL0$>J(OTzkY+S< z#nx$Y>)Tfq+0FO7EF!4rDRkHw(w9S&&Ur+6S@5!*L%dpMF_vB|8!GjW? z|4-4+XK-6Qv1*>XMB56j$Y~Q*I2q>pwP$VZ>evvWV=>o{r~UB#T^4<&=ZmF!*`|86 zIxS>4@VD-`g%qDf4^|*3pc#zV(erF Ph9ZNftDnm{r-UW|!`G|= literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/favourites16.png b/src/eu/engys/resources/images/favourites16.png new file mode 100644 index 0000000000000000000000000000000000000000..ae8fdeda0d20115532c96297d9544ef4064f198d GIT binary patch literal 830 zcmV-E1Ht@>P)%Au~nC3 zvt2gVpX==G+|JD64=Cs`XYS10bH4MP^W9-1?KQtmLw8Fv3CkE4U_zN^jMvhe!}^3x zWA>$hvA)gEij`c}^a@BAsURUR_`D&XK)x}yox6oW1-PPy8CP;`0BM?(ya9cx1yVAo z`Im6C=^en?R@Kx^rWQrTaO+jCP(>v%=~wI^xk?*pv@c*RbZ-S)3>X11``HRK!HaIw zw!}m*ru%(v>c@&qt`RM2mx=9`Y2kunrhgLAV2EC&4a`_Q#VRPya}3ekKBoW>htMnl z#V(a%%@F7tgUjteQ604;sa1Ui(446PDz(yn{eoh16FO!GrVt7I*f}ovDh?pKz=Ooh zGe{b8tgjbY$B#i|_@MI=#MX>Hg>jCJP=LUfQF*6}+9Ww8v)f4qTZuHusxYk2jU(s$ z4J`F{6UZqnj*TK1j&~`fH^@QjrzZz8K5L0>>%BZOK$Qc;Dgp21$29yE0(K$t@jk_< zrckvG#gb|H=K>1r_RuUBiLQH70tkl&&$&ksE;ka@L4Ia?6S;dsy!;PZ-Ih z+@S%T6}c8S^!>S-x4G%;3+`5tj0GTel^_v`BBQEpU%2z+tTOuY%<$oxJ=3Y<_m|1} zx3y1sx`x%EUIgcsKkfDXy68MqjqvLe4~StiBLMu%OoH=eQ&m$+eI**Z`(~#8{nv%@ zhU(nXC)fNRREL%&jdcgZ|E+@D`c)^$b#jf|Z~a!}gMS1V07WMfXqlcD+yDRo07*qo IM6N<$f<%>mk^lez literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/favouritesAdd16.png b/src/eu/engys/resources/images/favouritesAdd16.png new file mode 100644 index 0000000000000000000000000000000000000000..883e4decc0d4d3ac2e6e2179c2763c6cf67caef1 GIT binary patch literal 611 zcmV-p0-XJcP)5zRc*| z45Z&?emr^0j-8hchX+0Gr<3(lPlaS->quaKI}8l}Cj(chJE6`CptWZn49}0BdQeXr zFb`*1K)`^f69)m<>nk^-ebz)Wr?Hv>S88lX3_Hxi(`qq_sZvfi>DKohPB z2YFOoe_cQPWMX{F_!bmz?KA5$1OEUg3nvSh9cy&j=rm~GZ7*pr0Y>NwunUSD6FCM- z9h57SD`0$@wprT@(7B{@34oE(NC`0DJKzgYR8v#~u=4oI;{Ym|N(K%Z5`}vw|2I61~^c3pa@`uDBzF4g3$$|A$!Zz6H`yX#+_1}6bI6q zyEVHtaL{0!<2Xm~bBu|Li36|0=dPT)0_9zbLB$~0XAMRTMuEQSLG6QDC=Uur3`qnS z3LXlE&c?pUeUstOoRi5Xli_OBnUXUlaC6$fPQ>QaUiDrzv{@c%JJbeUg-%zUuEO5N z`I`9}P)~AKx+|ghsfd3+W`Dr`0BB9!XR^-(+HQ+^+qnyE7v6%Unct}L65#jd`0|9; zp>Wus%AgP|_P9p7M!(`p*qlmlPj3g6tvXg63zAg)u=pWJQb|%t5=fGFk9QBm+lqKg z{!X0Xp5YGa)o!g*)8K&F zoT}9SSOv)&I#iWvxD&p#Ed42HZ$`&TTJZlAYOg~JqyXHM5Cts#^_UAl!>B{k(|bUB za{spnu0VJ8*!uv>JiaIeaMo5=0n9hP>m}z$w8h(g)@wF0$SGB|rUIwpSMxW;#)6btCI+Wo1nf0Cgn%*-(8;%V3 z)c_c7>OKMR=(6jN0Lm|)n*;PWgrlW^`3#^w`^Zdyq%vb;fQIYU9snlWO%(w9GY72z#%Fi}8b6~cn#s^=4%L0IJ_Pj3 zpeF=gSb%dlxRycYHh69hhW7AM2Mh}(Dd+}7$iTY;_SnI|DUf@D?`9ErVZE*cVY&|J zL0t#5G{bHmP)9;$EzG(j)|-ZP9nd{FpLWnMf$w}FJ{)W}!J0XcJyHfBNy~TWIuHsD z!H{JO@r%K@3GBU~+6#IUz*GV2qhQb!T7zMRFKF7K$6V~ccUM@e5^9bLtqu#_>V;vt zql)s;6(FA{CcKowdDn%00m7m*T?f7rI#>y-`h<6{3Dq9}$Yd}7-o%pwkQ)oVb>FX9 zC3|(?sC&A=pM_6ygeINB@)yE>PvOwTS0(;0<1aek6Y2l3JEi~t002ovPDHLkV1n_Y Bl79dI literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/file16.png b/src/eu/engys/resources/images/file16.png new file mode 100644 index 0000000000000000000000000000000000000000..95a418541b41de1f40b13489cd2845bd98136797 GIT binary patch literal 594 zcmV-Y0I>_fbWCSW4uoFAZM#Z?y%5wpH# zX1i0}4znZUv*4Sqs;RE|`s*4dguu$`>R+!?sTG_<_?5Mk|%L?8IQFXrN zvf@4~l}aL=$=Klr5}FG5Rkvbs4~GZ)3j4((3WZ&jPuVss%R*~B{xY4-E`~W8;b3HL z3#Oqf-}5*o2iue{kKlS9>Khu+*3#0O$>mH+zlb!Le)kNzrbvO49*$d4{?q1Wd`YKO z?sXy|sXxDwfuUCb)O5*30v1^9K3 z4?S@t?JW!^S~0c!3p;-fFgKF8odIzmR0u9HafIt!2+xP$4#ABuxTe8CatUuHmy|SP z3!5aWj*qDy(CKO?Qa{n3T)ta_h;c3-{#vz&26S^igGKr(BMm?r)M2cz1H-fHNDg*l zeEu7D3Wt~-PuX+ECF4P=+5x20;bLko{SPRLnSs4 zG>uS8NGi{{r4-OI#d%?*AAMJ!AWkg4ULS=q_W07er8uRb`>h0ANsvR)cL7zOD9vN` zeHp6ZPpp8rI0sJ)bZBdR^3z~fTM2xnT>qLLSzlxJT^X;=k0LS#Lq)x5s4vP1GQPs0 z+oim0Zy`*xQiXKVfk-esxqu%lRZKscbISJq$uCeQ=62d!NPFhqL!H`{T7urJLJ}Da z?i+GGw%J#yC$2~fK_<}XB;}LgaXYIugPx2=X>koQj-9g2zAD9J`xag<{sa%65#%Td zZ{$~O(H$z>`55EYd`!!;)TSVxM3s=h&8$g?25otTY_tAZH|Po^#&>F**i!)0Yx->k z4;Bo?tRtS}6|q@}18q(Grk?-O({cGI4BNu+?-b@&TtyN> z#4%B`%Z8WAps_s)UfuD&mJ_{VpbKd=U#hD{$gvPx%%c0l1foMkW3&IzjGH^Zb z;;BQG7@c=fWEq%Q$zpiy7mEWZ2?fy7{u*b`)G4eeU|=-vLinOn2A+>#xuYTN`v_Tj zzNp0^9oO5sl(@6+qrxPg_B;q*bjm;;9!Jp75i~bWrL}VeWqT_zI1)qoj%^AHnmR1Q zQ2cxi)N!b!w#neZ`Gc7IHihclWr%EFGq5;sb785_z|fGHNfPhZfN2z55{{?M4d{;! zp{gRHFp~|0Cw$SZ)nGaPqWjYnb~+Fc`)oo@RRw%rr^{F2S!)BHcfM5^FH-S@FS^{% z_S80a(dW4o&1Q+FQbd!hMB_=Ku>?_Undr-cOFz=2^1>6o=yDh7XL9`gm8%c?@rTbj z%(dlOsr^dGcd5g7!h*^RPxzuM?2D2E=WaHMb6fN~O(Z<}D?Pv=ZKDZkY-@0ru_$R;s X2%$`8?C&{f00000NkvXXu0mjf9V}YK literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/first_grey16.png b/src/eu/engys/resources/images/first_grey16.png new file mode 100644 index 0000000000000000000000000000000000000000..1319cbb24daedc9388c69c33595afa3a952d8cb2 GIT binary patch literal 609 zcmV-n0-pVeP)H{lq2OZiPeQKCi@ZdX`b~%LobS7T&N;#e3WdT!W6WhB z4;%)>d;d{HHjFXL^?H3PT`z+m3`5iDbSl72zynW#P7)sl^4|MBB61g~s%r1IK_Y$t z1i(_i-@n~#Hov4#DwRt6yWQ?QPyyC~i>lho0A#b-5V$TPbE>-3ZnwXWKCRVi{fy)I zSuU4*11tdJaU4GpYwaQ6y@)KT>J4^*AP5$KDsak($Tbn!F~-~(6gcPB(gNq)M4HQF zGK;`AP#y!Ofc1L4zLU~SC&GQeJWz?EXzw6dtJQu4LGTDTXMhPH9=)b>ZYJTwv^a%# zz@!1jfFAz|5$OTO09(M3(Sj(7R)LeiE$7@HUGd&e0-p@<5||FdFq6u!B_`jZD5?S{ zoO7$Gp_AmFUWm2!jEKAjuBz(&UAA!!SOM~q5G&sM8Dq@ZMx*ieUt(+RaS?e1Y^v(4 zN%~p_K6vjpf*>gVOrlRs!vVHCxG_sfe(TWZ^+ zQVGfXUfyeIt)P{Mh+C^T3Qjuc=p+Sk5Cy@((M4$ou}-dn6goNh2SHGfh~QMLQq$sK zYbX`cXqxXj)Rfr9*)tx_Irn_`<4PEYzSP|~34Q`KpeCO8Zed|zg}-4!-=8p==tM{X zX{WO2(P$jR$V2px%rV=O?K#J8IKhN!^gbW}DsILIY_y1~n?^5{N~L<606vu$9{?}5 zD?!c3R&8+Z8_?-FeKL~EW!nXW)=mQ_9J&f9+X0T*>Sn#D=p4ozt|z=_J3~Tirv;gG z=(1^e#~peR*x=B>Kvx{cNq{(xlSMz6jclNiwQqq0KSMfqqjECjEId_QdWwEv4lJ2JBNcDAqYS7mMO3&2P&m))Dm%ye~k zzg%BmZ~b;mbAc`9yC7FxgL};Z^5k)a?s=9D+;crS)Ar*6rE@sH*5 z=hkL%949L)-ya#_49?ACj1M|x6w&}<7z3&a)rp;EfKsVc&+N;d1$~7v!$1d+Hmcgu zqU%&iO#W-*Ypbg#oztV+gi6ZWghda%1zYDVLT$KE$jvV;ecjnV?cw`oRY7>2F7;x;OuaX?Gl^e5`8?clevzHySmL9j69JQJqqKYHJqaVbi z9nP#D$*CdCtRvL1Al0)V*t8(nw;M*rGE|J*_U+)Dr6RsY{y;mmFS;Yt<8 z%Sl8*R2b7^V89BR8wv|5YT(?K#y~k)8ReqNVhF#fzFMD;gPYAIKQj(2P*)Wq%q%a+ zq?DKz1>)D1<(V?GJ1a5^c%(-800qiRk`$OEVhov>bW)?dfC8m?p8QN&Ij+3S5@FHq zK!L1WJtkJi>_};5R{IDypg?-K6q9&pN~$&!vucnXP$0&Jl}RHdA;W>4MaanvWQ__F zi&aK^a;O+HqbArLB0Qpgv2pRS>Rg4gUbq(tw1lgoXx`HVs0gK|-QT;Nk*gBnKlTn_z-{ zmhYU)-7d3t&KJ-ik94}dotgJ$-pr9P27{QufTqgxGmAP3uNoaE7bGM|sxpx{$6x!S zseeO+ZJ)Bq=VzY*TTvP$C03r?ILjc0=nnu+A|W7D<`Wa0NdS!2oVvxShDKmPGuu1Z{X#D3g|-0BZ&qN9*G%zO46N zD4sVu^%@Qrc`Ds1baRPAMG7LbeA>HftOGIA&>{S+y14WB!(!4xyYUUh=}X*79hA*; zs@NUjK4So91b$-;-y6->tMfCSvO&Q{3%OG#fnJLTF^s=9aIa;Dv9bIfwI98O6QfM# z&RzC+V0j(IuuEljHs;@Ei!vnIlXu^Ym7iYmY~+PRvHvr>_inmd1OCpx1sDLU%fF)P S!b7P50000 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/folder_add16.png b/src/eu/engys/resources/images/folder_add16.png new file mode 100644 index 0000000000000000000000000000000000000000..83761c296f342bf0fcfbc22f12f2421833d6ce0a GIT binary patch literal 772 zcmV+f1N;1mP)wAQ5gRIIcIj=)oi^5 zrD-Zz5^5x3y>_vnAVL!CA%dXnAu2JDAP9OYBYG&YUWDkuvdcrzgY;@4qPV6=Vv{bV znPPd_HTN>7|IBzJ3i_FUX3l@U|Nc>b%Yh$uJQ`4T0$RurAR)gJ8Hf4g)h4V6IgbQU z*NRzc=d!w1AQpE)LZJ8lsca51K(yw&8iNxU(wrhgZgK)B+h*q_M2DN86v51{#-6$- zfI+KS-IsDd(nPTNbe1qh1y|B79gqt1g^%wA;*)Py!MXzCK;-;upbew&3STP>g=VA0 zc>(T6BNGuWi`yl!)-rz#Vc>K3N6dsK_^6x!M74~SDBA4pyAk}*7W-IE)8Lop(QgBYKRwMpJL z<|f9FnzIv#Sg@x%bPgvMi6jW^D12xgc#8HJbre5hW9^vu)iEQv#$XuY40!;nZ>pv@Edwf^WP@n&)>@6B~VI$ zb)%z5)|!UrBi$&?2g1DV(u^jABfzd)hTFI(ZAEjumek^?e;*!I1xwC#jJON_tJp^mq1_tC$=pn!bF`895AYd_Gk8H90RIwR9{kFK{PVAK ztMA}$ayqIt9W-^cb9)2o3I8uVHe{_kPqBu63ornQFypdoHl1n!0000 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/folder_delete16.png b/src/eu/engys/resources/images/folder_delete16.png new file mode 100644 index 0000000000000000000000000000000000000000..bb56a9e6f9b274f40000c2b79208c7343c61c651 GIT binary patch literal 767 zcmV>wa6MEbuIXhZn!v0Gs} z6iwDtdYO+CnciYpOqYxtW!{7#FhBGaze3A=RJs6B8^=nVIAo4--}*8IunoiQ6p;F< z3~EAfa0&%p6TWLq$fg;YVgP2cA@g@aTHgSAQgO^Nz9ta zuRv0qM0Cpu!!PkT6=^!@P^S~lz!;S)yORPHRwFt-h3{*L9?A2@ z#_|F@6{mo$AnervouqLZrsga1CFZ+F5$>OX<0AAUub~9Do{YTG6k_2;l$}1$THL3!g}I4o3^$#7D4a3H!Vw%eb{KFcKm}g5qO5rU zPZ5^-rcmuGhx#3X{WAo$9)a&@8I+;!N?Xwe!}J86KZ7GGl~a$_08Cbgn`ty&1)6W< zbp7cK)R#$pu6xi{Q=hWZY4wk6Z3R0TPsRQ5;&=5`9w;ltJ+`$z$i<3Wia}0vHw9|% z49sR{wBNE@E_&Y1uEnoc6*xUqP+Vkg!$LS=^=c_|kQWXFI literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/freeSurface16.png b/src/eu/engys/resources/images/freeSurface16.png new file mode 100644 index 0000000000000000000000000000000000000000..7215c4539b0ca7818fd6412321b1c617d5047e2f GIT binary patch literal 1166 zcmZXTNoZ416o$`zncBuSG2o^xbfJp~)nbX_j7mZh)KF9$a3Bg@bt6tt92P+>x=>L! zf)%X`U1=8*3!-2}O{Ih;Di*C3q*bv(oo$Af=l{RHLaHZx@BH_F_ub*#n^P^ZaCKE} zm55YFBf$;GUQ*%2v*Cxa8_Bt6Z8#_fe^>9{xB#beZ)Dqk5#L#&HXlyEfay9AT_17{ zyB*#}|DAP*CPeIY(ctP$i)SjYeY_xZBmFDUZCb#KgN@TnG~jIqZRNg#k%jRFoB=i9 zB$x*@@Dv=ebOL!PVDOuRAjbi&LF@wMp<4}Gxe09mRqk`G}U9Wlq?JpzQ(&@A+^_CuLMd@W*c{NkEp)?CotDhoe_KJVzum@x+f zjTe0C!9=~*spMW}Cv0BjehD=d(Z)fVMLmza1KfuH8@?NQE4U0MiymsqaRA=$$KVfO z(YR;AqOnH2Tr4EF$68JKdFVVld;|;@u+mhMkCdfZJo@a*cnLTW>sP5^dE8qU7_-bF p1BCpEP)G!OK;l*0DwO`c4Eg# zoTPbo?Lz2dQoE^Wh; zo95*vZXS-E#Euhlnl$*%pT65C@IPvo!TpwLY#M|1yN(;$BBZd8jFFP%kFvV@ML8Fp zy>JD~G_^z~<5UNMIvn*!|2#V3>Ddu8876+1w&@{-B%;EIdv9*>+KpBFYEg>=2rnu} z&2jMcgNL|7hnu&qQ>>JDe%|Krc)-#ACAuasvYM2a3Vitf-REnC_=;$BP5rnzy8G>e zhg8ppa(Q-mZ1Q4V2GZA49Ds-&q8;k)mDfAvYN_kq+h2Jdx7&L@YBA(k&< zc?!S%QAdzGg3z2sy^5BSvAhw^OhS^=?46!cs#;%4qlusV@uxr6>}iM~tgw6hl*Lk> zKybNe*AOFN5{UxtRKT)(=;=ItXHLzSAnB>JVD|dV=1Izx72JN8cE69RhLP1Y@kEkp zP_l6hn)OwYU^ zs)|Il1QX9knh{XCvdCe}N70h>9E-{68G;~V+b#>KENUdm)b%MYX0V(AGr`9hS%|qz z(hJR|R7#65lL$vs6s}w)o6D2SB*|xWc6J_<%jIYp7P`Jn=d8iC$}-|wA^zFMwK8Hb zA`z8o)an?`7U$I}wMK)}TAfHNfubtdgD%}plR`?SvZ!B*hG7(6-&+4cnD&T;1u9F+ zlnO;6kqE2nYe>;3`K2We4)?jSxr#gNkc~})t@Xk;VqB5N3k&+E_ujgVXAkJLJJ^;* z(`YevT~5xb2y%pw9HM6$#1xTt-rhdCzLNb|(vq1z@N>04TG3JKNj1&gBL{Fc)4v>ZsGZ^~<9c!hHPruf1K`)(`}NWK`w$%}wsS zvEfG~X=5d;9{*>ImpSi@@6QF_?0d*sOwoK__%)jhbu*$cYjw?BF`a1x{0k12VzM%g R2}u9|002ovPDHLkV1n$@smTBU literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/homeFolder16.png b/src/eu/engys/resources/images/homeFolder16.png new file mode 100644 index 0000000000000000000000000000000000000000..2cd28412b415b4491c3a15106b647feba5f572b6 GIT binary patch literal 887 zcmV--1Bm>IP)^ETwEew!5>tv%51pGoINkjSqU}-g!7T=XcKi-*ePp-?Qh!hTju~0kJ8= zM45U>DdS$eX)0wKqA95(Aq*<32~dv<2W`9 zqLV=wz9OJdw=$df+2cZ1SWCCjeW^7gS1-}%C(3F8D8GHY**&?MVo^l zyr`RHc~eB*Y@D9P)G4Veg<%NRPV(XYk9ndyMP^9{#S&b&I8Og}L+seOvA*u^MG_GM z!YYQNq-*%@YLt8}iiee z+SDX`&6h|qP{9m<_%ho4H@yZU5zx6Ey!NO~BqmTDK?d9sg zAjxEsa?xQjd!3KIdYAm=Gfd1@zt{5KIFsX~R&J1+OcT!iLhO?zVnWvH5p88TT9Ou|`hN`^j(pMtp_R%?Z-?u7&!DsP9T6l_*p__MhI(H{<(Qz4AVyz@=K6 zA(2RNY`BNla!2w{9nCswu=X6wo-qeJ}IgO@~#1kO_!wJLl`yqVX%%Ra(uAWBJy2MT(-nt z;)OK|w^Gr%>(JRP@AP(bd44vCn>>=%EIJi8*X{gtbt=vDw2Lpg?maf&`=X5&;D~Kg zskrE&FSq}(>A=r_&A0h23))xAa^cEimS*hM@Z36W&X?l+@Ep}j4JCkuC_{zZrae}j zdY|OYGjEu8J$h8SP5*oPnv52tp>hLnEB@cove(Ve@PAp1z4ng)0|55|Noj(bCItWh N002ovPDHLkV1oM`ug(Af literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/igs24.png b/src/eu/engys/resources/images/igs24.png new file mode 100644 index 0000000000000000000000000000000000000000..10e4c45a7a6a63f6b7dc4e302aacca6633753c22 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE)4%caKYZ?lYt_f1s;*b z3=De8Ak0{?)V>TT$X?><>&kwQLzs(8`|OVo!9XF|%#er@=ltB<)VvZPmw~~#C^fMp zHASI3vm`^o-P1Q9MK6^dD1OM(#WBR=_}j~dSx$~3tq=Ki7v&w!m=(@ZHtn0|TFn?o z5A~ZJ35lvN(wJU4^+YyIE4z5k!m&R+GnHm1ENiRQNnRvsr5Ycd(rf{uGBEm9V#XAndQI lEY)WBWY_U8j>4VNAK1UjSj=1`6)Oz#rl+f)%Q~loCIG}ggj@gs literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/import16.png b/src/eu/engys/resources/images/import16.png new file mode 100644 index 0000000000000000000000000000000000000000..691f6e0c7c86f88608e3a712044d0bf2b15d854a GIT binary patch literal 381 zcmV-@0fPRCP)EKoEw%ZLQCtk5Hm0 z@!kq57WxpPS1&$7QF_<6Q1GA+(1K`g9))_*g9kC-!K7rz*)&S9Zj^fPhhhHA%>Mkd zVU37ThA}43n|)5l8QYFG>YSbL({cRkd|oKW2U>^7Sgn?c~51DT;)X%j_2UZC8I$c`LE}~tl;rOoBTyJXCZ{9-C?s2oS z42uhs+UOpxuHo{4C7q9c5^yP4SCOzVI~>4;9#$It`Y}0?jU&W`k*wmQKA*3yEVO{RMa2{p7NDv#i%G;2jK+TQB{G8R zy2oY#8k$>mdF2WKJkLV`bY^=Hz!(ES->Y8COn|CVzA!{_Q2{xA8&MDNK>wW_zfEyb z0p*KAs4Dg>ea7&#=Q*LW5c7gT^7HdhRa6xbK@gIuF&rn#(EIm@kt~1+s=~K#KX9BF ze!rhNIXMJ!^B5Z+V|*fwJ2`>ty3^2E68`Et^wNX!~V03rUvK=H{m#&s9JmmcWRPA?i_-_xl~k?bE~=Kt{rxIxqbK&iF6lWP0!sj zLBijg*s^jDov*Lamn!5$^&OJGGA6$0drcref4eO}G(E)gPaU&1&eJx;2jL&rs9v>? zlZ_4Zza1v+PLNKgr%kj)Af_+z7yey_Oqy~t*|MNL+(3C?ZDy1rnML~ZQoCwNHK(t% zV+0JKQ<=irnhfjX2z>5eL(Q@}Y|AE@N)k`RiN#}l`Y>E4S%0N;XYGN_k&5~o`**|8 zI~aUc$u(v^Re+QC2dv>+ zS85PT*?2b-#mvedY;HLS_$7`VEJS_vUX=JG9u7`nHNK^aZ~?&ubn4vQehQ!F6L>bh zgt^rux?8HS^tc{2srbE?MBl`+!kNc>Pr1%BcU-K**snOggySgm>quuD2$7x6XG!ca zrTWjfX$mm^i4*FjP^WMl=X&{p0KP6Hh-koP=*sTBp2x{MAK^E3Smg6BK-{Dx3nX)I(&_xHP}RoAokKf{z-79-zqTri*W7#Fn_5wN^~FL{ z!wD1>S=gpe*i;=rb8T?v%C-;8s$_$TBobSA^L85R&o3XLixk!g4`&wNca4t8o=XkK zQA|Zf=Ms1|9aEQxnxoin&=>+6lsr221I*_aR|Kt0000N4Khe``7bj>dihdQ~~iYDOXV8uaPOS`z~ z*sYr&L0r2kA`Z66yADN+FEuvmfj3<4x#!$_-+S;!7}20$Su#vf-S>@wiD3kE&PWnD z=W)8~k|>%e@D|`4Z(g!k{a(b(c{F+}C*> zKP)+Pg8+&6C;^cSx1BTE9f$pm3Zt1_;XK6%I`)c{_y`7Y_f(@B@TCJ02o*5aw|Na7 z(=SoSQPYig(0ieAamBjQ+?9ek8>S{-IXgF?Pvz*$##>=M`dqsx6miOQGx6i{X@?nXbp;|MflSW8Kr(yE6)xM?= zy9e9-x};Vv@4g>=I=#H6Y#8IH+tbwP#uRmK=_2Y<^QudYR+|LhCrBh{>sA+Lp5SkE zgUN{!crK`)ci2c`;{^zmO95sp<9IezfjM@oeFcGB9NRC^Vb?5ME=3X}Jl-Ia?SI;v zo#F=sEErM}@VJPJZAu`=BRwLywcvA8FwE#l6=EY~A_Ab{sUS5YALSQxbkS_uWUuthB*0yUylZEEAfpunI-o2J0Dk-!kXekWs*>?&>Z9?S zC%Vg7BKqeXy&djo>wQUs(FIytr-~)M#3e6WxqwnAe$~PM5+1yC1e$4Jayf%U+Covk z&ab0&rwKcgL)SnAyt`v#y~jsIKowvkXNMnhaZ)kxW+{Wb0|dPq0v-iHLq(4LiKQ%3 zoEJ{`QhU<##r78X{08EyS&YX%;qK#6Yzuf0Fm+U!8iwD+5sghFzLtkCU_f}Oa|JBh zzHstj6J`WK2-a?|LCdastbAU?{c{H@1iZQeDi_cc`?nExyDhFP!idZ=oo{ zw(ro@!Rvak_LM^~WS;`4JTPlL@gjDw>khl~Y{~x#lx89)Sv=y+#jgR0t=krXzXA*Z Xss2t~lt3m600000NkvXXu0mjf1y)f- literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/last_grey16.png b/src/eu/engys/resources/images/last_grey16.png new file mode 100644 index 0000000000000000000000000000000000000000..9f5a7490c5e405b2dc2b532e2a9f9c59f772ae80 GIT binary patch literal 616 zcmV-u0+;=XP)rxI_Q|0rg2l zK~y-)m6I`OQ&AL#zjGs^gT*m!YKw}-NnBk*U23T)c`uX*B7#KjZo$fH1|96s6CFT4b$l z4)RPUGY@P4Wdn=@E45l}b3ky;T>xTh?VPoCe*#Yo>eXuXC-4L~Z-7xC9=@h?ZXXaO zMw5T(HTDt|z0jHdE%fof={TT4Y0Iz|GD2g&E@iK7I zIahJc{YceET`Ca)w2g0mv>7Pzje4|h1mX%fKh^{c0G7#ea#5#p0BRtN~wvYulD72!ewmvItxRTEOFEnfkzS;1X~K zcnVxm)s1ZiDWh=_DSPkpA~KS|-+`CF166IN`M&|S!?L(~zWJ*F0000X{unMOrd z6Gfy3PLY*E)8C5e1b;A@sMrwUo z!We@?Vgs^6IxI;{tjm9_g9mrSci>+#IW-sS9UALXoQ_&alClBp%r8Hs@M3ffKNeG1 z<#8jlr4+l0a&WdQfy?z_)J96_D?Y9#s^5;>-Ml7oZr%Msm zBe)9xnTZ1SMR^Z`-9#HjgD^8&~E>dn48E)rF=dz^umZ!~o z9v`0oACE?*D=s3mw+m~FOJUN4_+uCbHU@XE08HOHKxL}H{t0XdAA#}hJw7IrXl!YN zmo~&tHV`n4n3Q5kEf8BI#w&37?zdG1OxN&L(Ekn3h%~MOwFX> zb@M89xMa3cfnl=#jAq2Dk2hg}lG6`T)q?)M9KCt$mxKPbi5ABxY_j{DeaXg{WY}Tn&G*eW@4cO6oO4*l7!&X0gVP~yRPJ*_KgqdK$7C?M>nW2R zmxeDq&RDrdU9-U3nbC7FtFwcV2>Om+r=%({@GWRBC$YA&0!T{y@cH?NZ30WPXOGh2 z)ljq_uILpaIzeJJ0ZFksptO7gpFaEmXY5!kKKI&!6g1473WNi2dfec;25yw8vsr_f zM30lOUIfBUWK-)?ls)*LfXsNTXCMHhQi5Dur-s}*XkCB_F@uiOGq4@GbT($!Np|3L zyGg|Z=J0}*GI+j}0;_7mMO^wSFpDF&tpZj354fz-ZF{kh{D~706^VBR;a0qm)C6X6 zEUs;hBj^TS{k{2Zzi&qf9v_KGUW^>7eFY9iIUQ1$55K-=1h;JmPhR9EHoqjHmvsdF zewdOQCaXKeLH{m+SsaUN*EP?9diCOg(aUG{-P;)*@i?~a`S%qh8HSd|#`|Z*yK}2! zH>a29scx%nkjOmbk;yxck`gb|#!ZozWd$G88fI>d4--z)grZ&7GzY?pkl_li@b}gVeG8lQ!5-8Au|etZV??= zT?f*cEQ$_1W&789HO3gmHW3I&7%EjEotplP!^u6E`0(9Rw%Nxq#xORJ+7leN@}>0G zKCmTjA{L8#Z$5Lh!zYL53sVQb*K7~l)WPKIR|EOgJTXPGUMy)ij?UeQqnFI7{k~gPc&?zNtztIdw&}KW(uJ| zp+%Tqu<&5`<}q^3k=j9CZ3e#Z2hOx7IG s`^o>ce)#_*U^(7!pQ^tEdH)0$0Qy++7FlQeod5s;07*qoM6N<$f=v4=(*OVf literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/lightning.png b/src/eu/engys/resources/images/lightning.png new file mode 100644 index 0000000000000000000000000000000000000000..c933224385c1f9cb514b70790eccee6e223f4646 GIT binary patch literal 683 zcmV;c0#yBpP)q*k#mBL_ujk;APze5wU&<8^~6g)wCp;E@N!7 zZEddYtewBF?<^NObNWYYhYKIe4P5^oVM5sdC zH-MkhaqQk~c2C_p;5LRxc%eAdKjU2_z|P-pacqFDCBX@nVsHK79yppPC{z%dW0gb1 z(~r4mc4%w415rf1*qFx`o6Y1X0>tBo*Bdf*u&Um!AsxO=Eb~d2|w7iVS>mdwJ&R=BY+iW>i@jECs z1ThMflY-oWB=pedJ5NS&6(%VCH_qNvcss4kPY=j|+pLHb#EQmK3alB?7Wa zyG%SV7w~`Ie&%BU;z1t_xB=B RLMZ?M002ovPDHLkV1gn=pQ5k2669Fs@}&zywLNv* z-vm>c`(G1@_`cZTgS3f3RTXf~@p17Jayj$c)zo0;KMBSsCZ`jzSgO6F1IAke8-+rc z+Y^mKPwH4(T}3XR&x~9f9;)FKG=yzCDMiyTGn<8(&reOHZ$A#!M@Fv?lr4KW7CS`U z2s#?-N0Ax{HZ1|ylTf0Oz&B}WKKRDdcWy0z-w1O|+13bYCir1V;4FfljvD-~G^AGQ zIa_NYsB4f*cNt8SdLTG_CP6@>Q4ZvyDjp=C(^P=TDm*#z>d5GqvrQV5x#;P=G6|^L zE4C2{q^h+Z74f}b0yq|4-y1tq!_^5K$Ah)L2=mzu!YX8+jHP8a%VWLzXh9IP z#i@gLvtdPruJFM5_A0rc4rbtyLwZ{m9IwR@1lh@mK<_&hI$*xflK8c24jentPa=_! zrFAq&@Q0vS_Kg?M-{@5gfh5!(Xz-{O7Use`5xg1Og|X!#Q6f&mPW)dK311rE-JM;(+3ePh$-xhX+5NtGZ{ECbhFO*c5sWdo@!;W;S-?uta5AFCo=OrMxjcMv zOJsI%{}RmHz4x`dI~qE9qKg(W`28{rT}OVUhP0w~kj)ek& z08*(}D3!~0KG?Y*v3?cdqhS<^g*2rOx|k+{dR&Q?IS@$vKfYYG0W};SFLGJk&VP$Hc53An|yB0YtL)SS>!$AL~$Ivy7 z76QYhjViy;GjI+*S;1=VE$+W;wDC@2AEIg;T&n@KGIVaWA>hQye`7hDAp$>kcPKa# zbdF8uUe2b;o;qU3&(mgY6zB%AYFp@y4U$hXK9hpZy^R_t4|>!y;D$yD*6C)V4S|rQ zlY$S6_Kq@L;o%Dh9CA(y7GP3`)L%>IcK*eC)xi)*g8M+lqgq-@+iet&u5KXPa*?PIrD+fTFDit~iH|=53;+eM V4xMmEo$TNFAse0ew=gf_s(}X5JI3fX0{;+_(vFTYXv5^AkxqK28eeh;EO<9XLrP590rI} zu9E;GG8=^m2R3n^Uxlv00P%1jWYpS;D5NqMRSIPtcJDAS*k=}UZ@^_1&=`uRYv}D{ zVMM}1zHf3X;^+#(XU@Q5)mmCmEq+TMrT}H}4nfAu##5aJ$?E(_l=K2Bl1zCWSlk;B zT?tT>QH0I`XMYby-MpiS+RyJSi#70$>Txz5yWmHi|M+-$(sI&^9BJbDB2e^%cqRYSqRJWbTpaY2R8l)aJhA{ y80=MUrJpRcUS&n8Ix@D7Tf9&*0?J85 zK~y-)b&^YLRCN@_f9HSaQA?+{Oh^j1(?VlGg%Bf#M+kvLK@x-@X-GGs(FI##TQ%+s z5XFc?SnvoBby0{-1(ep1Hkh<6hLR52LX&R0NlBI8#CEcRqAUUs_YQKfDcg* z@Ia?mFyN!g4pCp{psM&bd^vIF=09H(iO<8SahMYhQ&CZlsy>q;A_zim>?wnTLv$w+ zh!G?<)TFbFLr*Vs#=2-)dI-NiNFWfPEEr_g3*~qUg~C(vg(B{F0oQeL$6ZnbY0UlM zcH*f6)Hy}gFJHou_}ln=7M5k`Pxf)}$~&~4tHv0EWf?5X!m=!kF$jV=)ee6p;qKpu zSWr`9+v;^3_~lL1^LUcW(v!Kt=UeyCa=s2#k8CzaDwXEmz55Ig4R#8!bi-bLUcG|q zy1B5>Zlt>}&*^KOh`^dfupkUeB2hm5v6+uo-5?yEO+!OHr`tQuPR989yN7FkT~z-V zyP`m48CVLGpyWcS2r>>UUOGl=$4;V+N&3@ilBxdxVtiig|A$8dk12T`06yTA^}A_% zv7wL16bWrJCCrbq>xZ4}e(QIN#Ue%o5y8B%mp@jmaF8JJZZpn|mfm#=zu%bPYCXnL2o0p2WjES8x5sj%6pXD{TfIrMcAIN^dU4 z{%vUrg(4%_5i;2fqnS}2B>s%b_YY9U!5(Yj=!KIvH`N@>RD>$m0%eL$Ge$%J^0{p0 z+O632wo~68zbYH|O^g`BnaiK>K2QzVFx}uO@PJWZ0C@5*51ladUR(r600000NkvXX Hu0mjfhof}@ literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/monitor16.png b/src/eu/engys/resources/images/monitor16.png new file mode 100644 index 0000000000000000000000000000000000000000..e4ba988ed349f2e149979dfc7fbbfffecafa056d GIT binary patch literal 850 zcmV-Y1FigtP)k=vm;Mg8Ssk5Y~gtQC@>Mp4>@qm;61Cx)Dxeg`PG~F9d-MQ><4=KoC-B z0v`*SjiaM(F#y15fDqk)&v5~G+|h>R9b;B_3R2JS!Zdv^mO3Eao0!iHGyW# z6C)F0C>erpT1ayX9t^k+$t8n5YT(ft*Cue@L;F?|!pP**6e&;v5s*BZwRQ0Us@7&p zrg}vO%ax57Z#f5pS{?j(AKSCjCF1u(+Th9(35}qTaTN9?pWx7*Iw{-CdN>>h7MNsOxz!X(x({vsj@{ zy?s}Z%jTecDmq21Bvw#anFQk;1;;@uorZD#`n^<3(~d>E=$?{N*0k+!Lt{e&#gyam z@MFXYq_{*P9z&$L8Lh3Yh(sb-Tw21nnVCT3zQ3gt#&PS$z==#IJ3KNn(ikc$LoSn{ z_=OPJdmL7IMgHy3oz%k9XZ7*r7;M`{GMP+FO--I=8xCtTRoVY%n$iQ>LC|^ndr_V- c{ab(m0F}XVLf~s zwIs_&TA4F?AANUbt{E<>1BdUsmvjE#|D69hQfq5#kD@3=ny!Q4|6mr21zDD-D=I2h z$%>*DRa91@82PG-q-p5F!zM|;L6_WR*~W$QEza;=gkyw1$xb4@yPv@~ugG$_!hr#Q zfUGQ!kxd}r$L)5b3GlSE)bJSwFi;KLm`o1~PrI;r>jcz4oxzl^SdPLAwoq{LIs_~;}ak6SR9kG`#&48SVf;Y`L= zb(+qb$Ef`pU|pPxrd_=hY}~|+w_`N*jPkJE4~mL@cK6Z}3|XMCPQo4sDFv|aK@z1W zJF&%R>~DX}o#9#P3!R)OT*;bPL0vNX7G+?{-+NrgD&YLXW7sDf2vzQ-y4;6fjc4Z6 zHb(pdWVkXBvZIOyo9afIC_oj0LVpXIGL5U@90$%^gLv5A}6(ynkqfTvs~gu!C;rq=POxUAVVM>^uKJQ p)oT52f@cYL^8coaKJ@+)U;v(21ii69<$3@B002ovPDHLkV1icVU>5)Y literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/network-cloud16.png b/src/eu/engys/resources/images/network-cloud16.png new file mode 100644 index 0000000000000000000000000000000000000000..51fce7eb420bd8250682280ffdc7e6008452705f GIT binary patch literal 1417 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHnQV@oqrOGgt&b5kcnLsvsbM*~w=6H_-M zQ)6c{b5k>zUYGpj(%jU%5}4i;gkDpedO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPre z(>$o&6x?nx#;I2y=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6T4w#{ISdSpe?46s zLn>}93G(#_2^9JFt~P((<1fs?Lb_6iN@p+n<`}@@)E)JG^O{tVs53u$W=<)~bz+a= zd8)Q>W0~h=rxmT-s;dK6_NoR=G|RHAf4{fd|GDjlsgHzD7Vn%>eBSo??(cKnbGUev zZ?kw%^-3#~S5wvJ@`>kfxUX-JJ(<$|xAma;m-RL}Jwnaj^0^lne^&8Xb5-?14N4|5{PUJ?j98f*ze#kZ^Y4e#h4VXgXGR5o^800@p4HQP-jSp6 z=~F8YhTdJma~PWv8J@m;zafe3T&WEAwz<-NT-Lw8Ouw|nUD)x5w~~iYjz=Pk*~I(& zXQMW&T}#Mf<4`>Nev{Vn%>8h-bA`mt zt2QCA+^h3)PR|q!6u-}vE^m2j&y(*5CcS&y9PXy)&UDA?w&MCDZ`W6{t=m5RLfuE7 z2eV~sI)86oKG8tb{Ofyzd#}%SB?#I3O?6(L)}X~)u~O^av-#}%?&`Kk_T4q3_uqg075M${ zKLd!53>X<17?^KvUo3)-|Fmbp#5JRPL+kZmf@SWHH73#MxLpA_}SwI|+%^JkhbMQa&;^aV4_k2Z}=WZ261pwT-LW)KUqb2wO-fzAaQ0E9sE z8U8}WL0p!T=(yWviM9MZW z`~mWR_6IZk{`)T&#RV|H&ddaKKEwbJ_{a30;nBzM4E@0dUWBO zfRw%c_KV@o*I#foMpFC`32X*{yuiqS3H~!c0u>uT^8!RWE<*?!z{So2iAG$mAY{O? zhwp%~07(ZJ27uB95C>^VVj2Kb&jd}jSPeiT88Hli>Hx<*kYxPNh{b^aa4#?-*#I_x zg$W`Ms42-n41lSJ8^HSe%R$wq?e?IQ_8(_>Ly|a1Ge|vL43rOmPErQ41sI42AAtJq df*1e+1^{LjuSj(qlb8Si002ovPDHLkV1jM_%ntwn literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/next16.png b/src/eu/engys/resources/images/next16.png new file mode 100644 index 0000000000000000000000000000000000000000..184be23125a64eb0a80617582aa9e45c6f0e8c58 GIT binary patch literal 742 zcmVA-TnxX&OtGGJ9Wl9&at> z64AfGk*-8jW5*!%ji%`L0eUi4SZHM6v>KBKEQj>>WiQCI2u7w!vB_@dJWeh^$fvA-VU>18;| zfD;BK*&2BtFFTCx*GhLOySwhGvGONLMk=jWfx{L#JjFwu~?wkz~_uRx5khd9>ep_ zQ}9EA1QVX{MYpmC*>wNV`){a;^4cvEmdOU(IJj>co;;1C|MqG4zMMDdgu)ZP=!z-o z8gC5H$Dd0yohO>e5GDEMrE)}{e)%++CHk6Kf%JtZe9;vz()Y~7o2zXPM=?8>M|HWZ zlcVt+-N14ARN>it8@Voh;R#=KrSGC*&)N1?aqf9FMalVq=Hv}9E*8hQsV!CXoP--)f>Q|(JO5%k>T%?Ey1sBC)Vm_CvTth1QrpNdHzyEuG-uHx|s8lKklu|Q5 z2{;6ZG3KL)tSP0Io6Y7%o-f-;5Ckes(>dT8V1Oq;n&p!~$r!UoL~a8Ot#$v8KvsMg z@PNg^U~r?=YJJUjs?}=ydcEEiU=DZ)oYPwOEr4RN7yy?=e zd1~AC8(W)iN{x;U>bbi^kJqeT)Fb*W6I)!1l z7YKmF_xn082Ul<=w_l)AW4yJL{6|^`0@Ntdu$x zMbX>8d3Rm+sEE7-*0t8tD%)!v_+X4#^E|J*TXD5oofeUG;0thR$1%CCyI(|>fiplG zc#s{_05}4i1x^BwfQwq|%^d4gUbq(tw1lgoXx`HVs0gK|-QT;Nk*gBnKlTn_z-{ zmhYU)-7d3t&KJ-ik94}dotgJ$-pr9P27{QufTqgxGmAP3uNoaE7bGM|sxpx{$6x!S zseeO+ZJ)Bq=VzY*TTvP$C03r?ILjc0=nnu+A|W7D<`Wa0NdS!2oVvxShDKmPGuu1Z{X#D3g|-0BZ&qN9*G%zO46N zD4sVu^%@Qrc`Ds1baRPAMG7LbeA>HftOGIA&>{S+y14WB!(!4xyYUUh=}X*79hA*; zs@NUjK4So91b$-;-y6->tMfCSvO&Q{3%OG#fnJLTF^s=9aIa;Dv9bIfwI98O6QfM# z&RzC+V0j(IuuEljHs;@Ei!vnIlXu^Ym7iYmY~+PRvHvr>_inmd1OCpx1sDLU%fF)P S!b7P50000 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/openFoam16.png b/src/eu/engys/resources/images/openFoam16.png new file mode 100644 index 0000000000000000000000000000000000000000..55293f8b8d9b66946ee8774adbefbecea1ce4759 GIT binary patch literal 493 zcmVkJ1<0G5Ix^_H`|HA zBMLu)WL<=K#7b7-RiF_h9-$CFgibUbg@}$~kq{cH{Q)W!N>(=Zs`h@5qxceb-Fq?R zWX_zKIcLQBM#w@z0svZD4FvuUrGZjOA~iiFQ7E{iF+|Gy8$LD)l*W0Myk9EG-%Uz|paVF^t{y{6b@5+@Pt^9T?S}`v=|l*Edo2V$pDDIHa}qD<`Wv zx3@XQlhY`3{>-AchY+GljhgOnntrEZN2lWB(>Hq%80JPoRw}k;ni}TD1`l1`1Szn& z_07J2V35rUq|>z?kUz(pnQ{g9_X0{;e0*5k-T@2qkx~efkp*Yx6doQVCMOKE7HDY^ zSXoX*&mX7f<(2xr~2C6%-Q}00000NkvXXu0mjf*{RY$ literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/opening16.png b/src/eu/engys/resources/images/opening16.png new file mode 100644 index 0000000000000000000000000000000000000000..2d868ebe6a5ad01e06c3b091a86226b4461c71b0 GIT binary patch literal 420 zcmV;V0bBlwP)jZ(aCra#0WnEL zK~y-)t&_1!!$1_qe~BkpaCFI{9UL-=*!T}PiBr`o3SE@eEyXF6{sE;!D3ZaU3N8vd zXdIlZICklzQ~U#TREN5hGv}ZI+h&NZ9~|8AzW2R%@4kZ(q5VFro2E*VbQuI%Y#@n1 zKSxj6YQ03m-DjXcVgV^AZskr{Tn>6?P%q(2$c75qO>=+{VfF*2x{%&I=G-q(KKP!W zkdVz=dq^c|H(PAa@5Bm(Lh#%=;^nNs=2{g!tSHAr6T?1VZlwxTls>8t1i<@a0~rFC zygi)6UttU;QlM)fyRTf|xi}u0=ydRJCRvS$x1TY|3Kqs;It6O3$kn||*~5zBGe8E& zETz*b+V`)Tje5G+P&J!~^EW3tc@AA0Wf_J_Y||JRKV9|?ahMPFZ}Ej O0000X*~r9E97Lo80Ooow%YI6&lRy?)pW z_5uS(FSdz!e4UH>9+?Lm1OhI-K1B?Ij>*$ht}p!8 z>DeM-ThM;o^8KB|wciiQFTB)#H!b*7j8w})EtOLeDW*{`*UX+Sd#x#^`4gLd;Okx0 z2Nu+Q`OL%f+D9#mQ>D?u)r0A^_JxQA+mnlGs+g0*pYm+DT_hwUwAZbpW@+d~gZ2xu zb_e#fZQpug=k4~1i?^&g|NLil!uF-pRILuHcPx&4W3r4hpxxu~N6S?PM|hat^SSl? zns#7Do6j%Fr7D{@s?dgE;GG&uW28+`jh-W(R>ZIgr)O*u6hAOj=|H_&t;ucLK6V+qo%X~ literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/parMap16.png b/src/eu/engys/resources/images/parMap16.png new file mode 100644 index 0000000000000000000000000000000000000000..a442ed2b93aa3cc8fce604ab4939f7840e17b120 GIT binary patch literal 598 zcmV-c0;&CpP)_9BOBU zmAQx^B+%KIAc+!!CKMViuSa@?%Rvwm3KA+MP+B2|f(yl6VPj_xm5D}UjKSk_+#$2G z`}k&N?^vagu*u7O`{w<9Z{8EkOc(k5>#wR7m@r`!Z#7l)AdHD(C`9K*B<2na{05S! zr^`F=+mT{;80UKF{(oohE$&?I1Te8xl+gJ&ibMe>Y3UHrXHr7H!Kjp%lT zLL~Lu&Kf0vf;F5!SS1#cBudT7kQQohtlr>xU}HCzIQkkMFmlsU5Pgdk+wEf=p_w6tFUS8HmbV}F=;@vO z8En381d#1Ae$Lz*?hd>&)0TEfV@t`Cu7b`kgu33;oHK*c*#(hYrm)=wIQRIXA^u4? k2=UIbjFGtLI-dwI0HJOSEz8U}EdT%j07*qoM6N<$f|N86CIA2c literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/paraview16.png b/src/eu/engys/resources/images/paraview16.png new file mode 100644 index 0000000000000000000000000000000000000000..153fd840b07eb32ebd2f03f70b1989bed8f841a5 GIT binary patch literal 1318 zcmV+>1=;$EP)A6c%=eUQ_@81hYv* zK~y-)UDL~NRCOE$@bmrs?w$LXJI}V$&d{nT3N~6GwxTUiRD9zjCSbw>qY+b0NN@op z5=D$b6BnAeFh*7^42njA5C}*RD5X5wfNiCrwbD*YA4BKWnL9K0^>aaN(DMg;7ANNr z{+B(wc7Al_$ieNtifejBi|nE$g_bp4{qES2HScbH^T5Ew;FCGa^vc2&`9hJeS=6>| z&-Rb|H@>&yM7HSJMavQ;$0MDrqI4%*7DD^s{mpAP#B2R?!_$7Z#8EC2reg7d{bzpC ztJ|V0qH2A#m`?*_fhHuky>{i`;onX_qb%DHG-qAR7D_NHHkyptB>NXm7YaCd>O?#^ zG5P|?9+X9X1 zeHQ`n;hfxTEn0o#lh3|dGF4Inj$;b|P$da9DpFijdj5m6=~SzfuK)xvmBUtmY<27c zfcSN5^kIt$KzQV55=HHR^ZM%7j{lVrZCOWB;JO3?f{KiY;@((#PdGJ?k7cuU-rr+O zsp0})kfS~^3m~v+&FQ`SzFj%3Rg(*l1jtc^QmRpTW5?F+uF38vOuq-u^~leC2s1zGv{>iQ zhtBE~S*OW%J%E6yt_tp&c&NdDj)+{QNw?RSJp21|;fx6(AXrcmo-Uz$*TO3RX2G6??#!+i>iA01tC5V_mN?ul&?`(X#`{bX~?eGQQ zW1xnhjz~a8bgB zpd{Ve-2eT^tGm~K!D|?tqJw^WocfdF*c5%`*N$zUFPO8a9#j@{WkFpxCZW3d!uq9Z c*PW052dg+Fh)Vy34gdfE07*qoM6N<$f`4OUi2wiq literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/patch16.png b/src/eu/engys/resources/images/patch16.png new file mode 100644 index 0000000000000000000000000000000000000000..2d868ebe6a5ad01e06c3b091a86226b4461c71b0 GIT binary patch literal 420 zcmV;V0bBlwP)jZ(aCra#0WnEL zK~y-)t&_1!!$1_qe~BkpaCFI{9UL-=*!T}PiBr`o3SE@eEyXF6{sE;!D3ZaU3N8vd zXdIlZICklzQ~U#TREN5hGv}ZI+h&NZ9~|8AzW2R%@4kZ(q5VFro2E*VbQuI%Y#@n1 zKSxj6YQ03m-DjXcVgV^AZskr{Tn>6?P%q(2$c75qO>=+{VfF*2x{%&I=G-q(KKP!W zkdVz=dq^c|H(PAa@5Bm(Lh#%=;^nNs=2{g!tSHAr6T?1VZlwxTls>8t1i<@a0~rFC zygi)6UttU;QlM)fyRTf|xi}u0=ydRJCRvS$x1TY|3Kqs;It6O3$kn||*~5zBGe8E& zETz*b+V`)Tje5G+P&J!~^EW3tc@AA0Wf_J_Y||JRKV9|?ahMPFZ}Ej O0000|7~{y-Exc@RNS(4(HLfoc{ke5TQ`5A$jrAgVBx3sYoDvn6cyxXnpIpUP|@rQZ^rsqLb%! zR_pnBy$GcZ-d~;5rBwEQB%oq0n;xum8p2M5J5weD?KJ`42dMED} z#^y=UeMYzqNZW=?Bp{?jZsr1E-){};%y7}-LZL(z{ zj7A4gxg4sWS3vxI>(B_aZyYt-^)Ug1`lf(VF#KS36|Lnm6uSb8hM7{kE<%?B3V$dT zAS1vQ?6EP>f&K8`Er5&wnO2In0JSZMn1hCKz!@kDQb@?*Ap|RBBq#Pla4RL-k|bH6 z-ot@86o;cM8^j&3rY7M(e+j>^h|HtA@SZ+{uC7BH2d`ft3PHp|G#N;?*_VWU;uz$> zc38W2qIT#gn)e=d0ya*2hgjQyb>uMY>2vUAE+bedaD{?0yRQF)fAdZlE(V=mM_{-v z5=?Ggy8-%8giNJ7Va4Eif9Zmmj-TcL338j$vH9nvg1gqK?+E+=UKHQFJ&4WA^-nO_ r)Q7LpZ6u-*p0fCVRG7Q`OMn3YukhRVY_OIH00000NkvXXu0mjf3jigk literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/pencil16.png b/src/eu/engys/resources/images/pencil16.png new file mode 100644 index 0000000000000000000000000000000000000000..d5ba3d5962359f1d6e4c7965e89850570307fe0e GIT binary patch literal 474 zcmV<00VV#4P)RCwBy(#=Z(K^O+`$FQyiC3%oK zWOa$6@}mDhhloB7-Re|ARQC|1AW$jjuq6bB5Z;3bx=2b%Mui{grMgHUMQfs^;@8?V zyJTS6G7ap)%`si2O~Czmj&i09A<0Y66>`{b))W1-3P{8e zYgvHnmSAu|3-6T|+@?)Odk|2_;u$r-zX2(FWnK|!Tg72WfgQ_+j=mBQo2Zb-Ns3cI z_MNU4;0kLnzZaD7pSw_xKWL!>4kGYPb+{(rQU)8ji-uSnO7Z4f z(-Fgz>bqfSW-J9HjweaSupW4H14$Z?%hCT5n6Oj=DOPAqCraJ3KvAGyE;3^&;N-p? zr=BM$OL;(JfFsnyjHMD{d3*w12$F&nRljud<^41OQ4xHPZ+e0iax# zmFu(2so~O1J38|g6a*z%b^`#HGzb7p9LH@JMY$*a!8xJVcD?UEcO}^3@%A@=-PCzG z!)gohqWH;FIb=9&oCqPaIYHP)fVi@A@&;enxIOgb)6e%4!j16-ZgxnoJ014uok%rf z?4!700OLV~kbF^+-eQcEJhJGqQ0eBXzQu)($V34E06y<;DOInmvFntUA!5U%AVNry zBrCg_VH6iFU)5W>xvF>GLkpvm0bOxZd6$C@6IBk|cWwAt@vC1QCJf`N~-) z%f9;4E$x=H3?o^XPBl_lx-z%BqrH_|pfnoeS?)me>%7lI4IX$yj^r z^gm`xS`p8SbpQaPhk{bA{6?F1@aTa(vy&zPfH^gdeelKE4p~vlc%I)m3PQvPrP>*j}h zDzc^v=?Qd;E~jH&r{8y#Qf(O`_5s9fhFBpYrJA<(7tc4QZyUZ$OBCX7^QtbV!`>GR zoS~Yw8W9Ia*5ZPOVO@ryudl1AviW`2)Ttn?mwq&Dd+{lIBpm*jQtf3#9Mfec1P#MH zj1BFteq+Pj$iQuWBHwrJlMlSJ#W|lD`c}sD>Uf?B@1s!zA)F{HKRmkR@%);@4PE!H zpFDaX^Q%L(R>q9=h4*I z-`jUM-;Z-R9AakZa=YE4#bVhFH>)sHk@#nf&DU`!jlmyk757 zWuKblPTR*%sci<;9BG>;#|!cuz!cC1!pGKoT|W z&F*0Er#X>0D%T)fM21ESYz(D#{YwJX)zW%Bp2sfGeGBc+o0IyY5 zZ7fVCeculsZZg_z>B`E=nS=H9QCXI=0FX+hgitbR8LO$eMnrAdZ1%CHX`78k<3kAm z`uh5o14QRi6%_}L4Gn35K%lszqhr6xWJ(heClU#Rq9{vyCnl!aLZO}d{$8&al5S2j zXC5fZltY%S?d|Ph0O;!K+C@a%+1WV`07IdW`4-WhOUz&OoPbr*=I8y9Cr`|}x7lo} z)oRsrUshWyrkzYIM|;YYInsIo%~H%?VhVoO~4S@0Zrrb(NhuB}s*aCvpO|0q-YAM%E1{ zqESQa<3~|28eMvgJRVPgh+={u-0}H*VF0+VC@;?jgVz4R!EKz$(4oA%+3|b#IPv@U zujN?m_UFdNAEGFpXJ#icGdvzo1%L}gWMgLEfu~P*R5UeRc{4L(PR8Ra%DZ>h=i>3+ zaC37d5w$Y&9DqALJw0D&^*6S(v=lLOE2Y!NH$@_uKP4r9GWq%Q%p4*jHxa!hB42lR z_sqW)c%75E-R?Y##d3y-E&~8F-&kB+?DzZq+S=Z~o)IfZMozF}00000NkvXXu0mjf DZ_jW+ literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/png16.png b/src/eu/engys/resources/images/png16.png new file mode 100644 index 0000000000000000000000000000000000000000..0e2f0e92cd7f894f14ceb24fc9eb38e0ba574acc GIT binary patch literal 1361 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHnAM>kg^7gJY9a}!5HLsvr!3j;$ZXIB?< z7dK}UOIKHzUYGpj(%jU%5}4i;gkCqCdO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZUE6 z(>$o&6x?oc!Kqgt=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6`st+Kz?{W+)YHW= zq~g|;VDBywM}b<&$oubB6_p)+a7ucIfK5wx<3ZsH&crutiD^|AFo`@q`rzL?0d@IzJ(`P`t?c*r zpZ{Rlw;wly=j_o|XL|2+|JlK6g~iFdV%&~1xw>Kkp0c^BZAki!i|!* z>;z;sl=A8soxYa(UO!lI+{p^v>P-hDjdnyy-8rTEcfwX5PZxWC9=+Fg!QM>T z#!Yn#RyJ)ZS$BkKdhhY+^1Q6VDk^FXI{P1gUi=`~=i-9(b7qR`L^s}l?O7o^U-$RD zzd7IEcXoyp2pE}{{;kSU>}H)iFI(ro&%H?sZ%xx&H$<&{_ceO=#05{k)Mp+Lb-!L% zl6Qk6xZZefQ%jHh`TYAH?9P8Y5^}%fZoWBX-mZE73&R~aw_W(L|7iX9S*O+;pZ!u+ c@l*Ez1NWnKJC!G&(*zZAp00i_>zopr0P2eK0{{R3 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/pointField16.png b/src/eu/engys/resources/images/pointField16.png new file mode 100644 index 0000000000000000000000000000000000000000..b9c8e0245426ee1b12a2aaae02c190bcf17b4f4e GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X9(%ethE&{2`t$$4J+o>W`1lYo=NA|-ew3Wq(bM{0{{EW1HSf)uS@^k|_b8~(VEgF!NMc%|cc+8&Qx$LV z?}i^bSq{e>`0(=Vt>hB;ALKT@9s RivqpN;OXk;vd$@?2>{8?f^7f* literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/preferences16.png b/src/eu/engys/resources/images/preferences16.png new file mode 100644 index 0000000000000000000000000000000000000000..305e2ca3bb76452062380117c3f6cfe9bfe7154a GIT binary patch literal 707 zcmV;!0zCbRP))x4hY-ZA= ziHRssD>H+EtQJ8~1TG>l#+48vEvikMGJ+OHwTo6gAku}4O3dY;wg_5DiwfyAD3U~& zlu44#+{d~7_ud&pu-Ac)d+t5wevkA2hh?sgd~-aV)Y^lGzYj*>oIx_aAUIFSlB<*L z4Xr3TF1#|spNKdiq6CHtrDU}EbvOCgiHcXTX%{>j`)` z+IIcB;H~O0&wMNKF0{AoVt%kLqG-?i-FuJb1v(i?hQDyc5> zGhdnhw3e50a?ACxmuvm#@3pCYpY$A>k?oyxbDw8FW)B{Hy|9?1~bA${kmC6yN)ErO( zjsfDF`zRutN~yIl47bzu@+$~}K*e#~0B!;fcnZWxd;%yr=MIR-U7%^L9sD*(#PzEAmvpCEt#+v2?=JuiU<0^htsUe53WY)dTo;im*4pJ>ueX;St=sMXh@$9O zu~>W!ECS1K*JbwFr90)THk%&e+XPqzyuIw#N~twvf>op0+R~J0|WjO zA~FD!0=9wU>7+4c9XJEr(pvBBXW*Qh1U@O?B`_TXK`vwR%^1@JPHU~#)43oB1egY1 z#R$%*Za=7vQp}NyWM{Cx7j_PP-7`SS! x-5D`R8BK{u-8okhk@1B73Ool^thFOo`4csuwRW#0r<(u(002ovPDHLkV1nbV`_upc literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/reconstruct16.png b/src/eu/engys/resources/images/reconstruct16.png new file mode 100644 index 0000000000000000000000000000000000000000..51e7de9765b5abb13e8d881f9be28611fcae0000 GIT binary patch literal 556 zcmV+{0@MA8P)P2t$oJKICIFV z@0{_Jr*WO1FLV!b26d0q(2`SFCBSQS{lO*^N76rW!`=_H4%*_mBpP7NZ4`TCp zNQ})wf;s2R3{<0Y=>SAeMK=yES|KcuV9q(#jP(%)pRZWznCXP;4$z`>Fy|a=_;oL# zNF(IfY2V{(I_&xkast|qJ_{n_L@%I+_FXJr+a|SUK=9IIMHvgvq7u4J9lG1IlIDVYQ{R`e0%sEGzgK8$jdxA44c4Dfb zu*G3Ze8=w1FwU=N7^lgxat4|kLLEm|N+X&}+N!PEpq0{Vaf9&tQDM4;SN|onXlmX97CPVvOn!T@3+1bufLFPM@!Wz2 z8nJiHgXlQGsvqBeSlywO7X4xIAc{7nDkd`^gXjK{Z|9d}5FEOxFG0(2Z2W ue&_7a)q#(&WAMlz#0U5T^~nqOCBOg?%iH-hmFx2W0000KLvvT literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/refresh16.png b/src/eu/engys/resources/images/refresh16.png new file mode 100644 index 0000000000000000000000000000000000000000..bc323e3b01d8bdde0439e09f110230480b9471f4 GIT binary patch literal 753 zcmVqh^X z9rcA+BAQ#6=X$Funx0a3WSA0@G|v(#QgPWAT%mxLBfqHPQ+m7Ww!m$8@ov<@SSkz0 zaUf@u89FwW2ViG1IM5m4IBg3zZGR~OE)n=^*}d19oYcG+_-di$ZWN1y9xU?f2zoT6 zrycZtP9q5)1Sj~}@}%b4t*c=Ky%OhR=`=WpN`{QVfb^EDO|zj z%?WU(%Dg;wauzPWpHKie(h*j1nPUbwPe9jTeNO>FPH642V$@s?qppol+&)yDK@2OmYhTZF-@yX=m{PqbGdoSiPxZh|ZJq48V`+V?v z7{beEv9#j!6N>$sq7jQI&aZB8BIiSCqEVZu^873MHcj+{U2uXIUj89{nfMSre6%Zq zu|x(X1`zP(dckSJwtTm?R}ppp0w$Y`~h|uKPDaO z;JEAyPVn>oLSBS@<)&lZC*7g4T@Jx3c?y7U#LA||AHTV>zm=D9_T>KrW_u$4Cx68= j#x2G8!n8%;p8x{@y(3m-P>yqW00000NkvXXu0mjfssL~| literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/refreshChartGray32.png b/src/eu/engys/resources/images/refreshChartGray32.png new file mode 100644 index 0000000000000000000000000000000000000000..5590f1235e29398570dc109161303d886fcd9de8 GIT binary patch literal 846 zcmV-U1F`&xP)UXi*DSkyHe= zj-V_tX(R1z%sFN+DU_fVJyu2%hFIXVxdYeRckeu$P0)dXx%WK&=bZ1H@0<(&sRS~! zNdDN^Sd?zU%&LPnV#R<;!pv3!$ACk?9-z@D_5sKOk0m_-$Y!%7lgYe|9^g9gNK(7s ze!Pgl*PGc*;7Ekb7Vp<(W&^-A;5?8svvWYdCs!9#tcpstnVkl{6##e9S>U&s-S&Yy zDISsXhd{>)N@f*svXIbU4tU^0KwE^~Q{W9S4{QMT0=vuc(v^YU5b)o?8A-Q7j;$K# z1^UWzz&rOw;EJomfEGzhVTL6AGP8K88L0B79=PL>$w*2AO9k4s54c>m17_9$vkGCkPri7bvGmtBQ_0_ZM?1H9% z!cZ|02&_@dr2u^8*mkv2~l|kTml*-9R_BL@ibO!NWm5~vsz${x3(?(vmd;F Y0RK%FgJju0kpKVy07*qoM6N<$f_{j7O#lD@ literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/refreshChartWhite32.png b/src/eu/engys/resources/images/refreshChartWhite32.png new file mode 100644 index 0000000000000000000000000000000000000000..0ccce8d3ed308cbe1fef6f42a10f04a83fc3441b GIT binary patch literal 796 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 B$A$m^ literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/save16.png b/src/eu/engys/resources/images/save16.png new file mode 100644 index 0000000000000000000000000000000000000000..d0d400ec6459b70b39a5b97890f9073cfc8a080a GIT binary patch literal 730 zcmV<00ww*4P)RCwBqQ%y)!K^Q%A@7(vE_o>eo zlKmUjqT1WW7A-1i7qkhB2%>1?wjw3+iP)l*e~T7|B(_j=6BfRL5W&ZoFDpqK1Oy*Tyl3hv#|jpA*=#wa#ImpKF3} zB_k{w1p2TvbNac(lHV`ebnNI8oA&vFdixEE#m z(B9EaRfRY{aB08u>TN=G5U%fm>Iu~fDZNdbmHOU z9h4?Uk@4Z?tu@3Rb{yeqNn?ff=Q+xEe7!WAFH^3DIaxi8Xw-#WK@;gPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*n> z5Fa_TO!5{000P=cL_t(I%Z-y?Xq9ys$3M^S{k`wm&W>jbnwx*xlqqoxBqF8|0}F+^ ziS7#KMKTSAFwiS$k~))l;e~8ArO|5s>tebQ)XFVEju*PMC|aZ?OWWGff9)=FPVhv&J*x7mzRl&I! z5J1`a?m?U?2Ia3pj9syYhoM6Rj3~@4MAWX^gsP*Xt(Bp^Q}|ZsJhYdK{hu;??lgf1 zLw%=EjTz5ms5zTO6y(W$Uuef08`yVwhHEX$n2UtSQPN(d=~Pj5{C49P&JXmnb?uw{ zK6RV2+$08pg~(Cq3t#^Fh?IqNprjM9$X6EmN@W0P-*A3lknP*H)BE!o?oZugB%j9$ z5JpO6!gBb^1K!KtXCW?KEqU(=ymM<8yEZp-wC61A*RAK$4?od;uMP_kI!FaV7#p@W z2+fU4{t3=ps7!v+LgwW^;k(_uo@wF4g^Sd``Zin`EirIVZVjL`H&%1))-0a&F`h8{ z(Q7omBrx>{_f#XTKu-!Zw(lhw-CykJS@wI>7SOb5!^S zr>3~Th+sXBs-%xCIIJ-g!UE^UYp5;E^UB&Z-D6J?YBdARm-FJ!wzK5TW}Fao zdVyorHx6crE!SC6ykGpzRt=BbcjEO;221^u8>RLL{n*Cja4%@N%Av9b*SIwzj$GRt zrttY#8D2iUIr&okVuwp2HTNX8FOaOV|B*bwYp!m;AIFC13rPo`^E#{*ci$<}aMrx& ze%mxL3B42A9l1ZAK6t>T@m%d?Mt0!HjlPQ;IQ$8eZYU|r^?k?mrr5k%jcJDt#}qhEFVk#X%;X(;rfN) z;`%h^4#p=9%T}p>pF5?5>!2?GH=adIQJsdjlDh;}aZGJu@0_;9qGM^G@Xt4kRijL; hK212x|1Wqi!`Epki@g^tn+7r(I#2T*8>r;B5V#p$KNo_x&)JaZ=gaG%Wn z@zytMmX);~)hE)dpIw;5-Nn0^i%H;)g*3yP-60aUQVonwKkpV*cpA!nH{;ITB<6-c zGq@k7C@gDP=fD=NYUZtFx~gWx zBy(BCw~xD a|Cl!aQc0@Q30MnsHG`+CpUXO@geCx{gJXyQ literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/HSVBlueToRed16.png b/src/eu/engys/resources/images/scalarbar/HSVBlueToRed16.png new file mode 100644 index 0000000000000000000000000000000000000000..b360fc4f3d24612072363f17a2a12160951dc360 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4&HECyrsn$JLrv%n*= zn1O*?7=#%aX3dcR3bL1Y`ns~;V;AG(<2-G%mJ=v6)zif>#NzbQ$p?8G6nI?gdkdM; zFZ?wx;QjjOtmK{u{vf8MOH>Ln1%LnYn!;dUb*+PsiIZW*WOu7cfoiYC4rIwhwTjfJ z_BSjI%6OW2CyFt|u#v6e=+k{n9_d$O+u!ss7(6bVlB<2_gLKS{uKdQ(DRVYUb12Ik z>z3n?T4240*G+JP_1)O!V95oEb?YQ6$`>eq{dZ3Ox4ZG~jW?Xn0v*WU>FVdQ&MBb@ E0Qy2$F#rGn literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/HSVBlueToYellow16.png b/src/eu/engys/resources/images/scalarbar/HSVBlueToYellow16.png new file mode 100644 index 0000000000000000000000000000000000000000..68775231d7453e79afa58237dafbe3b3abddbfbc GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4&HkfC?Kha6CZv%n*= zn1O*?7=#%aX3dcR3bL1Y`ns~;V;AETQfmCpDFPH);pyTSVsU!uWLqI7MIN{KvK2ae z`X4Xd+me_4TJ%kBFYALNIZVcSzCV6e)U+rxY+5YJ@K;#z5<|b)Maz8UAmjCocbN)` z8T79(d|{4IpRLl6Ba_nbM(e%}Lzi51_?b#39luwLY*sT{s4FpbT#d1M@I-88k1A8o z8@)#3jg}RxCC>uAiVN(Yti1NoIK&~$^RHn|=Bx~%L7#I!9Ire!~K13Htz M)78&qol`;+06pzub^rhX literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/HSVYellowToBlue16.png b/src/eu/engys/resources/images/scalarbar/HSVYellowToBlue16.png new file mode 100644 index 0000000000000000000000000000000000000000..d26920200f30b04a50a8193590e563db3e0a6955 GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4&HkfC?Kha6CZv%n*= zn1O*?7=#%aX3dcR3bL1Y`ns~;V;AETGJm7>7O0wGou`Xqh{frp!Pb1u20XR=8#k7} zyybl$boV!%rz~@KIzQ(!zS1UebJ?P4i*6Kt`tygAk>lS4F@^$NgB7PQ`%3Xz2QvP8 zV)%8_^VvNI3j{hDXS;JYFu$6Yuc{$$`m}xTg`1kpJ)y=v^O+Z%4QH&FSQO1T@8si~ ziE5?1dY<>#lwAEwKmN7d=^6FnLS106gp7K#;0?wI-d_u@3Uc3m?;%lfMLIo#)8WaJ fdX?=V{->E1t+&0`{$iOF(B%xCu6{1-oD!M<{5ENV literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/RGBBlueToRed16.png b/src/eu/engys/resources/images/scalarbar/RGBBlueToRed16.png new file mode 100644 index 0000000000000000000000000000000000000000..3f6d4185fbcb623e956493ff0977c312ba6c4825 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkEqTSyQhm|h{frpldXjg8SuEwPs>=S zu=D@b9SkNr8#MkzbNBvSc_QLl*51gIY!>xLI3GN)$+b#gkmyT}*n9MK-p@D-u7k~c znW7`kNB^{t{le4atH9bPa)!%i%RM$nn>gv@&FtU3CbWJRdOh>>F0CDGnLpQV_SZPL zFCgLM{(c`D4Ts!?za9m>SkJXB;m(}{XZCF4W0~fpZ0Mv@oREL(S&~||6U literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/RGBBlueToYellow16.png b/src/eu/engys/resources/images/scalarbar/RGBBlueToYellow16.png new file mode 100644 index 0000000000000000000000000000000000000000..08b321d58cc41e0bac4ff279eab1625421673228 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPqyQqMS;KFA`bAdv#nIRD+&iT2ysd*(pE(3#eQEFmI zYKlU6W=V#EyQgnJie4%^Q2d>zi(`nz>7|nlgN_>TxZFP%!03ADZ@;_j?w?z{6}6{% z{xIgzn-noI{C5hc!T$(-hW_KP&+7MXpFV^4#EB2z{)sZ}eJe4cqvgij<2?afy+>~F zHeTDlkY|%Y-{-zny9$;aNav8r)%TQ=pQoX;cJ8?#C7CUIuUxFLN}4vomixg2-^P32 z)N8Mud{?sQ=EBPdbLQml*s8=kQPgqqkrTCMGXE^u_vSa>5?y~|-PxFvYEFBf-KuS} zKDegT&5OV2Qj83T37@pi-$x7b*DPKU{bJ9#ZU=iikI8{rN1kL~J~4X@llyI@2Prxn ibN=PK&ANSK{xx&gGmWN9>-Jm+1&ODtpUXO@geCwU3ZBCN literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/RGBRedToBlue16.png b/src/eu/engys/resources/images/scalarbar/RGBRedToBlue16.png new file mode 100644 index 0000000000000000000000000000000000000000..13b74d32e186fe1341c727aedee8ba2f7c9b8740 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE#D&!rwRb0<5jI>aFK&o{3zHZ3*a72AZ#NN%q0y_5_4|B$O z6bSv^xlLlt4aW$<;Jy!s8gAT4aMUVdTX<=MV7uD73Ul`@@|NFc7QQ@q&r!R7cF~0g zP7~NNBVYS}KfoDccAr-zopr036tD-2eap literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/RGBYellowToBlue16.png b/src/eu/engys/resources/images/scalarbar/RGBYellowToBlue16.png new file mode 100644 index 0000000000000000000000000000000000000000..04264208ffc17ae169d4ce3e7e7aa91f3c56fb2b GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPqyQqMSlAM`vH&946GbEzKIX^cyHLnE7WngeFN=+#-%qQeF}&hqazT|YPD_5c5oHfnFh6`DN) zORC=r@S3RxD==JQIwSp>sbKfr=Z!*vY}$OQ+jJ&ud}v|Eeqf*dM#on#c5Y2jIm7ED z!_GRvNk?(F@)^-kAsyA6-{F>u6M9809cQX2n%?em44KgSamSolHga*EFL@qp?&dR_ z`lch)Q!%mnpWe@$jC+#{OI|P)__F!N9~G^1eJNzKfAz(G`RAtTiR_B9PA+h&4Ez4- zU}^P|_o0DW#_9DdnY5ex|5iIbU!M2WJ7V7FD>edKIHjlDT`n+}y>OyHvEJO?%k$G- c-M#;lHL0xV@yUp)%b@V^boFyt=akR{06dM6)Bpeg literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/blackToWhite16.png b/src/eu/engys/resources/images/scalarbar/blackToWhite16.png new file mode 100644 index 0000000000000000000000000000000000000000..326d480545e1a3c3d9b1f12ff7a00c9624f4c0e3 GIT binary patch literal 381 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPqyQqLP<7a^{c0eK7%#er@=ltB<)VvZPmw~~#C^fMp zHASI3vm`^o-P1Q9MK6^dDE`pX#WBR<^wPy9Y!IL}{t^ZcFvlUjs-=ucwGwZH0d zc+n~a!@gXW8S>Y-7kuZ-Xntz7I+*#?-t)ibG6)v3&!|m4%yCorO~M3**JY)*cGRUB zFiA#6%wy1HO3ayHk{R`bK~!aye@<|7N6xVYpEcq-|1J(T%-~rkp_%V@YxlKowpFv| z*`D3#_K_juuOi>(Oo_*{xpS}2+I5A&?Mgv7@1qmPPWto(H7{N18EF}tp?g*S$|vnc zcL5{uaL?=(yXV4F*~9m~V~n{XE z)7O>#9=jkvm)zEyD-QyNwt2cZhFF|lI@yr#kO7bDeC;Ea5dr!KkFi}}+jS*+gP~zz zUtOD(hVSGpT9L1A^}YS~TuR}e1v^7*!!cVi+w5(Pym1ZHiiSHkoRCxtu1af~dhTHQ zTJawlLP{MIZ&}W7*!)xdi>HE0-#wq1Gm->5*rh98K;OmdKI;Vst0Mr3$QUCw| literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/rainbowInverted16.png b/src/eu/engys/resources/images/scalarbar/rainbowInverted16.png new file mode 100644 index 0000000000000000000000000000000000000000..ad2f41b5f104f2e4e84f46811d0abeae2bfddd8e GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#9=jkvr}fnjdagjBwVp1HAr_~XPB!E_WWeJ(f3;jQubJM#wkwy*w8RseIawKR5oXGigY>{Wtrcbb_aVNoBUh>)P3qLk(CQr5b7&SpwEc-9No*@7`5re^8b0Z2hU2gEOzF?0?pO?a+k@ zQH|@APGne?$ExrDUViP+LotE1qEGMa%I^vgUdpgzO%2nO_rBZeo{K-x_IMVypuZF7 Oa0X9TKbLh*2~7aeMPk_i literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar/whiteToBlack16.png b/src/eu/engys/resources/images/scalarbar/whiteToBlack16.png new file mode 100644 index 0000000000000000000000000000000000000000..db23658b0461a6523e3325569fbf2ba79c95a748 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPqyQqMaNc%O#DL^6F%#er@=ltB<)VvZPmw~~#C^fMp zHASI3vm`^o-P1Q9MK6^dD1OP)#WBR<^wPc17>@T_~%&G_`)e?AiYp zo$R@OiFZ6*l$3NoZEkgIZJFZq_nJ8mc4Z4z{8)5cLiCN^!QK`o`)7-)E>t;(bzYJT zj@TrxvX5Q` literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/scalarbar16.png b/src/eu/engys/resources/images/scalarbar16.png new file mode 100644 index 0000000000000000000000000000000000000000..4af75ed71d40427524888bb9a59eacdeeeb52cd6 GIT binary patch literal 252 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 fPO~zE=DbYzVEwgPQ1Re$Az3MlQ zs-#ADwCLgR>0#=g%_V)O-Bjm8>BzD z)eUvCje%)S%sLyoMuK1C)a@?LXjRy5>fM}hj!Ih|FuL*Xze&|^*=RFZ6+0J`Bv&Wz zbWy!0AAK@{J{Tl7{yUZou`HXple&z|07Y>xu;kEYO7!S?56Jcvoq$(!yQ0jX-)-#Xep5fX3E_|Z6f9rKz4j4~Y?)7fMm$;Raop)0CvQa| zInF3Kgvk+MS%X*#72672?f3b3`>Yv9pCoIppT3a6(3FFk=p)`I%PIY)Y2s)Ks{P9o zW@Pu8g|s~}(RG7?kck;EP!heQqy_LqOs1wH2+N>)aw9&s4q`UIhU+a1`{(f{*v!5> z!SIAl#DIy2MUfh&DcFjcv;f^!(H$R}q~t7s*Mq~_vPlF3wRz3qV(q3UT~Z7 zWc)L(7P9`l! z%Lk`Hx3)J{*Q5FZz~NP02jM2_1fQEI*$25Z#*u`v8tdz_`p|74wt>ed7f*%CcNNDM nOeV}5VElN7`}|~=eu1Aq;<;aBDAzsV00000NkvXXu0mjfhn%QM literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/shape_outline16.png b/src/eu/engys/resources/images/shape_outline16.png new file mode 100644 index 0000000000000000000000000000000000000000..d0923a8c945245c03e5bf88cc041fb94600a4df3 GIT binary patch literal 396 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPggKR(>8$(U3={_5w}e@pN$vu{b?- zvaR1?2Z7f8H*ap8YvLFZprq1wKyU}c@dXZ#e|~wkSC;XH{Z8Au+2PU*hwg8BYAw0^`pcUScQVA>vA^-|oS5hJ-tDWh zlE3{pa`E6imxlgZGtSLRopOb>Vttlc8k<0LyxY7fI&9(#3>V}~?_9n2lf(&=9Zm+! z+L8=BpG5BP`6MJVGdQ#R>Hc_h;Kbrda~K2@XC}^foH#|I#x!ffJNqw^84i0H40C22 zT-Ex3#iaM|BL&Szv-7k6yi>T`P%I~X$Av{AwejuQLqFQPe5@N{?%s)=A9t?$%`Lga mIj!OgymiZCKK1J~eiAk@4Xb3Cqnr&4Dh5wiKbLh*2~7al+MO2w literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/shape_surface16.png b/src/eu/engys/resources/images/shape_surface16.png new file mode 100644 index 0000000000000000000000000000000000000000..aa47e08733f0fb6cdeae67cab2baefe6c027e15b GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)t01o>kMC^{Nd^W+4o?@y5R21OCmZ@5b`WsA|K`oQ zxh9Sw0ZJ-;2LyL89ADt@NKPRzK;c$E(8agLDSZ_Z+N_!0f>XJ6aP)S|KqJqGde@7s27cD+>kEi5$GM_$g->c(V_4{_3y zUkW!b(K`?wYP`wJJEvIEHK>S3&msB1B6foX9gS-ahBiswXp%dyz~kWD11!(3F<_Q#h`b2?*pEAtdru{! z8K1TuKNkQm-e-cy$^!LTi`kj80H|7>^Pw|T^yUzAynyUsi6;-EVidr2ed0NT>|u$G zwPgU}sXVbOVN&}=He&tEvOT6;AAnJS5lJGMR-K6K_;(ZS~g#EDgX`3=6k+E zV~`ap9627*naQqz=lR^dw#2@yvJqYA_|24vMdnCl%l&M14%ZJT|5UpIk|dFq%d{+; zwA{IoGq$(vyMbb3eAkuB@?nsq@NDXHZM@9 z+AN300Z??C@boxEW0(m6Z$32s2#8nP?_O`cG`p+zuMsdcF6n@D634`UZ1Ujvfc+bG W5-QrBvGe@^0000;X(KEMIp`PWxEXV*pfX1GG=IW?h5RKGyUI!0o5Q9MvcYOnh)q7XYnR zkk+*=gTN${3m{kfaqw2w7C0&uIdoL{f6%8 z%rsw^$Z_ps$7*`KkZkbhXh}}{Skof_H|9U&_mayI5Cg@yCk09%@vv~M{8fE_F?+bg zWO1bn&|lxZ>LxhtV*p9E+H(mce*F6VXn+5V>WMxhA`nn-|9ID#b89*6uJa#dfzdxw WLeyaZ@jV^@0000dVHn51cfBOFB=nln z*pQPnnotm$p(dpu)DE@klA%K|I=JXmaLDS=|Di*rL&XfDloo0SC7@eH45bP-{)kAT zL#a?>E_Z3~?tSllebcz9Q-?17!e@A&_jy0?@bF5Ua~vfyj+o;YDDUp4{&U5_8H3^r zfb7@77=f0)31ep)UQZW3srl7sYs)h-IQNK7bl`_@=7PE8Dx>ziOAczm_$3}0z0MhN zIHR=bQnE2MnVzw13yNr5;oQvt(ql=IA1FTm3oz$VZ*=^I8cm`1%muhc6|S`>2KFEn zPX-jlbFpDESe6YXbpCQi8_UAnspO2^kGb7)5$aGH+Q{AYP5+wAF5Z6r z^vSgJerX)Uaxgl(6>7^CX5-h!h68g#?QPrlnzXq2#azGlu=++Eo9&Xo5`+bP(m(bW r6bv1X+euyU^UveIBAxsN{1#vUQVPVZp-?3m00000NkvXXu0mjfAu#-` literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/shortcut16.png b/src/eu/engys/resources/images/shortcut16.png new file mode 100644 index 0000000000000000000000000000000000000000..11e06e44ca7cf21aaf5db4815c6e1899e02f55f9 GIT binary patch literal 1572 zcmaJ>drT8|9B-f?mdJ1l0}(k-@JV}jg|_yjXxjr@wG2uHG9PfXSGeHy&fY;w@qwrT zM}osRhKtH(P>IWmx{S#*3K3;6h7L0)4jrhO#s|ny<6yE~5!n71yX5Zo$mjFKQu4m0v=py&1T<-ZX_f8qQR$|YoQskD`I;C4cww$RxGpr`O0!bsqj z!mVvYoIv0WlBNtU!>|rD)071FU?fh8;n@N~+)5{doAU?`$R=_~n+hB_e+dLgiwaDa z8DImWC2~of%TA=al1ye-o>^%DSH=TzPLvm*2o49F)D|0yI#uA9F3Rsc*ANJdLAX2> z_%^8wLo%SH?F1l`z+y8jM*w-O1c`-}vC3#b3L`LtNFi7uMqpH?Kw$(Je?UH(-C{+J zSmJmr{-gqPIgUXg$l-8E95E8wo&zCDr4oXrkW?z>5n{H`#^Fw}ja@LIfDx?OPBI)x z+W?Ouo=xX-Dv;0gZ3z@JDQjcL+r&2va^ehxNMKJ%6F`IE|DhB$iDo$?@lU@0Da@J* z83HmAES+yR^MkW4@PuMet)0L*+HRuhEfZZ#&ZRk;&7~PYn<|qaKssr&&<=JCZ!n;G z8_VG~Goi;+Ag>@HNehZ#h;lhBOH{};3Is`zs^#kC8U+@skR@t0upFM?VzfD*B5d3Q z*D}eK!&7oSR-hO@GDg_R0>YALrzv2pWR#pb7i>zsajs>`Tx1DTav?q$$TQe~4SM2= zcaLW~XoK*-d3#&x2AwHo_NIr2M?&T|KU!9{W9gaC z>W}8iW7b6U#l$98gLS~^`m)H%vUuNp!|ex3npVNJrN|q<<82raw7Ame(89E==?3MA z%>$~F+dIFGZkBKC-+lh(?Yw8(Z;cK&*sl4Xsx|qQh=t*9j@HPHneCD8$*tI17Pd>I z+ny<|{YH2btg70&DNN%R*B^1^`t!&hndpH2&%=k1sx7UFfx3<&OZz)3W(ga7q*d1T zwtc-_KgGJbB2E{!rdeV_x4B|`XKoF&=3V|IzCUW)>!ZcB0bFVRk?8%UpRZ;VFGats z5mml<6+STS*L%7<1uX^c)~7us^RwDD#QD9CH>~rppxmKQdJQP0RBRkvy0!V@7E zFL*EXz5FVC(cG`1UUbymyW$h_Xi3wWXMXkYAlYh`S#P|)*Z3i&@9l1E*=cX4y-EXg;v-Vm0=Q=NPSU^J_xH@=fcM2m rW7b|@>~o@9^dPM2;aQE(C1Hplc+bd>-wuxUc>de^ge1(Z$tw99s^(9L literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/showResults16.png b/src/eu/engys/resources/images/showResults16.png new file mode 100644 index 0000000000000000000000000000000000000000..5bd9491fcb0cf1a07858a3142aa2cee6741f1ab0 GIT binary patch literal 789 zcmV+w1M2*VP)O(P%)!vcMu}rKP8%QwbCviSjGB3=Q%7(h{sUn<2|) zlQ$_r6h&EtM<$D+oFc&SYBm&av^(_4CKKP|^^SIXJX4swR991z+u(K=pn{ggCW7E& zJc41U>sayGwoRVCzLCdc{ufs-U(cYM7p`=^)M)REwUw27BIrP`a==mtDr9ZmzSHoq zzklpVWkc%cAAABu?a@;ij|Kqt(jc@5qB8VG{X zVu=b!{DT1}CMAKwTkT+aequP}E-TA_|M8VSfk@(7Eik^Rp~)(jYez5~hGiV5fT6}6 zguYUiW6z&>H%s@Fix#@G}X@*8KAgUjYUHJhUyp T-`aj_00000NkvXXu0mjfvq^0n literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/slice24.png b/src/eu/engys/resources/images/slice24.png new file mode 100644 index 0000000000000000000000000000000000000000..23874c4d25a8229c4777fff0d24754f1958e3d32 GIT binary patch literal 1283 zcmV+e1^oJnP)P000;W1^@s654Bdt00004b3#c}2nYxW zd)lmmYNX8^x>`s5r!BH1T| z&;d`9=rX_sv?mFk2i5@fiXyy*A#;HMa4IS0tduf#OBbjImIF)7Gnf?Y2fBd@pw^zL z*F~dopUtKjWfl2BkFO}&-F400*3$RAjLWX17n=uknCBM(!~hM50G|Ty0S_sPQfsrT zb&+sxa8XV!Rg5OShUjYh7H&bYyzynqyQxF zB(Mc|46v%I5?^?K?&z9zWr4-ZibwMcvu>51YGc8ux_)_Mr4g5J0-MdMV?YbA7dV!H zVmhXIAFDD zlR_Z#3$sFH56-)(Y0932Mv|5bkkcv=LS(3_GW_{>>(3|J6daAH2lsZm&z!uHH*zzq zJ6*O|&Et0sy}ZTS@5r{sPyck;x%>SVV|*<7KysytN~S>o>~_n^=U?|MT=!zdKyuQ^ za9Dk&_K^2Tb3>;y#}-dKpBSH1o__R;DkCoQq?Dtn5M`#z425Dx{7pU9*)BWP?3tQT zSdx8%slUQBn-KyWzi@6aFC31~=AULBpF5`O$`ffrq?G--u3m0y?#)gY;;nWEHH%u8 zHUuCViGSs9>d8tM;_(%YMZ=S&LWrESA%akXtNQdl+v1^9XomS;)?72K}*R(S9r(U&36Or+ul0Ac!4vt zs4{z(QHX0ur%G=e*x}gV7;z$fJp!V002ovPDHLkV1laVTBZO1 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/sliderLock16.png b/src/eu/engys/resources/images/sliderLock16.png new file mode 100644 index 0000000000000000000000000000000000000000..9063ec617f38e57f3c95b5c8b54f7a06cd4b5175 GIT binary patch literal 1323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHmZ6JsM2Q&(eCOD9u9Lsuh9XA5IXb8`zf z0|Pfx6GLa1UYGpj(%jU%5}4i;gkBSzdO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPri z(>$o&6x?nx!l_pu=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6TBWRh8Uq94d`}n0 zkcwMZg6;L414Zn=-}}C5?UX1j9x)}wjR}(kqA%}^e$4$q*<+1Z;^mHmZ3nM$Hgk5G zXq-yOIO4#&bnTa=>)+pdJ?DEsZS&H}pNsDOEIz;U`JDTe{h4bQ%09ZFwzal#_i_P9CjY~qT+^&A!sl%~n z$y27M+g3MxJ81CY*(aF{%h-tmQ|xrYg+%4vHSSXQb#I>HQk#vr)m++5&p&TaxV=f1 zV^*8?)Ub};D_?i<%84C$Br+|0y9wKCwoScVf0wS$O)ps)bh-8Urn=SFzF6JrKU)61 zXGW36^%t+@S1c>%Q!-(yaNf~>fQ$EyiVRP~TZ_D-XD;6Kf8E0VRO<7}A3V1X?Z5x! zouZTOovB<051RN!cpO!)O`MebPIg-bN21fMO=})I7?^mAa=s6+h>?_%d;85QSLpX+ sWoehbf16~V%(3tI`+xq+;08v9_=9)X&#C0z4=TPqUHx3vIVCg!06wzi%m4rY literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/sliderUnlock16.png b/src/eu/engys/resources/images/sliderUnlock16.png new file mode 100644 index 0000000000000000000000000000000000000000..70f23cf39888aa6eef057e7cb70452164a44a654 GIT binary patch literal 1241 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHmZCl^CECl_;5OD9u9Lsugwb4NF4Cl^-} zM{{RKBWH7%UYGpj(%jU%5}4i;gkB4rdO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPrk z(>$o&6x?nx!>Lyv=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6+P3lWX$A&HUr!gu zkcwMZf^EH-9R=pz-2J)e8FQ{)Mq<8VQyJqyv$b27&b@IXYks}JM}8JhMF%^4u&z`&ebK18HQQWT68k$ybXxM)}tNGfi?3Oi| zYZD7Ij~>0Lby&jM;MftTj)ejd=hrh_Y%~+Hsd8~V`S<3`qCI3lHhWr~AP)sEeTi?(L5oY$Y3-1qy*=NPY>1~%vB zbnfb{V>l*tVo6ib1M4zhp2aIJ-n!5D_ulq9Wj4IR7Iv1*n#Tp&g8Swkxbx@Giv^e0 z7M+~zeSlvuPopVBYMHmnf+@eBz0b>Clm1fsU)r;`e%}u*TClP2;Ab0-6JqL*9$tLe z|9z%dqSMbpCAE>bLboFyt I=akR{0I|rw-T(jq literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/sphere24.png b/src/eu/engys/resources/images/sphere24.png new file mode 100644 index 0000000000000000000000000000000000000000..2e1e8fbd91e5e166ef6e1d93198eee703dbd230f GIT binary patch literal 1186 zcmV;T1YP@yP)456SuEXHGR z5khW0cuzfeplSLjjq&yBLq}BYJ=c8e!2tjYETz%*o@>79Lq}9J#{D!+A6>NqgpifS z_`1V+ZnU^;kFXwiHF@2A8oRC1EKAb!gb>e41qdOARVX_T)YkEvg#!Q-m+cV_)YkE= zLfMHBVpa?=#!WiCQCnNrII~&!vTExZXLNd_7PD*<004y$;s}BI28T0%X}mJ=x!Eud z&jgt95wG&EzRRgo0{ep;XNT*bcmtC!AYXmtkBm~W2yeWR+qFYliX1|}6^EJpe6 z-qZj9^me(ji%NDyK00>LT=VXSfvNEk7$CMZ647uV)+maCD2q=I*uKbji{iI3!&iR?1pPphyZ+pH#48!^gcUm)B zUA@B$R;>N3A3~v^pE=*<()N6FdY&QxSycz$=N}au06?cVCJKwogk+MKC|Q zjF|xh03W~b(*C!LN}i4V_`Q?+Clpi|O!?8=f*nF$QAs3Imo28IWyopinNn(ch716( zI5$f#%-zR}3$yh7&UALisNxK{UwwVS zGY$X{^xtFec=|O%-T}>|@2+}jVGc)yB^-$ebS$z&0{|%1DY9CvkyV-$DJ3mkGUY!V zu@pZe?68&#dgFEx0O0Ve);vBi@eTq2j;8VC=be{_HnQ9{qOqYt)v=lvEwU_`C_)I2 z5VW?~Z3an}&{pA+ETI;=&46gCl@P*H005FCHHU)!a7Ww8?5!Gfw4KZj1^r=36q^D5 zTXuwygcy(2ba%9IUU#2nvv9AwPt)De#)(mMEVcI3h z5^|k7!P#wKhzwNUT_!CR=#Q*>R07*qoM6N<$g2WFc AegFUf literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/starcd16.png b/src/eu/engys/resources/images/starcd16.png new file mode 100644 index 0000000000000000000000000000000000000000..dc66cb18a6b53a613072d7f7df31f010736a950a GIT binary patch literal 854 zcmV-c1F8IpP)%>(_~Xtyou^hJjasrmY$#5~W>L8YVJ<2eW6=m^w11*s5X;Q|s1>si zqN0I;Yb|PR49hukMcG;<&Af_DPq%3{Z+GW;ch5a{_uM_-{)pA#_JYqpZ{DBx`z@4G z*qA15(Lq8%+ol3Vhva}TLni=hhNr1C~%yUzJJK7!Ya-1GF zc2^n2-b%K&mNR}{=j7xHTQ=On+PXD(yk$gU>GtJF{9tRxtC}|QtI_bCpJ#8YFUIGE zoF*`{3b(XT>lN(#Okpo9;p@o=chy%h@p~4B$TC0sSLgV#m$TYLAk)2TbCF|Plf-FL z5@0wetPL*EGZ0sWRQpO)T%XNDC}k^*h@%-Z-NOm0)Ql zAQWt_5d6HT@VXobqkxdEvy!wJJU)ega+*yIRaDn_9+C4`td0F&!Sl_6Dmw%XMYR)r z1@K!491ak`&5QN *0hF7A}OTVIfYxgds-c1nrKr$1!r8noEv73{5+thWh5NqBEm zar%3clVeu_=;{0S0J@*Jhs#SVmaHkuT9%RI!W=w)NO9&5#nvjATu`LLifAZ?p(j{P z-#f>NMq@!O98K)c>Bfsf+DMs&42=n%Y7$J%SnMjYOX{xs1z=~(D-!T&W+vHB#@J)U zvu@IE8f#04#+~#Zxx((+|0m~@ugNc8Zw##|PQ7a;7BJ&;+`TS|VWf$LXK!4+3Zayu zZSOaw7XslU$+Ws}u&0GgR&oAPg52yK@P&S92j}cTHSnm<5*=+pAyA-TnxX&OtGGJ9Wl9&at> z64AfGk*-8jW5*!%ji%`L0eUi4SZHM6v>KBKEQj>>WiQCI2u7w!vB_@dJWeh^$fvA-VU>18;| zfD;BK*&2BtFFTCx*GhLOySwhGvGONLMk=jWfx{L#JjFwu~?wkz~_uRx5khd9>ep_ zQ}9EA1QVX{MYpmC*>wNV`){a;^4cvEmdOU(IJj>co;;1C|MqG4zMMDdgu)ZP=!z-o z8gC5H$Dd0yohO>e5GDEMrE)}{e)%++CHk6Kf%JtZe9;vz()Y~7o2zXPM=?8>M|HWZ zlcVt+-N14ARN>it8@Voh;R#=KrSGC*&)N1?aqf9FMalVq=Hv}99VF?>KK}%aFj9*=Zy1z=A|2$46!7^-%)c4W}6kGKjR3kD>{h@9+w5B z`|MESNnCjzfT-@wVAI(FHjtPUODg_XHRV`0TQU42fw)3&$|kt260+?UY-m8>TMVnP z;zjjI!B_pM>+zkdD-Oe*CF61T7d(9JN3KhTTL?J@M<(&0a{ze)3;vG7;k4m;MX}y1 z-9S;*Yn8_e5nKUArxtLbssc^zeaLpoa0vqgYhlbGV|qnJ<KYu=1vj7c2!WJ=H9YNwDsrz2V4ZHDcTG9oVA}6G(f! zGy{1P@Z{y9c)u4*GxKP@RI&rRTUC;2U^XGSxCUfxjZIO$2Sb4oylM2Mhz8bq+XsgQ zScno>x7mZW<@bGK^VlVBR9cjecU>Rxw%G?oi~*^c80Q|*uYSR2ol!*rPuN5#K_M|2 zlVO!+)`+GeMAIVXVnh=w3eBz)EhdS^m*P~`*u%vY7=!dZGBsRx<5>WUp#;1+60D+3 zn+REiBt|jEWk!|*_!Ul|zI_Oh>CbhnOW%v^BNrQL*|{w+OTkr@{_qZn;4kNl^MB?s zKVugR6A_1w*LU2qxIO1Jf|a&*K~#}cqRZVQt(WhMG$>;Ae+H?Z@XHxbymffWmbaJ9 c27d(@04e@l1Vs&G*Z=?k07*qoM6N<$f?sk`7XSbN literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/stl24.png b/src/eu/engys/resources/images/stl24.png new file mode 100644 index 0000000000000000000000000000000000000000..0c9e9ee578e81078f91b93049c1722e6bf1d4e5c GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE)4%caKYZ?lYt_f1s;*b z3=De8Ak0{?)V>TT$X?><>&kwQLzs)3kw1dt2vA5iGbEzKIX^cyHLnE7WngeFN=+XIEHu}e|yQ6i^))c?ZR=hD%R|+w@)eGxc!@X-YMlZ z(*@t;>}i-LCU$GBFW1xqdJ=1%IdaStIb6e|*fPhmui`;Z>8kBBAHRL~wn?{bM#BHE z_sjO!hs?Yst9&MCv+v7}V>cc)NKf1Eb7ASRttBqJ%OsYtg}&?v%dDPfk$5q==}uXz bz`v)guO$_qOqUkj405WctDnm{r-UW|@z-hf literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/stop16.png b/src/eu/engys/resources/images/stop16.png new file mode 100644 index 0000000000000000000000000000000000000000..f602055b5104af1d3d5ea4dc57adeba418c7d1d5 GIT binary patch literal 739 zcmV<90v!E`P)|{ZQ4uMWi6-15B{Rbq_!7(Tz z9o-66P-w~E7}P~j9854|i3Ve80{QjwaymToL+ynxmwWCx-}^o1%T;)?lHqXN68Tye z@wQ_gMXBkE@?$EUj`rq?NcV6Q4o@GNrsUVx#meWUW!oKC`Ml)U*X7VOhn=OKE^H-I^?cEfESaKv`Qr|W@oWPK7B~1|8xirO;e^04gjc~ouTNu zQ>m)ZYB{f27T&Qjr_GreK3-iZB7&9-hvUPGi@5xLDkmr0ZEtg(NGtvWewH+a2|W}|7)uyQ%K%kOu3eo&+j z4Rvkw`#TC;x{j60p+N&cE86z%-<_Q=fu$wv`+Ek*$I0yNJ#%4jd>k|lSARc+jSY&n zz1zMEB}`K)r>D{^7R9=~b#Qmr#Y3!FEK23{R1&5sKuAPTfo!r;S-FTrXk@dfhT+gQ zo6u-DJD?f{jck^SNQ7jivI1m#75df&2BHbml$%&g>Y0q#wOR-DOh#^EF-e%FtPKoA z0pFv)&?W&!e}+Qe0xs9*Cb)a7Y7}hyS0tPL4qO7I{}FU%0t5iHC)NTAPi2b;{{WrM VMD_=VLd5_8002ovPDHLkV1nj*LxcbT literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/streamlinesolutions16.png b/src/eu/engys/resources/images/streamlinesolutions16.png new file mode 100644 index 0000000000000000000000000000000000000000..d1071aa88240260d1f850e93c6c7b6254af82f3d GIT binary patch literal 980 zcmV;_11tQAP)WFU8GbZ8()Nlj2>E@cM*00THlL_t(I%XO1~Xw-EW z$6uej`+o24yYKz@?zY>lEvG1fuw0RUM4%P@K!PBHV1Fb8TZ^I~Yf8V|rX?w>Aj>3Z z(M<9$qt!4o)YjUNK6i#l?obDljG;y{LEPH%uj2z znpz3K*Q0|k4Gs^;PX_xo0zCiz#v6_H{auP@ljMfKd>}tOAg>Pg@4luW`TL2JrZqo) z*Qzz^0i=`&At)3I&jEx&q4ySM09Outc&TEW4Q@8G%mYwoB>YCGrt__jw*W9S^u3Zw zrKW7h-DNxOu2gC=H8L{lTM%SUPo8u0Ih<0t&6mzhk%-l=1X%WPKLEO}8~NEnqF5^P zkD{COs;U?;4Palrta(&FZn?bHlZe&x*ycm=ww@#RXN$HEKv5J+Q4~~Fm8z;rj}TG{ zQBJ-43INu0an#Dp?r`#X%h%C;?9n@$69XRp!F^^N;A7_JIVM zx9#@ZZ)=%7>QO_ok@6k`HB?-z`(!5 zs9wIL-8niEpVbru5>a;F@a0N&F7FhikO(QkYdJFjuWmiU_U`*`jMJ@T++U^<2n0ye z%e2SiR-VFgFG^S9SWf@FO_2w;zBzO<9@AGZzWdb|e%n_H`1ae1hqCHTSwZEAYtPjB z%s^uz>_2XV0}at|kVqszG!o3!)@nZ{>a=J`SD%c>^-}=f-O{YybM~}_5ZAwP0k6G& ztfM*-e5l$8t~89GVnhSu)ka__8V$VD*btsu%>N52|6Mz#-*x){0000Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i^r7 z4jDFR>!Bk600In2L_t(I%YBhMPgFq^fWMjhUN)@ma#=uv1QQn27?)sF2!=#~L<$=U zF&aqR&|63>Bs4ZY!f&uK7Pg9w7B*08?;r3Hh_1lS&YiKi0b#v*y2&}`JKs4YXo+Wc zHouv~mONj6z4!c5=jyffFHK`&DdqP^@2+-8TbgGo7fYr4FD|3@OboE6biDj( zmP)l;dN}oFrgh*EK%>#94UeTmj4=R+#A5cKzgk8qRr@bM;?9-&@~NKrqltlH=P`tJ z=Kcv-Ti6`w8pyL#*R3@O;MWgLxxby2skbAU0IgJQbhexNR+Fr#Z!4--`cchBEqetc z7f+opk|g%8W@Er4mflJXRxJJnSXQheVsZM*t=f%hl;Fv^Mxz2G$Y;4o1V-u|Blc5B5_oKp1%^ z@1Se+z`6i?xaQG%DI^kFLLm6E>^H76jU@o-I^JaOP0=Sx;Pfu=boJ*P(Yb`d>IM= literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/symmetryPlane16.png b/src/eu/engys/resources/images/symmetryPlane16.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c25e975b145d8c76caada02b79b9cb0e852191 GIT binary patch literal 630 zcmV-+0*U>JP)z?=S$#vjT`DRbZ(Espa2`<$u-u(0KVlrSKfOFoSId>Q&3|0I-5CBt+ zG6=!j{{?7jEss?S(Oktc5rT`de+o3QmQMscdb2fMFBPCCBn%9M{5g;?UM|A?+QxJ$ zKycB%dvO%D_k(Cn5{#Wa0kNEkMaKBmeaZXnT04RUFG~~Lr z%^+*hR6y3Dz-$Y=p`5$0wvp=t1VY@q(ePoHO9Zg^)2;T3Jzo_fh?n`Rd8(z84Jtlgn@sgNG8r`|I zNDKag;-VBPQbly3Ac1z%ZVO$vl^|wi_gz)GD=Kv(ejth>i2opHHvR;)U`x$=Z>DG7 zdnOYpv^enK%$?Xs{;}`^_gN2W zI~5(eYu!2?1!TYr3~HBOu+aZH3D+)`yKx_}q1=%@xLVQkVaxuik7Iu098xK0O4B5X zZ7N#{+l50T5XJ_JlY=OJ+=fnl0oCV&OrSRftRFN{9etF^exQu zlO)KKpqEZ6*-1Gsx-rjgWTy|but^IO__W!8RuZLx!rSFDV$mLe&DtboYX5gDhFO_L zX`U9cGrSrb2J2C#f_Gn=ct1OgIJQW8oMuVRPf})mt&!eN^0oyxS4WT|j#)J{(2JWW zhBcmCcg`-GTS@Q;R`(kukSG_^kYJ@HkujZQ>3$*>d-WZHH?-h-LkD>I`IMs+2q@7A z(IN09-z5nAC=&~ur(%UK*YzN9K7~ghvfa1Cv!u(#oI=FrO)Z@yQZ1~F%&(vC!WkS4YUgg z6jEAI1gMeHuRv@F8(`5L3yQ=Ku!IdiktIT^5K^IH!Gzdk8X&1b{3vV5uRW#Fp!9L_kyRoo)<& zA`3Yo$w(lOL?!`Y5HJlDYxMi=J^#N2YzA!-kU<7AE5XTj6-Orl38zrq1if~I%536% z#|m_MF+3TfNyHyr>QLx|2@dW@V9G#5RHn^fYzc&oPKh=TT0g0p9dyLERWUa-=Vaz3^Ed!nPN5`wm6FES3m2Ywxg4fmW8Uoh0s08WUXUM12&G6;N-sFnj!9EY1{M&n$vS{GWXg z=jFEi{#(+mPYdl{bJ+sm-!h2X0+2YXqDA3r`Z z{0G?zlwk(Ok%)vW!-P4vv1&#KAea1K`JDUz+#3vF3}U;W`I!(fb_Hr!{gNAuT}jjo tH^dVdGoGE~X@(m@tY$_^vok<|0RUEP!L?xlWyb&j002ovPDHLkV1gj@#Tx(s literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/toolbox16.png b/src/eu/engys/resources/images/toolbox16.png new file mode 100644 index 0000000000000000000000000000000000000000..ae4d8a97cb86134a7523a3be0b1a9278fc1e333a GIT binary patch literal 779 zcmV+m1N8ifP)r)E#L28Nyfsq(g20;`eE{lj2 z%o5pf%kAZJ+k3bB-m{Is4?!2s<=%7dIp_B~=UhT5#s4fp+Xx}>4h~H$MItSP7c|Aj zuURsxq*3g2PIPy69LxmJR??o|(%;$P{+Fz`N5|j&ITMY-OAGPSHMCKVCE+yf-wuQt z!YhDg)`VRH4M3fafa%+6@7}@cw=ag7Xe_u)AfhNxRf-o|YY|LSaExNn=fDmO__7pu z7Bh0s2c#6}z7`8pGBZ`d$uedd523vEIF9bFM=TaYFzCYdvIcnHyvFA7=We}-Q)WWl173u0Tt!GuG722ZtQJ-c3L%{Y zFG-jld$`$m;fqHF9s91aKWPlqt{)(3UF3!%Ic zTm#l!jx!U-f{@iF2ceuiHcmunX3s?tWfg3N3IYRK56x%uof?;nVvVc7uh zoXlWUs}0nCT9_-XLY}?x1|$3QM1NnD1u^LXxxKS37V!I!o?XDmP#klmRX6tP{S;q3 zF$BwAZ`=98*B>Z%6uR- zO%H!Cb8sA|ExQnc`lH73THT7wd?_Mv;n+RVU?p;BFouF1Z2Jxl#;{ViBYVOcGP!c{ z`!Mu&s|000073@$~X zo0I6|;2QL45670jdXu`25tUho@01bT;y7Xg`B$alp}i*`N8zQ zyyMsc(o`0$tZSu6C!ZG!ORJ@V09?BBLeCu^A}p_MNjk^a+?#sCtqa3q`p=H%awjt+ z{n(Zbp}@s#hMAH3IpcfY_SbU@L{aot2C^&*4ZgOSK%E_f`@5Mae*QzxT7KC>JNZGp z-2k+DF?!m4Pz8}1fKV-pA_xj>^J2f9m~;)hQZ6D=*Hh7r-dd@M3Q2d}#70a!OgJ{3 zDIY|uBBGn(QhW9t8!_?Fw7ABdm|dV$j+&;ek+0qvix$`R1n_~5e@yeIpSnnjqIusE Qc>n+a07*qoM6N<$g1*!OhX4Qo literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/update16.png b/src/eu/engys/resources/images/update16.png new file mode 100644 index 0000000000000000000000000000000000000000..b7639f15582efa20b1019a4973f60b72b4399ba6 GIT binary patch literal 814 zcmV+}1JV46P)l0X9KYi)B`pkZS64i$=K zYreF6+52|y?!BFRbv8ph++ndIkJn&wHiVa-16YWpdi&cPCuJKWPu{Ec z+KSSG@P%VlXrYcRC-x#OimNw}fe(lL_??t+#$E|aiJ{5X>AAZKpyOR&A!_t}4Wi3E zhPOW!0qLIvh7v-d7+y~-qI-B64g1Ss(5lbZyF5D-0Hw9pR+x~23OX$dbD>^2lo{Wj z-EU0JO!hF*2%?;Tfr$|6s>&dw#hc4F5XCEbMm^@DJXkJ?9^c0?CM&R0gHPQ9w@$al zgZ>`EarhbLq1EYV1WD5}fDmnnBgkPj^y(r;?lqsH=TljUkk|hAkFPmJE`=Pe24R5# zp*j_S{I8{?fV^A{_(T%nz}SaZuBJoTsdRMpsbWF@R4N`v9tAAXfRaoQ<;9;QP@Jzt zSxG+4yGO;vLZjILn(nZz!<}Q^QlR)ncmi4FiUfHfBEkV%3yly2@dno90iZRa+g4-< zSxYxzJ^}DNPodxx03TcOCSx%WMh$DZ2?d7SOSbFo+jf`NngP&4L!)gEYc`vp(WsG# zMiHO?^+*8(MxJ-hPtSs7Rq#iFqjlA&t~58(L*rQ*@F^(39|KJ`5S*FC(4DjG3SivV zJ)Bsa>z(}a4Y9O@K!U;UT~=B5nqmU0MT*hDT%?D^v^h+-r%6^bZLe#6@<3l$Twi9{ zi7lpLyy+jri?+jx(eCm{vJ6RX7V6J1j0{ba|GLpqapc@VQ;q#1n`<~A@Ao+!8RNcn s8dW0ev@?P)h zH388YG>sl=O*A1INraXN7~;VLf;WvCf)_nmFLF^2nh;GiUXY_l4-kmaXbC1-yZ|98 z5~|Rod?=~gZrj~`&f7}C!of*q_r3Y}y_xq$zy|T`J&N7oZfy6TfJ0Fr$?{2VHx1)$ zUe~ca^$rU|eb8n<7IP&2an~Nf&bA0D8ZNBw@6WO<5O{RO5cO4u0_r;} zJDv5SDBAZ#fb|Mme)kv1Hl2Z44EzwiM!(>KQFMRzjkV#sDPKkm8jboEH@cprk*hU|HF4)V_zH1Iv7{I~8E3DN5v^HFS zeC7M>EaEdWP-v97a?xpwxz_l6;0L^Zc-2`1j3)s94m-}JmY1V05U};-zyO~}+d)Hw z*3QmiLAn9kF||m5$SV_(Qz8ylKus+zA(zP%%IWI*=W>?gar^I7RRS<|dI`Am#1&W>84^hl#VOYFJ#X2yELbG1 z^bY$=b1=4x;W@7N`a{Idj-!jj3j*Zs?iL^#&4A-_;ZzVjacz5%0W4id)AwQS6k(8r z;rq`aCHh-5o`)ETKoEos4dw1-hSbzh_rUt*;l&^b%D(S^_FR{EL3oBem`6uZGh^F! z?#|6&wNf!rE*qGh>{rvhiaCk`7%?r!G1>Nq}h-9WXvOWMbkbF#{Moen1Z>xU$>;B3m~Do+`) zpb7BD!I^`6n~X-+AP&(Bqh4oQTf3Yr?8*WIY|{H67LTLX{SL*fgh7UYzJrxk7(^cw zMI3Rbu!2dpRjlx_y}f7v+cdwi4b@yiPjCRw^Fo&=UV#-Gm<(31?5b;8AeMCj@NBy_ zB^A)a9d(X_%Vx7}2MT@vTeMX0?`qI}cufu(p@X&+`n^3nJNq;qkEbllglQTii|qRB zIV6b`fngY13kxsE7hZ*cYPE_)BEiNI5$0j*w8H|vk(4Ot!!N2x}} zy1Keeu#wTx3!w|!cK&i;zV)&8wYXic*Q2FUsgLEsIz6NTa&SqKq|5k^a$R?w9DJf> c^``&>09jXAhv@$a5&!@I07*qoM6N<$g4fw%X8-^I literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/wall16.png b/src/eu/engys/resources/images/wall16.png new file mode 100644 index 0000000000000000000000000000000000000000..431ebc57befeac062edca36e968d626f0ca86aee GIT binary patch literal 597 zcmV-b0;>IqP)0pdwS zK~y-)rIXD|lu;DMf6u+|Fn*1WCJtGFyCNvEmO-?uoeQT$pc`%BpX5Jb)HVo$))56E z)GiBU9A*4yl6mKz)8c){7-^Mvb?@(74$pHw!?_8(X zqsWL8CEjd*=gI9G^h@6tStfY<^(UE2wD#MWgCz(N>QfWou-`er-7yc$)W^;lZcNu} z;Gp%DW$z~=nG*ttLav)b*@1!d;!(sTQOP2iIXqu%(9JVq5L=&ic(`zt#&pDhn8eoS z9iBb7M&1)v36MioiI-pY$PgT~kH``Ai7^09&VDh{&PgVw#>WBZv<^uwtW;H>oG1jX ztv0>i?~_t#LFEqz$ItKQopHwuVic7a$=sZc`?GXY#$Xyp$=UqaW@B-d-&BBM)~f_Y zm9zQbm<-_f=#(=8E)ism#E63Ebi3px6nu!8V5AxlLhCEb$L7@BhpQgS*&pzWOcFty j2)GBt|6InT%dYbu$UXfEd>1C|00000NkvXXu0mjfmyZ;4 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/wedge16.png b/src/eu/engys/resources/images/wedge16.png new file mode 100644 index 0000000000000000000000000000000000000000..593613de0d6d1c8bd2faa73ba9c6d3e1b0dfc0d6 GIT binary patch literal 3302 zcmVou@P)|D^_ww@lRz|vCuzLs)$;-`! zo*{AqUjza0dRV*yaMRE;fKCVhpQKsoe1Yhg01=zBIT!& zC1$=TK@rP|Ibo3vKKm@PqnO#LJhq6%Ij6Hz*<$V$@wQAMN5qJ)hzm2hoGcOF60t^# zFqJFfH{#e-4l@G)6iI9sa9D{VHW4w29}?su;^hF~NC{tY+*d5%WDCTXa!E_i;d2ub z1#}&jF5T4HnnCyEWTkKf0>c0%E1Ah>(_PY1)0w;+02c53Su*0<(nUqKG_|(0G&D0Z z{i;y^b@OjZ+}lNZ8Th$p5Uu}MTtq^NHl z*T1?CO*}7&0ztZsv2j*bmJyf3G7=Z`5B*PvzoDiKdLpOAxi2$L0#SX*@cY_n(^h55xYX z#km%V()bZjV~l{*bt*u9?FT3d5g^g~#a;iSZ@&02Abxq_DwB(I|L-^bXThc7C4-yr zInE_0gw7K3GZ**7&k~>k0Z0NWkO#^@9q0fwx1%qjZ=)yBuQ3=5 z4Wo^*!gyjLF-e%Um=erBOdIALW)L%unZshS@>qSW9o8Sq#0s#5*edK%>{;v(b^`kb zN5rY%%y90wC>#%$kE_5P!JWYk;U;klcqzOl-UjcFXXA75rT9jCH~u<)0>40zCTJ7v z2qAyk54cquI@7b&LHdZ`+zlTss6bJ7%PQ)z$cROu4wBhpu-r)01)S~6}jY?%U? zgEALn#wiFzo#H}aQ8rT=DHkadR18&{>P1bW7E`~Y4p3)hWn`DhhRJ5j*2tcg9i<^O zEt(fCg;q*CP8+7ZTcWhYX$fb^_9d-LhL+6BEtPYWVlfK zTBusSTASKKb%HuWJzl+By+?gkLq)?+BTu761jmyXF)a;mc z^>(B7bo*HQ1NNg1st!zt28YLv>W*y3CdWx9U8f|cqfXDAO`Q48?auQqHZJR2&bcD4 z9Ip>EY~kKEPV6Wm+eXFV)D)_R=tM0@&p?(!V*Qu1PXHG9o^TY0bZ?)4%0 z1p8F`JoeS|<@=<@RE7GY07EYX@lwd>4oW|Yi!o+Su@M`;WuSK8LKk71XR(_ zRKHM1xJ5XYX`fk>`6eqY>qNG6HZQwBM=xi4&Sb88?zd}EYguc1@>KIS<&CX#T35dw zS|7K*XM_5Nf(;WJJvJWRMA($P>8E^?{IdL4o5MGE7bq2MEEwP7v8AO@qL5!WvekBL z-8R%V?zVyL=G&{be=K4bT`e{#t|)$A!YaA?jp;X)-+bB;zhj`(vULAW%ue3U;av{9 z4wp%n<(7@__S@Z2PA@Mif3+uO&y|X06?J#o zSi8M;ejj_^(0<4Lt#wLu#dYrva1Y$6_o(k^&}yhSh&h;f@JVA>W8b%oZ=0JGnu?n~ z9O4}sJsfnnx7n(>`H13?(iXTy*fM=I`sj`CT)*pTHEgYKqqP+u1IL8No_-(u{qS+0 z<2@%BCt82d{Gqm;(q7a7b>wu+b|!X?c13m#p7cK1({0<`{-e>4hfb-UsyQuty7Ua; zOu?B?XLHZaol8GAb3Wnxcu!2v{R_`T4=x`(GvqLI{-*2AOSimkUAw*F_TX^n z@STz9kDQ$NC=!KfXWC z8h`dn#xL(D3Z9UkR7|Q&Hcy#Notk!^zVUSB(}`#4&lYA1f0h2V_PNgUAAWQEt$#LR zcH#y9#i!p(Udq2b^lI6wp1FXzN3T;~FU%Lck$-deE#qz9yYP3D3t8{6?<+s(e(3(_ z^YOu_)K8!O1p}D#{JO;G(*OVf24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV z0GgZ_00007bV*G`2i*x74<97BaB@cg00J&aL_t(I%bkpLjdkXl1*H4URljA9_4K?iZe9PS?B*ztPX zpy1QUdd1gYH{3V^g(4Lp6-Y(UN;ubli0dZ{O#H0cB$p{t@M#{q;_zcl~synS~AqyPW_07*qoM6N<$g8c+RzyJUM literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/win_close16.png b/src/eu/engys/resources/images/win_close16.png new file mode 100644 index 0000000000000000000000000000000000000000..e44a306849de5c64ae7ef462749356a25ed2ebe7 GIT binary patch literal 448 zcmV;x0YCnUP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*!4 z4m2h#xcc^f|KE{B^-C?7x4D6s&a1nc3Z8XW`#fp6Bid&gxjJCRhUY;y7NY zs%lc>5=mQe9KVDR-ahcpZCRE%U+M=9*W4W8ezdooNC1VkyhA4ln@Pz(~@O zbFPwfX=bUU5wKsDqb%Z5JGtVDaJ(7iJ9fVlcc_L z?i%O8fKZ;i8hm&sr0000EoR?Bw1HA%Ga;Ca?$G2FA9ZhY)Jp z?2#_+Lg2o z98M;ao}@PL8dwAV07sJAnaQ)1(h%TEj8V2XByDHqUcUKrr_%|NUID9;Hf$f;?#(g@ zDJ27+YV_CfYSNGVO0FgecYTaw1Md((%s#QT?+gb=X(Hv8m< z?WZZF(aQXAj8VXrq?fZy>bgEDisGxJJK3?rqA0#C+#tqy71)t9?)Uqnx$QP>w`_kL j3QL70(Y)*K0-AbW|YuPggK4i;WEzDFm7b_0cGdb&7jLoa2K z$r(3Zhi*4VN5{70<^6_ROt$_xzVzY0=HEPSZEjb*JtPj?yeYXnt)_^Xo#B_FiSeEZ SMNU9RGI+ZBxvXQL70(Y)*K0-AbW|YuPggK4i;Vx*&ko)UIT?*d%8G=Se!mP zX(LxtfJAHmHEs(t7EQAqQ}qQN247jS#Y>@lYFoxsIYrJYo^bJlySK1jlR3D5*A(Al zx_VPguH1b0bpQQ&zUNH)rzy#Woep(%x#Z}3*B`An#bJ0 z?ZBs?6tS!|Lsrv>f&0ecxsNTfCaIV+1k8T&w3<(BLzazHe7Ez)%AyZ`yViL>uHpIc ze4kSH;=1VM=rx*WgElmTZcQzG9ev=;?4t}ZN=)}ZKjX8y+ZSFQvpa*O;%{lvoN!rx z_Z!aA3>PNxzS*|>-qRY%DXE%wvtFgTe~DWM4f D4r`1| literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/zip16.png b/src/eu/engys/resources/images/zip16.png new file mode 100644 index 0000000000000000000000000000000000000000..183511d3ff6201afad5548e353391ea1dd5029de GIT binary patch literal 704 zcmV;x0zdtUP)~?B6dLZY-YXJ9FnfKeoRg{{Q^;5w5vo&YEZNFaQz%zJFr) z^Yjvm)ht2^VA|raI)i@8Z|Ui44?R_okzgq7ocr|O-+zq%p|*hy`1|uS!<+m2Pz(^| z4h7T4ZLTxS+xqb-$OR9cya2mk-nMhVnD_^FG1!3rf4(t@Xn3O-01^Wm{`U_vPK(Wd4{nx+U_qHE)#TJ4fIR#na|64D;hKs4`L(G5v@BuLL z{)2-{2&mvKt~9V``z8!AIa%2qY;5eF;P5`zD9&J1|5B=T&X!qk-oEt4W(dgNGuIw` zdgIO=FdHcJ1DJl^fekp{D8_I=e>X#6fW8or&wW?21Pk}#!sI< z0uvu3zFA<3dY9~e_v+;{P^x4Q;Nt_O_qozy0!dF^eVG30^@}V;1x2vB*Kb}jaB^@} z$%qNG0_7GmF(9QK5MX0tWBB_0JHxAY?~*uqMHpVcdzbm`$It&)Z`^<+;cq|w1I1dQ za`7z4PW|=!H^ZO5f5Gg3fBzgmcKVd%-`~FuO{&R^L{^vAGJQEv&JLu8kpVXl0XYbW me*!UjEC~ZKJIGFe00RIYB^8IWtoO)=unK*%0wc12wy75o)XPQK?Is1R1cy;`qHB>l28zVP)tTq)NBs_&=4Qm zoc~u=YE!q}-P_qpxk?26;9TxK=llJf-}&A{Agke?6KzsdxCtq$+L|Qn24T7Of_g_Y zc9bMZAe$e~uCm$P=0irawHickimg&JffSg9_rn0bdOdSRO>azp1-$P(K5IT!ZcNOn z!Xsx2hUV4ac><1OU^T6yE^i6TV*~KH9COwiuT63Q^R~01O_z~n)L6<<_k0i1^n1~9 zZXa5!47ggH0!Fn9cbsOV9Ik*a{h%?Xmv_NLBEqc$g=Oe=>QIxbLuIxGYqa|_4INk` z40t62wVFe}FCCc$Wr*pw0VGjWGCD1W0?8;$Pr&yGp+**Jl@gKo;E}53F%dR^P1QoA zdO3g-L>hyz4uygRSO(SC+L1twN}fZ@?Jk5iLa^PpAw+)b;(9qi6dAf8(7;&umm}zT zcpYI1h?(zpHz67Yf4rwdB*_7> zevD6B%14eI&C;84^6}(H2_}&ZjhY3gAh0lAoFsO5hlerkU&5)=2E4O-P}<}m@|&2~ z-&|qO$k6Na@-vZ;nn-Vn80QDS1u^3OjMc>%RF$LwmRewW5Kj9i6gAih_XjX`p>43T ztG=|+H}&NrMJuGu+Xi}Oj!&vh^8hox_@6@VB}Aq1ts}_GNQWVojckra3AXRvSyyd_ z3(zKGN^N~MH#vRY+W3m>1pKQC`dVvTv^#K&h?gIImmk0I^!^VZ4w1c2&=7;a1Q-CC WEDyZO>!7Cq0000T2Xy6Md2 zR5o1<%UGolDz*wkw+ksL=pwwyKrgzG?E9vW3W>T99Ar0j=Zzo~L?9H36q2siNF|Xj z+Wef(57=azJD!VW9bodQlFj$BZ|`f!_{@@^%&7qVT9|b9uZN-nxG&e ztKfJ7osPpmpcG|Qbx7(n0IH(!jM0Fvp*&QVW@AGDV&EWfT8LTOo^Q}#MkoTCZ-7Ge z=>SerXd9$Bv|1Km8C+=ZhK6Io(gqS*qb$j|`|J)9WLuZgrvns)p&Jr78Z;Lc(fj-+ zVhn>A%Yn~kz))^1sz4(qbt27RA3#=#AcR)5r%cP32x?)-1>!VHuctx0CUp`D1==-p zh=*1nNMtjk2Mgx(dIVxc;LZ}ExNGjrS6_F@t8Gs8TnDF?Z&th^j0N34L z9?klLtHH@}Jhi<+IX{oE$Rm>Av9ZOWFzQE(@S4uR7$Ol7&L%rX-Sz6;pzb^?2RfZY zR;$TWd9n=I`8jk-l+<=~BZ?os-`HGPK;xMbz}^gmhv6CeiP{@Ogxdj3Ug;Wkx!ccn z1ZG#S((Y?_e?fjDio}0@q%>pYHn~KnjxfK0_~4^p5}o0JAO? UZdqLNK>z>%07*qoM6N<$f_@8O7XSbN literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/images/zoomReset16.png b/src/eu/engys/resources/images/zoomReset16.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d17536e97eb0f24ea82c432e777aeb03646d16 GIT binary patch literal 846 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 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/old/splash_HelyxOS.gif b/src/eu/engys/resources/old/splash_HelyxOS.gif new file mode 100644 index 0000000000000000000000000000000000000000..0b3b88e6e99e3ff9de71945cf2eb72fec8e7371f GIT binary patch literal 9536 zcmV-GCBNE7Nk%w1VUPg^0q6e!0096106GH(0ssdJ0}2fQ0%!;e208!$2@eqt5e+#2 zIXD1S4-^&>6cG^>7c~QEXaE2e7Zer%{}>k;X)MMFj;JO9}nBu7O^jyV8HM@nTmk3~vM zOG!;lNl1@4J4sDXkT+&eO;Bey|4~mE>XHE3;bXJ)vkTw#u7V`^`4Zg6e5WdUVp{*7mi zcXDyHW;b?pcyV@kv}a~`d3UUAY_V%?e0qL(e1ExZaeIG)et>;0kK2ENeuaR4wPyc> zf`&Vd{FhiHnVn z|F?~hl$e{_jyIQ_p4*OPnVzAdot)T@kes2TpP`+}mz=|yoS~(t*^d9DsjOnQ|Bkkc zsI9NDtg5Q7vdgEauCT4qrm3{IXRWfejJE%=wz$~0WVE@wzqz=#yua4Bwz|Kz#L3Ie$Hs`-+yAuu;lskl%g(mhj+5E_%h1x#(aq1) z*VfyQwc7pF*VO3K*3{YD+t}UL+}{7$jN0Gg|Jtgn$Bwf_I_@$T*N_1OQn_wn%Y^YGdK+4T1F*8l(V`1Ot`S&!h;VhUd-5S;>M68OSbxWvgON|eOAuQxwGe% zn?H9ghYT4nNvMUW)=*H=(9@_T!75D~SvJxB^qm`5u6J){(1L5zr#Ce2rR4yr7BbQG z(0IH6v395$3u@be`K9{?tr)Ias5bs#+C;unr%&k7|H2lpB{Eo&)GV(q$rG~nS&bi0 z>gl2lkBB3hP@WWCzk}ww$3V`r(m45pj zCCNp|ECmY+0$3!3C*`EY&p5@*LduPzIQSqbIf`;#dgwJW%Q`H@XuB>+f_Q;|rQ zi%(W0gj*+Clp<5kV9}yQ8US(|Sp0-D3@NCP@?$4De!^pqK5o(pCWpLI4@>2!;Sm;B zGUen?P`-rBMQTuq;#Aqp(Evs$z|xgE(A47SERaI_$}6lyI?JS#qM`~ZjnpDfkyU;K zfEr9HwWmw*Tr{Ph7dfX^sQwh?DHSqve1K5`lHfO0JlGU7jIYH6Gt98V1oMlr$0myl zF0(v>%A71AgQTbcB=Dc9T=Dd$MS#GxZAGr8;1_+?>#sh5Z zvBq?iYScaBi~|lh-+-e{$>Fq&ayTWI49+;=VDk$q&7g`xzzZc%Zc(SY$M8$M46T;K z6M3Z#E|rYXz|&AW0Cm(-Pu+kAs2r6~Jo4Nl57+Cg^Ugc&#BXdy>*y*ezrZO6~ zl+A!V_pE5aJ|Wy3{!Fk=B;r~~OZ3$}*k~h(3K=A>_~MK=9)&hT>66br@zhff*Ikco zw%74=?oQcUtAh=ZF3nxHLw6GuG)u4;-BRBY$%@v_7KK%hJl)JO!tT8D9zyTH^G-@n z{H$}%+Uls2PTT3k472jfFQ2?R{L~Y-+;pGbQ0hXhz7p&a$^QMIYh9$lSow_e$`CWO z@BaHT$lwACEVy9*{c41x(>vjO)4%^T)5bTxp$!50uVo1Q1~$Ioj+n$Fd)jNr&wAoL zm4FW-;cv8WXT<{?oOo^SW_3?mtp@e5oigJAyx;)jM(M3fxSAxT6@;39G`*eGW{LQq3&c!7)| zMu{S;I*a-+(S;^B@{y2?Bordq21Bj{ip0t!v4X)#VRaH&H&X>OuE#1lMnqwPF_=!U zu)&t>5h6Az2Q1Vut%(E@7M4s&IXY+(($wacz^n}%QId^d8uOR_aK|eeL53+f^O?|$ zCKRSQ%_elA7%!>EFqVZ2U3|w;+~j60A~mU5sNxZufSgR?QA<-wP&2B`$txcclX*I1 zCh`7Q(MJ+B%#-L%BHc2{9UGEIlC%>d=ko_YX0Zn@RNnExKkpD+({izV$X)u^CAwE1Oz`~t%X@cVgHQC zwN$c8iv+49xClcNpditvR)L~bxacGe;l-0^LqZdh(0I;Mo;OuUJZI3tBN{l9a_kf# zLI4CLW>XqSKmrQ~?U@kVO32c{!mW@{O+pGflbM>NrVNS6Ss{`DnDAn-q8gY=f(j9Z zrRt|FDVjz8RuW_&Ap=Orf@U>)1*b-Jl90>;=}hvALo}ihk4Wt!PK#RAKH?CtjsEQ) zT%ZC*+@mH-Oo$LDyOMH109;oTcRqr5kx^h8T$}a#?>K5 zRSCdqhZ1FcKmaP(Y!LBrX<1gLc}N8 zimZgX4#_1+vaz!dWTDKHtRk9$po3DE+JsGrbDYm0=NP-1)vJ#2s;97LoMa;**{w-Y z3xZ^sY}g=tKD3iU*lAa?( zgW%F7m)5y63m^gMGho5eIY4+0uz(9;5JRg~4Qm?Dx$1R3L)J$glYjDdz&nMsN$73z z#a3kD!fw0V`%UxFll`waO-ZF^ev;J#6rVer01g5lf)8*Y0~N491xDb7jmOyB9w#^C zC(o0(Gu!iMT?s2SUlQN`(clIVdrc7C@@0S7^>U|a>QVj@ZI~u|vNWNx15{9Z+()1R z4)8!0!odD8s9NfCUOc%&UTdDf&e+LUiAx2Is_0yo`F%BPG+}(EmtZK7b5dd*v4I*E zAu@J%5Gw(F0t09j@nGS%GYRkk84v*ufB*(y0bHPJaYhD=$8m86d^9F}#}GC6 zh7f2Hl}HlZ7d{$R5p;(WR0afMK!R~*ilpd-jF*b4co2lxipU25klg?|rI65bdQH7J1zabUN2WIPcMO~8I)z>KEYhp{GSRWJYm0D3%uG#2P}(wGv| zhL0|RG_t4@LMTW6gb_8kjSVr3y2y1bA%x*Fjt|j=GC>Mm&;?x31!5ou7>S2m@R1+c zhkW=1ErJ7(a9c#dg5YQnFGy$xp#iYK{)s99UBgIh*(ehQ2}Ep&kSk$^50PsPX%PNa z5^b1km*^0$coV3wk?)9yP8bGw=mqR2mF-880DuED)(9vm6!$lcEV&Xci4Z1$c6HSf zVOfKGVug&T5IYGdzyu$Tc7`Sql&uk2`sNR9D19|S3R-ZHUeE?Usi^7O{v7!^Czy)5Q z1+19`7s-(xiH93W22MEx03ZO1d2Vw+ku>p7!KODFAawpP9YO#L%E1tpsYC}cnl{K2 z=2&HrmXp+Sb3R#JE%BVYsD=~%v5z*vm#mqQAK8}}d68NmnB(aJx0#z!xSQRB5Sb~C zwb2s0mYn_&55Odo4kK?WfoPn$iUzfovO|jiz*j<861PSX?7df60 zdXXMbEm{zTuT}@V=|c#?oi#CJmp2m-v~on$pI^y~jQE}c%2#c8C7SpUho}Y(P?1zJ!6004p_*l|%vq&sn-2Qj5WmYqgs5CAC?{Q0D! z8KtIIWOmd_DFLSv;T-W2(Rt?UbM| zVLAnYg)||k0I;Epc9RIkC4iKw%Mq8S#HVtH0z!v?5uv2oIjHsdc{OninpFk6dIcs% zUYk`>&IAMo002WEUwdF*$hxe|imalrl{aCe2EnNt0zuR&hlc8;+TuDsm3JuWc51+h zIr$O~2x3Rs5Tt4npHOC>#Z>3zuD%LUIItxnz*_ctulUMZpTJT#@r$3TVDS)^1wo&c zS4%Nks@s}j`^K$qCtR+yeJmlZ4>2WUSd%WX4twwf)C5(|Hc9H?;L?I@7 zvK7(^>U0wd+5RQGU`fc}39|aBSO5uxq-ojUe+iM4DVMO`>JkEaU@z4r8#=Boait1T zSP!U|E8z@WFa=K#wNfj!)D%%2TLnHUT_n*T4bTXv@U>tYwqgsmH}VO^KuTq$rv-7a z2)h&K>JZE+P=G3(Fa-#>gp&}v5~2!AgID8^7|qL+|jR zCd#y%s}s;0M`^gV7h$n5kqt6im;1SfD;<+Zl3rO%jGav&G96v7L!0rRVAyBON zJC_<@0EaL`G?XtO3_~z94ru!lGrMeZ3QvpJzYlp4a1@$oIhXJeIHPGkvvIWA!->$q z1|tvxKHS5<)5Aar|)_M61*1ye=`l zSW2#WTdUitfD0HK&qo~$#}W9uw;wT?{%{U-P*DMcT(>dDQIk!{GD1o%6v%T1ukGouY z+|`Yv=am?tz$Agd96@)yFv-=DD?Y&s8h`+sFva|QKu_$%<8ZmGqr4q~%jLWiMjK^! zX%b#sH!#Z)1trd{5)YDq#n^SaNu~i2&m^o^Pbg3UVSouhQrL!l*q?w3#V`)K^wbD}0?eDs*f`fA zc5EB6Y(x3d{;6GSDFl+B#Y~Y;STF)wa0rNf+J>#z<3Jp9>DVwS6;oZ;2dS_sA<>ED z*0TK)tm+X3A_iSUd>HgQ-kTq24A-TwWj7Qwa@ zeb*6@0M;R3bwbe0iwx2Uz!?4)epL=-{NgZv9o`b-G#(rCoehAX-x1N>lJK$>-XZBI z-kT;J8u834ju(hl7%@xWLQqTd0SNVh9nV1<@bTiMGfN=85c7TH<)h$SJ{IqBoVWeu zgpuTAo)qQa32LC@91-AWjuvMA=0+i)tSje$5$AS36m-sd{&}7kc;4qX7(odj1JW+oIVqozS*DNM5CS+p>7a^ zUg~k->8kD$Sx#7>-RfV#>awmC`yK1G-W9Z->s2i(;mYfz4(xjJ5o++;!rml~e(YPU z5h$PrUajn14(&++bJSiMxGwE`k?h#M?fbFo-2Ux`;qBl)?kukD;0 zAMs=X@e*J0NP+McpYc(q@f;r(7|-jheh#xB1`$C1BE%pB7b670;1VKF@*m$BFJJ4d zevPbij?GJ_(jM~-&jD&s3+rGU>o6dapvotb00NB?Jn!>5j~PoJ@y5{~RbUcVaF1!p z?M<&3H2?sYS2Q(H62Y(p8Djy2P*nwS4}dTrB%um3kTD6+1#apOe1Qrqa4|KIQ9tMp zl~4f&@By{p$SX1Ryj3(=Q1#n>^@o89000Fi0R;e%QH+ofA>c&?kp*N2K6hUdU62r6 zfTC@H5W_(DD}knt`STF~`Z-VWTz(H4Gg|AQF}I}*0KfskpdsA=1OUJYKR5w-G9b34 zP{E-1YFHAr000I63#tqY#X1W=SOF>G4psh;_@u(*l!qr@&P5m0RRC& znLmFC02n}MKmY&$0totJ$nT-QIt&d!!L)87!-oa{#G6SGdvrIG3 zM3X2h(`2(vH@{r-O*!YJ{!_#_>%=opJwv;5Pe1GgmqS1Z^da< zTz4H+S6+YB)K_4Kom5z2k6qMQWS1>eS!SR0(^+VzjkH#3uZ2`vY_~;I+cU|u_8~G_ z5@S>4Sb`PYD8nt&Tj)IDzyJ?yq^mUNW+9~|Pc)=zs<-T&X)_ZHKw+zOW)MIJjr{e8 zmk$U&vL$2yAf_aUcmnuCcExm;xlLy1#-DWnu`A=^UQ{U?&o(N#$AHD%j+eF6V8kCr z)UcQ!Iy4HV0hy})AfpM3H_o|e0f`2)Y_c)oAr8s`01$^* zY9?Mr(8VNy2xd_bu!o*rh#>Qfo~-P%{R!KEv9Z>=oJtI`a3zkid3fxW*2$ot@!och zm=IbzM==x1ne5_{yuP?@!2ysP?Wy(#s%wY9LHL7a{NbD>&;<}3BCpG-fFOPYjbh1)CbojdqQuWSo4g3(oCL^ECziQGa1SsH(N>?QZ-dzcJlK{IDQ$REG@w-f*x z&mUdL7b*TCG{FD)qkeNznsPD#xs=%EYftem5M=F$~{`(2PjN*a|^tW;2}8&=7MB#spL{3+oW13G0a?4e7TY zKI%~bgX9kNyi$W&s05It45UAFP=)XK1CQ%Kmrmc2WOHuV|SotGXvTiD?WkqYf&YD)Xwgs$hP3v3XT2{HvRjhTjt5@-w{@1PU zm9JOz>tClDSiwG(uzB(ZJqmlfY0+Z~A`rnP7R#l>(n%31*uf4~V2sIrb*-dI0}YCB z1Q?X!A?TonH#)nn&ti%mmrw*X9-;^s_+SSqkgY#1A%YT!KoP5bQf1L31sJ@b1n3|L zJ;kw;60VuNQ34+n;RU9Z$tYH^10@8ZwAVE&v2L&fAHX2D zE!jm0c5sCD#^NURXa+Apv0qR$<27Px1~K>xidHluWYEg4nT)Z89DuhbTS&nRU~mJ) z%7hnD*g%Fgtl=I^!Z8HVFDNS33_@Ud!(bo;FFyRoNq}L)8vw&3n$e8@{TirY`@Kns z|Lc!>5aPuzCIKOKe5?e&i5{t)2t8tvhEh~mCG{}zkAZw(f4F!9B(SoSGfV<169g1m z{xKLH;^H3M#LDaQN0h;QDS?uJ?83sdv9n%eBOo9Ykc1)Hv90f2G z8VqVC!9-edVnXcK4uXd9m?LeIGZTau8YVg1J>3-8 zAj!+kK`&sPVOz`O9EM(B+^xR8qI2EyCg!(~LCtIpum11OQLu@I4Gyi{o;uYx&^S)+ z3~Eh31izs8H0qaLcbOpDAM?JljMv=?!E2b`ZU+M|*4<|{udf>#wnNnY!Rg}jn^-YF zlQH@*=S6@!C!*(g6h5r^eqVj#95?<%z>j`3=NtXzC-T=_MGb4WgcrbYsn8!%#cxwgQs zR^TsUIIyW}2~Oj$0{buDdx&lbG5%6M$LKp~lRrq=g%zLy=duafvaLA45)&2i9Qf5AMn8|;Wg{a{)q(iiEfAj8soiPQ9>=DhfHt;Yx4$b zb24fu0T@UD$@369AOvFQx_a<5x|;|h?5`6nKF{+BO*@AVoRu#W6B~Ge7g)H{Iy?`_ zGAy$LP$;ww6TdoiL=I0FIF-{mrPDgK(>ujeH67D{0028SR6Z2| literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/pbs.run b/src/eu/engys/resources/pbs.run new file mode 100644 index 0000000..25b5bb0 --- /dev/null +++ b/src/eu/engys/resources/pbs.run @@ -0,0 +1,173 @@ +#!/bin/bash + +echo +echo "---------------------------------" +echo " PBS QUEUE LAUNCHER " +echo "---------------------------------" + +HEADER() { + [[ -e ~/.profile ]] && source ~/.profile + [[ -e ~/.bash_profile ]] && source ~/.bash_profile + + echo " Environment" + echo "---------------------------------" + echo " APPLICATION = $APPLICATION" + echo " APP_OPT = $APP_OPT" + echo " ENV_LOADER = $ENV_LOADER" + echo " HOSTFILE = $HOSTFILE" + echo " CASE = $CASE" + echo " LOG = $LOG" + echo " NP = $NP" + echo " OPTIONS = $1" + echo "---------------------------------" + echo " PBS_O_WORKDIR = $PBS_O_WORKDIR" + echo " PBS_NODEFILE = $PBS_NODEFILE" + echo "---------------------------------" + echo " SYSTEM = `uname -a`" + echo " PWD = `pwd`" + echo " HOSTNAME = `hostname`" + echo " TIME = `date`" + echo " PWD = `pwd`" + +} + +setJobId() { + # Save job ID information + if [[ -e JOBID.log ]] + then + JOBID=$(cat JOBID.log) + echo " JOBID = $JOBID" + echo "---------------------------------" + else + echo "No running jobs. Aborting." + exit 1 + fi +} + +do_kill() { + JOB_STATUS=$(qstat $JOBID | awk 'NR==3''{print $5}') + echo ">> Deleting $JOBID" + qdel $JOBID + echo ">> Job DELETED" + exit 0 +} + +do_monitor() { + typeset -i n=0 + typeset -i TIMEOUT=1000 + + # Check job status and wait for job start + while : + do + JOB_STATUS=$(qstat $JOBID | awk 'NR==3''{print $5}') + STATUS=${JOB_STATUS:=E} + #echo "STATUS = '$STATUS'" + case "$STATUS" in + C) + #tail -n +1 out.log + echo ">> Job $JOBID COMPLETED!" + + JOB_EXIT_STATUS=$(qstat -f $JOBID | awk '/exit_status/''{print $3}') + echo ">> Exit Status: $JOB_EXIT_STATUS" + exit $JOB_EXIT_STATUS + ;; + E) + echo ">> Job $JOBID ERROR!?" + + JOB_EXIT_STATUS=$(qstat -f $JOBID | awk '/exit_status/''{print $3}') + echo ">> Exit Status: $JOB_EXIT_STATUS" + exit $JOB_EXIT_STATUS + ;; + R) + echo ">> Job $JOBID RUNNING" + break 1 + ;; + *) + sleep 10 + echo ">> Job $JOBID QUEUED. Waiting." + ;; + esac + + if [[ $n -gt $TIMEOUT ]] + then + echo ">> EXIT: Timeout Exceeded!" + exit 1 + fi + n=$(echo "$n+1" | bc -l) + done + + #tail -n +1 -F out.log & + #PID=$! + while : + do + JOB_STATUS=$(qstat $JOBID | awk 'NR==3''{print $5}') + STATUS=${JOB_STATUS:=E} + #echo "STATUS = '$STATUS'" + case "$STATUS" in + C) + sleep 10 + echo ">> Job COMPLETED!" + JOB_EXIT_STATUS=$(qstat -f $JOBID | awk '/exit_status/''{print $3}') + echo ">> Exit Status: $JOB_EXIT_STATUS" + kill -9 $PID + exit $JOB_EXIT_STATUS + ;; + E) + echo ">> Job $JOBID ERROR!?" + + JOB_EXIT_STATUS=$(qstat -f $JOBID | awk '/exit_status/''{print $3}') + echo ">> Exit Status: $JOB_EXIT_STATUS" + exit $JOB_EXIT_STATUS + ;; + *) + sleep 10 + echo ">> Job RUNNING." + ;; + esac + done +} + +check_command() { + echo -n "Check command '$1': " + # Check if pbs commands are available + command -v $1 >/dev/null 2>&1 || { echo >&2 "Not installed! Aborting."; exit 1; } + echo "OK" +} + +do_launch() { + check_command "qsub" + check_command "qdel" + check_command "qstat" + + # Submit ELEMENTS job to PBS queue system + qsub < driver.pbs > JOBID.log + + setJobId + echo ">> Job SUBMITTED." +} + +case "$1" in + -kill) + HEADER + setJobId + do_kill + ;; + -launch) + HEADER + do_launch + do_monitor + ;; + -monitor) + HEADER + setJobId + do_monitor + ;; + *) + HEADER + do_launch + do_monitor + ;; +esac + +echo "Fail: Unexpected termination" +exit 1 \ No newline at end of file diff --git a/src/eu/engys/standardVOF/StandardVOFBoundaryConditionsView.java b/src/eu/engys/standardVOF/StandardVOFBoundaryConditionsView.java new file mode 100644 index 0000000..568c422 --- /dev/null +++ b/src/eu/engys/standardVOF/StandardVOFBoundaryConditionsView.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.standardVOF; + +import eu.engys.core.modules.boundaryconditions.BoundaryConditionsView; +import eu.engys.core.modules.boundaryconditions.BoundaryTypePanel; +import eu.engys.core.modules.boundaryconditions.IBoundaryConditionsPanel; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.BoundaryType; +import eu.engys.gui.casesetup.boundaryconditions.panels.patch.MomentumPatch; +import eu.engys.gui.casesetup.boundaryconditions.panels.wall.StandardMomentumWall; + +public class StandardVOFBoundaryConditionsView implements BoundaryConditionsView { + + private static final String MOMENTUM = " " + BoundaryTypePanel.MOMENTUM + " "; + private StandardVOFModule module; + + public StandardVOFBoundaryConditionsView(StandardVOFModule module) { + this.module = module; + } + + @Override + public void configure(BoundaryTypePanel panel) { + if (panel.getType() == BoundaryType.WALL) { + panel.addPanel(MOMENTUM, new VOFStandardMomentumWall(panel), 0); + } else if (panel.getType() == BoundaryType.PATCH) { + panel.addPanel(MOMENTUM, new VOFStandardMomentumPatch(panel), 0); + } + } + + class VOFStandardMomentumWall extends StandardMomentumWall { + public VOFStandardMomentumWall(BoundaryTypePanel parent) { + super(parent); + } + + @Override + public boolean isEnabled(Model model) { + return module.isVOF(); + } + } + + class VOFStandardMomentumPatch extends MomentumPatch { + + public VOFStandardMomentumPatch(BoundaryTypePanel parent) { + super(parent); + } + + @Override + public boolean isEnabled(Model model) { + return module.isVOF(); + } + } + + @Override + public void configure(IBoundaryConditionsPanel panel) { + } + +} diff --git a/src/eu/engys/standardVOF/StandardVOFModule.java b/src/eu/engys/standardVOF/StandardVOFModule.java new file mode 100644 index 0000000..cabe261 --- /dev/null +++ b/src/eu/engys/standardVOF/StandardVOFModule.java @@ -0,0 +1,194 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.standardVOF; + +import java.util.HashSet; +import java.util.Set; + +import javax.inject.Inject; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.FieldElement; +import eu.engys.core.modules.ApplicationModuleAdapter; +import eu.engys.core.modules.ModuleDefaults; +import eu.engys.core.modules.ModulePanel; +import eu.engys.core.modules.boundaryconditions.BoundaryConditionsView; +import eu.engys.core.modules.solutionmodelling.SolutionView; +import eu.engys.core.modules.tree.TreeView; +import eu.engys.core.project.Model; +import eu.engys.core.project.defaults.DefaultsProvider; +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.Solver; +import eu.engys.core.project.state.State; +import eu.engys.core.project.state.StateBuilder; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.fields.FieldsDefaults; +import eu.engys.gui.casesetup.phases.PhasesPanel; + +public class StandardVOFModule extends ApplicationModuleAdapter { + + private static final String MODULE_NAME = "standardVOF"; + + public static final String VOF_LABEL = "VOF"; + public static final String VOF_KEY = "VOF"; + + public static final Solver INTER_FOAM = new Solver("interFoam"); + public static final MultiphaseModel VOF_MODEL = new MultiphaseModel(VOF_LABEL, VOF_KEY, true, true); + + private StandardVOFSolutionView solutionView; + private StandardVOFBoundaryConditionsView boundaryConditionsView; + + private PhasesPanel phasesPanel; + private TreeView treeView; + + private double sigma; + + private Model model; + + private DefaultsProvider defaults; + private StandardVOFReader reader; + + @Inject + public StandardVOFModule(Model model) { + this.model = model; + this.solutionView = new StandardVOFSolutionView(this); + this.boundaryConditionsView = new StandardVOFBoundaryConditionsView(this); + + this.phasesPanel = new PhasesPanel(model, new StandardVOFPhasesView(this, model)); + this.treeView = new StandardVOFTreeView(this, phasesPanel); + + this.reader = new StandardVOFReader(model, this); + + this.defaults = new ModuleDefaults(this, model.getDefaults(), model.getDefaults().getDefaultStateData()) { + @Override + public Dictionary getDefaultsFieldMapsFor(State state, String region) { + Dictionary fieldMaps = super.getDefaultsFieldMapsFor(state, region); + fixAlphaFieldName(fieldMaps); + return fieldMaps; + } + }; + } + + private void fixAlphaFieldName(Dictionary fieldMaps) { + if (model.getState().getMultiphaseModel().isMultiphase() && model.getState().getPhases() > 1 && fieldMaps != null && fieldMaps.found(Fields.ALPHA)) { + String alpha = ((FieldElement) fieldMaps.remove(Fields.ALPHA)).getValue(); + fieldMaps.add(Fields.ALPHA + "." + model.getMaterials().getFirstMaterialName(), alpha); + } + } + + @Override + public String getName() { + return MODULE_NAME; + } + + @Override + public TreeView getTreeView() { + return treeView; + } + + @Override + public Set getCaseSetupPanels() { + Set panels = new HashSet<>(); + panels.add(phasesPanel); + return panels; + } + + @Override + public void updateSolver(State state) { + if (state.isTransient()) { + if (state.isIncompressible()) { + if (state.getMultiphaseModel().equals(VOF_MODEL)) { + state.setSolver(INTER_FOAM); + } + } + } + } + + @Override + public void loadState() { + reader.loadState(); + } + + @Override + public void loadMaterials() { + reader.loadMaterials(); + } + + @Override + public void save() { + new StandardVOFWriter(model, this).write(); + } + + @Override + public void write() { + } + + @Override + public void saveDefaultsToProject() { + if (isVOF()) { + StateBuilder.saveDefaultsToProject(model, defaults); + } else { + } + } + + @Override + public Fields loadDefaultsFields(String region) { + if (isVOF()) { + return FieldsDefaults.loadFieldsFromDefaults(model.getState(), defaults, model.getPatches(), region); + } else { + return new Fields(); + } + } + + @Override + public SolutionView getSolutionView() { + return solutionView; + } + + @Override + public BoundaryConditionsView getBoundaryConditionsView() { + return boundaryConditionsView; + } + + public boolean isVOF() { + return model.getState().getMultiphaseModel().equals(VOF_MODEL); + } + + public void setSigma(double sigma) { + this.sigma = sigma; + } + + public double getSigma() { + return sigma; + } + + /* + * For test purposes only + */ + public PhasesPanel getPhasesPanel() { + return phasesPanel; + } +} diff --git a/src/eu/engys/standardVOF/StandardVOFPhasesView.java b/src/eu/engys/standardVOF/StandardVOFPhasesView.java new file mode 100644 index 0000000..dcfbb5c --- /dev/null +++ b/src/eu/engys/standardVOF/StandardVOFPhasesView.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.standardVOF; + +import static eu.engys.core.project.constant.TransportProperties.SIGMA_KEY; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DimensionedScalar; +import eu.engys.core.dictionary.model.DictionaryModel; +import eu.engys.core.project.Model; +import eu.engys.gui.casesetup.phases.PhasesView; +import eu.engys.util.DimensionalUnits; +import eu.engys.util.ui.builder.PanelBuilder; + +public class StandardVOFPhasesView implements PhasesView { + + public static final String SURFACE_TENSION_LABEL = "Surface Tension [N/m]"; + + private static final Logger logger = LoggerFactory.getLogger(StandardVOFPhasesView.class); + + private Model model; + private StandardVOFModule module; + private DictionaryModel sigmaModel = new DictionaryModel(new Dictionary("")); + + private PanelBuilder parametersBuilder; + + public StandardVOFPhasesView(StandardVOFModule module, Model model) { + this.module = module; + this.model = model; + } + + @Override + public void layoutComponents(PanelBuilder parametersBuilder) { + this.parametersBuilder = parametersBuilder; + } + + @Override + public void load(Model model) { + if (module.isVOF()) { + _layoutComponents(); + _load(model); + } + } + + private void _layoutComponents() { + parametersBuilder.clear(); + parametersBuilder.addComponent(SURFACE_TENSION_LABEL, sigmaModel.bindDimensionedDouble(SIGMA_KEY, DimensionalUnits.KG_S2, 0D, Double.MAX_VALUE)); + } + + private void _load(Model model) { + Dictionary dict = new Dictionary(""); + dict.add(new DimensionedScalar(SIGMA_KEY, String.valueOf(module.getSigma()), DimensionalUnits.KG_S2)); + sigmaModel.setDictionary(dict); + } + + @Override + public void save(Model model) { + if (module.isVOF()) { + _save(model); + } + } + + private void _save(Model model) { + Dictionary sigmaDict = sigmaModel.getDictionary(); + if (sigmaDict.found(SIGMA_KEY)) { + module.setSigma(sigmaDict.lookupScalar(SIGMA_KEY).doubleValue()); + } + } + +} diff --git a/src/eu/engys/standardVOF/StandardVOFReader.java b/src/eu/engys/standardVOF/StandardVOFReader.java new file mode 100644 index 0000000..40e7111 --- /dev/null +++ b/src/eu/engys/standardVOF/StandardVOFReader.java @@ -0,0 +1,139 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.standardVOF; + +import static eu.engys.core.project.constant.ThermophysicalProperties.MATERIAL_NAME_KEY; +import static eu.engys.core.project.constant.TransportProperties.PHASES_KEY; +import static eu.engys.core.project.constant.TransportProperties.SIGMA_KEY; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.project.Model; +import eu.engys.core.project.constant.ConstantFolder; +import eu.engys.core.project.constant.TransportProperties; +import eu.engys.core.project.materials.Material; +import eu.engys.core.project.materials.Materials; + +public class StandardVOFReader { + + private static final Logger logger = LoggerFactory.getLogger(StandardVOFReader.class); + + private Model model; + private StandardVOFModule module; + + private TransportProperties transportProperties; + + public StandardVOFReader(Model model, StandardVOFModule module) { + this.model = model; + this.module = module; + } + + public void loadState() { + if (isVOF()) { + model.getState().setMultiphaseModel(StandardVOFModule.VOF_MODEL); + model.getState().setPhases(2); + } + } + + public void loadMaterials() { + if (isVOF()) { + if (model.getState().isIncompressible()) { + readIncompressibleMaterials(); + } else { + readCompressibleMaterials(); + } + } + } + + boolean isVOF() { + ConstantFolder constantFolder = model.getProject().getConstantFolder(); + TransportProperties transportProperties = constantFolder.getTransportProperties(); + if (transportProperties != null) { + if ((transportProperties.found(PHASES_KEY))) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + private void readIncompressibleMaterials() { + Materials materials = model.getMaterials(); + ConstantFolder constantFolder = model.getProject().getConstantFolder(); + transportProperties = constantFolder.getTransportProperties(); + + if (transportProperties.found(PHASES_KEY)) { + model.getState().setPhases(2); + + String phases = transportProperties.lookup(PHASES_KEY).replaceAll("\\(", "").replaceAll("\\)", "").trim(); + + Dictionary dict1 = new Dictionary(transportProperties.subDict(phases.split(" ")[0])); + if (!dict1.isEmpty()) { + if (!dict1.found(MATERIAL_NAME_KEY)) { + dict1.add(MATERIAL_NAME_KEY, "material1"); + } + String name1 = dict1.lookup(MATERIAL_NAME_KEY); + dict1.setName(name1); + materials.add(new Material(name1, dict1)); + } + + Dictionary dict2 = new Dictionary(transportProperties.subDict(phases.split(" ")[1])); + if (!dict2.isEmpty()) { + if (!dict2.found(MATERIAL_NAME_KEY)) { + dict2.add(MATERIAL_NAME_KEY, "material2"); + } + String name2 = dict2.lookup(MATERIAL_NAME_KEY); + dict2.setName(name2); + materials.add(new Material(name2, dict2)); + } + + if (transportProperties.found(SIGMA_KEY)) { + double sigma = transportProperties.lookupScalar(SIGMA_KEY).doubleValue(); + module.setSigma(sigma); + } else if (dict1.found(SIGMA_KEY)) { + double sigma = dict1.lookupScalar(SIGMA_KEY).doubleValue(); + module.setSigma(sigma); + } else if (dict2.found(SIGMA_KEY)) { + double sigma = dict2.lookupScalar(SIGMA_KEY).doubleValue(); + module.setSigma(sigma); + } + + model.materialsChanged(); + + } else { + logger.warn("Multiphase case but no phases found in transportProperties"); + } + } + + public void readCompressibleMaterials() { + logger.error("Multiphase Compressible not supported"); + } + +} diff --git a/src/eu/engys/standardVOF/StandardVOFSolutionView.java b/src/eu/engys/standardVOF/StandardVOFSolutionView.java new file mode 100644 index 0000000..d059de6 --- /dev/null +++ b/src/eu/engys/standardVOF/StandardVOFSolutionView.java @@ -0,0 +1,75 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.standardVOF; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.modules.solutionmodelling.AbstractSolutionView; +import eu.engys.core.modules.solutionmodelling.MultiphaseBuilder; +import eu.engys.core.project.state.MultiphaseModel; +import eu.engys.core.project.state.SolutionState; +import eu.engys.util.ui.textfields.SpinnerField; + +public class StandardVOFSolutionView extends AbstractSolutionView { + + private static final Logger logger = LoggerFactory.getLogger(StandardVOFSolutionView.class); + + private StandardVOFModule module; + private MultiphaseBuilder builder; + + public StandardVOFSolutionView(StandardVOFModule module) { + this.module = module; + } + + @Override + public void buildMultiphase(MultiphaseBuilder builder) { + this.builder = builder; + builder.addMultiphaseChoice(StandardVOFModule.VOF_MODEL); + } + + @Override + public void fixSolutionState(SolutionState ss) { + if (ss.areSolverTypeAndTimeAndFlowAndTurbulenceChoosen()) { + boolean isVOFState = ss.isTransient() && ss.isIncompressible(); + if (isVOFState) { + builder.enableChoice(StandardVOFModule.VOF_MODEL); + } else { + builder.disableChoice(StandardVOFModule.VOF_MODEL); + } + } + } + + @Override + public void fixMultiphase(MultiphaseModel mm) { + SpinnerField phasesNumber = builder.getPhasesField(); + if (mm.equals(StandardVOFModule.VOF_MODEL)) { + phasesNumber.setIntValue(2); + phasesNumber.setEnabled(false); + } + } + +} diff --git a/src/eu/engys/standardVOF/StandardVOFTreeView.java b/src/eu/engys/standardVOF/StandardVOFTreeView.java new file mode 100644 index 0000000..50b5f4f --- /dev/null +++ b/src/eu/engys/standardVOF/StandardVOFTreeView.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.standardVOF; + +import eu.engys.core.modules.ModulePanel; +import eu.engys.core.modules.tree.ModuleElementPanel; +import eu.engys.core.modules.tree.TreeView; +import eu.engys.gui.casesetup.phases.PhasesPanel; + +public class StandardVOFTreeView implements TreeView { + + private StandardVOFModule module; + private ModulePanel phasesPanel; + + public StandardVOFTreeView(StandardVOFModule module, PhasesPanel phasesPanel) { + this.module = module; + this.phasesPanel = phasesPanel; + } + + @Override + public void updateTree(ModuleElementPanel viewElementPanel) { + if (module.isVOF()) { + viewElementPanel.addPanel(phasesPanel); + } else { + viewElementPanel.removePanel(phasesPanel); + } + } + +} diff --git a/src/eu/engys/standardVOF/StandardVOFWriter.java b/src/eu/engys/standardVOF/StandardVOFWriter.java new file mode 100644 index 0000000..aa15350 --- /dev/null +++ b/src/eu/engys/standardVOF/StandardVOFWriter.java @@ -0,0 +1,101 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.standardVOF; + +import static eu.engys.core.project.constant.TransportProperties.PHASES_KEY; +import static eu.engys.core.project.constant.TransportProperties.SIGMA_KEY; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.dictionary.Dictionary; +import eu.engys.core.dictionary.DimensionedScalar; +import eu.engys.core.project.Model; +import eu.engys.core.project.constant.ConstantFolder; +import eu.engys.core.project.constant.TransportProperties; +import eu.engys.core.project.materials.Material; +import eu.engys.core.project.materials.Materials; + +public class StandardVOFWriter { + + private static final Logger logger = LoggerFactory.getLogger(StandardVOFWriter.class); + + private Model model; + private StandardVOFModule module; + + public StandardVOFWriter(Model model, StandardVOFModule module) { + this.model = model; + this.module = module; + + } + + public void write() { + if (module.isVOF()) { + if (model.getState().isIncompressible()) { + writeIncompressibleMaterials(); + } else { + writeCompressibleMaterials(); + } + } + } + + private void writeCompressibleMaterials() { + logger.error("Multiphase Compressible not supported"); + } + + private void writeIncompressibleMaterials() { + Materials materials = model.getMaterials(); + ConstantFolder constantFolder = model.getProject().getConstantFolder(); + TransportProperties transportProperties = constantFolder.getTransportProperties(); + + if (materials.size() == 2) { + transportProperties.clear(); + + Material mat1 = materials.get(0); + String mat1Name = mat1.getName(); + Material mat2 = materials.get(1); + String mat2Name = mat2.getName(); + + transportProperties.add(PHASES_KEY, "(" + mat1Name + " " + mat2Name + ")"); + + Dictionary dict1 = new Dictionary(mat1.getDictionary()); + dict1.remove(SIGMA_KEY); + dict1.setName(mat1Name); + transportProperties.add(dict1); + + Dictionary dict2 = new Dictionary(mat2.getDictionary()); + dict2.remove(SIGMA_KEY); + dict2.setName(mat2Name); + transportProperties.add(dict2); + + double sigmaValue = module.getSigma(); + transportProperties.add(new DimensionedScalar(SIGMA_KEY, String.valueOf(sigmaValue), "[1 0 -2 0 0 0 0 ]")); + + } else { + logger.warn("Multiphase solution choosen but '{}' materials found", materials.size()); + } + } +} diff --git a/src/eu/engys/standardVOF/resources/standardVOF.fields b/src/eu/engys/standardVOF/resources/standardVOF.fields new file mode 100644 index 0000000..6a910a8 --- /dev/null +++ b/src/eu/engys/standardVOF/resources/standardVOF.fields @@ -0,0 +1,130 @@ +U +{ + allowedFieldInitialisationMethods (default fixedValue ); + + initialisation + { + type default; + } + + + fieldDefinition + { + type vector; + dimensions [ 0 1 -1 0 0 0 0 ]; + internalField uniform (0 0 0); + + boundaryConditions + { + regionDefaults + { + wall {type fixedValue; value uniform (0 0 0);} + + outlet {type inletOutlet; inletValue uniform (0 0 0); value uniform (0 0 0);} + + inlet {type inletOutlet; inletValue uniform (0 0 0); value uniform (0 0 0);} + + patch {type pressureInletOutletVelocity; value uniform (0 0 0);} + + processor {type processor; value uniform (0 0 0);} + } + + partialNamed {} + + exactNamed{} + } + } +} + +pmultiphase +{ + allowedFieldInitialisationMethods (default fixedValue ); + + initialisation + { + type default; + } + + + fieldDefinition + { + type scalar; + dimensions [ 1 -1 -2 0 0 0 0 ]; + internalField uniform 0; + + boundaryConditions + { + regionDefaults + { + wall + { + type fixedFluxPressure; + value uniform 0; + } + + outlet {type fixedValue; value uniform 0;} + + inlet + { + type fixedFluxPressure; + value uniform 0; + } + + patch + { + type totalPressure; + p0 uniform 0; + U U; + value uniform 0; + phi phi; + rho rho; + psi none; + gamma 1; + } + + processor {type processor; value uniform 0;} + } + + partialNamed {} + + exactNamed{} + } + } +} + +phase +{ + allowedFieldInitialisationMethods (default fixedValue cellSet); + + initialisation + { + type fixedValue; value uniform 0; + } + + fieldDefinition + { + type scalar; + dimensions [ 0 0 0 0 0 0 0 ]; + internalField uniform 0; + + boundaryConditions + { + regionDefaults + { + wall {type zeroGradient;} + + outlet {type inletOutlet; inletValue uniform 0; value uniform 0;} + + inlet {type fixedValue; value uniform 0;} + + patch {type inletOutlet; inletValue uniform 0; value uniform 0;} + + processor {type processor; value uniform 0;} + } + + partialNamed {} + + exactNamed{} + } + } +} \ No newline at end of file diff --git a/src/eu/engys/standardVOF/resources/standardVOF.stateData b/src/eu/engys/standardVOF/resources/standardVOF.stateData new file mode 100644 index 0000000..4e7dffb --- /dev/null +++ b/src/eu/engys/standardVOF/resources/standardVOF.stateData @@ -0,0 +1,470 @@ +states +{ + interFoamRAS (transient incompressible ras VOF); + interFoamRAS2 (PIMPLE incompressible ras VOF); + interFoamRAS3 (PIMPLE incompressible ras multiphaseVOF); + + interFoamLES (transient incompressible les VOF); + interFoamLES2 (PIMPLE incompressible les VOF); + interFoamLES3 (PIMPLE incompressible les multiphaseVOF); + +} + + +"interFoamRAS.*" +{ + fieldMaps + { + U U; + p_rgh pmultiphase; + alpha phase; + } + materialProperties + { + air{} + water{} + } + system + { + controlDict + { + startFrom startTime; + startTime 0; + stopAt endTime; + endTime 10; + deltaT 0.001; + writeControl adjustableRunTime; + writeInterval 0.1; + purgeWrite 0; + writeFormat ascii; + writePrecision 10; + writeCompression uncompressed; + timeFormat general; + timePrecision 6; + graphFormat raw; + runTimeModifiable yes; + adjustTimeStep yes; + maxCo 0.5; + maxAlphaCo 0.25; + maxDeltaT 1.0; + } + fvSchemes + { + ddtSchemes {$fvSchemes_ddtSchemes_ras_trans;} + + gradSchemes + { + $fvSchemes_gradSchemes; + grad(U) cellLimited Gauss linear 1; + grad(rho) cellLimited Gauss linear 1; + grad(p_rgh) cellLimited Gauss linear 1; + grad(pcorr) cellLimited Gauss linear 1; + } + + divSchemes + { + $fvSchemes_divSchemes_trans; + div(rhoPhi,U) Gauss linearUpwindV grad(U); + div(phi,alpha) Gauss vanLeer; + div(phirb,alpha) Gauss interfaceCompression; + div((nuEff*dev(T(grad(U))))) Gauss linear; + } + + $fvSchemes_misc; + fluxRequired + { + default no; + p_rgh; + pcorr; + "alpha.*"; + } + } + fvSolution + { + PIMPLE + { + momentumPredictor no; + nCorrectors 2; + nOuterCorrectors 1; + nNonOrthogonalCorrectors 0; + nAlphaCorr 1; + nAlphaSubCycles 3; + cAlpha 1.5; + correctPhi yes; + pRefCell 0; + pRefValue 0; + + residualControl + { + "(U|k|epsilon|omega|nuTilda|T|p_rgh|p)" + { + relTol 0; + tolerance 1e-5; + } + "alpha.*" + { + relTol 0; + tolerance 1e-5; + } + } + + } + solvers + { + + $fvSolution_solvers_PIMPLE; + + pcorr + { + solver PCG; + preconditioner + { + preconditioner GAMG; + tolerance 1e-5; + relTol 0; + smoother DICGaussSeidel; + nPreSweeps 0; + nPostSweeps 2; + nFinestSweeps 2; + cacheAgglomeration false; + nCellsInCoarsestLevel 10; + agglomerator faceAreaPair; + mergeLevels 1; + } + + tolerance 1e-05; + relTol 0; + maxIter 100; + minIter 1; + } + + "alpha.*" + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0; + nSweeps 1; + minIter 1; + nAlphaCorr 1; + nAlphaSubCycles 3; + cAlpha 1.5; + } + } + relaxationFactors {$fvSolution_relaxationFactors_trans;} + + } + } + + constant + { + g{$g;} + transportProperties + { + sigma sigma [1 0 -2 0 0 0 0 ] 0.0; + } + } +} + +"interFoamLES.*" +{ + fieldMaps + { + U U; + p_rgh pmultiphase; + alpha phase; + } + materialProperties + { + air{} + water{} + } + system + { + controlDict + { + startFrom startTime; + startTime 0; + stopAt endTime; + endTime 10; + deltaT 0.001; + writeControl adjustableRunTime; + writeInterval 0.1; + purgeWrite 0; + writeFormat ascii; + writePrecision 10; + writeCompression uncompressed; + timeFormat general; + timePrecision 6; + graphFormat raw; + runTimeModifiable yes; + adjustTimeStep yes; + maxCo 0.5; + maxAlphaCo 0.25; + maxDeltaT 1.0; + } + fvSchemes + { + ddtSchemes {$fvSchemes_ddtSchemes_les;} + + gradSchemes + { + $fvSchemes_gradSchemes; + grad(U) cellLimited Gauss linear 1; + grad(rho) cellLimited Gauss linear 1; + grad(p_rgh) cellLimited Gauss linear 1; + grad(pcorr) cellLimited Gauss linear 1; + } + + divSchemes + { + $fvSchemes_divSchemes_trans; + div(rhoPhi,U) Gauss LUST grad(U); + div(phi,alpha) Gauss vanLeer; + div(phirb,alpha) Gauss interfaceCompression; + div((nuEff*dev(T(grad(U))))) Gauss linear; + } + + $fvSchemes_misc; + fluxRequired + { + default no; + p_rgh; + pcorr; + "alpha.*"; + } + } + fvSolution + { + PIMPLE + { + momentumPredictor no; + nCorrectors 5; + nOuterCorrectors 1; + nNonOrthogonalCorrectors 1; + nAlphaCorr 1; + nAlphaSubCycles 5; + cAlpha 1.5; + correctPhi yes; + pRefCell 0; + pRefValue 0; + + residualControl + { + "(U|k|epsilon|omega|nuTilda|T|p_rgh|p)" + { + relTol 0; + tolerance 1e-5; + } + "alpha.*" + { + relTol 0; + tolerance 1e-5; + } + } + + } + solvers + { + pcorr + { + solver PCG; + preconditioner + { + preconditioner GAMG; + tolerance 1e-5; + relTol 0; + smoother DICGaussSeidel; + nPreSweeps 0; + nPostSweeps 2; + nFinestSweeps 2; + cacheAgglomeration false; + nCellsInCoarsestLevel 10; + agglomerator faceAreaPair; + mergeLevels 1; + } + + tolerance 1e-05; + relTol 0; + maxIter 100; + minIter 1; + } + + p_rgh + { + solver GAMG; + tolerance 1e-8; + relTol 0.01; + smoother DIC; + nPreSweeps 0; + nPostSweeps 2; + nFinestSweeps 2; + cacheAgglomeration true; + nCellsInCoarsestLevel 10; + agglomerator faceAreaPair; + mergeLevels 1; + minIter 1; + } + + p_rghFinal + { + solver PCG; + preconditioner + { + preconditioner GAMG; + tolerance 1e-8; + relTol 0; + nVcycles 2; + smoother DICGaussSeidel; + nPreSweeps 2; + nPostSweeps 2; + nFinestSweeps 2; + cacheAgglomeration true; + nCellsInCoarsestLevel 10; + agglomerator faceAreaPair; + mergeLevels 1; + } + + tolerance 1e-8; + relTol 0; + maxIter 20; + minIter 1; + } + + U + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0.1; + nSweeps 1; + minIter 1; + } + k + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0.1; + nSweeps 1; + minIter 1; + } + kl + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0.1; + nSweeps 1; + minIter 1; + } + epsilon + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0.1; + nSweeps 1; + minIter 1; + } + nuTilda + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0.1; + nSweeps 1; + minIter 1; + } + omega + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0.1; + nSweeps 1; + minIter 1; + } + + + UFinal + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0; + nSweeps 1; + minIter 1; + } + kFinal + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0; + nSweeps 1; + minIter 1; + } + klFinal + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0; + nSweeps 1; + minIter 1; + } + epsilonFinal + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0; + nSweeps 1; + minIter 1; + } + nuTildaFinal + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0; + nSweeps 1; + minIter 1; + } + omegaFinal + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0; + nSweeps 1; + minIter 1; + } + "alpha.*" + { + solver smoothSolver; + smoother GaussSeidel; + tolerance 1e-6; + relTol 0; + nSweeps 1; + minIter 1; + nAlphaCorr 1; + nAlphaSubCycles 3; + cAlpha 1.5; + } + } + relaxationFactors {$fvSolution_relaxationFactors_trans;} + } + } + + constant + { + g{$g;} + transportProperties + { + sigma sigma [1 0 -2 0 0 0 0 ] 0.0; + } + } + +} \ No newline at end of file diff --git a/src/eu/engys/suite/Suite.java b/src/eu/engys/suite/Suite.java new file mode 100644 index 0000000..34058ce --- /dev/null +++ b/src/eu/engys/suite/Suite.java @@ -0,0 +1,138 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.suite; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.inject.Named; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +import com.google.inject.Inject; + +import eu.engys.core.Arguments; +import eu.engys.launcher.ApplicationLauncher; +import eu.engys.util.ui.UiUtil; + +public class Suite { + + private String product; + private ImageIcon icon; + private Set applications; + + @Inject + public Suite(@Named("Product") String product, @Named("Product") ImageIcon icon, Set applications) { + this.product = product; + this.icon = icon; + this.applications = applications; + } + + protected Set getApplications() { + return applications; + } + + public void batch() { +// if (applications.size() == 1) { + try { + ApplicationLauncher application = applications.iterator().next(); + application.batch(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(-1); + } +// } else { +// System.err.println("Only suites with one application can run batch. Exit"); +// System.exit(0); +// } + } + + public void launch() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (applications.size() == 1 || Arguments.baseDir != null) { + try { + ApplicationLauncher application = applications.iterator().next(); + application.checkLicense(); + application.launch(); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + JFrame frame = createAndShowFrame(); + UiUtil.centerAndShow(frame); + } + } + }); + } + + protected JFrame createAndShowFrame() { + JFrame frame = new JFrame(product); + List actions = createActions(); + + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(new SuitePanel(actions, "Select Application"), BorderLayout.CENTER); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setIconImage(icon.getImage()); + frame.setResizable(false); + return frame; + } + + private List createActions() { + List actions = new ArrayList(); + for (final ApplicationLauncher app : applications) { + AbstractAction action = new AbstractAction(app.getTitle(), app.getIcon()) { + @Override + public void actionPerformed(ActionEvent e) { + SwingUtilities.getWindowAncestor((Component) e.getSource()).setVisible(false); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + app.checkLicense(); + app.launch(); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + }); + } + }; + actions.add(action); + } + return actions; + } + +} diff --git a/src/eu/engys/suite/SuitePanel.java b/src/eu/engys/suite/SuitePanel.java new file mode 100644 index 0000000..829fb1c --- /dev/null +++ b/src/eu/engys/suite/SuitePanel.java @@ -0,0 +1,141 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.suite; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JPanel; + +import com.google.inject.Inject; + +public class SuitePanel extends JPanel { + + public static final ImageIcon BANNER = new ImageIcon(SuitePanel.class.getClassLoader().getResource("eu/engys/resources/elements_banner.png")); + public static final ImageIcon BG_IMAGE = new ImageIcon(SuitePanel.class.getClassLoader().getResource("eu/engys/resources/elements_startup.png")); + + private List actions; + private String title; + + @Inject + public SuitePanel(List actions, String title) { + super(new BorderLayout()); + this.actions = actions; + this.title = title; + layoutComponents(); + } + + public void layoutComponents() { + JPanel topPanel = createTopPanel(); + JPanel centerPanel = createCenterPanel(); + add(topPanel, BorderLayout.NORTH); + add(centerPanel, BorderLayout.CENTER); + } + + private JPanel createTopPanel() { + JPanel panel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + setOpaque(false); + g.drawImage(BANNER.getImage(), (getWidth() - BANNER.getImage().getWidth(null)) / 2, 0, null); + super.paintComponent(g); + } + }; + panel.setPreferredSize(new Dimension(BANNER.getImage().getWidth(null), BANNER.getImage().getHeight(null))); + return panel; + } + + protected JPanel createCenterPanel() { + JPanel containerPanel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + setOpaque(false); + g.drawImage(BG_IMAGE.getImage(), (getWidth() - BG_IMAGE.getImage().getWidth(null)) - 10, getHeight() - BG_IMAGE.getImage().getHeight(null), null); + super.paintComponent(g); + } + }; + containerPanel.setLayout(new BorderLayout()); + containerPanel.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 25)); + + int width = actions.size() >= 3 ? 700 : BG_IMAGE.getImage().getWidth(null); + int height= 260 * (((actions.size() - 1) / 3) + 1); + containerPanel.setPreferredSize(new Dimension(width, height)); + + JPanel titlePanel = new JPanel(new GridBagLayout()); + titlePanel.setBorder(BorderFactory.createTitledBorder(title)); + titlePanel.setOpaque(false); + containerPanel.add(titlePanel, BorderLayout.CENTER); + + JPanel buttonsPanel = createButtonsPanel(); + titlePanel.add(buttonsPanel, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(10, 10, 10, 10), 0, 0)); + + return containerPanel; + } + + private JPanel createButtonsPanel() { + List buttons = createButtons(); + + int colNumber = 3; + int rows = ((buttons.size() - 1) / colNumber) + 1; + int cols = Math.min(buttons.size(), colNumber); + + JPanel panel = new JPanel(new GridLayout(rows, cols, 30, 30)); + panel.setOpaque(false); + + for (JButton button : buttons) { + button.setName("suite." + button.getText()); + button.setHorizontalTextPosition(JButton.CENTER); + button.setVerticalTextPosition(JButton.BOTTOM); + button.setFocusable(false); + panel.add(button); + } + return panel; + } + + private List createButtons() { + List buttons = new ArrayList(); + for (Action action : actions) { + final JButton button = new JButton(); + button.setAction(action); + //button.setOpaque(true); + buttons.add(button); + } + return buttons; + } + +} diff --git a/src/eu/engys/util/ApplicationInfo.java b/src/eu/engys/util/ApplicationInfo.java new file mode 100644 index 0000000..b98f2a7 --- /dev/null +++ b/src/eu/engys/util/ApplicationInfo.java @@ -0,0 +1,257 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util; + +import java.io.File; +import java.net.InetAddress; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.UnknownHostException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.Scanner; + +import org.apache.commons.io.FileUtils; + +import eu.engys.util.ui.ASCIIArt; + +public class ApplicationInfo { + + private static final String DEFAULT_COPYRIGHT = "productCopyright"; + private static final String DEFAULT_SITE = "productSite"; + private static final String DEFAULT_MAIL = "productMail"; + private static final String DEFAULT_NUMBER = "-1"; + private static final String DEFAULT_VENDOR = "productVendor"; + private static final String DEFAULT_NAME = "productName"; + private static final String BUILD_KEY = "build"; + private static final String VERSION_KEY = "version"; + private static final String COPYRIGHT_KEY = "copyright"; + private static final String SITE_KEY = "site"; + private static final String MAIL_KEY = "mail"; + private static final String VENDOR_KEY = "vendor"; + private static final String NAME_KEY = "name"; + + private static String name; + private static String vendor; + private static String versionNumber; + private static String majorNumber; + private static String minorNumber; + private static String buildDate; + private static String mail; + private static String site; + private static String copyright; + + public static void init() { + try { + ResourceBundle version = ResourceBundle.getBundle("eu.engys.resources.version"); + name = version.getString(NAME_KEY); + vendor = version.getString(VENDOR_KEY); + mail = version.getString(MAIL_KEY); + site = version.getString(SITE_KEY); + copyright = version.getString(COPYRIGHT_KEY); + + String v = version.getString(VERSION_KEY); + + try (Scanner s = new Scanner(v)) { + s.useDelimiter("\\."); + versionNumber = s.next(); + majorNumber = s.next(); + minorNumber = s.next(); + } catch (Exception e) { + name = DEFAULT_NAME; + vendor = DEFAULT_VENDOR; + versionNumber = DEFAULT_NUMBER; + majorNumber = DEFAULT_NUMBER; + minorNumber = DEFAULT_NUMBER; + mail = DEFAULT_MAIL; + site = DEFAULT_SITE; + copyright = DEFAULT_COPYRIGHT; + } + + buildDate = version.getString(BUILD_KEY); + } catch (Exception e) { + e.printStackTrace(); + name = DEFAULT_NAME; + vendor = DEFAULT_VENDOR; + versionNumber = DEFAULT_NUMBER; + majorNumber = DEFAULT_NUMBER; + minorNumber = DEFAULT_NUMBER; + mail = DEFAULT_MAIL; + site = DEFAULT_SITE; + copyright = DEFAULT_COPYRIGHT; + } + } + + public static String getTitle() { + return name != null ? ASCIIArt.toAA(name) : ""; + } + + public static String getName() { + return name != null ? name : DEFAULT_NAME; + } + + public static String getLicenseServerName() { + return name != null ? name + "_LICENSE_SERVER_NAME" : DEFAULT_NAME; + } + + public static String getLicenseServerPort() { + return name != null ? name + "_LICENSE_SERVER_PORT" : DEFAULT_NAME; + } + + public static String getVendor() { + return vendor != null ? vendor : DEFAULT_VENDOR; + } + + public static String getMail() { + return mail != null ? mail : DEFAULT_MAIL; + } + + public static String getSite() { + return site != null ? site : DEFAULT_SITE; + } + + public static String getCopyright() { + return copyright != null ? copyright : DEFAULT_COPYRIGHT; + } + + public static String getVersionRelease() { + return versionNumber; + } + + public static String getVersionMajor() { + return majorNumber; + } + + public static String getVersionMinor() { + return minorNumber; + } + + public static String getBuildDate() { + return buildDate; + } + + public static String getVersion() { + return "v" + versionNumber + "." + majorNumber + "." + minorNumber; + } + + public static String getRootPath() { + URL appJarURL = ApplicationInfo.class.getProtectionDomain().getCodeSource().getLocation(); + File appJarFile; + try { + appJarFile = new File(appJarURL.toURI()); + } catch (URISyntaxException e) { + appJarFile = new File(appJarURL.getPath()); + } + return appJarFile.getParentFile().getParent(); + } + + public static File getHome() { + String userHome = FileUtils.getUserDirectoryPath(); + File userDir; + try { + userDir = new File(userHome, "." + getName()); + } catch (Exception e) { + userDir = new File(userHome, ".test"); + } + + if (!userDir.exists()) { + userDir.mkdirs(); + } + + return userDir; + } + + public static File getPrefsFile() { + final File userHome = getHome(); + final File userPrefs = new File(userHome, "application.properties"); + return userPrefs; + } + + public static String getHeaderInfo() { + StringBuilder sb = new StringBuilder(); + sb.append(getTitle()); + sb.append("\n PRODUCT"); + sb.append("\n -----------------------------------------------------"); + sb.append("\n Name: " + getName()); + sb.append("\n Vendor: " + getVendor()); + sb.append("\n Release Date: " + getBuildDate()); + sb.append("\n Version: " + getVersion()); + sb.append("\n Mail: " + getMail()); + sb.append("\n Site: " + getSite()); + sb.append("\n Copyright: " + getCopyright()); + sb.append("\n"); + sb.append("\n SYSTEM"); + sb.append("\n -----------------------------------------------------"); + sb.append("\n Date: " + new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy").format(new Date())); + sb.append("\n OS: " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch")); + sb.append("\n Language " + Locale.getDefault().getLanguage()); + sb.append("\n Country " + Locale.getDefault().getCountry()); + sb.append("\n"); + String hostName = ""; + String hostIp = ""; + try { + InetAddress address = InetAddress.getLocalHost(); + hostName = address.getHostName(); + hostIp = address.getHostAddress(); + } catch (UnknownHostException ex) { + hostName = "UNKNOWN"; + hostIp = "UNKNOWN"; + } + sb.append("\n NETWORK"); + sb.append("\n -----------------------------------------------------"); + sb.append("\n Hostname " + hostName); + sb.append("\n Ip " + hostIp); + sb.append("\n"); + sb.append("\n JAVA"); + sb.append("\n -----------------------------------------------------"); + sb.append("\n Version " + System.getProperty("java.version")); + sb.append("\n Vendor " + System.getProperty("java.vendor")); + sb.append("\n Home " + System.getProperty("java.home")); + sb.append("\n ClassVersion " + System.getProperty("java.class.version")); + sb.append("\n ClassPath " + getClassPath()); + sb.append("\n"); + sb.append("\n USER"); + sb.append("\n -----------------------------------------------------"); + sb.append("\n Name " + System.getProperty("user.name")); + sb.append("\n Home " + System.getProperty("user.home")); + sb.append("\n Dir " + System.getProperty("user.dir")); + if (System.getProperty("license.status") != null) { + sb.append("\n LICENSE"); + sb.append("\n -----------------------------------------------------"); + sb.append("\n " + System.getProperty("license.status")); + sb.append("\n Register " + System.getProperty("license.register")); + sb.append("\n Exp. Date " + System.getProperty("license.exp.date")); + } + return sb.toString(); + } + + public static String getClassPath() { + return System.getProperty("java.class.path").replace(File.pathSeparator, "\n "); + } +} diff --git a/src/eu/engys/util/ArchiveUtils.java b/src/eu/engys/util/ArchiveUtils.java new file mode 100644 index 0000000..9fa5568 --- /dev/null +++ b/src/eu/engys/util/ArchiveUtils.java @@ -0,0 +1,363 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveOutputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; +import org.apache.commons.compress.utils.IOUtils; +import org.apache.commons.io.FilenameUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ArchiveUtils { + + private final static int BUFFER = 2048; + + public static final String ZIP = "zip"; + public static final String BZ2 = "bz2"; + public static final String TAR = "tar"; + public static final String GZ = "gz"; + + private static final Logger logger = LoggerFactory.getLogger(ArchiveUtils.class); + + public static List unarchive(File archiveFile, File destinationDir) { + return unarchive(archiveFile, destinationDir, ""); + } + + public static List unarchive(File archiveFile, File destinationDir, String prefix) { + String fileName = archiveFile.getName(); + if (isZip(fileName)) { + return unzip(archiveFile, destinationDir, prefix); + } + if (isTarGz(fileName)) { + return untarGZ(archiveFile, destinationDir, prefix); + } + if (isTarBz2(fileName)) { + return untarBZ2(archiveFile, destinationDir, prefix); + } + if (isGz(fileName)) { + return unGZ(archiveFile, destinationDir, prefix); + } + logger.error("Unknown archive type"); + return new ArrayList<>(); + } + + /* + * ZIP + */ + + public static void zip(File zipFile, File... sourceFiles) { + try { + ZipArchiveOutputStream zOut = new ZipArchiveOutputStream(zipFile); + for (File file : sourceFiles) { + addToZipArchive(zOut, file, ""); + } + IOUtils.closeQuietly(zOut); + } catch (IOException e) { + logger.error("Error creating archive", e); + } + } + + public static List unzip(File zipFile, File destinationDir) { + return unzip(zipFile, destinationDir, ""); + } + + public static List unzip(File zipFile, File destinationDir, String prefix) { + try { + ZipFile zip = new ZipFile(zipFile); + return extractFromZipArchive(destinationDir, zip, prefix); + } catch (IOException e) { + logger.error("Error creating archive", e); + } + return new ArrayList<>(); + } + + /* + * TAR.BZ2 + */ + + public static void tarBZ2(File tarBZ2File, File... sourceFiles) { + try { + FileOutputStream fOut = new FileOutputStream(tarBZ2File); + BufferedOutputStream bOut = new BufferedOutputStream(fOut); + BZip2CompressorOutputStream bz2Out = new BZip2CompressorOutputStream(bOut); + TarArchiveOutputStream tOut = new TarArchiveOutputStream(bz2Out); + + for (File file : sourceFiles) { + addToTarArchive(tOut, file, ""); + } + + IOUtils.closeQuietly(tOut); + IOUtils.closeQuietly(bz2Out); + IOUtils.closeQuietly(bOut); + IOUtils.closeQuietly(fOut); + } catch (IOException e) { + logger.error("Error creating archive", e); + } + } + + public static List untarBZ2(File tarBZ2File, File destinationDir) { + return untarBZ2(tarBZ2File, destinationDir, ""); + } + + public static List untarBZ2(File tarBZ2File, File destinationDir, String prefix) { + try { + InputStream fin = new FileInputStream(tarBZ2File); + InputStream in = new BufferedInputStream(fin); + InputStream bz2In = new BZip2CompressorInputStream(in); + return extractFromTarArchive(destinationDir, new TarArchiveInputStream(bz2In), prefix); + } catch (IOException e) { + logger.error("Error creating archive", e); + } + return new ArrayList<>(); + } + + /* + * TAR.GZ + */ + + public static void tarGZ(File tarGZFile, File... sourceFiles) { + try { + FileOutputStream fOut = new FileOutputStream(tarGZFile); + BufferedOutputStream bOut = new BufferedOutputStream(fOut); + GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(bOut); + TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut); + + for (File file : sourceFiles) { + addToTarArchive(tOut, file, ""); + } + + IOUtils.closeQuietly(tOut); + IOUtils.closeQuietly(gzOut); + IOUtils.closeQuietly(bOut); + IOUtils.closeQuietly(fOut); + } catch (IOException e) { + logger.error("Error creating archive", e); + } + } + + public static List untarGZ(File tarGZFile, File destinationDir) { + return untarGZ(tarGZFile, destinationDir, ""); + } + + public static List untarGZ(File tarGZFile, File destinationDir, String prefix) { + try { + FileInputStream fin = new FileInputStream(tarGZFile); + BufferedInputStream in = new BufferedInputStream(fin); + GzipCompressorInputStream gzIn = new GzipCompressorInputStream(in); + return extractFromTarArchive(destinationDir, new TarArchiveInputStream(gzIn), prefix); + } catch (IOException e) { + logger.error("Error creating archive", e); + } + return new ArrayList<>(); + } + + /* + * GZ + */ + + public static void gz(File gzFile, File sourceFile) { + try { + FileOutputStream fOut = new FileOutputStream(gzFile); + BufferedOutputStream bOut = new BufferedOutputStream(fOut); + GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(bOut); + FileInputStream fin = new FileInputStream(sourceFile); + + IOUtils.copy(fin, gzOut); + + IOUtils.closeQuietly(fin); + IOUtils.closeQuietly(gzOut); + IOUtils.closeQuietly(bOut); + IOUtils.closeQuietly(fOut); + } catch (IOException e) { + logger.error("Error creating archive", e); + } + } + + public static List unGZ(File tarGZFile, File destinationDir) { + return unGZ(tarGZFile, destinationDir, ""); + } + + public static List unGZ(File gzFile, File destinationDir, String prefix) { + try { + FileInputStream fin = new FileInputStream(gzFile); + BufferedInputStream in = new BufferedInputStream(fin); + GzipCompressorInputStream gzIn = new GzipCompressorInputStream(in); + + File newFile = new File(destinationDir, prefix + FilenameUtils.removeExtension(gzFile.getName())); + copyInputStreamToOutputStream(gzIn, newFile); + + IOUtils.closeQuietly(gzIn); + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(fin); + + return Arrays.asList(new File[] { newFile }); + + } catch (IOException e) { + logger.error("Error creating archive", e); + } + return new ArrayList<>(); + } + + /* + * Utils + */ + + private static boolean isZip(String fileName) { + return FilenameUtils.getExtension(fileName).equalsIgnoreCase(ZIP); + } + + private static boolean isGz(String fileName) { + String firstExtension = FilenameUtils.getExtension(fileName); + String secondExtension = FilenameUtils.getExtension(FilenameUtils.removeExtension(fileName)); + return firstExtension.equals(GZ) && !secondExtension.equals(TAR); + } + + private static boolean isTarGz(String fileName) { + String firstExtension = FilenameUtils.getExtension(fileName); + String secondExtension = FilenameUtils.getExtension(FilenameUtils.removeExtension(fileName)); + return firstExtension.equals(GZ) && secondExtension.equals(TAR); + } + + private static boolean isTarBz2(String fileName) { + String firstExtension = FilenameUtils.getExtension(fileName); + String secondExtension = FilenameUtils.getExtension(FilenameUtils.removeExtension(fileName)); + return firstExtension.equals(BZ2) && secondExtension.equals(TAR); + } + + public static boolean isArchive(File file) { + return isZip(file.getName()) || isGz(file.getName()) || isTarGz(file.getName()) || isTarBz2(file.getName()); + } + + private static void addToZipArchive(ArchiveOutputStream zOut, File fileToAdd, String basePath) throws IOException { + String entryName = basePath + fileToAdd.getName(); + + ArchiveEntry entry = new ZipArchiveEntry(fileToAdd, entryName); + zOut.putArchiveEntry(entry); + + if (fileToAdd.isFile()) { + FileInputStream fInputStream = new FileInputStream(fileToAdd); + IOUtils.copy(fInputStream, zOut); + zOut.closeArchiveEntry(); + IOUtils.closeQuietly(fInputStream); + } else { + zOut.closeArchiveEntry(); + for (File child : fileToAdd.listFiles()) { + addToZipArchive(zOut, child, entryName + File.separator); + } + } + } + + private static void addToTarArchive(ArchiveOutputStream zOut, File fileToAdd, String basePath) throws IOException { + String entryName = basePath + fileToAdd.getName(); + + ArchiveEntry entry = new TarArchiveEntry(fileToAdd, entryName); + zOut.putArchiveEntry(entry); + + if (fileToAdd.isFile()) { + FileInputStream fInputStream = new FileInputStream(fileToAdd); + IOUtils.copy(fInputStream, zOut); + zOut.closeArchiveEntry(); + IOUtils.closeQuietly(fInputStream); + } else { + zOut.closeArchiveEntry(); + for (File child : fileToAdd.listFiles()) { + addToTarArchive(zOut, child, entryName + File.separator); + } + } + } + + private static List extractFromTarArchive(File destinationDir, TarArchiveInputStream tarIn, String prefix) throws IOException { + List extractedFiles = new ArrayList<>(); + ArchiveEntry entry = null; + while ((entry = (ArchiveEntry) tarIn.getNextEntry()) != null) { + File entryFile = new File(destinationDir, prefix + entry.getName()); + if (entry.isDirectory()) { + entryFile.mkdirs(); + } else { + entryFile.getParentFile().mkdirs(); + entryFile.createNewFile(); + copyInputStreamToOutputStream(tarIn, entryFile); + + extractedFiles.add(entryFile); + } + } + tarIn.close(); + return extractedFiles; + } + + private static List extractFromZipArchive(File destinationDir, ZipFile zipFile, String prefix) throws IOException { + List extractedFiles = new ArrayList<>(); + List entries = Collections.list(zipFile.getEntries()); + for (ZipArchiveEntry entry : entries) { + File entryFile = new File(destinationDir, prefix + entry.getName()); + if (entry.isDirectory()) { + entryFile.mkdirs(); + } else { + entryFile.getParentFile().mkdirs(); + entryFile.createNewFile(); + + InputStream is = zipFile.getInputStream(entry); + copyInputStreamToOutputStream(is, entryFile); + IOUtils.closeQuietly(is); + + extractedFiles.add(entryFile); + } + } + zipFile.close(); + return extractedFiles; + } + + private static void copyInputStreamToOutputStream(InputStream is, File outputFile) throws IOException { + FileOutputStream fos = new FileOutputStream(outputFile); + BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER); + IOUtils.copy(is, bos); + IOUtils.closeQuietly(bos); + } + +} diff --git a/src/eu/engys/util/ColorUtil.java b/src/eu/engys/util/ColorUtil.java new file mode 100644 index 0000000..e07c4f9 --- /dev/null +++ b/src/eu/engys/util/ColorUtil.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; + +public class ColorUtil { + + private static final List colors = new ArrayList<>(); + + static { + colors.add(Color.RED); + colors.add(Color.BLUE); + colors.add(Color.GREEN); + colors.add(Color.YELLOW); + colors.add(Color.PINK); + colors.add(Color.CYAN); + colors.add(Color.MAGENTA); + colors.add(Color.ORANGE); + colors.add(Color.RED.darker()); + colors.add(Color.BLUE.darker()); + colors.add(Color.GREEN.darker()); + colors.add(Color.YELLOW.darker()); + colors.add(Color.PINK.darker()); + colors.add(Color.CYAN.darker()); + colors.add(Color.MAGENTA.darker()); + colors.add(Color.ORANGE.darker()); + } + + public static Color getColor(int index) { + Color color = colors.size() > index ? colors.get(index) : null; + return color; + } + +} diff --git a/src/eu/engys/util/CompactCharSequence.java b/src/eu/engys/util/CompactCharSequence.java new file mode 100644 index 0000000..ba2b094 --- /dev/null +++ b/src/eu/engys/util/CompactCharSequence.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; + +public class CompactCharSequence implements CharSequence, Serializable { + + static final long serialVersionUID = 1L; + + private static final String ENCODING = "ISO-8859-1"; + private final int offset; + private final int end; + private final byte[] data; + + public CompactCharSequence(String str) { + try { + data = str.getBytes(ENCODING); + offset = 0; + end = data.length; + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Unexpected: " + ENCODING + " not supported!"); + } + } + + public CompactCharSequence(byte[] data, int offset, int end) { + this.data = data; + this.offset = offset; + this.end = end; + } + + public char charAt(int index) { + int ix = index+offset; + if (ix >= end) { + throw new StringIndexOutOfBoundsException("Invalid index " + + index + " length " + length()); + } + return (char) (data[ix] & 0xff); + } + + public int length() { + return end - offset; + } + + public CharSequence subSequence(int start, int end) { + if (start < 0 || end > (this.end-offset)) { + throw new IllegalArgumentException("Illegal range " + + start + "-" + end + " for sequence of length " + length()); + } + return new CompactCharSequence(data, start + offset, end + offset); + } + + public String toString() { + try { + return new String(data, offset, end-offset, ENCODING); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Unexpected: " + ENCODING + " not supported"); + } + } + + public void getBytes(int srcBegin, int srcEnd, byte[] dst, int dstBegin) + { + if (srcBegin < 0) + throw new StringIndexOutOfBoundsException(srcBegin); + if ((srcEnd < 0) || (srcEnd > end)) + throw new StringIndexOutOfBoundsException(srcEnd); + if (srcBegin > srcEnd) + throw new StringIndexOutOfBoundsException("srcBegin > srcEnd"); + + System.arraycopy(data, srcBegin, dst, dstBegin, srcEnd - srcBegin); + } +} diff --git a/src/eu/engys/util/CompactStringBuilder.java b/src/eu/engys/util/CompactStringBuilder.java new file mode 100644 index 0000000..fd2a247 --- /dev/null +++ b/src/eu/engys/util/CompactStringBuilder.java @@ -0,0 +1,107 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import java.util.Arrays; + + +public class CompactStringBuilder { + + /** + * The value is used for character storage. + */ + byte[] value; + + /** + * The count is the number of characters used. + */ + int count; + + /** + * Creates an CompactStringBuilder of 16 . + */ + public CompactStringBuilder() { + value = new byte[16]; + } + + /** + * Creates an CompactStringBuilder of the specified capacity. + */ + public CompactStringBuilder(int capacity) { + value = new byte[capacity]; + } + + public int length() { + return count; + } + + public void append(String str) { + if (str == null) str = "null"; + int len = str.length(); + + ensureCapacityInternal(count + len); + + CompactCharSequence compactString = new CompactCharSequence(str); + compactString.getBytes(0, len, value, count); + + count += len; + } + + /** + * This method has the same contract as ensureCapacity, but is + * never synchronized. + */ + private void ensureCapacityInternal(int minimumCapacity) { + // overflow-conscious code + if (minimumCapacity - value.length > 0) + expandCapacity(minimumCapacity); + } + + /** + * This implements the expansion semantics of ensureCapacity with no + * size check or synchronization. + */ + void expandCapacity(int minimumCapacity) { + int newCapacity = value.length * 2 + 2; + if (newCapacity - minimumCapacity < 0) + newCapacity = minimumCapacity; + if (newCapacity < 0) { + if (minimumCapacity < 0) // overflow + throw new OutOfMemoryError(); + newCapacity = Integer.MAX_VALUE; + } + value = Arrays.copyOf(value, newCapacity); + } + + @Override + public String toString() { + return new CompactCharSequence(value, 0, count).toString(); + } + + public CharSequence toCompactCharSequence() { + return new CompactCharSequence(value, 0, count); + } +} diff --git a/src/eu/engys/util/DimensionalUnits.java b/src/eu/engys/util/DimensionalUnits.java new file mode 100644 index 0000000..7bab234 --- /dev/null +++ b/src/eu/engys/util/DimensionalUnits.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +public class DimensionalUnits { + + /* + * [ + * 0 -> Mass [kg] + * 0 -> Length [m] + * 0 -> Time [s] + * 0 -> Temperature [K] + * 0 -> Quantity [kg-mol] + * 0 -> Current [A] + * 0 -> Luminous Intensity (cd) + * ] + */ + + public static final String NONE = "[0 0 0 0 0 0 0]"; + public static final String _K = "[0 0 0 -1 0 0 0]"; + public static final String K = "[0 0 0 1 0 0 0]"; + public static final String S = "[0 0 1 0 0 0 0]"; + public static final String _M = "[0 -1 0 0 0 0 0]"; + public static final String _M2 = "[0 -2 0 0 0 0 0]"; + public static final String M2_S = "[0 2 -1 0 0 0 0]"; + public static final String M2_S2 = "[0 2 -2 0 0 0 0]"; + public static final String M2_S2K = "[0 2 -2 -1 0 0 0]"; + + public static final String KG_S2 = "[1 0 -2 0 0 0 0]"; + public static final String KG_M3 = "[1 -3 0 0 0 0 0]"; + public static final String KG_MS = "[1 -1 -1 0 0 0 0]"; + public static final String KG_MS2 = "[1 -1 -2 0 0 0 0]"; + public static final String KGM_S3K = "[1 1 -3 -1 0 0 0]"; + + +} diff --git a/src/eu/engys/util/FormatUtil.java b/src/eu/engys/util/FormatUtil.java new file mode 100644 index 0000000..f6bc9fb --- /dev/null +++ b/src/eu/engys/util/FormatUtil.java @@ -0,0 +1,115 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +public class FormatUtil { + + private static final DecimalFormat decFormat = new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.US)); + private static final DecimalFormat centsFormat = new DecimalFormat("#.##", new DecimalFormatSymbols(Locale.US)); + private static final DecimalFormat millisFormat = new DecimalFormat("#.###", new DecimalFormatSymbols(Locale.US)); + + public interface Formatter { + String toCents(); + String toMillis(); + } + + private static class FormatterImpl implements Formatter { + + private double value; + + public FormatterImpl(double value) { + this.value = value; + } + + @Override + public String toCents() { + return centsFormat.format(value); + } + + @Override + public String toMillis() { + return millisFormat.format(value); + } + + @Override + public String toString() { + return toCents(); + } + } + + private static class ArrayFormatterImpl implements Formatter { + + private double[] value; + + public ArrayFormatterImpl(double[] value) { + this.value = value; + } + + @Override + public String toCents() { + return format(centsFormat); + } + + @Override + public String toMillis() { + return format(millisFormat); + } + + private String format(DecimalFormat format){ + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i=0; i lines = Arrays.asList(text.split(lineEnding)); + writeLinesToFile(file, lines); + } + + public static void writeLinesToFile(File file, List lines) { + String lineEnding = Util.isWindowsScriptStyle() ? WIN_EOL : EOL; + try { + FileUtils.writeLines(file, null, lines, lineEnding); + } catch (IOException e) { + logger.error("Error writing file {}: {} ", file, e.getMessage()); + } + } + + /* + * Read File + */ + + public static List readLinesFromFile(File file) { + try { + return FileUtils.readLines(file, (Charset) null); + } catch (IOException e) { + logger.error("Error reading file {}: {} ", file, e.getMessage()); + } + return Collections.emptyList(); + } + + public static String readStringFromFile(File file) { + try { + return FileUtils.readFileToString(file, (Charset) null); + } catch (IOException e) { + logger.error("Error reading file {}: {} ", file, e.getMessage()); + } + return ""; + } + + public static String readStringFromStream(InputStream input) throws IOException { + return org.apache.commons.io.IOUtils.toString(input); + } + + public static File getSupportFile(File pwd) { + String extension = Util.isWindows() ? ".bat" : ".run"; + String name = "temp" + System.currentTimeMillis() + extension; + return new File(pwd, name); + } + +} diff --git a/src/eu/engys/util/LineSeparator.java b/src/eu/engys/util/LineSeparator.java new file mode 100644 index 0000000..cbae5f5 --- /dev/null +++ b/src/eu/engys/util/LineSeparator.java @@ -0,0 +1,64 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +public enum LineSeparator { + + DOS("\r\n", "DOS (CR+LF)"), + UNIX("\n", "UNIX (LF)"), + MAC("\r", "Mac (CR)"), + PLATFORM_DEPENDENT(System.getProperty("line.separator"), "Platform dependent"); + + private String separator; + private String label; + + LineSeparator(String separator, String label) { + this.separator = separator; + this.label = label; + } + + public String getSeparator() { + return separator; + } + + public String getLabel() { + return label; + } + + public static LineSeparator getLineSeparator(String separator) { + for (LineSeparator lineSeparator : LineSeparator.values()) { + if (separator.equals(lineSeparator.getSeparator())) { + return lineSeparator; + } + } + throw new IllegalArgumentException("Unknown line separator: " + separator); + } + + public static LineSeparator getDefaultLineSeparator() { + return getLineSeparator(System.getProperty("line.separator")); + } + +} diff --git a/src/eu/engys/util/MemoryWidget.java b/src/eu/engys/util/MemoryWidget.java new file mode 100644 index 0000000..dd0808f --- /dev/null +++ b/src/eu/engys/util/MemoryWidget.java @@ -0,0 +1,153 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ +package eu.engys.util; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.Rectangle2D; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.Timer; +import javax.swing.ToolTipManager; + +public class MemoryWidget extends JComponent implements ActionListener { + + public static final String PROTOTYPE_STRING = " 9999 / 9999 MB "; + + private final LineMetrics lm; + private final Color progressForeground = new JTable().getSelectionForeground(); + private final Color progressBackground = new JTable().getSelectionBackground(); + + private Timer timer; + + private long free = Runtime.getRuntime().freeMemory(); + private long total = Runtime.getRuntime().totalMemory(); + private long max = Runtime.getRuntime().maxMemory(); + + class MouseHandler extends MouseAdapter { + @Override + public void mousePressed(MouseEvent evt) { + if (evt.getClickCount() == 2) { + System.gc(); + repaint(); + } + } + } + + public MemoryWidget() { + Font font = new JLabel().getFont(); + setFont(font); + + FontRenderContext frc = new FontRenderContext(null, false, false); + Rectangle2D bounds = font.getStringBounds(PROTOTYPE_STRING, frc); + Dimension dim = new Dimension((int) bounds.getWidth(), (int) bounds.getHeight()); + setPreferredSize(dim); + setMaximumSize(dim); + lm = font.getLineMetrics(PROTOTYPE_STRING, frc); + + setForeground(new JLabel().getForeground()); + setBackground(new JLabel().getBackground()); + +// progressForeground = jEdit.getColorProperty("view.status.memory.foreground"); +// progressBackground = jEdit.getColorProperty("view.status.memory.background"); + + addMouseListener(new MouseHandler()); + } + + @Override + public void addNotify() { + super.addNotify(); + timer = new Timer(2000, this); + timer.start(); + ToolTipManager.sharedInstance().registerComponent(this); + } + + @Override + public void removeNotify() { + timer.stop(); + ToolTipManager.sharedInstance().unregisterComponent(this); + super.removeNotify(); + } + + /** + * see specification at http://stackoverflow.com/a/18375641 + */ + public void actionPerformed(ActionEvent evt) { + Runtime runtime = Runtime.getRuntime(); + this.free = runtime.freeMemory(); + this.total = runtime.totalMemory(); + this.max = runtime.maxMemory(); + repaint(); + } + + @Override + public void paintComponent(Graphics g) { + Insets insets = new Insets(0, 0, 0, 0);// MemoryStatus.this.getBorder().getBorderInsets(this); + + long used = total - free; + + int width = getWidth() - insets.left - insets.right; + int height = getHeight() - insets.top - insets.bottom - 1; + + float fraction = ((float) used) / max; + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + g2.setColor(progressBackground); + g2.fillRect(insets.left, insets.top, (int) (width * fraction), height); + + String str = (used / 1024 / 1024) + " / " + (max / 1024 / 1024) + " MB"; + FontRenderContext frc = new FontRenderContext(null, false, false); + Rectangle2D bounds = g2.getFont().getStringBounds(str, frc); + + Graphics g3 = g2.create(); + g3.setClip(insets.left, insets.top, (int) (width * fraction), height); + g3.setColor(progressForeground); + + int textX = insets.left + ((int) (width - bounds.getWidth()) / 2); + int textY = (int) (insets.top + height/2 + lm.getAscent() / 2); + g3.drawString(str, textX, textY); + g3.dispose(); + + g3 = g2.create(); + g3.setClip(insets.left + (int) (width * fraction), insets.top, getWidth() - insets.left - (int) (width * fraction), height); + g3.setColor(getForeground()); + g3.drawString(str, insets.left + ((int) (width - bounds.getWidth()) >> 1), textY); + g3.dispose(); + } +} diff --git a/src/eu/engys/util/OpenFOAMCommands.java b/src/eu/engys/util/OpenFOAMCommands.java new file mode 100644 index 0000000..722aa32 --- /dev/null +++ b/src/eu/engys/util/OpenFOAMCommands.java @@ -0,0 +1,249 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import static eu.engys.util.IOUtils.WIN_EOL; + +import java.io.File; + +public class OpenFOAMCommands { + + private static final String _ALL_REGIONS = "-allRegions"; + private static final String _NO_FUNCTION_OBJECTS = "-noFunctionObjects"; + private static final String _FORCE = "-force"; + private static final String _CONSTANT = "-constant"; + private static final String _ZERO_TIME = "-zeroTime"; + private static final String _WITH_ZERO = "-withZero"; + private static final String _OVERWRITE = "-overwrite"; + private static final String _SCALE = "-scale"; + private static final String _PARALLEL = "-parallel"; + + // Flag to solve a problem with mpirun on OpenSUSE 12.3 where a default file is not installed correctly + private static final String _DEFAULT_HOST_FILE = PrefUtil.getBoolean(PrefUtil.DEFAULT_HOSTFILE_NONE) ? "--default-hostfile none" : ""; + + private static final String GENVLIST = "-genvlist HOME,PATH,USERNAME,WM_PROJECT_DIR,WM_PROJECT_INST_DIR,WM_OPTIONS,FOAM_LIBBIN,FOAM_APPBIN,FOAM_USER_APPBIN,FOAM_CONFIG,MPI_BUFFER_SIZE"; + + private static final String CASE() { + return Util.isWindowsScriptStyle() ? "\"%CASE%\"" : "$CASE"; + } + + private static final String SOLVER() { + return Util.isWindowsScriptStyle() ? "\"%SOLVER%\"" : "$SOLVER"; + } + + private static final String _CASE() { + return "-case " + CASE(); + } + + private static final String _TEE_LOG() { + return "2>&1 | " + (Util.isWindowsScriptStyle() ? "wtee -a \"%LOG%\"" : "tee -a $LOG"); + } + + private static final String _MPI_NP() { + return Util.isWindowsScriptStyle() ? "mpiexec -n %NP% %MACHINEFILE% %MPI_ACCESSORY_OPTIONS% " + GENVLIST : "mpirun " + _DEFAULT_HOST_FILE + " -np $NP $MACHINEFILE"; + } + + private static final String _BLOCK_MESH_DICT() { + return "-dict " + (Util.isWindowsScriptStyle() ? "system\\blockMeshDict" : "system/blockMeshDict"); + } + + private static final String COMMAND(String command, String log) { + if (Util.isWindowsScriptStyle()) { + String errorFile = "errorcode.txt"; + StringBuilder sb = new StringBuilder(); + sb.append("set COMMAND=" + command + WIN_EOL); + sb.append(WIN_EOL); + sb.append("set ERROR_HANDLER=call echo %%^^errorlevel%% ^>" + errorFile + WIN_EOL); + sb.append(WIN_EOL); + sb.append("(%COMMAND% & %%ERROR_HANDLER%%) " + log + WIN_EOL); + sb.append(WIN_EOL); + sb.append("set /p ERR=<" + errorFile + WIN_EOL); + sb.append("del " + errorFile + WIN_EOL); + sb.append(WIN_EOL); + sb.append("IF %ERR% NEQ 0 exit %ERR%" + WIN_EOL); + return sb.toString(); + } else { + return command + " " + log; + } + } + + /* + * MESH Commands + */ + public static final String BLOCK_MESH() { + return COMMAND("blockMesh " + _BLOCK_MESH_DICT() + " " + _CASE(), _TEE_LOG()); + } + + public static final String MERGE_MESHES(String filePath) { + return COMMAND("mergeMeshes " + _OVERWRITE + " " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + CASE() + " \"" + filePath + "\"", _TEE_LOG()); + } + + public static final String RECONSTRUCT_PAR_MESH() { + return COMMAND("reconstructParMesh " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String RECONSTRUCT_PAR_MESH_CONSTANT() { + return COMMAND("reconstructParMesh " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + _CONSTANT, _TEE_LOG()); + } + + public static final String RECONSTRUCT_PAR_MESH_ALLREGIONS() { + return COMMAND("reconstructParMesh " + " " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + _ALL_REGIONS, _TEE_LOG()); + } + + public static final String RECONSTRUCT_PAR_MESH_CONSTANT_ALLREGIONS() { + return COMMAND("reconstructParMesh " + " " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + _CONSTANT + " " + _ALL_REGIONS, _TEE_LOG()); + } + + public static final String CHECK_MESH_SERIAL() { + return COMMAND("checkMesh " + _CASE(), _TEE_LOG()); + } + + public static final String CHECK_MESH_PARALLEL() { + return COMMAND(_MPI_NP() + " checkMesh " + _PARALLEL + " " + _CASE(), _TEE_LOG()); + } + + public static final String SNAPPY_CHECK_MESH_SERIAL() { + return COMMAND("snappyCheckMesh -writeAllMetrics " + _CASE(), _TEE_LOG()); + } + + public static final String SNAPPY_CHECK_MESH_PARALLEL() { + return COMMAND(_MPI_NP() + " snappyCheckMesh -writeAllMetrics " + _PARALLEL + " " + _CASE(), _TEE_LOG()); + } + + public static final String RUN_MESH_SERIAL() { + return COMMAND("snappyHexMesh " + _OVERWRITE + " " + _CASE(), _TEE_LOG()); + } + + public static final String RUN_MESH_PARALLEL() { + return COMMAND(_MPI_NP() + " snappyHexMesh " + _PARALLEL + " " + _OVERWRITE + " " + _CASE(), _TEE_LOG()); + } + + public static final String EXTRUDE_REGION_TO_MESH() { + return COMMAND("extrudeToRegionMesh " + _OVERWRITE + " " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + /* + * Solver + */ + public static final String RUN_CASE_SERIAL() { + return COMMAND(SOLVER() + " " + _CASE(), _TEE_LOG()); + } + + public static final String RUN_CASE_PARALLEL() { + return COMMAND(_MPI_NP() + " " + SOLVER() + " " + _PARALLEL + " " + _CASE(), _TEE_LOG()); + } + + /* + * Fields + */ + + public static final String SET_FIELDS_SERIAL() { + return COMMAND("setFields " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String SET_FIELDS_PARALLEL() { + return COMMAND(_MPI_NP() + " setFields " + _PARALLEL + " " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String INITIALISE_FIELDS_SERIAL() { + return COMMAND("caseSetup " + _CASE(), _TEE_LOG()); + } + + public static final String INITIALISE_FIELDS_PARALLEL() { + return COMMAND(_MPI_NP() + " caseSetup " + _PARALLEL + " " + _CASE(), _TEE_LOG()); + } + + public static final String PAR_MAP_FIELDS_SERIAL() { + return COMMAND("parMapFields " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String PAR_MAP_FIELDS_PARALLEL() { + return COMMAND(_MPI_NP() + " parMapFields " + _PARALLEL + " " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + /* + * Other + */ + + public static final String DECOMPOSE_PAR() { + return COMMAND("decomposePar " + _FORCE + " " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String DECOMPOSE_PAR_CONSTANT() { + return COMMAND("decomposePar " + _FORCE + " " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + _CONSTANT, _TEE_LOG()); + } + + public static final String DECOMPOSE_PAR_ALLREGIONS() { + return COMMAND("decomposePar " + _FORCE + " " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + _ALL_REGIONS, _TEE_LOG()); + } + + public static final String DECOMPOSE_PAR_CONSTANT_ALLREGIONS() { + return COMMAND("decomposePar " + _FORCE + " " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + _CONSTANT + " " + _ALL_REGIONS, _TEE_LOG()); + } + + public static final String RECONSTRUCT_PAR(boolean useWithZeroFlag) { + return COMMAND("reconstructPar " + (useWithZeroFlag ? _WITH_ZERO : _ZERO_TIME) + " " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String RECONSTRUCT_PAR_ALLREGIONS(boolean useWithZeroFlag) { + return COMMAND("reconstructPar " + (useWithZeroFlag ? _WITH_ZERO : _ZERO_TIME) + " " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + _ALL_REGIONS, _TEE_LOG()); + } + + public static final String FLUENT_TO_FOAM(Double scale, String fluentFileName) { + String separator = Util.isWindowsScriptStyle() ? "\\" : "/"; + return COMMAND("fluent3DMeshToFoam " + _SCALE + " " + scale + " " + _NO_FUNCTION_OBJECTS + " " + _CASE() + " " + CASE() + separator + fluentFileName, _TEE_LOG()); + } + + public static final String RENUMBER_SERIAL() { + return COMMAND("renumberMesh " + _OVERWRITE + " " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String RENUMBER_PARALLEL() { + return COMMAND(_MPI_NP() + " renumberMesh " + _PARALLEL + " " + _OVERWRITE + " " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String FOAM_MESH_TO_STAR() { + return COMMAND("foamToStarMesh " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String FOAM_MESH_TO_FLUENT() { + return COMMAND("foamMeshToFluent " + _NO_FUNCTION_OBJECTS + " " + _CASE(), _TEE_LOG()); + } + + public static final String CAD_TOOL(boolean split, double precision, File input, File output) { + String byComponentFlag = split ? " -byComponent" : ""; + String precisionFlag = "-relativeSpacing " + precision; + String inputFlag = "-inputFile " + input.getName(); + String outputFlag = "-outputFile " + output.getName(); + + return COMMAND("CADtoSurface" + byComponentFlag + " " + precisionFlag + " " + inputFlag + " " + outputFlag, _TEE_LOG()); + } + + public static final String FRONTAL_AREA = "frontalArea"; + public static final String MOVE_TO_CASE_FOLDER_WIN = "cd /D \"%CASE%\""; + public static final String PARA_FOAM = "paraFoam"; + +} diff --git a/src/eu/engys/util/PDFFileFilter.java b/src/eu/engys/util/PDFFileFilter.java new file mode 100644 index 0000000..392fdae --- /dev/null +++ b/src/eu/engys/util/PDFFileFilter.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import java.io.File; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.filefilter.IOFileFilter; + +public class PDFFileFilter implements IOFileFilter { + + private String toBeContained; + + public PDFFileFilter(String toBeContained) { + this.toBeContained = toBeContained; + } + + @Override + public boolean accept(File file) { + boolean isPDF = FilenameUtils.getExtension(file.getAbsolutePath()).equals("pdf"); + boolean containsKey = file.getName().contains(toBeContained); + return isPDF && containsKey; + } + + @Override + public boolean accept(File parentDir, String fileName) { + return false; + } + +} diff --git a/src/eu/engys/util/PrefUtil.java b/src/eu/engys/util/PrefUtil.java new file mode 100644 index 0000000..a086f0f --- /dev/null +++ b/src/eu/engys/util/PrefUtil.java @@ -0,0 +1,257 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.io.FileUtils; + +public class PrefUtil { + + public static final String USER_NAME = System.getProperty("user.name"); + public static final String USER_HOME = System.getProperty("user.home"); + public static final String USER_DIR = System.getProperty("user.dir"); + + public static final String FAVORITES_KEY = "filechooser.favorites"; + +// public static final String DOC_KEY = "doc.basedir"; + public static final String OPENFOAM_KEY = "openfoam.basedir"; + public static final String PARAVIEW_KEY = "paraview.basedir"; + public static final String FIELDVIEW_KEY = "fieldview.basedir"; + public static final String ENSIGHT_KEY = "ensight.basedir"; + + // batch + public static final String SERVER_CONNECTION_MAX_TRIES = "batch.connection.max.tries"; + public static final String SERVER_CONNECTION_REFRESH_TIME = "batch.connection.wait.time"; + public static final String SERVER_WAIT_FOR_RUN_REFRESH_TIME = "batch.running.wait.time"; + + public static final String SCRIPT_RUN_REFRESH_TIME = "batch.script.refresh.time"; + public static final String SCRIPT_WAIT_FOR_KILL_REFRESH_TIME = "batch.script.kill.wait.time"; + + public static final String BATCH_MONITOR_DIALOG_MAX_ROW = "batch.monitor.dialog.max.row"; + + // 3d + public static final String _3D_LOCK_INTRACTIVE_MEMORY = "3d.lock.intractive.memory"; + public static final String _3D_LOCK_INTRACTIVE_TIME = "3d.lock.intractive.time"; + public static final String _3D_TRANSPARENCY_MEMORY = "3d.transparency.memory"; + + // misc + public static final String RECENT_PROJECTS = "recent.projects"; + public static final String HELYX_DEFAULT_TERMINAL = "helyx.default.terminal"; + public static final String DEFAULT_HOSTFILE_NONE = "default.hostfile.none"; + public static final String HELYX_DEFAULT_FILE_MANAGER = "default.file.manager"; + public static final String HELYX_DEFAULT_FILE_OPENER = "default.file.opener"; + public static final String MATERIALS_USER_LIB = "materials.user.lib."; + public static final String HIDE_EMPTY_PATCHES = "hide.empty.patches"; + + // files + public static final String WORK_DIR = "last.open.dir"; + public static final String LAST_IMPORT_DIR = "last.import.dir"; + public static final String LAST_OPEN_EXPORT_DIR = "last.export.dir"; + + // license + public static final String LICENSE_SERVER_NAME = "license.server.name"; + public static final String LICENSE_SERVER_PORT = "license.server.port"; + + private static CompositeConfiguration configuration; + + private static CompositeConfiguration configuration() { + if (configuration == null) { + reload(); + } + return configuration; + } + + public static void reload() { + try { + deleteOldPrefsFolders(); + removeDuplicatedLines(ApplicationInfo.getPrefsFile()); + + PropertiesConfiguration defaults = new PropertiesConfiguration("eu/engys/resources/application.properties"); + + PropertiesConfiguration preferences = new PropertiesConfiguration(ApplicationInfo.getPrefsFile()); + preferences.setDelimiterParsingDisabled(true); + preferences.setAutoSave(true); + + configuration = new CompositeConfiguration(); + configuration.setDelimiterParsingDisabled(true); + configuration.addConfiguration(preferences, true); + configuration.addConfiguration(defaults); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void deleteOldPrefsFolders() throws IOException { + File home = new File(PrefUtil.USER_HOME); + File java = new File(home, ".java"); + if (java.exists()) { + File userPrefs = new File(java, ".userPrefs"); + if (userPrefs.exists()) { + File eu = new File(userPrefs, "eu"); + if (eu.exists()) { + FileUtils.deleteQuietly(eu); + } + } + } + File helyx = new File(home, ".HELYX"); + if (helyx.exists()) { + File userPrefs = new File(helyx, ".userPrefs"); + if (userPrefs.exists()) { + FileUtils.deleteQuietly(userPrefs); + } + } + } + + private static void removeDuplicatedLines(File file) throws IOException { + if (file.exists()) { + List fileLines = FileUtils.readLines(file); + Set lines = new LinkedHashSet<>(fileLines); + boolean hasDuplicateLines = fileLines.size() > lines.size(); + if(hasDuplicateLines){ + String lineEnding = Util.isWindowsScriptStyle() ? LineSeparator.DOS.getSeparator() : LineSeparator.UNIX.getSeparator(); + FileUtils.writeLines(file, null, lines, lineEnding); + } + } + } + + public static File getWorkDir(String key) { + return Util.isWindows() ? getFile(key, USER_HOME) : new File(USER_DIR); + } + + private static File getFile(String key) { + return getFile(key, null); + } + + private static File getFile(String key, String def) { + String path = configuration().getString(key, def); + return path == null ? null : new File(path); + } + + public static void putFile(String key, File file) { + configuration().setProperty(key, file == null ? "" : file.getAbsolutePath()); + } + + public static String getString(String key) { + return getString(key, ""); + } + + public static String getString(String key, String def) { + return configuration().getString(key, def); + } + + public static void putString(String key, String value) { + configuration().setProperty(key, value); + } + + public static int getInt(String key) { + return configuration().getInt(key, 0); + } + + public static int getInt(String key, int def) { + return configuration().getInt(key, def); + } + + public static void putInt(String key, int value) { + configuration().setProperty(key, String.valueOf(value)); + } + + public static void putBoolean(String key, boolean value) { + configuration().setProperty(key, Boolean.valueOf(value)); + } + + public static Boolean getBoolean(String key) { + return configuration().getBoolean(key); + } + + public static InetAddress getInetAddress(String key, InetAddress def) { + try { + return InetAddress.getByName(configuration().getString(key, def.getHostAddress())); + } catch (Exception e) { + return def; + } + } + + public static void putInetAddress(String key, InetAddress value) { + configuration().setProperty(key, value.getHostAddress()); + } + + public static File getFieldViewEntry() { + return getFile(FIELDVIEW_KEY); + } + + public static void setFieldViewEntry(File value) { + putFile(FIELDVIEW_KEY, value); + } + + public static File getEnsightEntry() { + return getFile(ENSIGHT_KEY); + } + + public static void setEnsightEntry(File value) { + putFile(ENSIGHT_KEY, value); + } + + public static File getParaViewEntry() { + return getFile(PARAVIEW_KEY); + } + + public static void setParaViewEntry(File value) { + putFile(PARAVIEW_KEY, value); + } + + public static File getOpenFoamEntry() { + return getFile(OPENFOAM_KEY); + } + + public static void setOpenFoamEntry(File value) { + putFile(OPENFOAM_KEY, value); + } + + public static void remove(String key) { + configuration().clearProperty(key); + } + + public static Object getDefaultValue(String key) { + try { + PropertiesConfiguration defaults = new PropertiesConfiguration("eu/engys/resources/application.properties"); + Object defaultProp = defaults.getProperty(key); + return defaultProp; + } catch (ConfigurationException e) { + return null; + } + + } +} diff --git a/src/eu/engys/util/RegexpUtils.java b/src/eu/engys/util/RegexpUtils.java new file mode 100644 index 0000000..5562f13 --- /dev/null +++ b/src/eu/engys/util/RegexpUtils.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +public class RegexpUtils { + + public static final String DOUBLE = "\\-?\\d+\\.?\\d*(?:[eE][+-]?\\d+)?"; + public static final String INTEGER = "\\-?\\d+[^.eE\\d+]"; + + public static final String POINT = "\\(\\s*" + DOUBLE + "\\s" + DOUBLE + "\\s" + DOUBLE + "\\s*\\)"; + + public static final String SPACES = "\\s*"; + + public static final String OPEN_BRACKET = "\\("; + public static final String CLOSED_BRACKET = "\\)"; + + public static final String OPEN_TAG_BRACKET = "\\<"; + public static final String CLOSED_TAG_BRACKET = "\\>"; + public static final String COMA = "\\s*,\\s*"; + +} diff --git a/src/eu/engys/util/Symbols.java b/src/eu/engys/util/Symbols.java new file mode 100644 index 0000000..34d6f10 --- /dev/null +++ b/src/eu/engys/util/Symbols.java @@ -0,0 +1,123 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util; + +public class Symbols { + + public static final String THETA = "\u03B8"; + public static final String PHI = "\u03C6"; + + public static final String CUBE = "\u00B3"; + public static final String SQUARE = "\u00B2"; + public static final String SUBSCRIPT_2 = "\u2082"; + public static final String MINUS_ONE = "\u02C9\u00B9"; + public static final String DOT = "\u00B7"; + + public static final String PASCAL = "[Pa]"; + public static final String KELVIN = "[K]"; + public static final String KELVIN_ON_SECONDS = "[K/s]"; + public static final String KELVIN_PER_VOLUME_ON_SECONDS = "[K"+DOT+"m"+CUBE+"/s]"; + public static final String M2_S2 = "[m" + SQUARE + "/s" + SQUARE + "]"; + public static final String M2_S = "[m" + SQUARE + "/s]"; + + public static final String M_S = "[m/s]"; + public static final String K_SYMBOL = "[m" + SQUARE + "/s" + SQUARE + "]"; + public static final String EPSILON_SYMBOL = "[m" + SQUARE + "/s" + CUBE + "]"; + public static final String OMEGA_SYMBOL = "[1/s]"; + + public static final String MU_MEASURE = "[Pa" + DOT + "s]"; + public static final String NU_MEASURE = "[m" + SQUARE + "/s]"; + public static final String LAMBDA_MEASURE = "[W/m" + DOT + "K]"; + + public static final String WATT = "[W]"; + public static final String WATT_ON_KELVIN = "[W/K]"; + public static final String WATT_ON_VOLUME = "[W/m"+CUBE+"]"; + public static final String WATT_ON_VOLUME_PER_KELVIN = "[W/K"+DOT+"m"+CUBE+"]"; + + public static final String LAMBDA = "\u03BB"; + public static final String MU = "\u03BC"; + public static final String NU = "\u03BD"; + public static final String RHO = "\u03C1"; + + public static final String CP = "[J/Kg" + DOT + "K]"; + public static final String HF = "[J/Kg]"; + public static final String DENSITY = "[Kg/m" + CUBE + "]"; + public static final String MASS_ON_SECONDS_PER_VOLUME = "[kg/s"+DOT+"m"+CUBE+"]"; + public static final String VOLUME_ON_SECONDS = "[m"+CUBE+"/s]"; + public static final String MASS_ON_SECONDS = "[Kg/s]"; + public static final String AREA = "[m" + SQUARE + "]"; + + public static final String HOURS = "hrs"; + + public static final String COPYRIGHT = "\u00A9"; + public static final String REGISTERED = "\u00AE"; + public static final String DELTA = "\u0394"; + public static final String DELTA_T = DELTA + "t"; + public static final String DOTS = "\u2026"; + public static final String ESC = "\u001b"; + public static final String TILDE = "\u223C"; + + public static final String PLUS_UPPERCASE = "\u207A"; + public static final String DOUBLE_ARROW = "\u2194"; + public static final String DEGREE_SIGN = "\u00B0"; + + public static String PEDICE(int number) { + String numberToString = String.valueOf(number); + String pedice = ""; + for (char c : numberToString.toCharArray()) { + pedice += PEDICE(c); + } + return pedice; + } + + public static char PEDICE(char c) { + switch (c) { + case '0': + return '\u2080'; + case '1': + return '\u2081'; + case '2': + return '\u2082'; + case '3': + return '\u2083'; + case '4': + return '\u2084'; + case '5': + return '\u2085'; + case '7': + return '\u2086'; + case '8': + return '\u2087'; + case '9': + return '\u2088'; + default: + return ' '; + } + + } + +} diff --git a/src/eu/engys/util/TempFolder.java b/src/eu/engys/util/TempFolder.java new file mode 100644 index 0000000..6ae3eb7 --- /dev/null +++ b/src/eu/engys/util/TempFolder.java @@ -0,0 +1,80 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ +package eu.engys.util; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TempFolder { + + private static final Logger logger = LoggerFactory.getLogger(TempFolder.class); + + private static final String sessionID; + + static { + sessionID = String.valueOf(System.currentTimeMillis() / 1000); + } + + public static File get(String... folders) { + File userTemp = new File(ApplicationInfo.getHome(), "tmp"); + if (!userTemp.exists()) { + userTemp.mkdirs(); + } + + final File sessionTemp = new File(userTemp, "tmp_" + sessionID); + if (!sessionTemp.exists()) { + if (sessionTemp.mkdirs()) { + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + public void run() { + FileUtils.deleteQuietly(sessionTemp); + } + })); + } else { + logger.error("Cannot create session temporary folder: {}"); + } + } + + if (folders.length > 0) { + Path path = Paths.get(sessionTemp.getAbsolutePath(), folders); + try { + Files.createDirectories(path); + return path.toFile(); + } catch (IOException e) { + logger.error("Cannot create path: {}", path); + throw new RuntimeException(e); + } + } else { + return sessionTemp; + } + } + +} diff --git a/src/eu/engys/util/TooltipUtils.java b/src/eu/engys/util/TooltipUtils.java new file mode 100644 index 0000000..068a251 --- /dev/null +++ b/src/eu/engys/util/TooltipUtils.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import java.util.ArrayList; +import java.util.List; + +public class TooltipUtils { + + private static final int TOOLTIP_MAX_SIZE = 80; + private static final String HTML_START = ""; + private static final String HTML_END = ""; + public static final String NEW_LINE = "
"; + + public static String format(String tooltip) { + if(tooltip == null) return null; + List chunks = getChunks(tooltip); + StringBuilder sb = new StringBuilder(HTML_START); + for (int i = 0; i < chunks.size() - 1; i++) { + sb.append(chunks.get(i) + NEW_LINE); + } + sb.append(chunks.get(chunks.size() - 1)); + sb.append((HTML_END)); + return sb.toString(); + } + + private static List getChunks(String tooltip) { + List chunks = new ArrayList<>(); + if (tooltip.length() <= TOOLTIP_MAX_SIZE || tooltip.contains(NEW_LINE)) { + chunks.add(tooltip); + } else { + int splitIndex = tooltip.substring(0, TOOLTIP_MAX_SIZE + 1).lastIndexOf(" "); + chunks.add(tooltip.substring(0, splitIndex)); + chunks.addAll(getChunks(tooltip.substring(splitIndex + 1, tooltip.length()))); + } + return chunks; + + } +} diff --git a/src/eu/engys/util/Util.java b/src/eu/engys/util/Util.java new file mode 100644 index 0000000..c4d036b --- /dev/null +++ b/src/eu/engys/util/Util.java @@ -0,0 +1,595 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import static java.nio.file.LinkOption.NOFOLLOW_LINKS; +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.OVERFLOW; + +import java.awt.Desktop; +import java.io.BufferedReader; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.WatchEvent; +import java.nio.file.WatchEvent.Kind; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.net.util.Base64; + +import com.jcraft.jsch.jce.Random; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinNT; + +public final class Util { + + public enum ScriptStyle { + WINDOWS, LINUX; + } + + private static ScriptStyle scriptStyle = ScriptStyle.LINUX; + + public static void initScriptStyle() { + scriptStyle = isWindows() ? ScriptStyle.WINDOWS : ScriptStyle.LINUX; + } + + public static boolean isWindowsScriptStyle() { + return scriptStyle == ScriptStyle.WINDOWS; + } + + public static boolean isUnixScriptStyle() { + return scriptStyle == ScriptStyle.LINUX; + } + + public static void setScriptStyle(ScriptStyle scriptStyle) { + Util.scriptStyle = scriptStyle; + } + + public static String getTrimmedSingleSpaceLine(String string) { + return string.trim().replaceAll("\\s+", " "); + } + + public static final String getStringFromList(List list, int itemsPerRow) { + StringBuilder sb = new StringBuilder(); + sb.append("[ "); + for (int i = 0; i < list.size(); i++) { + sb.append(list.get(i)); + if (i == list.size() - 1) { + sb.append("]"); + } else { + sb.append(", "); + if ((i + 1) % itemsPerRow == 0) { + sb.append("\n"); + } + } + + } + return sb.toString(); + } + + public static String replaceForbiddenCharacters(String name) { + char[] charArray = name.toCharArray(); + if (Character.isDigit(charArray[0])) + charArray[0] = '_'; + for (int i = 0; i < charArray.length; i++) { + if (Util.isForbidden(charArray[i])) { + charArray[i] = '_'; + } + } + return new String(charArray); + } + + public static String padWithSpaces(String string, int lenght) { + if (string.length() > lenght) { + return string; + } else { + StringBuilder sb = new StringBuilder(); + sb.append(string); + for (int i = 0; i < lenght - string.length(); i++) { + sb.append(" "); + } + return sb.toString(); + } + } + + public static String[] fromKeystoLabels(String[] keys) { + String[] labels = new String[keys.length]; + for (int i = 0; i < labels.length; i++) { + labels[i] = fromKeyToLabel(keys[i]); + } + return labels; + } + + private static String fromKeyToLabel(String key) { + StringBuilder sb = new StringBuilder(); + sb.append(Character.toUpperCase(key.charAt(0))); + for (int i = 1; i < key.length(); i++) { + char c = key.charAt(i); + if (Character.isUpperCase(c)) + sb.append(" "); + sb.append(c); + } + return sb.toString(); + } + + public static boolean isWindows() { + String os = System.getProperty("os.name").toLowerCase(); + // windows + return (os.indexOf("win") >= 0); + } + + public static boolean isMac() { + String os = System.getProperty("os.name").toLowerCase(); + // Mac + return (os.indexOf("mac") >= 0); + } + + public static boolean isUnix() { + String os = System.getProperty("os.name").toLowerCase(); + // linux or unix + return (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0); + } + + public static boolean isSolaris() { + String os = System.getProperty("os.name").toLowerCase(); + // Solaris + return (os.indexOf("sunos") >= 0); + } + + public static int[] getFactorsFor(int np) { + int cubeRoot = (int) Math.ceil(Math.cbrt(np)); + int firstFactor = 1; + int secondFactor = 1; + int thirdFactor = 1; + + for (int i = cubeRoot; i <= np; i++) { + if (np % i == 0) { + firstFactor = i; + break; + } + } + + int remainder = np / firstFactor; + int squareRoot = (int) Math.ceil(Math.sqrt(remainder)); + + for (int j = squareRoot; j <= remainder; j++) { + if (remainder % j == 0) { + secondFactor = j; + break; + } + } + + if (secondFactor > firstFactor) { + int tmp = secondFactor; + secondFactor = firstFactor; + firstFactor = tmp; + } + + thirdFactor = np / firstFactor / secondFactor; + return new int[] { firstFactor, secondFactor, thirdFactor }; + } + + public static int getLinuxProcessId(Process proc) throws Exception { + if (proc.getClass().getName().equals("java.lang.UNIXProcess")) { + Field f = proc.getClass().getDeclaredField("pid"); + f.setAccessible(true); + int pid = f.getInt(proc); + return pid; + } + return 0; + } + + public static int getWindowsProcessId(Process proc) throws Exception { + if (proc.getClass().getName().equals("java.lang.Win32Process") || proc.getClass().getName().equals("java.lang.ProcessImpl")) { + /* determine the pid on windows plattforms */ + Field f = proc.getClass().getDeclaredField("handle"); + f.setAccessible(true); + long handl = f.getLong(proc); + Kernel32 kernel = Kernel32.INSTANCE; + WinNT.HANDLE handle = new WinNT.HANDLE(); + handle.setPointer(Pointer.createConstant(handl)); + return kernel.GetProcessId(handle); + } + return 0; + } + + public static boolean isRunning(String program) { + if (isWindows()) { + String listOfProcesses = getCommandOutput("tasklist"); + if (listOfProcesses == null || listOfProcesses.isEmpty()) { + return false; + } else { + if (listOfProcesses.contains(program)) { + return true; + } else { + return false; + } + } + } else { + String listOfProcesses = getCommandOutput("ps -f"); + // System.err.println(listOfProcesses); + if (listOfProcesses == null || listOfProcesses.isEmpty()) { + return false; + } else { + if (listOfProcesses.contains(program)) { + return true; + } else { + return false; + } + } + } + } + + public static String getCommandOutput(String command) { + String output = null; // the string to return + + Process process = null; + BufferedReader reader = null; + InputStreamReader streamReader = null; + InputStream stream = null; + + try { + process = Runtime.getRuntime().exec(command); + + // Get stream of the console running the command + stream = process.getInputStream(); + streamReader = new InputStreamReader(stream); + reader = new BufferedReader(streamReader); + + String currentLine = null; // store current line of output from the + // cmd + StringBuilder commandOutput = new StringBuilder(); // build up the + // output from + // cmd + while ((currentLine = reader.readLine()) != null) { + commandOutput.append(currentLine + "\n"); + } + + int returnCode = process.waitFor(); + if (returnCode == 0) { + output = commandOutput.toString(); + } + System.err.println(output); + } catch (IOException e) { + System.err.println("Cannot retrieve output of command"); + System.err.println(e); + output = null; + } catch (InterruptedException e) { + System.err.println("Cannot retrieve output of command"); + System.err.println(e); + } finally { + // Close all inputs / readers + + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + System.err.println("Cannot close stream input! " + e); + } + } + if (streamReader != null) { + try { + streamReader.close(); + } catch (IOException e) { + System.err.println("Cannot close stream input reader! " + e); + } + } + if (reader != null) { + try { + streamReader.close(); + } catch (IOException e) { + System.err.println("Cannot close stream input reader! " + e); + } + } + } + // Return the output from the command - may be null if an error occured + return output; + } + + public static void deepCopy(double[] source, double[] target) { + if (source == null || target == null) + throw new IllegalArgumentException("Arrays should be not null"); + if (source.length != target.length) + throw new IllegalArgumentException("Arrays should have same length"); + + for (int i = 0; i < source.length; i++) { + target[i] = source[i]; + } + } + + public static void deepCopy(int[] source, int[] target) { + if (source == null || target == null) + throw new IllegalArgumentException("Arrays should be not null"); + if (source.length != target.length) + throw new IllegalArgumentException("Arrays should have same length"); + + for (int i = 0; i < source.length; i++) { + target[i] = source[i]; + } + + } + + @SuppressWarnings("unchecked") + public static boolean isVarArgsNotNull(O... objs) { + return isVarArgsNotNullAndOfSize(-1, objs); + } + + @SuppressWarnings("unchecked") + public static boolean isVarArgsNotNullAndOfSize(int length, O... objs) { + boolean notNull = objs != null; + if (!notNull) + return false; + boolean correctSize = length < 0 ? objs.length > 0 : objs.length == length; + if (!correctSize) + return false; + boolean elementsNotNull = true; + for (O object : objs) { + elementsNotNull &= (object != null); + } + return notNull && correctSize && elementsNotNull; + } + + public static Map invertMap(Map map) { + Map out = new HashMap<>(map.size()); + java.util.Map.Entry entry; + for (Iterator> it = map.entrySet().iterator(); it.hasNext(); out.put(entry.getValue(), entry.getKey())) + entry = it.next(); + + return out; + } + + public static Map sortMapByValues(Map passedMap, boolean descending, boolean useAbsoluteValues) { + List mapKeys = new ArrayList(passedMap.keySet()); + Collections.sort(mapKeys); + + List mapValues = new ArrayList(passedMap.values()); + if (useAbsoluteValues) { + Collections.sort(mapValues, new Comparator() { + @Override + public int compare(Double o1, Double o2) { + return Double.valueOf(Math.abs(o1)).compareTo(Double.valueOf(Math.abs(o2))); + } + }); + } else { + Collections.sort(mapValues); + } + if (descending) { + Collections.reverse(mapValues); + } + + Map sortedMap = new LinkedHashMap(); + + Iterator valueIt = mapValues.iterator(); + while (valueIt.hasNext()) { + Double val = valueIt.next(); + Iterator keyIt = mapKeys.iterator(); + + while (keyIt.hasNext()) { + String key = keyIt.next(); + String comp1 = String.valueOf(Math.abs(passedMap.get(key))); + String comp2 = String.valueOf(Math.abs(val)); + + if (comp1.equals(comp2)) { + passedMap.remove(key); + mapKeys.remove(key); + sortedMap.put(key, val); + break; + } + + } + + } + return sortedMap; + } + + public static boolean canWrite(File folder) { + if (!folder.canWrite()) { + return false; + } + try { + File testFile = Paths.get(folder.getAbsoluteFile().toURI()).resolve("testWrite").toFile(); + if (testFile.exists()) { + testFile.delete(); + } + boolean res = testFile.createNewFile(); + if (res) { + testFile.delete(); + } + return res; + } catch (Exception e) { + return false; + } + } + + public static void openWebpage(URL url) { + try { + openWebpage(url.toURI()); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + + private static void openWebpage(URI uri) { + Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; + if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { + try { + desktop.browse(uri); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public static String encrypt(String value) { + if (!value.isEmpty()) { + try { + return Base64.encodeBase64String(value.getBytes()); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + return value; + } + + public static String decrypt(String value) { + if (!value.isEmpty()) { + return new String(Base64.decodeBase64(value)); + } + return value; + } + + public static String[] getNumericSubFolders(File parentDir) { + String[] folders = parentDir.list(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + try { + Double.parseDouble(name); + return dir.isDirectory(); + } catch (NumberFormatException nfee) { + return false; + } + } + }); + if (folders != null) { + Arrays.sort(folders, new Comparator() { + public int compare(String s1, String s2) { + return Double.valueOf(s1).compareTo(Double.valueOf(s2)); + } + }); + return folders; + } else { + return new String[0]; + } + } + + public static void watchDirectoryPath(Path path) { + // Sanity check - Check if path is a folder + try { + Boolean isFolder = (Boolean) Files.getAttribute(path, "basic:isDirectory", NOFOLLOW_LINKS); + if (!isFolder) { + throw new IllegalArgumentException("Path: " + path + " is not a folder"); + } + } catch (IOException ioe) { + // Folder does not exists + ioe.printStackTrace(); + } + + // System.out.println("Watching path: " + path); + + // We obtain the file system of the Path + FileSystem fs = path.getFileSystem(); + + // We create the new WatchService using the new try() block + try (WatchService service = fs.newWatchService()) { + + // We register the path to the service + // We watch for creation events + path.register(service, ENTRY_CREATE); + + // Start the infinite polling loop + WatchKey key = null; + while (true) { + key = service.take(); + + // Dequeueing events + Kind kind = null; + for (WatchEvent watchEvent : key.pollEvents()) { + // Get the type of the event + kind = watchEvent.kind(); + if (OVERFLOW == kind) { + continue; // loop + } else if (ENTRY_CREATE == kind) { + // A new Path was created + // Path newPath = ((WatchEvent) + // watchEvent).context(); + // Output + // System.out.println("New path created: " + newPath); + } + } + + if (!key.reset()) { + break; // loop + } + } + + } catch (IOException ioe) { + ioe.printStackTrace(); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + + } + + public static String generateID() { + byte[] foo = new byte[4]; + Util.rnd.fill(foo, 0, foo.length); + String id = new String(Hex.encodeHex(foo)).toUpperCase(); + return id; + } + + public static String getMachineName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (Exception e) { + return ""; + } + } + + public static final Random rnd = new Random(); + public static final int WINDOWS_MAX_FILENAME_LENGTH = 200; + + public static int boolToInt(boolean b) { + return b ? 1 : 0; + } + + public static boolean isForbidden(char ch) { + return !Character.isLetterOrDigit(ch) && " \"/\\*#$;".indexOf(ch) >= 0; + } + +} diff --git a/src/eu/engys/util/VTKSettings.java b/src/eu/engys/util/VTKSettings.java new file mode 100644 index 0000000..34744e3 --- /dev/null +++ b/src/eu/engys/util/VTKSettings.java @@ -0,0 +1,156 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkNativeLibrary; + +public class VTKSettings { + + private static final Logger logger = LoggerFactory.getLogger(VTKSettings.class); + + private static boolean librariesAreLoaded = false; + + public static void LoadAllNativeLibraries() { + librariesAreLoaded = true; + try { + if (!_LoadAllNativeLibraries()) { + for (vtkNativeLibrary lib : vtkNativeLibrary.values()) { + String libName = lib.GetLibraryName(); + if (lib.IsLoaded()) { + logger.info(libName + " loaded"); + } else { + librariesAreLoaded = false; + logger.error(libName + " NOT loaded"); + } + } + } else { + librariesAreLoaded = true; + logger.info("ALL VTK libraries loaded"); + } + } catch (Exception e) { + librariesAreLoaded = false; + logger.error("Error loading VTK libraries: " + e.getMessage()); + } + + if (librariesAreLoaded) { + vtkNativeLibrary.DisableOutputWindow(null); + } else { + librariesAreLoaded = false; + } + } + + private static boolean _LoadAllNativeLibraries() { + boolean isEveryThingLoaded = true; + for (vtkNativeLibrary lib : vtkNativeLibrary.values()) { + try { + if(lib.IsBuilt()) { + lib.LoadLibrary(); + } + } catch (UnsatisfiedLinkError e) { + isEveryThingLoaded = false; + //e.printStackTrace(); + } + } + + return isEveryThingLoaded; + } + + public static boolean librariesAreLoaded() { + return librariesAreLoaded; + } + +// private static final String COMMON = "vtkCommonJava"; +// private static final String FILTERING = "vtkFilteringJava"; +//// private static final String GEOVIS = "vtkGeovisJava"; +// private static final String GRAPHICS = "vtkGraphicsJava"; +// private static final String HYBRID = "vtkHybridJava"; +//// private static final String IMAGING = "vtkImagingJava"; +//// private static final String INFOVIS = "vtkInfovisJava"; +// private static final String IO = "vtkIOJava"; +// private static final String RENDERING = "vtkRenderingJava"; +// private static final String VIEWS = "vtkViewsJava"; +// private static final String VOLUME_RENDERING = "vtkVolumeRenderingJava"; +// private static final String WIDGETS = "vtkWidgetsJava"; +//// private static final String CHARTS = "vtkChartsJava"; +// private static final String PARALLEL = "vtkParallelJava"; +// +// private static boolean librariesAreLoaded = false; +// +// public static void LoadAllNativeLibraries() { +// librariesAreLoaded = true; +// +// loadLibrary(COMMON); +// loadLibrary(FILTERING); +// // loadLibrary(GEOVIS); +// loadLibrary(GRAPHICS); +// loadLibrary(PARALLEL); +// loadLibrary(HYBRID); +// // loadLibrary(IMAGING); +// // loadLibrary(INFOVIS); +// loadLibrary(IO); +// loadLibrary(RENDERING); +// loadLibrary(VIEWS); +// loadLibrary(VOLUME_RENDERING); +// loadLibrary(WIDGETS); +// // loadLibrary(CHARTS); +// +// if (librariesAreLoaded) { +// disableOutputWindow(null); +// } else { +// logger.warn("Make sure the search path is correct: "); +// logger.warn(System.getProperty("java.library.path")); +// librariesAreLoaded = false; +// return; +// } +// } +// +// private static void loadLibrary(String libName) { +// try { +// System.loadLibrary(libName); +// logger.info(libName + " loaded"); +// } catch (UnsatisfiedLinkError e) { +// logger.warn(libName + " NOT loaded: " + e.getMessage()); +// librariesAreLoaded = false; +// } +// } +// +// public static boolean librariesAreLoaded() { +// return librariesAreLoaded; +// } +// +// private static void disableOutputWindow(File logFile) { +// if (logFile == null) { +// logFile = new File("vtkError.txt"); +// } +// vtkFileOutputWindow outputError = new vtkFileOutputWindow(); +// outputError.SetFileName(logFile.getAbsolutePath()); +// outputError.SetInstance(outputError); +// } + +} diff --git a/src/eu/engys/util/VersionChecker.java b/src/eu/engys/util/VersionChecker.java new file mode 100644 index 0000000..587f68a --- /dev/null +++ b/src/eu/engys/util/VersionChecker.java @@ -0,0 +1,140 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.StringTokenizer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VersionChecker { + + private static final Logger logger = LoggerFactory.getLogger(VersionChecker.class); + + private static final String PATH = "http://engys.com/helyx-os/version.txt"; + + public enum VersionType { + + UPDATED, OLD, NOT_AVAILABLE; + + public boolean isUpdated(){ + return this == UPDATED; + } + + public boolean isOld(){ + return this == OLD; + } + + public boolean isNotAvailable(){ + return this == NOT_AVAILABLE; + } + + } + + public static VersionType isNewVersionAvailable() { + try { + String actual = getActualVersion(); + String online = getOnlineVersion(); + if (actual.isEmpty() || online.isEmpty()) { + return VersionType.NOT_AVAILABLE; + } + int[] actualNumber = extractVersionNumber(actual); + int[] onlineNumber = extractVersionNumber(online); + if (isEarlier(actualNumber, onlineNumber)) { + return VersionType.OLD; + } else { + return VersionType.UPDATED; + } + } catch (Exception e) { + return VersionType.NOT_AVAILABLE; + } + } + + public static int[] extractVersionNumber(String version) { + String versionNumber = version.replace("v", "").trim(); + final int[] vers = new int[3]; + final StringTokenizer token = new StringTokenizer(versionNumber, "."); + + for (int i = 0; i < 3; i++) { + if (token.hasMoreTokens()) { + try { + vers[i] = Integer.parseInt(token.nextToken()); + } catch (final Exception e) { + break; + } + } + } + + return vers; + } + + public static String getActualVersion() { + return ApplicationInfo.getVersion(); + } + + public static String getOnlineVersion() { + try { + URL url = new URL(PATH); + URLConnection uc = url.openConnection(); + + InputStreamReader input = new InputStreamReader(uc.getInputStream()); + BufferedReader in = new BufferedReader(input); + String inputLine; + StringBuffer sb = new StringBuffer(); + while ((inputLine = in.readLine()) != null) { + sb.append(inputLine); + } + in.close(); + return sb.toString(); + } catch (IOException e) { + logger.warn("Unable to find latest version online", e.getMessage()); + return ""; + } + } + + public static boolean isEarlier(int[] v1, int[] v2) { + boolean returnValue = false; + + if (!((v1 == null) || (v2 == null))) { + for (int i = 0; i < 3; i++) { + if (v1[i] < v2[i]) { + returnValue = true; + break; + } else if (v1[i] > v2[i]) { + break; + } + } + } + + return returnValue; + } + +} diff --git a/src/eu/engys/util/bean/AbstractBean.java b/src/eu/engys/util/bean/AbstractBean.java new file mode 100644 index 0000000..d8fbfef --- /dev/null +++ b/src/eu/engys/util/bean/AbstractBean.java @@ -0,0 +1,74 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.bean; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +import org.apache.commons.lang.ArrayUtils; + +public class AbstractBean { + + private transient PropertyChangeSupport support; + + public void addPropertyChangeListener(PropertyChangeListener listener) { + if (support == null) { + support = new PropertyChangeSupport(this); + } + support.addPropertyChangeListener(listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + if (support != null) { + support.removePropertyChangeListener(listener); + } + } + + public boolean isListenedBy(PropertyChangeListener listener) { + return ArrayUtils.contains(support.getPropertyChangeListeners(), listener); + } + + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + if (support == null) { + support = new PropertyChangeSupport(this); + } + support.firePropertyChange(propertyName, oldValue, newValue); + } + + protected void firePropertyChange(String propertyName, int oldValue, int newValue) { + if (support == null) { + support = new PropertyChangeSupport(this); + } + support.firePropertyChange(propertyName, oldValue, newValue); + } + + protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { + if (support == null) { + support = new PropertyChangeSupport(this); + } + support.firePropertyChange(propertyName, oldValue, newValue); + } +} diff --git a/src/eu/engys/util/bean/Bindings.java b/src/eu/engys/util/bean/Bindings.java new file mode 100644 index 0000000..244a3e4 --- /dev/null +++ b/src/eu/engys/util/bean/Bindings.java @@ -0,0 +1,64 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.bean; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.Method; + +import eu.engys.util.ui.textfields.DoubleField; + +public class Bindings { + + public static void bind(final DoubleField field, final Object bean, final String key) { + field.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + set(bean, key, field.getDoubleValue()); + } + } + }); + } + + private static void set(Object bean, String key, Object value) { + try { + Method method = bean.getClass().getMethod(toSetter(key), value.getClass()); + method.invoke(bean, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static String toSetter(String key) { + return "set" + key.substring(0, 1).toUpperCase() + key.substring(1); + } + + private static String toGetter(String key) { + return "get" + key.substring(0, 1).toUpperCase() + key.substring(1); + } + +} diff --git a/src/eu/engys/util/connection/QueueParameters.java b/src/eu/engys/util/connection/QueueParameters.java new file mode 100644 index 0000000..e3550a5 --- /dev/null +++ b/src/eu/engys/util/connection/QueueParameters.java @@ -0,0 +1,79 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.connection; + +public class QueueParameters { + + public static final String QUEUE_NODES = "numberOfNodes"; + public static final String QUEUE_CPUS = "cpuPerNode"; + public static final String QUEUE_TIMEOUT = "timeout"; + public static final String QUEUE_FEATURE = "feature"; + public static final String QUEUE_NAMES = "nodeNames"; + + private int numberOfNodes = 1; + private String nodeNames = ""; + private int cpuPerNode = 1; + private int timeout = 12; + private String feature = ""; + + public int getNumberOfNodes() { + return numberOfNodes; + } + public void setNumberOfNodes(int numberOfNodes) { + this.numberOfNodes = numberOfNodes; + } + public int getCpuPerNode() { + return cpuPerNode; + } + public void setCpuPerNode(int cpuPerNode) { + this.cpuPerNode = cpuPerNode; + } + public int getTimeout() { + return timeout; + } + public void setTimeout(int timeout) { + this.timeout = timeout; + } + public String getFeature() { + return feature; + } + public void setFeature(String feature) { + this.feature = feature; + } + public void setNodeNames(String nodeNames) { + this.nodeNames = nodeNames; + } + public String getNodeNames() { + return nodeNames; + } + + @Override + public String toString() { + return "Queue Parameters [ Number Of Nodes: " + numberOfNodes + " - Cpu Per Node: " + cpuPerNode + " - Feature: " + feature + " - Timeout: " + timeout + " ]"; + } + + +} diff --git a/src/eu/engys/util/connection/SshParameters.java b/src/eu/engys/util/connection/SshParameters.java new file mode 100644 index 0000000..c18cbfc --- /dev/null +++ b/src/eu/engys/util/connection/SshParameters.java @@ -0,0 +1,186 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.connection; + +import java.io.Serializable; + +public class SshParameters implements Serializable { + + public static final String USER = "user"; + public static final String SSH_PWD = "sshpwd"; + public static final String SSH_KEY = "sshkey"; + public static final String HOST = "host"; + public static final String PORT = "port"; + public static final String AUTHENTICATION = "sshauth"; + public static final String REMOTE_BASEDIR = "remoteBaseDir"; + public static final String REMOTE_BASEDIR_PARENT = "remoteBaseDirParent"; + public static final String APPLICATION_DIR = "applicationDir"; + public static final String OPENFOAM_DIR = "openFoamDir"; + public static final String PARAVIEW_DIR = "paraviewDir"; + + public enum AuthType { + SSH_KEY, SSH_PWD; + + public boolean isKey() { + return this == SSH_KEY; + } + } + + private int port = 22; + private String user = ""; + private String host = ""; + private String sshkey = ""; + private String sshpwd = ""; + + private String remoteBaseDir = ""; + private String remoteBaseDirParent = ""; + private String openFoamDir = ""; + private String paraviewDir = ""; + private String applicationDir = ""; + private AuthType sshauth = AuthType.SSH_PWD; + + public void copy(SshParameters sshParameters) { + setUser(sshParameters.getUser()); + setSshpwd(sshParameters.getSshpwd()); + setSshkey(sshParameters.getSshkey()); + setHost(sshParameters.getHost()); + setPort(sshParameters.getPort()); + setSshauth(sshParameters.getSshauth()); + setRemoteBaseDir(sshParameters.getRemoteBaseDir()); + setRemoteBaseDirParent(sshParameters.getRemoteBaseDirParent()); + setApplicationDir(sshParameters.getApplicationDir()); + setOpenFoamDir(sshParameters.getOpenFoamDir()); + setParaviewDir(sshParameters.getParaviewDir()); + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public AuthType getSshauth() { + return sshauth; + } + + public void setSshauth(AuthType sshauth) { + this.sshauth = sshauth; + } + + public String getSshkey() { + return sshkey; + } + + public void setSshkey(String sshkey) { + this.sshkey = sshkey; + } + + public String getSshpwd() { + return sshpwd; + } + + public void setSshpwd(String sshpwd) { + this.sshpwd = sshpwd; + } + + public String getRemoteBaseDir() { + return remoteBaseDir; + } + + public void setRemoteBaseDir(String remoteBaseDir) { + this.remoteBaseDir = remoteBaseDir; + } + + public String getRemoteBaseDirParent() { + return remoteBaseDirParent; + } + + public void setRemoteBaseDirParent(String remoteBaseDirParent) { + this.remoteBaseDirParent = remoteBaseDirParent; + } + + public String getOpenFoamDir() { + return openFoamDir; + } + + public void setOpenFoamDir(String openFoamDir) { + this.openFoamDir = openFoamDir; + } + + public void setParaviewDir(String paraviewDir) { + this.paraviewDir = paraviewDir; + } + + public String getParaviewDir() { + return paraviewDir; + } + + public String getApplicationDir() { + return applicationDir; + } + + public void setApplicationDir(String elementsDir) { + this.applicationDir = elementsDir; + } + + public boolean isValidForRemoteChooser() { + return (user != null) && (sshpwd != null) || (host != null); + } + + @Override + public String toString() { + return "SSHParameters: " + + "\nUSER [ " + getUser() + " ]" + + "\nHOST [ " + getHost() + " ]" + + "\nPORT [ " + getPort() + " ]" + + "\nAUTH [ " + getSshauth() + " ]" + + "\nPASS [ ******* ]" + + "\nKEY [ " + getSshkey() + " ]" + + "\nRDIR [ " + getRemoteBaseDir() + " ]" + + "\nCDIR [ " + getRemoteBaseDirParent() + " ]" + + "\nOFDIR [ " + getOpenFoamDir() + " ]" + + "\nPVDIR [ " + getParaviewDir() + " ]" + + "\nAPDIR [ " + getApplicationDir() + " ]"; + } +} diff --git a/src/eu/engys/util/connection/SshUtils.java b/src/eu/engys/util/connection/SshUtils.java new file mode 100644 index 0000000..a204b74 --- /dev/null +++ b/src/eu/engys/util/connection/SshUtils.java @@ -0,0 +1,618 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.connection; + +import java.awt.Container; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.URL; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.Vector; + +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.net.telnet.TelnetClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcraft.jsch.Channel; +import com.jcraft.jsch.ChannelExec; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.ChannelSftp.LsEntry; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.SftpATTRS; +import com.jcraft.jsch.SftpException; +import com.jcraft.jsch.SftpProgressMonitor; +import com.jcraft.jsch.UIKeyboardInteractive; +import com.jcraft.jsch.UserInfo; + +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public class SshUtils { + + public static final int TIMEOUT = 21000; + + private static final Logger logger = LoggerFactory.getLogger(SshUtils.class); + + private static final URL PLINK_URL = SshUtils.class.getClassLoader().getResource("eu/engys/gui/vtk/depot/ssh/plink.exe"); + + public enum Terminal { + XTERM, GNOMETERMINAL, KONSOLE + } + + public static boolean testTelnetConnection(String machine, int port) { + TelnetClient c = new TelnetClient(); + try { + c.connect(machine, port); + c.disconnect(); + return true; + } catch (IOException e) { + logger.error("TELNET: {}", e.getMessage()); + return false; + } + } + + public static boolean testPingConnection(String machine) { + try { + InetAddress address = InetAddress.getByName(machine); + address.isReachable(3000); + return true; + } catch (IOException e) { + logger.error(e.getMessage()); + return false; + } + } + + private static void checkParameters(SshParameters parameters) throws JSchException { + if (parameters.getUser() == null || parameters.getUser().isEmpty()) + throw new JSchException("Username not set"); + if (parameters.getHost() == null || parameters.getHost().isEmpty()) + throw new JSchException("Hostname not set"); + } + + public static Session createSession(SshParameters parameters) throws JSchException { + checkParameters(parameters); + + String user = parameters.getUser(); + String host = parameters.getHost(); + int port = parameters.getPort(); + String passwd = parameters.getSshpwd(); + boolean authWithKey = parameters.getSshauth().isKey(); + + if (authWithKey) { + Path key = Paths.get(parameters.getSshkey()); + return createSession(user, host, key, port); + } else { + return createSession(user, host, passwd, port); + } + } + + private static Session createSession(String user, String host, String password, int port) throws JSchException { + Session session = new JSch().getSession(user, host, port); + session.setPassword(password); + UserInfo ui = new MyUserInfo(); + session.setUserInfo(ui); + session.setConfig("compression.s2c", "zlib@openssh.com,zlib,none"); + session.setConfig("compression.c2s", "zlib@openssh.com,zlib,none"); + session.setConfig("compression_level", "9"); + logger.info("CREATE SESSION: CONNECT"); + session.connect(TIMEOUT); + logger.info("CREATE SESSION: CONNECTED"); + return session; + } + + private static Session createSession(String user, String host, Path privateKey, int port) throws JSchException { + JSch jsch = new JSch(); + jsch.addIdentity(privateKey.toString()); + Session session = jsch.getSession(user, host, port); + UserInfo ui = new MyUserInfo(); + session.setUserInfo(ui); + session.setConfig("compression.s2c", "zlib@openssh.com,zlib,none"); + session.setConfig("compression.c2s", "zlib@openssh.com,zlib,none"); + session.setConfig("compression_level", "9"); + session.connect(20000); + return session; + } + + public static ChannelExec createEXEChannel(Session session) throws JSchException { + Channel channel = session.openChannel("exec"); + logger.info("EXE CHANNEL: CREATED"); + return (ChannelExec) channel; + } + + public static ChannelSftp createSFTPChannel(Session session) throws JSchException { + Channel channel = session.openChannel("sftp"); + logger.info("SFTP CHANNEL: OPENED"); + channel.connect(); + logger.info("SFTP CHANNEL: CONNECTED"); + return (ChannelSftp) channel; + } + + public static void uploadFileOrFolder(Path localFile, String remoteDestination, ChannelSftp channel, ProgressMonitor monitor) throws SftpException, JSchException, IOException { + channel.cd(remoteDestination.toString()); + String remoteFile = remoteDestination + getFilePathSeparator(remoteDestination) + localFile.getFileName(); + if (remoteFileAlreadyExists(remoteFile, channel)) { + int res = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "File " + remoteFile + " already exists. Override?"); + if (res == JOptionPane.OK_OPTION) { + if (localFile.toFile().isDirectory()) { + // channel.rmdir gives an error + execSSHCommand("rm -rf " + remoteFile.toString(), channel.getSession()); + } else { + channel.rm(localFile.getFileName().toString()); + } + createFileOrFolder(localFile, remoteDestination, channel, monitor); + } + } else { + createFileOrFolder(localFile, remoteDestination, channel, monitor); + } + } + + public static void uploadFileOrFolderForced(Path localFile, String remoteDestination, ChannelSftp channel, ProgressMonitor monitor) throws SftpException, JSchException, IOException { + channel.cd(remoteDestination.toString()); + createFileOrFolder(localFile, remoteDestination, channel, monitor); + } + + public static void createFileOrFolder(Path localFile, String remoteDestination, ChannelSftp channel, ProgressMonitor monitor) throws SftpException, JSchException, IOException { + if (localFile.toFile().isDirectory()) { + channel.mkdir(localFile.getFileName().toString()); + if (monitor != null) { + monitor.info("New folder: " + localFile.getFileName().toString()); + } + for (File file : localFile.toFile().listFiles()) { + uploadFileOrFolder(Paths.get(file.toURI()), remoteDestination + getFilePathSeparator(remoteDestination) + localFile.getFileName(), channel, monitor); + } + } else { + if (monitor != null) { + monitor.info("Uploading: " + localFile.toString()); + } + channel.put(new FileInputStream(localFile.toFile()), localFile.getFileName().toString(), monitor != null ? new UploadProgressMonitor(monitor, (int) Files.size(localFile)) : null); + } + } + + public static void removeFileOrFolder(Path localFile, String remoteFile, ChannelSftp channel, ProgressMonitor monitor) throws JSchException, IOException, SftpException { + if (localFile.toFile().isDirectory()) { + execSSHCommand("rm -rf " + remoteFile.toString(), channel.getSession()); + } else { + channel.rm(localFile.getFileName().toString()); + } + } + + public static void removeFile(String remoteFolder, String fileName, ChannelSftp channel) throws SftpException { + channel.cd(remoteFolder); + channel.rm(fileName); + } + + public static boolean remoteFileAlreadyExists(String file, ChannelSftp channel) throws SftpException { + try { + SftpATTRS attrs = channel.stat(file); + return attrs != null; + } catch (SftpException e) { + return false; + } + } + + @SuppressWarnings("unchecked") + public static void downloadFolder(String remoteFolder, Path localDestination, ChannelSftp channel, ProgressMonitor monitor) throws SftpException { + Path localFolder = localDestination.resolve(new File(remoteFolder).getName()); + if (!localFolder.toFile().exists()) { + localFolder.toFile().mkdirs(); + } + Vector list = channel.ls(remoteFolder.toString()); + for (ChannelSftp.LsEntry file : list) { + if (!isCurrentOrParentDir(file)) { + if (file.getAttrs().isDir()) { + downloadFolder(remoteFolder + getFilePathSeparator(remoteFolder) + file.getFilename(), localFolder, channel, monitor); + } else { + downloadFile(remoteFolder + getFilePathSeparator(remoteFolder) + file.getFilename(), localFolder, channel, monitor); + } + } + + } + } + + public static class UploadProgressMonitor implements SftpProgressMonitor { + + private ProgressMonitor monitor; + private int total; + + public UploadProgressMonitor(ProgressMonitor monitor, int total) { + this.monitor = monitor; + this.total = total; + } + + @Override + public void init(int op, String src, String dest, long max) { + monitor.setTotal(total); + monitor.setCurrent(null, 0); + } + + @Override + public boolean count(long l) { + monitor.setCurrent(null, monitor.getCurrent() + (int) l); + return true; + } + + @Override + public void end() { + } + } + + public static class DownloadProgressMonitor implements SftpProgressMonitor { + + private ProgressMonitor monitor; + + public DownloadProgressMonitor(ProgressMonitor monitor) { + this.monitor = monitor; + } + + @Override + public void init(int op, String src, String dest, long max) { + monitor.setTotal((int) max); + monitor.setCurrent(null, 1); + monitor.infoN(src + " -> " + dest); + } + + @Override + public boolean count(long l) { + monitor.setCurrent(null, monitor.getCurrent() + (int) l); + return true; + } + + @Override + public void end() { + monitor.info(" DONE"); + } + } + + public static void downloadFile(String remoteFile, Path localDestination, ChannelSftp channel, ProgressMonitor monitor) throws SftpException { + channel.get(remoteFile, localDestination.toString(), new DownloadProgressMonitor(monitor)); + } + + public static void downloadFile(String remoteFile, Path localDestination, ChannelSftp channel) throws SftpException { + channel.get(remoteFile, localDestination.toString()); + } + + public static void exexRemoteScriptInLocalShell(String user, String host, String privateKeyPath, String scriptFile) throws IOException, InterruptedException { + String nameOS = System.getProperty("os.name"); + String command = null; + if (nameOS.startsWith("Windows")) { + String openTerminalcommand = "cmd /C start cmd.exe /K"; + String plinkPath = PLINK_URL.getFile().substring(1); + String sshCommand = "-ssh " + host + " -l " + user + " -i " + privateKeyPath + " -m"; + File scriptLauncher = createScriptLauncher(scriptFile); + String scriptLauncherPath = scriptLauncher.getAbsolutePath(); + command = openTerminalcommand + " " + plinkPath + " " + sshCommand + " " + scriptLauncherPath; + } else if (nameOS.startsWith("Linux")) { + Terminal terminal = getConsoleType(); + String openTerminalcommand = null; + switch (terminal) { + case GNOMETERMINAL: + openTerminalcommand = "gnome-terminal -x"; + break; + case KONSOLE: + openTerminalcommand = "konsole -e"; + break; + case XTERM: + openTerminalcommand = "xterm -x"; + break; + default: + break; + } + + String sshCommand = "ssh " + user + "@" + host + " -i " + privateKeyPath.toString() + " " + scriptFile; + command = openTerminalcommand + " " + sshCommand; + + } else { + System.out.println("OS NOT SUPPORTED!"); + } + Process p = Runtime.getRuntime().exec(command); + p.waitFor(); + } + + public static void execSSHCommand(String command, Session session) throws JSchException, IOException { + execSSHCommand(command, session, null); + } + + public static void execSSHCommand(String command, Session session, Map env) throws JSchException, IOException { + ChannelExec channel = (ChannelExec) session.openChannel("exec"); + channel.setCommand(addEnvToCommand(command, env)); + channel.setInputStream(null); + // InputStream stdout = channel.getInputStream(); + InputStream stderr = channel.getErrStream(); + + channel.connect(); + + waitForChannelClosed(channel); + + String ERR = IOUtils.toString(stderr); + // String OUT = IOUtils.toString(stdout); + + // System.out.println("SSHUtils.execSSHCommand() OUT: "+OUT); + + try { + if (channel.getExitStatus() > 0) { + throw new JSchException(ERR); + } + } finally { + channel.disconnect(); + } + } + + public static String addEnvToCommand(String command, Map env) { + StringBuilder sb = new StringBuilder(); + if (env != null) { + for (String key : env.keySet()) { + sb.append("export " + key + "=" + env.get(key)); + sb.append(" && "); + } + } + sb.append(command); + return sb.toString(); + } + + public static String addProfileLoaderToCommand(String command) { + StringBuilder sb = new StringBuilder(); + sb.append("[[ -e ~/.profile ]] && source ~/.profile; "); + sb.append("[[ -e ~/.bash_profile ]] && source ~/.bash_profile; "); + sb.append(command); + return sb.toString(); + } + + private static void waitForChannelClosed(ChannelExec channel) { + while (channel.getExitStatus() == -1 && !channel.isClosed()) { + try { + Thread.sleep(1000); + } catch (Exception e) { + } + } + } + + public static void makeExecutable(String filePath, Session session) { + try { + execSSHCommand("chmod +x " + filePath, session); + } catch (JSchException | IOException e) { + e.printStackTrace(); + } + } + + private static Terminal getConsoleType() throws IOException, InterruptedException { + Process p = Runtime.getRuntime().exec("which gnome-terminal"); + p.waitFor(); + if (p.exitValue() == 0) { + return Terminal.GNOMETERMINAL; + } + Process p1 = Runtime.getRuntime().exec("which konsole"); + p1.waitFor(); + if (p1.exitValue() == 0) { + return Terminal.KONSOLE; + } + return Terminal.XTERM; + } + + private static File createScriptLauncher(String string) throws IOException { + File file = File.createTempFile("xxx", null); + FileWriter fstream = new FileWriter(file); + BufferedWriter out = new BufferedWriter(fstream); + out.write(string); + out.close(); + return file; + } + + public static boolean testConnection(SshParameters sshParameters) { + return testConnection(sshParameters, null, false, false); + } + + public static boolean testConnection(SshParameters sshParameters, Path localDestination, boolean testUpload, boolean testDownload) { + logger.info("TEST SSH CONNECTION"); + try { + Session session = createSession(sshParameters); + + // TEST FTP CONNECTION + logger.info("TEST SFTP CONNECTION"); + ChannelSftp channel = SshUtils.createSFTPChannel(session); + + File tmpFile = File.createTempFile("xxx", null); + + String remoteDestination = sshParameters.getRemoteBaseDirParent(); + + // TEST UPLOAD FILE + if (testUpload) { + logger.info("TEST SFTP CONNECTION: UPLOAD"); + uploadFileOrFolder(Paths.get(tmpFile.toURI()), remoteDestination, channel, null); + execSSHCommand("rm " + remoteDestination + getFilePathSeparator(remoteDestination) + tmpFile.getName(), session); + } + + // TEST DOWNLOAD FILE + if (testDownload) { + logger.info("TEST SFTP CONNECTION: DOWNLOAD"); + downloadFile(remoteDestination + getFilePathSeparator(remoteDestination) + tmpFile.getName(), localDestination, channel); + new File(localDestination + File.separator + tmpFile.getName()).delete(); + } + + tmpFile.delete(); + channel.disconnect(); + session.disconnect(); + + logger.info("TEST SSH CONNECTION: SUCCESS"); + + return true; + } catch (Exception e) { + showErrorDialog(e); + logger.error("TEST SSH CONNECTION: ERROR {} PARAMETERS ARE {}", e.getMessage(), sshParameters); + return false; + } + } + + public static void showErrorDialog(Exception e) { + showError(decodeErrorMessage(e)); + } + + public static String decodeErrorMessage(Exception e) { + String message = ""; + if (e instanceof SftpException) { + message = "Remote path does not exists!"; + } else if (e instanceof JSchException) { + JSchException ex = ((JSchException) e); + if (ex.getCause() != null && ex.getCause() instanceof UnknownHostException) { + message = "Unknown host!"; + } else { + message = "Wrong username or password/key!"; + } + } else { + message = "Unknown exception: " + e.getMessage(); + + } + return message; + } + + private static void showError(final String message) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Connection failed!\n" + message, "SSH connection status", JOptionPane.ERROR_MESSAGE); + } + }); + } + + private static boolean isCurrentOrParentDir(LsEntry file) { + return file.getFilename().equals("..") || file.getFilename().equals("."); + } + + public static String getFilePathSeparator(String path) { + return path.indexOf("/") == -1 ? "\\" : "/"; + } + + private static class MyUserInfo implements UserInfo, UIKeyboardInteractive { + private String passphrase; + private JTextField passphraseField = null; + + public MyUserInfo() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + passphraseField = (JTextField) new JPasswordField(20); + } + }); + } + + public String getPassword() { + return null; + } + + public boolean promptYesNo(String str) { + return true; + } + + public String getPassphrase() { + return passphrase; + } + + public boolean promptPassphrase(String message) { + Object[] ob = { passphraseField }; + int result = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), ob, message, JOptionPane.OK_CANCEL_OPTION); + if (result == JOptionPane.OK_OPTION) { + passphrase = passphraseField.getText(); + return true; + } else { + return false; + } + } + + public boolean promptPassword(String message) { + return true; + } + + public void showMessage(String message) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), message, "SSH Info", JOptionPane.INFORMATION_MESSAGE); + } + + final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0); + private Container panel; + + public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) { + panel = new JPanel(); + panel.setLayout(new GridBagLayout()); + + gbc.weightx = 1.0; + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.gridx = 0; + panel.add(new JLabel(instruction), gbc); + gbc.gridy++; + + gbc.gridwidth = GridBagConstraints.RELATIVE; + + JTextField[] texts = new JTextField[prompt.length]; + for (int i = 0; i < prompt.length; i++) { + gbc.fill = GridBagConstraints.NONE; + gbc.gridx = 0; + gbc.weightx = 1; + panel.add(new JLabel(prompt[i]), gbc); + + gbc.gridx = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weighty = 1; + if (echo[i]) { + texts[i] = new JTextField(20); + } else { + texts[i] = new JPasswordField(20); + } + panel.add(texts[i], gbc); + gbc.gridy++; + } + + if (JOptionPane.showConfirmDialog(panel, "SSH Info", destination + ": " + name, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) { + String[] response = new String[prompt.length]; + for (int i = 0; i < prompt.length; i++) { + response[i] = texts[i].getText(); + } + return response; + } else { + return null; // cancel + } + } + } +} diff --git a/src/eu/engys/util/filechooser/AbstractFileChooser.java b/src/eu/engys/util/filechooser/AbstractFileChooser.java new file mode 100644 index 0000000..71cfa87 --- /dev/null +++ b/src/eu/engys/util/filechooser/AbstractFileChooser.java @@ -0,0 +1,174 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser; + +import java.awt.Dimension; +import java.awt.HeadlessException; +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; + +import javax.swing.JDialog; + +import eu.engys.util.filechooser.gui.FileChooserPanel; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.UiUtil; + +public class AbstractFileChooser { + + public enum ReturnValue { + Approve, Cancelled; + + public boolean isApprove() { + return equals(Approve); + } + + public boolean isCancelled() { + return equals(Cancelled); + } + } + + protected FileChooserPanel panel; + private ReturnValue returnValue = ReturnValue.Cancelled; + protected String initialPath; + private JDialog dialog; + private SelectionMode selectionMode = SelectionMode.DIRS_AND_FILES; + private boolean multiSelectionEnabled; + private String title; + private Window parent; + private File fileToSelect; + + public AbstractFileChooser() { + this(null); + } + + public AbstractFileChooser(String initialPath) { + this.initialPath = initialPath; + } + + protected ReturnValue initializeAndShow(Dimension d) { + this.panel.layoutComponents(); + this.panel.setSelectionMode(selectionMode); + this.panel.setSelectedFile(ensureValidFileToSelect(fileToSelect)); + this.panel.setMultiSelectionEnabled(multiSelectionEnabled); + this.panel.initialize(ensureValidInitialPath(initialPath)); + return showDialog(d); + } + + protected String ensureValidInitialPath(String pathToCheck) { + return pathToCheck; + } + + protected File ensureValidFileToSelect(File fileToCheck) { + return fileToCheck; + } + + private ReturnValue showDialog(Dimension d) throws HeadlessException { + dialog = new JDialog(parent != null ? parent : UiUtil.getActiveWindow()); + dialog.setName("helyx.chooser.dialog"); + dialog.setTitle(title != null ? title : createTitle()); + dialog.getContentPane().add(panel); + dialog.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + returnValue = ReturnValue.Cancelled; + } + }); + dialog.setSize(d); + dialog.setLocationRelativeTo(null); + dialog.setModal(true); + dialog.setVisible(true); + dialog.getRootPane().setDefaultButton(panel.getOkButton()); + return returnValue; + } + + private String createTitle() { + switch (selectionMode) { + case DIRS_ONLY: + return "Select Folder"; + case FILES_ONLY: + return "Select File"; + case DIRS_AND_FILES: + return "Select File or Folder"; + default: + return "Select File or Folder"; + } + } + + public HelyxFileFilter getSelectedFileFilter(){ + return panel.getSelectedFilter(); + } + + public void setMultiSelectionEnabled(boolean multiSelectionEnabled) { + this.multiSelectionEnabled = multiSelectionEnabled; + } + + public void setSelectionMode(SelectionMode selectionMode) { + this.selectionMode = selectionMode; + } + + public void selectFile(File fileToSelect) { + this.fileToSelect = fileToSelect; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setReturnValue(ReturnValue returnValue) { + this.returnValue = returnValue; + } + + public void disposeDialog() { + if (dialog != null) {// FOR TESTS + dialog.setVisible(false); + dialog.dispose(); + } + } + + public void setParent(Window parent) { + this.parent = parent; + } + + /* + * For test purpose only + */ + public void setPanel(FileChooserPanel panel) { + this.panel = panel; + } + + public FileChooserPanel getPanel() { + return panel; + } + + private static final int WIDTH = 750; + private static final int HELIGHT = 500; + + protected Dimension getDimension(Dimension d) { + return d != null ? d : new Dimension(WIDTH, HELIGHT); + } +} diff --git a/src/eu/engys/util/filechooser/FileChooserEventListener.java b/src/eu/engys/util/filechooser/FileChooserEventListener.java new file mode 100644 index 0000000..ffc4165 --- /dev/null +++ b/src/eu/engys/util/filechooser/FileChooserEventListener.java @@ -0,0 +1,32 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser; + +public interface FileChooserEventListener { + + public void urlSelected(); + +} diff --git a/src/eu/engys/util/filechooser/HelyxFileChooser.java b/src/eu/engys/util/filechooser/HelyxFileChooser.java new file mode 100644 index 0000000..04a687e --- /dev/null +++ b/src/eu/engys/util/filechooser/HelyxFileChooser.java @@ -0,0 +1,163 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser; + +import java.awt.Dimension; +import java.io.File; + +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileObject; + +import eu.engys.util.filechooser.gui.Accessory; +import eu.engys.util.filechooser.gui.BrowserFactory; +import eu.engys.util.filechooser.gui.Options; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.VFSUtils; + +public class HelyxFileChooser extends AbstractFileChooser { + + public HelyxFileChooser() { + super(); + } + + public HelyxFileChooser(String initialPath) { + super(initialPath); + } + + public ReturnValue showOpenDialog() { + this.panel = BrowserFactory.createOpenBrowser(this); + return initializeAndShow(getDimension(null)); + } + + public ReturnValue showOpenDialog(Dimension d) { + this.panel = BrowserFactory.createOpenBrowser(this); + return initializeAndShow(getDimension(d)); + } + + public ReturnValue showOpenDialog(HelyxFileFilter... filters) { + this.panel = BrowserFactory.createOpenBrowser(this, filters); + return initializeAndShow(getDimension(null)); + } + + public ReturnValue showOpenDialog(Accessory accessory) { + this.panel = BrowserFactory.createOpenBrowser(this, accessory); + return initializeAndShow(getDimension(null)); + } + + public ReturnValue showOpenDialog(Options options) { + this.panel = BrowserFactory.createOpenBrowser(this, options); + return initializeAndShow(getDimension(null)); + } + + public ReturnValue showOpenDialog(Accessory accessory, Dimension d, HelyxFileFilter... filters) { + this.panel = BrowserFactory.createOpenBrowser(this, accessory, filters); + return initializeAndShow(getDimension(d)); + } + + public ReturnValue showSaveAsDialog() { + this.panel = BrowserFactory.createSaveAsBrowser(this); + return initializeAndShow(getDimension(null)); + } + + public ReturnValue showSaveAsDialog(HelyxFileFilter... filters) { + this.panel = BrowserFactory.createSaveAsBrowser(this, filters); + return initializeAndShow(getDimension(null)); + } + + public File getSelectedFile() { + File[] files = getSelectedFiles(); + if (files != null && files.length > 0) { + return files[0]; + } + return null; + } + + public File[] getSelectedFiles() { + FileObject[] selectedFileObjects = panel.getFileObjects(); + if (selectedFileObjects == null) { + return null; + } else { + File[] selectedFiles = new File[selectedFileObjects.length]; + for (int i = 0; i < selectedFileObjects.length; i++) { + FileName name = selectedFileObjects[i].getName(); + selectedFiles[i] = new File(VFSUtils.decode(name.getURI(), null)); + } + return selectedFiles; + } + } + + @Override + protected String ensureValidInitialPath(String pathToCheck) { + if (pathToCheck == null || new File(pathToCheck).exists()) { + return pathToCheck; + } else { + File parentFile = new File(pathToCheck).getParentFile(); + if (parentFile == null) { + return null; + } else if (parentFile.exists()) { + return parentFile.getAbsolutePath(); + } else { + return ensureValidInitialPath(parentFile.getAbsolutePath()); + } + } + } + + @Override + protected File ensureValidFileToSelect(File fileToCheck) { + if (fileToCheck == null) + return null; + String path = ensureValidInitialPath(fileToCheck.getAbsolutePath()); + return path != null ? new File(path) : null; + } + + // public static void main(String[] args) { + // JFrame f = UiUtil.defaultTestFrame("a", new JButton(new AbstractAction("open") { + // @Override + // public void actionPerformed(ActionEvent e) { + // HelyxFileChooser fileChooser = new HelyxFileChooser("C:\\"); + // fileChooser.showOpenDialog(); + // } + // })); + // f.setSize(200, 200); + // f.setVisible(true); + // } +} diff --git a/src/eu/engys/util/filechooser/LinkFileObject.java b/src/eu/engys/util/filechooser/LinkFileObject.java new file mode 100644 index 0000000..0bb94d2 --- /dev/null +++ b/src/eu/engys/util/filechooser/LinkFileObject.java @@ -0,0 +1,60 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; + +import eu.engys.util.filechooser.util.FileObjectWrapper; + +public class LinkFileObject extends FileObjectWrapper { + + public LinkFileObject(FileObject parent) { + super(parent); + } + + @Override + public FileType getType() throws FileSystemException { + return FileType.IMAGINARY; + } +} diff --git a/src/eu/engys/util/filechooser/ParentFileObject.java b/src/eu/engys/util/filechooser/ParentFileObject.java new file mode 100644 index 0000000..f294759 --- /dev/null +++ b/src/eu/engys/util/filechooser/ParentFileObject.java @@ -0,0 +1,69 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser; + +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileObject; + +import eu.engys.util.filechooser.util.FileNameWrapper; +import eu.engys.util.filechooser.util.FileObjectWrapper; + +public class ParentFileObject extends FileObjectWrapper { + + public static final String PARENT_NAME = "[..]"; + private FileName fileName; + + public ParentFileObject(FileObject parent) { + super(parent); + fileName = new FileNameWrapper(parent.getName()) { + @Override + public String getBaseName() { + return PARENT_NAME; + } + }; + } + + @Override + public FileName getName() { + return fileName; + } +} diff --git a/src/eu/engys/util/filechooser/RemoteFileChooser.java b/src/eu/engys/util/filechooser/RemoteFileChooser.java new file mode 100644 index 0000000..68c70ab --- /dev/null +++ b/src/eu/engys/util/filechooser/RemoteFileChooser.java @@ -0,0 +1,111 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.connection.SshParameters; +import eu.engys.util.filechooser.gui.BrowserFactory; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.UiUtil; + +public class RemoteFileChooser extends AbstractFileChooser { + + private static final Logger LOGGER = LoggerFactory.getLogger(RemoteFileChooser.class); + + private SshParameters sshParameters; + + public RemoteFileChooser(SshParameters sshParameters) { + super(); + this.sshParameters = sshParameters; + } + + public RemoteFileChooser(SshParameters sshParameters, String initialPath) { + this.initialPath = encodePath(initialPath); + } + + public ReturnValue showOpenRemoteDialogConnectionTested(final ProgressMonitor progressMonitor) { + this.panel = BrowserFactory.createOpenRemoteBrowser(this, sshParameters); + return initializeAndShow(getDimension(null)); + } + + public ReturnValue showOpenRemoteDialog(final ProgressMonitor progressMonitor) { + Boolean retVal = UiUtil.testConnection(sshParameters, progressMonitor); + if (!retVal) { + return ReturnValue.Cancelled; + } + this.panel = BrowserFactory.createOpenRemoteBrowser(this, sshParameters); + return initializeAndShow(getDimension(null)); + } + + public FileObject getSelectedFileObject() { + FileObject[] files = getSelectedFileObjects(); + if (files != null && files.length > 0) { + return files[0]; + } + return null; + } + + public FileObject[] getSelectedFileObjects() { + return panel.getFileObjects(); + } + + private String encodePath(String filePath) { + try { + String encodePath = VFSUtils.encode(filePath, sshParameters); + FileObject fileObject = VFSUtils.resolveFileObject(encodePath, sshParameters); + if (fileObject != null) { + return fileObject.getName().getPath(); + } else { + return ""; + } + } catch (FileSystemException e1) { + LOGGER.error("Cannot resolve: " + filePath + ". " + e1.getMessage()); + return ""; + } + } + +} diff --git a/src/eu/engys/util/filechooser/actions/DeleteFileAction.java b/src/eu/engys/util/filechooser/actions/DeleteFileAction.java new file mode 100644 index 0000000..8f8d0ba --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/DeleteFileAction.java @@ -0,0 +1,82 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.actions; + +import java.awt.event.ActionEvent; +import java.io.File; + +import javax.swing.AbstractAction; +import javax.swing.Icon; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; + +public final class DeleteFileAction extends AbstractAction { + + private static final Logger logger = LoggerFactory.getLogger(DeleteFileAction.class); + private FileChooserController controller; + + public DeleteFileAction(FileChooserController controller) { + super("Delete"); + this.controller = controller; + putValue(SMALL_ICON, DELETE_FOLDER_ICON); + putValue(SHORT_DESCRIPTION, DELETE_FOLDER_TEXT); + setEnabled(!controller.isRemote()); + } + + @Override + public void actionPerformed(ActionEvent e) { + FileObject[] fileObjects = controller.getFileSystemPanel().getSelectedFileObjects(); + for (FileObject fo : fileObjects) { + File file = new File(VFSUtils.decode(fo.getName().getURI(), controller.getSshParameters())); + FileUtils.deleteQuietly(file); + } + refresh(controller.getUriPanel().getFileObject()); + } + + private void refresh(FileObject fileObject) { + try { + fileObject.refresh(); + controller.goToURL(fileObject); + } catch (FileSystemException e) { + logger.error("Can't refresh location", e.getMessage()); + } + } + + /** + * Resources + */ + private static final String DELETE_FOLDER_TEXT = ResourcesUtil.getString("delete.file.label"); + private static final Icon DELETE_FOLDER_ICON = ResourcesUtil.getIcon("delete.file.icon"); + +} diff --git a/src/eu/engys/util/filechooser/actions/ExtractArchiveAction.java b/src/eu/engys/util/filechooser/actions/ExtractArchiveAction.java new file mode 100644 index 0000000..0353943 --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/ExtractArchiveAction.java @@ -0,0 +1,122 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.actions; + +import java.awt.event.ActionEvent; +import java.io.File; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.ArchiveUtils; +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; + +public final class ExtractArchiveAction extends AbstractAction { + + private static final Logger logger = LoggerFactory.getLogger(ExtractArchiveAction.class); + private FileChooserController controller; + + public ExtractArchiveAction(FileChooserController controller) { + super("Extract"); + this.controller = controller; + putValue(SMALL_ICON, EXTRACT_ARCHIVE_ICON); + putValue(SHORT_DESCRIPTION, EXTRACT_ARCHIVE_TEXT); + setEnabled(!controller.isRemote()); + } + + @Override + public void actionPerformed(ActionEvent e) { + controller.showLoading(); + new Thread(new Runnable() { + + @Override + public void run() { + extractArchives(); + controller.showTable(); + } + }).start(); + + } + + private void extractArchives() { + FileObject[] fileObjects = controller.getFileSystemPanel().getSelectedFileObjects(); + for (FileObject fileObject : fileObjects) { + extractFileObject(fileObject); + } + } + + private void extractFileObject(FileObject archivedFileObject) { + try { + final File selectedFile = new File(VFSUtils.decode(archivedFileObject.getName().getURI(), controller.getSshParameters())); + if (ArchiveUtils.isArchive(selectedFile)) { + File parentFile = new File(VFSUtils.decode(archivedFileObject.getParent().getName().getURI(), controller.getSshParameters())); + ArchiveUtils.unarchive(selectedFile, parentFile); + + controller.resetFileFilter(); + refresh(archivedFileObject.getParent()); + + controller.getFileSystemPanel().selectFileByName(removeExtension(selectedFile.getAbsolutePath())); + } else { + JOptionPane.showMessageDialog(SwingUtilities.getRoot(controller.getFileSystemPanel()), "The selected file is not a known archive file", "Archive Error", JOptionPane.ERROR_MESSAGE); + } + + } catch (Exception e) { + logger.error("Can't extract file", e); + } + } + + public String removeExtension(String fileName) { + String noFirstExtension = FilenameUtils.getBaseName(fileName); + String noEventualSecondExtension = FilenameUtils.getBaseName(noFirstExtension); + return noEventualSecondExtension; + } + + private void refresh(FileObject fileObject) { + try { + fileObject.refresh(); + controller.goToURL(fileObject); + } catch (FileSystemException e) { + logger.error("Can't refresh location", e); + } + } + + /** + * Resources + */ + private static final String EXTRACT_ARCHIVE_TEXT = ResourcesUtil.getString("extract.archive.label"); + private static final Icon EXTRACT_ARCHIVE_ICON = ResourcesUtil.getIcon("extract.archive.icon"); + +} diff --git a/src/eu/engys/util/filechooser/actions/NewFolderAction.java b/src/eu/engys/util/filechooser/actions/NewFolderAction.java new file mode 100644 index 0000000..7adbfe5 --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/NewFolderAction.java @@ -0,0 +1,112 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.actions; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.io.File; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.textfields.PromptTextField; + +public final class NewFolderAction extends AbstractAction { + + private static final String FOLDER_ALREADY_EXISTS = "Folder already exists"; + private static final String EMPTY_NAME_MESSAGE = "Cannot create folder with emptyName!"; + private static final String NEW_FOLDER_NAME = "New Folder Name"; + private static final Logger logger = LoggerFactory.getLogger(NewFolderAction.class); + private FileChooserController controller; + + public NewFolderAction(FileChooserController controller) { + super("New"); + this.controller = controller; + putValue(SMALL_ICON, NEW_FOLDER_ICON); + putValue(SHORT_DESCRIPTION, NEW_FOLDER_TEXT); + setEnabled(!controller.isRemote()); + } + + @Override + public void actionPerformed(ActionEvent e) { + FileObject fileObject = controller.getUriPanel().getFileObject(); + String newFolderName = askNewFolderName(); + if (newFolderName == null) { + return; + } else if (newFolderName.isEmpty()) { + JOptionPane.showMessageDialog(SwingUtilities.getRoot(controller.getUriPanel()), EMPTY_NAME_MESSAGE, NEW_FOLDER_NAME, JOptionPane.ERROR_MESSAGE); + } else { + String parentFile = VFSUtils.decode(fileObject.getName().getURI(), controller.getSshParameters()); + File newFile = new File(parentFile, newFolderName); + if (newFile.exists()) { + JOptionPane.showMessageDialog(SwingUtilities.getRoot(controller.getUriPanel()), FOLDER_ALREADY_EXISTS, NEW_FOLDER_NAME, JOptionPane.ERROR_MESSAGE); + } else { + newFile.mkdirs(); + refresh(fileObject); + } + } + } + + private void refresh(FileObject fileObject) { + try { + fileObject.refresh(); + controller.goToURL(fileObject); + } catch (FileSystemException e) { + logger.error("Can't refresh location", e.getMessage()); + } + } + + private String askNewFolderName() { + final PromptTextField textFieldName = new PromptTextField(); + textFieldName.setName("newFolder.name"); + textFieldName.setPrompt("newFolder"); + + Object[] options = { "Create", "Cancel" }; + Component parent = SwingUtilities.getRoot(controller.getUriPanel()); + int response = JOptionPane.showOptionDialog(parent, textFieldName, NEW_FOLDER_NAME, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + if (response == JOptionPane.YES_OPTION) { + return textFieldName.getText(); + } + return null; + } + + /** + * Resources + */ + private static final String NEW_FOLDER_TEXT = ResourcesUtil.getString("new.folder.label"); + private static final Icon NEW_FOLDER_ICON = ResourcesUtil.getIcon("new.folder.icon"); + +} diff --git a/src/eu/engys/util/filechooser/actions/favorite/AddFavorite.java b/src/eu/engys/util/filechooser/actions/favorite/AddFavorite.java new file mode 100644 index 0000000..17af0d1 --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/favorite/AddFavorite.java @@ -0,0 +1,91 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.actions.favorite; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; + +import eu.engys.util.filechooser.favorites.Favorite; +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; + +/** + */ +public class AddFavorite extends AbstractAction { + + private FileChooserController controller; + + public AddFavorite(FileChooserController controller) { + this.controller = controller; + putValue(NAME, NAV_ADDTOFAVORITES); + putValue(SHORT_DESCRIPTION, NAV_ADDTOFAVORITES); + putValue(SMALL_ICON, STAR_PLUS); + + } + + @Override + public void actionPerformed(ActionEvent e) { + FileObject currentLocation = controller.getUriPanel().getFileObject(); + if (currentLocation != null) { + try { + String url = currentLocation.getURL().toString(); + String name = VFSUtils.decode(url, controller.getSshParameters()); + Favorite favorite = new Favorite(name, url, Favorite.Type.USER); + controller.addFavorite(favorite); + } catch (FileSystemException e1) { + e1.printStackTrace(); + } + } + } + + /** + * Resources + */ + private static final String NAV_ADDTOFAVORITES = ResourcesUtil.getString("nav.AddToFavorites"); + private static final Icon STAR_PLUS = ResourcesUtil.getIcon("starPlus"); +} diff --git a/src/eu/engys/util/filechooser/actions/favorite/EditFavorite.java b/src/eu/engys/util/filechooser/actions/favorite/EditFavorite.java new file mode 100644 index 0000000..223b0d4 --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/favorite/EditFavorite.java @@ -0,0 +1,167 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.actions.favorite; + +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; + +import eu.engys.util.filechooser.favorites.Favorite; +import eu.engys.util.filechooser.favorites.list.MutableListModel; +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; + +/** + */ +public class EditFavorite extends AbstractAction { + + private JList favoriteList; + private MutableListModel listModel; + private FileChooserController controller; + + public EditFavorite(FileChooserController controller, JList favoriteList, MutableListModel listModel) { + super(EDITFAVORITES_ACTIONNAME, EDITSIGNATURE); + super.putValue(SHORT_DESCRIPTION, EDITFAVORITES_TOOLTIP); + this.controller = controller; + this.favoriteList = favoriteList; + this.listModel = listModel; + } + + @Override + public void actionPerformed(ActionEvent actionEvent) { + if (favoriteList.getSelectedValue() != null) { + Favorite favorite = favoriteList.getSelectedValue(); + JPanel panel = new JPanel(new GridLayout(4, 1)); + + JTextField nameField = new JTextField(favorite.getName()); + addNameListeners(nameField); + nameField.setName("favorite.name"); + panel.add(new JLabel(EDITFAVORITES_NAME)); + panel.add(nameField); + + JTextField urlField = new JTextField(decodedURL(favorite), 20); + urlField.setName("favorite.url"); + panel.add(new JLabel(EDITFAVORITES_URL)); + panel.add(urlField); + + int response = JOptionPane.showConfirmDialog(SwingUtilities.getRoot(favoriteList), panel, EDITFAVORITES_TITLE, JOptionPane.YES_NO_OPTION); + if (response == JOptionPane.YES_OPTION) { + favorite.setName(nameField.getText()); + favorite.setUrl(encodedURL(urlField)); + listModel.change(favoriteList.getSelectedIndex(), favorite); + } + } + } + + private String encodedURL(JTextField urlField) { + return VFSUtils.encode(urlField.getText(), controller.getSshParameters()); + } + + private String decodedURL(Favorite favorite) { + return VFSUtils.decode(favorite.getUrl(), controller.getSshParameters()); + } + + private void addNameListeners(final JTextField text) { + text.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent evt) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + text.selectAll(); + } + }); + } + + @Override + public void focusLost(FocusEvent e) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + text.select(0, 0); + } + }); + } + }); + text.addAncestorListener(new AncestorListener() { + + @Override + public void ancestorRemoved(AncestorEvent event) { + } + + @Override + public void ancestorMoved(AncestorEvent event) { + } + + @Override + public void ancestorAdded(AncestorEvent event) { + // doesn't work because the "yes" button grabs the focus + text.requestFocusInWindow(); + } + }); + text.setFocusable(true); + } + + /** + * Resources + */ + + private static final String EDITFAVORITES_ACTIONNAME = ResourcesUtil.getString("favorites.action"); + private static final String EDITFAVORITES_TOOLTIP = ResourcesUtil.getString("favorites.tooltip"); + private static final String EDITFAVORITES_NAME = ResourcesUtil.getString("favorites.name"); + private static final String EDITFAVORITES_URL = ResourcesUtil.getString("favorites.url"); + private static final String EDITFAVORITES_TITLE = ResourcesUtil.getString("favorites.title"); + + private static final Icon EDITSIGNATURE = ResourcesUtil.getIcon("favorites.edit"); +} diff --git a/src/eu/engys/util/filechooser/actions/favorite/OpenFavorite.java b/src/eu/engys/util/filechooser/actions/favorite/OpenFavorite.java new file mode 100644 index 0000000..6ba2812 --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/favorite/OpenFavorite.java @@ -0,0 +1,87 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.actions.favorite; + +import javax.swing.Icon; +import javax.swing.JList; + +import eu.engys.util.filechooser.actions.pathnavigation.BaseNavigateAction; +import eu.engys.util.filechooser.favorites.Favorite; +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.ui.ResourcesUtil; + +/** + */ +public class OpenFavorite extends BaseNavigateAction { + + private JList favoriteList; + + public OpenFavorite(FileChooserController controller, JList favoriteList) { + super(controller, "Open", FOLDEROPEN); + this.favoriteList = favoriteList; + } + + @Override + protected void performLongOperation(CheckBeforeActionResult checkBeforeActionResult) { + if (favoriteList.getSelectedValue() != null) { + Favorite favorite = favoriteList.getSelectedValue(); + controller.goToURL(favorite.getUrl(), true); + controller.updateOkButton(); + } + } + + @Override + protected boolean canGoUrl() { + return favoriteList.getSelectedValue() != null; + } + + @Override + protected boolean canExecuteDefaultAction() { + return true; + } + + /** + * Resources + */ + + private static final Icon FOLDEROPEN = ResourcesUtil.getIcon("folderOpen"); +} diff --git a/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateAction.java b/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateAction.java new file mode 100644 index 0000000..8c11956 --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateAction.java @@ -0,0 +1,175 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.actions.pathnavigation; + +import java.awt.Component; +import java.awt.KeyboardFocusManager; +import java.awt.event.ActionEvent; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; + +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.ui.UiUtil; + +public abstract class BaseNavigateAction extends AbstractAction { + + private static final int SWITCH_TO_LOADING_TIME = 120; + + public FileChooserController controller; + private static Executor executor = Executors.newSingleThreadExecutor(); + private volatile SwingWorker showLoadingAfterDelayWorker; + private Component focusOwner; + + public BaseNavigateAction(FileChooserController controller) { + super(); + this.controller = controller; + } + + public BaseNavigateAction(FileChooserController controller, String name) { + this(controller); + putValue(NAME, name); + } + + public BaseNavigateAction(FileChooserController controller, String name, Icon icon) { + this(controller, name); + putValue(SMALL_ICON, icon); + } + + protected abstract void performLongOperation(CheckBeforeActionResult checkBeforeActionResult); + + @Override + public final void actionPerformed(ActionEvent e) { + final CheckBeforeActionResult checkBeforeActionResult = doInUiThreadBefore(); + if (CheckBeforeActionResult.CANT_GO.equals(checkBeforeActionResult)) { + return; + } + + SwingWorker worker = new SwingWorker() { + + @Override + protected void done() { + doInUiThreadAfter(); + } + + @Override + protected Void doInBackground() throws Exception { + try { + performLongOperation(checkBeforeActionResult); + } catch (Exception e) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), e.getMessage(), "File Chooser Error", JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + return null; + } + }; + executor.execute(worker); + + } + + protected final void doInUiThreadAfter() { + if (showLoadingAfterDelayWorker != null) { + showLoadingAfterDelayWorker.cancel(false); + } + updateGuiAfter(); + controller.showTable(); + if (focusOwner != null) { + focusOwner.requestFocus(); + } + } + + protected void updateGuiAfter() { + } + + protected final CheckBeforeActionResult doInUiThreadBefore() { + CheckBeforeActionResult result = CheckBeforeActionResult.CAN_GO; + if (!canGoUrl()) { + if (canExecuteDefaultAction()) { + result = CheckBeforeActionResult.CANT_GO_USE_DEFAULT_ACTION; + } else { + result = CheckBeforeActionResult.CANT_GO; + } + } else { + if (canExecuteDefaultAction()) { + result = CheckBeforeActionResult.CAN_GO_OR_USE_DEFAULT_ACTION; + } else { + result = CheckBeforeActionResult.CAN_GO; + } + } + + focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + showLoadingAfterDelayWorker = new SwingWorker() { + + @Override + protected void done() { + boolean cancelled = isCancelled(); + if (!cancelled) { + controller.showLoading(); + } + } + + @Override + protected Void doInBackground() throws Exception { + Thread.sleep(SWITCH_TO_LOADING_TIME); + return null; + } + }; + executor.execute(showLoadingAfterDelayWorker); + return result; + } + + protected abstract boolean canExecuteDefaultAction(); + + protected abstract boolean canGoUrl(); + + protected void updateGuiBefore() { + + } + + public enum CheckBeforeActionResult { + CAN_GO_OR_USE_DEFAULT_ACTION, CANT_GO, CANT_GO_USE_DEFAULT_ACTION, CAN_GO; + } +} diff --git a/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionGoUp.java b/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionGoUp.java new file mode 100644 index 0000000..20f22d7 --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionGoUp.java @@ -0,0 +1,82 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.actions.pathnavigation; + +import javax.swing.Icon; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; + +public final class BaseNavigateActionGoUp extends BaseNavigateAction { + + private static final Logger LOGGER = LoggerFactory.getLogger(BaseNavigateActionGoUp.class); + + public BaseNavigateActionGoUp(FileChooserController controller) { + super(controller); + putValue(SMALL_ICON, ARROWTURN90); + putValue(SHORT_DESCRIPTION, NAV_GOFOLDERUP); + } + + @Override + public void performLongOperation(CheckBeforeActionResult actionResult) { + LOGGER.debug("Executing going up"); + try { + FileObject parent = controller.getUriPanel().getFileObject().getParent(); + controller.goToURL(parent); + } catch (FileSystemException e) { + LOGGER.error("Error go UP", e); + } + } + + @Override + protected boolean canGoUrl() { + try { + FileObject parent = controller.getUriPanel().getFileObject().getParent(); + return parent != null && VFSUtils.canGoUrl(parent); + } catch (FileSystemException e) { + LOGGER.error("Can't get parent of current location", e); + } + return false; + } + + @Override + protected boolean canExecuteDefaultAction() { + return false; + } + + /** + * Resources + */ + + private static final String NAV_GOFOLDERUP = ResourcesUtil.getString("nav.goFolderUp"); + private static final Icon ARROWTURN90 = ResourcesUtil.getIcon("arrowTurn90"); +} diff --git a/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionOpen.java b/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionOpen.java new file mode 100644 index 0000000..77b1414 --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionOpen.java @@ -0,0 +1,89 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.actions.pathnavigation; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.filechooser.util.VFSUtils; + +public final class BaseNavigateActionOpen extends BaseNavigateAction { + + private static final Logger LOGGER = LoggerFactory.getLogger(BaseNavigateActionOpen.class); + private final FileChooserController controller; + + public BaseNavigateActionOpen(FileChooserController controller) { + super(controller); + this.controller = controller; + } + + @Override + public void performLongOperation(CheckBeforeActionResult checkBeforeActionResult) { + // When double click a file on the table + FileObject fileObject = controller.getSelectedFileObject(); + if (canExecuteDefaultAction()) { + controller.closeAndReturn(ReturnValue.Approve); + } else { + controller.goToURL(fileObject); + } + } + + @Override + protected boolean canGoUrl() { + FileObject fileObject = controller.getSelectedFileObject(); + if (fileObject != null) { + try { + return VFSUtils.canGoUrl(fileObject); + } catch (FileSystemException e) { + LOGGER.error("Can't open location", e.getMessage()); + } + } + return false; + } + + @Override + protected boolean canExecuteDefaultAction() { + SelectionMode selectionMode = controller.getSelectionMode(); + if (selectionMode.isFilesOnly() || selectionMode.isDirsAndFiles()) { + FileObject fileObject = controller.getSelectedFileObject(); + if (fileObject != null) { + try { + return FileType.FILE.equals(fileObject.getType()) || FileType.FILE_OR_FOLDER.equals(fileObject.getType()); + } catch (FileSystemException e) { + LOGGER.warn("Cant' get file type", e); + } + } + } + return false; + } + +} diff --git a/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionRefresh.java b/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionRefresh.java new file mode 100644 index 0000000..2843edb --- /dev/null +++ b/src/eu/engys/util/filechooser/actions/pathnavigation/BaseNavigateActionRefresh.java @@ -0,0 +1,76 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.actions.pathnavigation; + +import javax.swing.Icon; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.filechooser.gui.FileChooserController; +import eu.engys.util.ui.ResourcesUtil; + +public final class BaseNavigateActionRefresh extends BaseNavigateAction { + + private static final Logger LOGGER = LoggerFactory.getLogger(BaseNavigateActionRefresh.class); + + public BaseNavigateActionRefresh(FileChooserController controller) { + super(controller); + putValue(SMALL_ICON, ARROWCIRCLEDOUBLE); + putValue(SHORT_DESCRIPTION, NAV_REFRESHACTIONLABELTEXT); + } + + @Override + public void performLongOperation(CheckBeforeActionResult checkBeforeActionResult) { + try { + FileObject fileObject = controller.getUriPanel().getFileObject(); + fileObject.refresh(); + controller.goToURL(fileObject); + } catch (FileSystemException e) { + LOGGER.error("Can't refresh location", e.getMessage()); + } + } + + @Override + protected boolean canGoUrl() { + return true; + } + + @Override + protected boolean canExecuteDefaultAction() { + return false; + } + + /** + * Resources + */ + + private static final String NAV_REFRESHACTIONLABELTEXT = ResourcesUtil.getString("nav.refreshActionLabelText"); + private static final Icon ARROWCIRCLEDOUBLE = ResourcesUtil.getIcon("arrowCircleDouble"); + +} diff --git a/src/eu/engys/util/filechooser/authentication/AuthStore.java b/src/eu/engys/util/filechooser/authentication/AuthStore.java new file mode 100644 index 0000000..45b5d09 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/AuthStore.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +import java.util.Collection; + +public interface AuthStore { + public void add(UserAuthenticationInfo auInfo, UserAuthenticationDataWrapper authenticationData); + + public UserAuthenticationDataWrapper getUserAuthenticationData(UserAuthenticationInfo auInfo); + + public Collection getUserAuthenticationDatas(String protocol, String host); + + public void remove(UserAuthenticationInfo authenticationInfo); + + public Collection getAll(); + + public void clear(); + +} diff --git a/src/eu/engys/util/filechooser/authentication/AuthStoreUtils.java b/src/eu/engys/util/filechooser/authentication/AuthStoreUtils.java new file mode 100644 index 0000000..5dde411 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/AuthStoreUtils.java @@ -0,0 +1,306 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Collection; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.vfs2.UserAuthenticationData; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; + +public class AuthStoreUtils { + + private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger(AuthStoreUtils.class.getName()); + + public static final String USER = "user"; + public static final String HOST = "host"; + public static final String PROTOCOL = "protocol"; + public static final String ENTRY = "Entry"; + public static final String USER_AUTHENTICATION_DATA = "UserAuthenticationData"; + public static final String TYPE = "Type"; + public static final String DATA = "Data"; + public static final String ALGORITHM_BLOW_FISH = "Blowfish"; + public static final int SALT_LENGTH = 64; + private char[] password = null; + + private PasswordProvider passwordProvider; + + public AuthStoreUtils(PasswordProvider passwordProvider) { + this.passwordProvider = passwordProvider; + } + + public void save(AuthStore authStore, OutputStream out) throws IOException { + Collection all = authStore.getAll(); + for (UserAuthenticationInfo userAuthenticationInfo : all) { + UserAuthenticationData userAuthenticationData = authStore.getUserAuthenticationData(userAuthenticationInfo); + } + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = null; + try { + documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document document = documentBuilder.newDocument(); + Element root = document.createElement("root"); + + document.appendChild(root); + for (UserAuthenticationInfo userAuthenticationInfo : all) { + UserAuthenticationDataWrapper userAuthenticationData = authStore.getUserAuthenticationData(userAuthenticationInfo); + Element entry = document.createElement(ENTRY); + entry.setAttribute(PROTOCOL, userAuthenticationInfo.getProtocol()); + entry.setAttribute(HOST, userAuthenticationInfo.getHost()); + entry.setAttribute(USER, userAuthenticationInfo.getUser()); + Map addedTypes = userAuthenticationData.getAddedTypes(); + + for (UserAuthenticationData.Type type : addedTypes.keySet()) { + Element elementUserAuthenticationData = document.createElement(USER_AUTHENTICATION_DATA); + char[] data = userAuthenticationData.getData(type); + String value; + // if (UserAuthenticationData.PASSWORD.equals(type)) { + // if (password == null){ + // password = + // passwordProvider.getPassword("Enter password for password store"); + // } + // if (password == null || password.length==0){ + // throw new + // IOException("Password for password store not entered"); + // } + // value = saltAndEncrypt(data); + // } else { + // value = new String(data); + // } + value = new String(data); + Element elementType = document.createElement(TYPE); + elementType.setTextContent(type.toString()); + Element elementData = document.createElement(DATA); + elementData.setTextContent(value); + elementUserAuthenticationData.appendChild(elementType); + elementUserAuthenticationData.appendChild(elementData); + entry.appendChild(elementUserAuthenticationData); + } + root.appendChild(entry); + } + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + DOMSource source = new DOMSource(document); + StreamResult result = new StreamResult(out); + transformer.transform(source, result); + } catch (Exception e) { + throw new IOException(e); + } + + } + + private String saltAndEncrypt(char[] data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { + String value; + Hex hex = new Hex(); + char[] saltedData = addSalt(data); + + byte[] encode = encrypt(saltedData, password); + value = new String(hex.encode(encode)); + return value; + } + + protected char[] addSalt(char[] data) { + char[] saltedData = new char[SALT_LENGTH + data.length]; + for (int i = 0; i < SALT_LENGTH; i++) { + saltedData[i] = 'a';// (char) random.nextInt(); + } + for (int i = 0; i < data.length; i++) { + saltedData[i + SALT_LENGTH] = data[i]; + } + return saltedData; + } + + protected char[] removeSalt(char[] data) { + char[] deSalted = new char[data.length - SALT_LENGTH]; + System.arraycopy(data, SALT_LENGTH, deSalted, 0, deSalted.length); + return deSalted; + } + + public void load(AuthStore authStore, InputStream in) throws IOException { + try { + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + xmlReader.setContentHandler(new AuthStoreHandler(authStore)); + xmlReader.parse(new InputSource(in)); + } catch (SAXException e) { + throw new IOException(e); + } + } + + private class AuthStoreHandler extends DefaultHandler { + + private UserAuthenticationDataWrapper userAuthenticationData; + private UserAuthenticationInfo info; + private StringBuilder sb = new StringBuilder(); + private String data; + private String type; + + private AuthStore authStore; + + private AuthStoreHandler(AuthStore authStore) { + this.authStore = authStore; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + + if (ENTRY.equals(localName)) { + userAuthenticationData = new UserAuthenticationDataWrapper(); + info = new UserAuthenticationInfo(atts.getValue(PROTOCOL), atts.getValue(HOST), atts.getValue(USER)); + + } + sb.setLength(0); + + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (ENTRY.equals(localName)) { + authStore.add(info, userAuthenticationData); + } else if (USER_AUTHENTICATION_DATA.equals(localName)) { + // if (UserAuthenticationData.PASSWORD.equals(new + // UserAuthenticationData.Type(type))) { + // if (password == null){ + // password = + // passwordProvider.getPassword("Enter password for password store"); + // } + // if (password == null || password.length==0){ + // throw new + // SAXException("Password for password store not entered"); + // } + // Hex hex = new Hex(); + // try { + // byte[] decode = (byte[]) hex.decode(data.trim()); + // byte[] decrypted = decrypt(decode, password); + // char[] passwordWithSalt = bytesToChars(decrypted); + // char[] password = removeSalt(passwordWithSalt); + // data = new String(password); + // } catch (Exception e) { + // password=null; + // throw new SAXException("Can't decrypt password", e); + // } + // } + userAuthenticationData.setData(new UserAuthenticationData.Type(type), data.toCharArray()); + } else if (DATA.equals(localName)) { + data = sb.toString(); + } else if (TYPE.equals(localName)) { + type = sb.toString(); + } + + sb.setLength(0); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + sb.append(ch, start, length); + } + } + + protected byte[] encrypt(char[] bytes, char[] password) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { + byte[] passBytes = charsToBytes(password); + SecretKeySpec secretKeySpec = new SecretKeySpec(passBytes, ALGORITHM_BLOW_FISH); + + Cipher cipher = Cipher.getInstance(ALGORITHM_BLOW_FISH); + + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); + byte[] encrypted = cipher.doFinal(new String(bytes).getBytes("UTF-8")); + return encrypted; + } + + protected byte[] decrypt(byte[] bytes, char[] password) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { + byte[] passBytes = charsToBytes(password); + SecretKeySpec secretKeySpec = new SecretKeySpec(passBytes, ALGORITHM_BLOW_FISH); + Cipher cipher = Cipher.getInstance(ALGORITHM_BLOW_FISH); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); + byte[] decrypted = cipher.doFinal(bytes); + return decrypted; + } + + protected byte[] charsToBytes(char[] chars) throws UnsupportedEncodingException { + return new String(chars).getBytes("UTF-8"); + } + + protected char[] bytesToChars(byte[] bytes) { + return new String(bytes, Charset.forName("UTF-8")).toCharArray(); + } + + public PasswordProvider getPasswordProvider() { + return passwordProvider; + } + + public void setPasswordProvider(PasswordProvider passwordProvider) { + this.passwordProvider = passwordProvider; + } + +} diff --git a/src/eu/engys/util/filechooser/authentication/AuthorisationCancelledException.java b/src/eu/engys/util/filechooser/authentication/AuthorisationCancelledException.java new file mode 100644 index 0000000..34e022d --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/AuthorisationCancelledException.java @@ -0,0 +1,59 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +public class AuthorisationCancelledException extends RuntimeException { + + public AuthorisationCancelledException() { + super(); + } + + public AuthorisationCancelledException(String message) { + super(message); + } + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/src/eu/engys/util/filechooser/authentication/CompositeAuthStore.java b/src/eu/engys/util/filechooser/authentication/CompositeAuthStore.java new file mode 100644 index 0000000..1db3e11 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/CompositeAuthStore.java @@ -0,0 +1,110 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +public class CompositeAuthStore implements AuthStore { + + public AuthStore[] authStores; + + public CompositeAuthStore(AuthStore... authStores) { + super(); + this.authStores = authStores; + } + + @Override + public void add(UserAuthenticationInfo auInfo, UserAuthenticationDataWrapper authenticationData) { + for (AuthStore authStore : authStores) { + authStore.add(auInfo, authenticationData); + } + + } + + @Override + public UserAuthenticationDataWrapper getUserAuthenticationData(UserAuthenticationInfo auInfo) { + for (AuthStore authStore : authStores) { + UserAuthenticationDataWrapper userAuthenticationData = authStore.getUserAuthenticationData(auInfo); + if (userAuthenticationData != null) { + return userAuthenticationData; + } + } + return null; + } + + @Override + public Collection getUserAuthenticationDatas(String protocol, String host) { + HashSet set = new HashSet(); + for (AuthStore authStore : authStores) { + set.addAll(authStore.getUserAuthenticationDatas(protocol, host)); + } + return set; + } + + @Override + public void remove(UserAuthenticationInfo authenticationInfo) { + for (AuthStore authStore : authStores) { + authStore.remove(authenticationInfo); + } + + } + + @Override + public Collection getAll() { + List l = new ArrayList(); + for (AuthStore authStore : authStores) { + l.addAll(authStore.getAll()); + } + return l; + } + + @Override + public void clear() { + for (AuthStore authStore : authStores) { + authStore.clear(); + } + } + +} diff --git a/src/eu/engys/util/filechooser/authentication/DialogPasswordProvider.java b/src/eu/engys/util/filechooser/authentication/DialogPasswordProvider.java new file mode 100644 index 0000000..44909a6 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/DialogPasswordProvider.java @@ -0,0 +1,67 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +import java.awt.GridLayout; + +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPasswordField; + +import eu.engys.util.ui.UiUtil; + +public class DialogPasswordProvider implements PasswordProvider { + @Override + public char[] getPassword(String message) { + JPanel jPanel = new JPanel(new GridLayout(2, 1)); + jPanel.add(new JLabel(message)); + JPasswordField comp = new JPasswordField(20); + jPanel.add(comp); + int i = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), jPanel, "Podaj haslo", JOptionPane.YES_NO_OPTION); + if (i == JOptionPane.OK_OPTION) { + return comp.getPassword(); + } + return null; + } + +} diff --git a/src/eu/engys/util/filechooser/authentication/MemoryAuthStore.java b/src/eu/engys/util/filechooser/authentication/MemoryAuthStore.java new file mode 100644 index 0000000..2410c95 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/MemoryAuthStore.java @@ -0,0 +1,101 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MemoryAuthStore implements AuthStore { + + private static final Logger LOGGER = LoggerFactory.getLogger(MemoryAuthStore.class); + + private Map map; + + public MemoryAuthStore() { + map = new HashMap(); + } + + @Override + public UserAuthenticationDataWrapper getUserAuthenticationData(UserAuthenticationInfo info) { + return map.get(info); + } + + @Override + public Collection getUserAuthenticationDatas(String protocol, String host) { + List list = new ArrayList(); + for (UserAuthenticationInfo key : map.keySet()) { + if (StringUtils.equalsIgnoreCase(key.getProtocol(), protocol) && StringUtils.equalsIgnoreCase(key.getHost(), host)) { + list.add(map.get(key)); + } + } + return list; + } + + @Override + public void add(UserAuthenticationInfo aInfo, UserAuthenticationDataWrapper authenticationData) { + LOGGER.debug("Adding auth info {}://{}@{}", new Object[] { aInfo.getProtocol(), aInfo.getUser(), aInfo.getHost() }); + map.put(aInfo, authenticationData); + } + + @Override + public void remove(UserAuthenticationInfo authenticationInfo) { + map.remove(authenticationInfo); + } + + @Override + public Collection getAll() { + return new ArrayList(map.keySet()); + } + + @Override + public void clear() { + map.clear(); + } + +} diff --git a/src/eu/engys/util/filechooser/authentication/PasswordProvider.java b/src/eu/engys/util/filechooser/authentication/PasswordProvider.java new file mode 100644 index 0000000..0abae91 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/PasswordProvider.java @@ -0,0 +1,47 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +public interface PasswordProvider { + + public char[] getPassword(String message); +} diff --git a/src/eu/engys/util/filechooser/authentication/StaticPasswordProvider.java b/src/eu/engys/util/filechooser/authentication/StaticPasswordProvider.java new file mode 100644 index 0000000..f856d75 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/StaticPasswordProvider.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +public class StaticPasswordProvider implements PasswordProvider { + + private char[] password; + + public StaticPasswordProvider(char[] password) { + this.password = password; + } + + @Override + public char[] getPassword(String message) { + return password; + } +} diff --git a/src/eu/engys/util/filechooser/authentication/UserAuthenticationDataWrapper.java b/src/eu/engys/util/filechooser/authentication/UserAuthenticationDataWrapper.java new file mode 100644 index 0000000..e3add8b --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/UserAuthenticationDataWrapper.java @@ -0,0 +1,102 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.vfs2.UserAuthenticationData; + +public class UserAuthenticationDataWrapper extends UserAuthenticationData { + + /** + * The password. + */ + public static final Type SSH_KEY = new Type("sshKey"); + + private HashMap map; + + public UserAuthenticationDataWrapper() { + super(); + map = new HashMap(); + } + + @Override + public void setData(Type type, char[] data) { + super.setData(type, data.clone()); + map.put(type, data); + } + + public Map getAddedTypes() { + return map; + } + + public UserAuthenticationDataWrapper copy() { + UserAuthenticationDataWrapper cp = new UserAuthenticationDataWrapper(); + for (Type type : map.keySet()) { + cp.setData(type, map.get(type)); + } + return cp; + } + + @Override + public void cleanup() { + } + + public void cleanWrapper() { + super.cleanup(); + for (char[] chars : map.values()) { + for (int i = 0; i < chars.length; i++) { + chars[i] = '0'; + } + } + } + + public void remove(Type type) { + super.cleanup(); + map.remove(type); + for (Type type1 : map.keySet()) { + super.setData(type1, map.get(type1)); + } + } + +} diff --git a/src/eu/engys/util/filechooser/authentication/UserAuthenticationInfo.java b/src/eu/engys/util/filechooser/authentication/UserAuthenticationInfo.java new file mode 100644 index 0000000..aa6607a --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/UserAuthenticationInfo.java @@ -0,0 +1,109 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +public class UserAuthenticationInfo { + public final String protocol; + public final String host; + public final String user; + + public UserAuthenticationInfo(String protocol, String host, String user) { + this.protocol = protocol; + this.host = host; + this.user = user; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((host == null) ? 0 : host.hashCode()); + result = prime * result + ((protocol == null) ? 0 : protocol.hashCode()); + result = prime * result + ((user == null) ? 0 : user.hashCode()); + return result; + } + + public String getProtocol() { + return protocol; + } + + public String getHost() { + return host; + } + + public String getUser() { + return user; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + UserAuthenticationInfo other = (UserAuthenticationInfo) obj; + if (host == null) { + if (other.host != null) + return false; + } else if (!host.equals(other.host)) + return false; + if (protocol == null) { + if (other.protocol != null) + return false; + } else if (!protocol.equals(other.protocol)) + return false; + if (user == null) { + if (other.user != null) + return false; + } else if (!user.equals(other.user)) + return false; + return true; + } + + @Override + public String toString() { + return "UserAuthenticationInfo [ user: " +user + " - host: " + host + " - protocol: " + protocol + " ]" ; + } + +} diff --git a/src/eu/engys/util/filechooser/authentication/UserAuthenticatorFactory.java b/src/eu/engys/util/filechooser/authentication/UserAuthenticatorFactory.java new file mode 100644 index 0000000..5133a72 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/UserAuthenticatorFactory.java @@ -0,0 +1,66 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication; + +import org.apache.commons.vfs2.FileSystemOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.filechooser.authentication.authenticator.AbstractUiUserAuthenticator; +import eu.engys.util.filechooser.authentication.authenticator.OtrosUserAuthenticator; +import eu.engys.util.filechooser.authentication.authenticator.UseCentralsFromSessionUserAuthenticator; + +public class UserAuthenticatorFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(UserAuthenticatorFactory.class); + + public OtrosUserAuthenticator getUiUserAuthenticator(AuthStore sessionAuthStore, String url, FileSystemOptions fileSystemOptions) { + LOGGER.info("Getting authenticator for {}", url); + AbstractUiUserAuthenticator authenticator = null; +// if (url.startsWith("sftp://")) { +// authenticator = new SftpUserAuthenticator(url, fileSystemOptions); +// } + UseCentralsFromSessionUserAuthenticator fromSessionUserAuthenticator = new UseCentralsFromSessionUserAuthenticator(sessionAuthStore, url, fileSystemOptions, authenticator); + return fromSessionUserAuthenticator; + + } + +} diff --git a/src/eu/engys/util/filechooser/authentication/authenticator/AbstractUiUserAuthenticator.java b/src/eu/engys/util/filechooser/authentication/authenticator/AbstractUiUserAuthenticator.java new file mode 100644 index 0000000..be68ba6 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/authenticator/AbstractUiUserAuthenticator.java @@ -0,0 +1,131 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication.authenticator; + +import java.awt.BorderLayout; +import java.text.MessageFormat; + +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.UserAuthenticationData; +import org.apache.commons.vfs2.UserAuthenticationData.Type; + +import eu.engys.util.filechooser.authentication.UserAuthenticationDataWrapper; +import eu.engys.util.filechooser.uri.VFSURIParser; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; + +public abstract class AbstractUiUserAuthenticator implements OtrosUserAuthenticator { + + private String url; + private VFSURIParser vfsUriParser; + private final FileSystemOptions fileSystemOptions; + protected UserAuthenticationDataWrapper data; + private final String title; + + public AbstractUiUserAuthenticator(String url, FileSystemOptions fileSystemOptions) { + this.url = url; + this.title = MessageFormat.format(AUTHENTICATOR_ENTERCREDENTIALSFORURL, url); + this.fileSystemOptions = fileSystemOptions; + this.vfsUriParser = new VFSURIParser(url); + } + + @Override + public UserAuthenticationData requestAuthentication(Type[] types) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + JPanel authOptionPanel = getOptionsPanelBuilder().getPanel(); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(authOptionPanel); + + String[] options = { "OK", "Cancel" }; + int showConfirmDialog = JOptionPane.showOptionDialog(UiUtil.getActiveWindow(), panel, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options, options[0]); + if (showConfirmDialog != JOptionPane.OK_OPTION) { + return; + } + data = new UserAuthenticationDataWrapper(); + updateAuthenticationData(data); + } + }); + return data; + } + + @Override + public UserAuthenticationDataWrapper getLastUserAuthenticationData() { + return data; + } + + // @Override + // public boolean isPasswordSave() { + // return saveCredentialsCheckBox.isSelected(); + // } + + protected abstract void updateAuthenticationData(UserAuthenticationData authenticationData); + + protected abstract PanelBuilder getOptionsPanelBuilder(); + + protected String getUrl() { + return url; + } + + protected VFSURIParser getVfsUriParser() { + return vfsUriParser; + } + + protected FileSystemOptions getFileSystemOptions() { + return fileSystemOptions; + } + + /** + * Resources + */ + + private static final String AUTHENTICATOR_SAVEPASSWORD = ResourcesUtil.getString("authenticator.savePassword"); + private static final String AUTHENTICATOR_ENTERCREDENTIALSFORURL = ResourcesUtil.getString("authenticator.enterCredentialsForUrl"); + +} diff --git a/src/eu/engys/util/filechooser/authentication/authenticator/OtrosStaticUserAuthenticator.java b/src/eu/engys/util/filechooser/authentication/authenticator/OtrosStaticUserAuthenticator.java new file mode 100644 index 0000000..75ba395 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/authenticator/OtrosStaticUserAuthenticator.java @@ -0,0 +1,83 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication.authenticator; + +import org.apache.commons.vfs2.UserAuthenticationData; +import org.apache.commons.vfs2.UserAuthenticationData.Type; +import org.slf4j.Logger; + +import eu.engys.util.filechooser.authentication.UserAuthenticationDataWrapper; + +public class OtrosStaticUserAuthenticator implements OtrosUserAuthenticator { + + private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(OtrosStaticUserAuthenticator.class); + + private final UserAuthenticationDataWrapper userAuthenticationDataWrapper; + private final UserAuthenticationData userAuthenticationData; + + public OtrosStaticUserAuthenticator(UserAuthenticationData userAuthenticationData) { + this.userAuthenticationData = userAuthenticationData; + userAuthenticationDataWrapper = new UserAuthenticationDataWrapper(); + } + + @Override + public UserAuthenticationData requestAuthentication(Type[] arg0) { + LOGGER.info("Received request for authentication"); + UserAuthenticationDataWrapper data = new UserAuthenticationDataWrapper(); + for (Type type : arg0) { + data.setData(type, userAuthenticationData.getData(type)); + userAuthenticationDataWrapper.setData(type, userAuthenticationData.getData(type)); + } + return data; + } + + @Override + public UserAuthenticationDataWrapper getLastUserAuthenticationData() { + return userAuthenticationDataWrapper; + } +// +// @Override +// public boolean isPasswordSave() { +// return false; +// } + +} diff --git a/src/eu/engys/util/filechooser/authentication/authenticator/OtrosUserAuthenticator.java b/src/eu/engys/util/filechooser/authentication/authenticator/OtrosUserAuthenticator.java new file mode 100644 index 0000000..ebf26ec --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/authenticator/OtrosUserAuthenticator.java @@ -0,0 +1,53 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.authentication.authenticator; + +import org.apache.commons.vfs2.UserAuthenticator; + +import eu.engys.util.filechooser.authentication.UserAuthenticationDataWrapper; + +public interface OtrosUserAuthenticator extends UserAuthenticator { + public UserAuthenticationDataWrapper getLastUserAuthenticationData(); + +// public boolean isPasswordSave(); + +} diff --git a/src/eu/engys/util/filechooser/authentication/authenticator/UseCentralsFromSessionUserAuthenticator.java b/src/eu/engys/util/filechooser/authentication/authenticator/UseCentralsFromSessionUserAuthenticator.java new file mode 100644 index 0000000..7789ec5 --- /dev/null +++ b/src/eu/engys/util/filechooser/authentication/authenticator/UseCentralsFromSessionUserAuthenticator.java @@ -0,0 +1,101 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright (c) 2012. Krzysztof Otrebski + * All right reserved + */ + +package eu.engys.util.filechooser.authentication.authenticator; + +import java.util.Collection; + +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.UserAuthenticationData; +import org.slf4j.Logger; + +import eu.engys.util.filechooser.authentication.AuthStore; +import eu.engys.util.filechooser.authentication.UserAuthenticationDataWrapper; +import eu.engys.util.filechooser.uri.VFSURIParser; +import eu.engys.util.ui.builder.PanelBuilder; + +public class UseCentralsFromSessionUserAuthenticator extends AbstractUiUserAuthenticator { + + private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(UseCentralsFromSessionUserAuthenticator.class); + + private final AuthStore sessionAuthStore; + private final AbstractUiUserAuthenticator otrosUserAuthenticator; + + public UseCentralsFromSessionUserAuthenticator(AuthStore sessionAuthStore, String url, FileSystemOptions fileSystemOptions, AbstractUiUserAuthenticator otrosUserAuthenticator) { + super(url, fileSystemOptions); + this.sessionAuthStore = sessionAuthStore; + this.otrosUserAuthenticator = otrosUserAuthenticator; + } + + @Override + public UserAuthenticationDataWrapper getLastUserAuthenticationData() { + if (otrosUserAuthenticator != null) { + return otrosUserAuthenticator.getLastUserAuthenticationData(); + } + return null; + + } + + @Override + protected void updateAuthenticationData(UserAuthenticationData authenticationData) { + otrosUserAuthenticator.updateAuthenticationData(authenticationData); + } + + @Override + protected PanelBuilder getOptionsPanelBuilder() { + return otrosUserAuthenticator.getOptionsPanelBuilder(); + } + + @Override + public UserAuthenticationData requestAuthentication(UserAuthenticationData.Type[] types) { + UserAuthenticationData userAuthenticationData = getStaticWorkingUserAuthForSmb(sessionAuthStore, getUrl()); + if (userAuthenticationData == null) { + userAuthenticationData = otrosUserAuthenticator.requestAuthentication(types); + } + return userAuthenticationData; + } + + protected UserAuthenticationData getStaticWorkingUserAuthForSmb(AuthStore authStore, String url) { + LOGGER.debug("Checking if have credentials for {}", url); + VFSURIParser parser = new VFSURIParser(url); + if (parser.getHostname() != null) { + Collection userAuthenticationDatas = authStore.getUserAuthenticationDatas(parser.getProtocol().toString(), parser.getHostname()); + LOGGER.debug("Credentials count: {}", userAuthenticationDatas.size()); + if (userAuthenticationDatas.size() > 0) { + UserAuthenticationData authenticationDataFromStore = userAuthenticationDatas.iterator().next(); + LOGGER.debug("Returning static authenticator for {}", url); + return authenticationDataFromStore; + } + } + LOGGER.debug("Do not have credentials for {}", url); + return null; + } + +} diff --git a/src/eu/engys/util/filechooser/depot/FTPUserAuthenticator.java b/src/eu/engys/util/filechooser/depot/FTPUserAuthenticator.java new file mode 100644 index 0000000..0b0ab6b --- /dev/null +++ b/src/eu/engys/util/filechooser/depot/FTPUserAuthenticator.java @@ -0,0 +1,169 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.depot; +///* +// * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package eu.engys.util.otrosfilechooser.authentication.authenticator; +// +//import java.awt.event.ActionEvent; +//import java.awt.event.ActionListener; +//import java.util.Collection; +// +//import javax.swing.JComboBox; +//import javax.swing.JPasswordField; +//import javax.swing.event.AncestorEvent; +//import javax.swing.event.AncestorListener; +// +//import org.apache.commons.lang.StringUtils; +//import org.apache.commons.vfs2.FileSystemOptions; +//import org.apache.commons.vfs2.UserAuthenticationData; +// +//import eu.engys.util.otrosfilechooser.authentication.AuthStore; +//import eu.engys.util.otrosfilechooser.authentication.UserAuthenticationDataWrapper; +//import eu.engys.util.otrosfilechooser.authentication.UserAuthenticationInfo; +//import eu.engys.util.ui.ResourcesUtil; +//import eu.engys.util.ui.builder.PanelBuilder; +// +//public class FTPUserAuthenticator extends AbstractUiUserAuthenticator { +// +// protected JComboBox nameTextField; +// protected JPasswordField passTextField; +// +// public FTPUserAuthenticator(String url, FileSystemOptions fileSystemOptions) { +// super(url, fileSystemOptions); +// } +// +// @Override +// protected void updateAuthenticationData(UserAuthenticationData authenticationData) { +// authenticationData.setData(UserAuthenticationData.USERNAME, nameTextField.getSelectedItem().toString().toCharArray()); +// authenticationData.setData(UserAuthenticationData.PASSWORD, passTextField.getPassword()); +// +// } +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// @Override +// protected PanelBuilder getOptionsPanelBuilder() { +// +// Collection userAuthenticationDatas = getAuthStore().getUserAuthenticationDatas(getVfsUriParser().getProtocol().getName(), getVfsUriParser().getHostname()); +// String[] names = new String[userAuthenticationDatas.size()]; +// int i = 0; +// for (UserAuthenticationData userAuthenticationData : userAuthenticationDatas) { +// names[i] = new String(userAuthenticationData.getData(UserAuthenticationData.USERNAME)); +// i++; +// } +// +// nameTextField = new JComboBox(names); +// nameTextField.setEditable(true); +// nameTextField.addActionListener(new ActionListener() { +// +// @Override +// public void actionPerformed(ActionEvent e) { +// userSelected(nameTextField.getSelectedItem().toString()); +// } +// }); +// +// nameTextField.addAncestorListener(new AncestorListener() { +// +// @Override +// public void ancestorRemoved(AncestorEvent event) { +// +// } +// +// @Override +// public void ancestorMoved(AncestorEvent event) { +// +// } +// +// @Override +// public void ancestorAdded(AncestorEvent event) { +// event.getComponent().requestFocusInWindow(); +// } +// }); +// +// passTextField = new JPasswordField(15); +// passTextField.setText(getVfsUriParser().getPassword()); +// +// if (StringUtils.isNotBlank(getVfsUriParser().getUsername())) { +// nameTextField.setSelectedItem(getVfsUriParser().getUsername()); +// } +// if (names.length > 0) { +// nameTextField.setSelectedIndex(0); +// } +// +// PanelBuilder pb = new PanelBuilder(); +// pb.addComponent(AUTHENTICATOR_USERNAME, nameTextField); +// pb.addComponent(AUTHENTICATOR_PASSWORD, passTextField); +// +// return pb; +// } +// +// private void userSelected(String user) { +// UserAuthenticationData userAuthenticationData = getAuthStore().getUserAuthenticationData(new UserAuthenticationInfo(getVfsUriParser().getProtocol().getName(), getVfsUriParser().getHostname(), user)); +// char[] passChars = new char[0]; +// +// if (userAuthenticationData != null && userAuthenticationData.getData(UserAuthenticationData.PASSWORD) != null) { +// passChars = userAuthenticationData.getData(UserAuthenticationData.PASSWORD); +// } +// passTextField.setText(new String(passChars)); +// +// userSelectedHook(userAuthenticationData); +// } +// +// protected void userSelectedHook(UserAuthenticationData userAuthenticationData) { +// +// } +// +// /** +// * Override this method to be notified when user from authstore is selected +// * +// * @param authenticationData +// */ +// protected void updateUserAuthenticationData(UserAuthenticationData authenticationData) { +// +// } +// +// /** +// * Resources +// */ +// +// private static final String AUTHENTICATOR_USERNAME = ResourcesUtil.getString("authenticator.username"); +// private static final String AUTHENTICATOR_PASSWORD = ResourcesUtil.getString("authenticator.password"); +// +//} diff --git a/src/eu/engys/util/filechooser/depot/OriginalVfsBrowser.java b/src/eu/engys/util/filechooser/depot/OriginalVfsBrowser.java new file mode 100644 index 0000000..1dbaeb0 --- /dev/null +++ b/src/eu/engys/util/filechooser/depot/OriginalVfsBrowser.java @@ -0,0 +1,519 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.depot; +///* +// * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package eu.engys.util.otrosfilechooser.panels; +// +//import java.awt.BorderLayout; +//import java.awt.CardLayout; +//import java.awt.Color; +//import java.awt.FlowLayout; +//import java.text.MessageFormat; +//import java.util.List; +// +//import javax.swing.Action; +//import javax.swing.BorderFactory; +//import javax.swing.Icon; +//import javax.swing.JButton; +//import javax.swing.JLabel; +//import javax.swing.JOptionPane; +//import javax.swing.JPanel; +//import javax.swing.JProgressBar; +//import javax.swing.JScrollPane; +//import javax.swing.JSplitPane; +//import javax.swing.JTable; +//import javax.swing.JTextField; +//import javax.swing.ListSelectionModel; +//import javax.swing.SwingWorker; +//import javax.swing.event.ListSelectionEvent; +//import javax.swing.event.ListSelectionListener; +// +//import org.apache.commons.vfs2.FileObject; +//import org.apache.commons.vfs2.FileSystemException; +//import org.apache.commons.vfs2.FileType; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import eu.engys.util.otrosfilechooser.FileChooserSelectionChangedListener; +//import eu.engys.util.otrosfilechooser.ParentFileObject; +//import eu.engys.util.otrosfilechooser.favorites.Favorite; +//import eu.engys.util.otrosfilechooser.preview.PreviewListener; +//import eu.engys.util.otrosfilechooser.util.SelectionMode; +//import eu.engys.util.otrosfilechooser.util.SwingUtils; +//import eu.engys.util.otrosfilechooser.util.TaskContext; +//import eu.engys.util.otrosfilechooser.util.VFSUtils; +//import eu.engys.util.ui.ResourcesUtil; +// +//public class OriginalVfsBrowser extends JPanel { +// +// private static final Logger LOGGER = LoggerFactory.getLogger(OriginalVfsBrowser.class); +// public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = "MultiSelectionEnabledChangedProperty"; +// public static final String MULTI_SELECTION_MODE_CHANGED_PROPERTY = "SelectionModeChangedProperty"; +// +// private static final String TABLE_KEY = "TABLE"; +// private static final String LOADING_KEY = "LOADING"; +// +// protected JPanel centralPanel; +// +// private JLabel statusLabel; +// +// private FileObject currentLocation; +// private CardLayout cardLayout; +// +// private SelectionMode selectionMode = SelectionMode.DIRS_AND_FILES; +// private Action actionApproveDelegate; +// private Action actionCancelDelegate; +// +// private boolean multiSelectionEnabled = false; +// private JButton actionApproveButton; +// private JButton actionCancelButton; +// private TaskContext taskContext; +// private URIPanel uriPanel; +// private FileSystemPanel fileSystemPanel; +// +// private FavoritesPanel favoritesPanel; +// +// private LoadingPanel loadingPanel; +// +// public OriginalVfsBrowser() { +// this(System.getProperty("user.home")); +// } +// +// public OriginalVfsBrowser(String initialPath) { +// this(initialPath, null); +// } +// +// public OriginalVfsBrowser(String initialPath, JPanel rightPanel) { +// this(initialPath, rightPanel, false); +// } +// +// public OriginalVfsBrowser(String initialPath, JPanel rightPanel, boolean remote) { +// this(initialPath, rightPanel, new String[0], remote); +// } +// +// public OriginalVfsBrowser(String initialPath, JPanel rightPanel, String[] filter, boolean remote) { +// this(initialPath, rightPanel, new String[0], remote, false, ""); +// } +// +// public OriginalVfsBrowser(String initialPath, JPanel rightPanel, String[] filter, boolean remote, boolean saveas, String currentProjectName) { +// super(new BorderLayout()); +// layoutComponents(initialPath, rightPanel, filter, remote, saveas, currentProjectName); +// VFSUtils.loadAuthStore(); +// } +// +// private void layoutComponents(final String initialPath, final JPanel rightPanel, String[] filter, boolean remote, boolean saveAs, String currentProjectName) { +// fileSystemPanel = new FileSystemPanel(this, filter); +// +// favoritesPanel = new FavoritesPanel(this); +// +// JSplitPane fileSystemAndPreviewPane = null; +// if (rightPanel != null) { +// if (rightPanel instanceof PreviewPanel) { +// fileSystemPanel.getTable().getSelectionModel().addListSelectionListener(new PreviewListener(this, (PreviewPanel) rightPanel)); +// } else if (rightPanel instanceof FileChooserSelectionChangedListener) { +// fileSystemPanel.getTable().getSelectionModel().addListSelectionListener(new ListSelectionListener() { +// +// @Override +// public void valueChanged(ListSelectionEvent e) { +// ((FileChooserSelectionChangedListener) rightPanel).onSelectionChanged(); +// } +// }); +// } +// fileSystemAndPreviewPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, fileSystemPanel, rightPanel); +// fileSystemAndPreviewPane.setOneTouchExpandable(false); +// fileSystemAndPreviewPane.setDividerLocation(350); +// +// } +// +// loadingPanel = new LoadingPanel(taskContext); +// +// centralPanel = new JPanel(cardLayout = new CardLayout()); +// centralPanel.add(loadingPanel, LOADING_KEY); +// if (fileSystemAndPreviewPane != null) { +// centralPanel.add(fileSystemAndPreviewPane, TABLE_KEY); +// } else { +// centralPanel.add(fileSystemPanel, TABLE_KEY); +// } +// +// showTable(); +// +// uriPanel = new URIPanel(this, remote); +// +// JSplitPane centralSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(favoritesPanel), centralPanel); +// centralSplitPane.setOneTouchExpandable(false); +// centralSplitPane.setDividerLocation(180); +// +// JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); +// mainPanel.add(uriPanel, BorderLayout.NORTH); +// mainPanel.add(centralSplitPane, BorderLayout.CENTER); +// mainPanel.add(createSouthPanel(saveAs, currentProjectName), BorderLayout.SOUTH); +// +// mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); +// +// this.add(mainPanel, BorderLayout.CENTER); +// +// postLayout(initialPath); +// } +// +// private void postLayout(final String initialPath) { +// try { +// selectionChanged(); +// } catch (FileSystemException e) { +// LOGGER.error("Can't initialize default selection mode", e); +// } +// try { +// if (initialPath == null) { +// goToUrl(VFSUtils.getUserHome()); +// } else { +// goToUrl(initialPath); +// } +// } catch (FileSystemException e1) { +// LOGGER.error("Can't initialize default location", e1); +// } +// } +// +// private JPanel createSouthPanel(boolean saveas, String currentProjectName) { +// JPanel southPanel = new JPanel(new BorderLayout()); +// +// JPanel leftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); +// JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); +// +// actionApproveButton = new JButton(actionApproveDelegate); +// actionCancelButton = new JButton(actionCancelDelegate); +// +// leftPanel.add(statusLabel = new JLabel()); +// if (saveas) { +// rightPanel.add(new JLabel("Name:")); +// newFileNameField = new JTextField(15); +// newFileNameField.setText(currentProjectName + "_copy"); +// rightPanel.add(newFileNameField); +// } +// rightPanel.add(actionApproveButton); +// rightPanel.add(actionCancelButton); +// +// southPanel.add(leftPanel, BorderLayout.WEST); +// southPanel.add(rightPanel, BorderLayout.CENTER); +// +// return southPanel; +// } +// +// public String getNewFileName() { +// if (newFileNameField != null) { +// return newFileNameField.getText(); +// } +// return null; +// } +// +// public void selectionChanged() throws FileSystemException { +// LOGGER.debug("Updating selection"); +// boolean acceptEnabled = false; +// if (getSelectedFilesOnTable().length == 0) { +// acceptEnabled = false; +// } else if (isMultiSelectionEnabled()) { +// boolean filesSelected = false; +// boolean folderSelected = false; +// +// for (FileObject fo : getSelectedFilesOnTable()) { +// FileType fileType = fo.getType(); +// if (fileType == FileType.FILE) { +// filesSelected = true; +// } else if (fileType == FileType.FOLDER) { +// folderSelected = true; +// } +// } +// if (selectionMode == SelectionMode.FILES_ONLY && filesSelected && !folderSelected) { +// acceptEnabled = true; +// } else if (selectionMode == SelectionMode.DIRS_ONLY && !filesSelected && folderSelected) { +// acceptEnabled = true; +// } else if (selectionMode == SelectionMode.DIRS_AND_FILES) { +// acceptEnabled = true; +// } +// } else { +// FileObject selectedFileObject = fileSystemPanel.getSelectedFileObject(); +// FileType type = selectedFileObject.getType(); +// if (selectionMode == SelectionMode.FILES_ONLY && type == FileType.FILE || selectionMode == SelectionMode.DIRS_ONLY && type == FileType.FOLDER) { +// acceptEnabled = true; +// } else if (SelectionMode.DIRS_AND_FILES == selectionMode) { +// acceptEnabled = true; +// } +// } +// +// if (actionApproveDelegate != null) { +// actionApproveDelegate.setEnabled(acceptEnabled); +// } +// actionApproveButton.setEnabled(acceptEnabled); +// } +// +// public FileSystemPanel getFileSystemPanel() { +// return fileSystemPanel; +// } +// +// public JTable getFileSystemTable() { +// return fileSystemPanel.getTable(); +// } +// +// public void fixSelection() { +// fileSystemPanel.fixSelection(); +// } +// +// public void goToUrl(String url) { +// // System.out.println("VfsBrowser.goToUrl(): " + url); +// LOGGER.info("Going to URL: " + url); +// try { +// FileObject resolveFile = VFSUtils.resolveFileObject(url); +// String type = "?"; +// if (resolveFile != null) { +// type = resolveFile.getType().toString(); +// } +// LOGGER.info("URL: " + url + " is resolved " + type); +// goToUrl(resolveFile); +// } catch (FileSystemException e) { +// LOGGER.error("Can't go to URL " + url, e); +// final String message = getRootCause(e).getClass().getName() + ": " + getRootCause(e).getLocalizedMessage(); +// +// Runnable runnable = new Runnable() { +// public void run() { +// JOptionPane.showMessageDialog(OriginalVfsBrowser.this, "Can't open location: " + message); +// } +// }; +// SwingUtils.runInEdt(runnable); +// } +// } +// +// public void goToUrl(final FileObject fileObject) { +// if (taskContext != null) { +// taskContext.setStop(true); +// } +// // +// final FileObject[] files = VFSUtils.getFiles(fileObject); +// LOGGER.info("Have {} files in {}", files.length, fileObject.getName().getFriendlyURI()); +// this.currentLocation = fileObject; +// // +// taskContext = new TaskContext(BROWSER_CHECKINGSFTPLINKSTASK, files.length); +// taskContext.setIndeterminate(false); +// SwingWorker refreshWorker = new SwingWorker() { +// int icon = 0; +// Icon[] icons = new Icon[] { NETWORKSTATUSONLINE, NETWORKSTATUSAWAY, NETWORKSTATUSOFFLINE }; +// +// @Override +// protected void process(List chunks) { +// JProgressBar loadingProgressBar = loadingPanel.getLoadingProgressBar(); +// loadingProgressBar.setIndeterminate(taskContext.isIndeterminate()); +// loadingProgressBar.setMaximum(taskContext.getMax()); +// loadingProgressBar.setValue(taskContext.getCurrentProgress()); +// loadingProgressBar.setString(String.format("%s [%d of %d]", taskContext.getName(), taskContext.getCurrentProgress(), taskContext.getMax())); +// loadingPanel.getLoadingIconLabel().setIcon(icons[++icon % icons.length]); +// } +// +// @Override +// protected Void doInBackground() throws Exception { +// try { +// while (!taskContext.isStop()) { +// publish(); +// Thread.sleep(300); +// } +// } catch (InterruptedException ignore) { +// // ignore +// } +// return null; +// } +// }; +// new Thread(refreshWorker).start(); +// +// if (!loadingPanel.getSkipCheckingLinksButton().isSelected()) { +// VFSUtils.checkForSftpLinks(files, taskContext); +// } +// taskContext.setStop(true); +// final FileObject[] fileObjectsWithParent = addParentToFiles(files); +// Runnable r = new Runnable() { +// +// @Override +// public void run() { +// fileSystemPanel.setContent(fileObjectsWithParent); +// uriPanel.setFileObject(fileObject); +// int filesCount = files.length; +// statusLabel.setText(MessageFormat.format(BROWSER_FOLDERCONTAINSXELEMENTS, filesCount)); +// JTable table = fileSystemPanel.getTable(); +// if (table.getRowCount() > 0) { +// table.getSelectionModel().setSelectionInterval(0, 0); +// } +// } +// }; +// SwingUtils.runInEdt(r); +// } +// +// public static Throwable getRootCause(Throwable t) { +// while (t.getCause() != null) { +// t = t.getCause(); +// } +// return t; +// } +// +// private FileObject[] addParentToFiles(FileObject[] files) { +// FileObject[] newFiles = new FileObject[files.length + 1]; +// try { +// FileObject parent = currentLocation.getParent(); +// if (parent != null) { +// newFiles[0] = new ParentFileObject(parent); +// System.arraycopy(files, 0, newFiles, 1, files.length); +// } else { +// newFiles = files; +// } +// } catch (FileSystemException e) { +// LOGGER.warn("Can't add parent", e); +// newFiles = files; +// } +// return newFiles; +// } +// +// public FileObject getCurrentLocation() { +// return currentLocation; +// } +// +// public void addFavorite(Favorite favorite) { +// favoritesPanel.getFavoritesUserListModel().add(favorite); +// } +// +// public void showLoading() { +// System.out.println("VfsBrowser.showLoading()----------------------"); +// LOGGER.trace("Showing loading panel"); +// JProgressBar loadingProgressBar = loadingPanel.getLoadingProgressBar(); +// loadingProgressBar.setIndeterminate(true); +// loadingProgressBar.setString(BROWSER_LOADING); +// loadingPanel.getSkipCheckingLinksButton().setSelected(false); +// loadingPanel.setBorder(BorderFactory.createLineBorder(Color.RED)); +// cardLayout.show(centralPanel, LOADING_KEY); +// } +// +// public void showTable() { +// LOGGER.trace("Showing result table"); +// fileSystemPanel.resetScroll(); +// cardLayout.show(centralPanel, TABLE_KEY); +// } +// +// public boolean isMultiSelectionEnabled() { +// return multiSelectionEnabled; +// } +// +// public void setMultiSelectionEnabled(boolean b) { +// int selectionMode = b ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION; +// fileSystemPanel.getTable().getSelectionModel().setSelectionMode(selectionMode); +// if (multiSelectionEnabled == b) { +// return; +// } +// boolean oldValue = multiSelectionEnabled; +// multiSelectionEnabled = b; +// firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, oldValue, multiSelectionEnabled); +// try { +// selectionChanged(); +// } catch (FileSystemException e) { +// LOGGER.error("Error during update state", e); +// } +// } +// +// public SelectionMode getSelectionMode() { +// return selectionMode; +// } +// +// public void setSelectionMode(SelectionMode mode) { +// if (selectionMode == mode) { +// return; +// } +// SelectionMode oldValue = selectionMode; +// this.selectionMode = mode; +// firePropertyChange(MULTI_SELECTION_MODE_CHANGED_PROPERTY, oldValue, selectionMode); +// try { +// selectionChanged(); +// } catch (FileSystemException e) { +// LOGGER.error("Error during update state", e); +// } +// } +// +// public JButton getActionApproveButton() { +// return actionApproveButton; +// } +// +// public Action getActionApproveDelegate() { +// return actionApproveDelegate; +// } +// +// public void setApproveAction(Action action) { +// actionApproveDelegate = action; +// actionApproveButton.setAction(actionApproveDelegate); +// if (action != null) { +// actionApproveButton.setText((String) actionApproveDelegate.getValue(Action.NAME)); +// } +// try { +// selectionChanged(); +// } catch (FileSystemException e) { +// LOGGER.warn("Problem with checking selection conditions", e); +// } +// } +// +// public void setCancelAction(Action cancelAction) { +// actionCancelDelegate = cancelAction; +// actionCancelButton.setAction(actionCancelDelegate); +// try { +// selectionChanged(); +// } catch (FileSystemException e) { +// LOGGER.warn("Problem with checking selection conditions", e); +// } +// +// } +// +// public FileObject[] getSelectedFilesOnTable() { +// return fileSystemPanel.getSelectedFileObjects(); +// } +// +// /** +// * Resources +// */ +// +// private static final String BROWSER_CHECKINGSFTPLINKSTASK = ResourcesUtil.getString("browser.checkingSFtpLinksTask"); +// private static final String BROWSER_FOLDERCONTAINSXELEMENTS = ResourcesUtil.getString("browser.folderContainsXElements"); +// private static final String BROWSER_LOADING = ResourcesUtil.getString("browser.loading..."); +// +// private static final Icon NETWORKSTATUSAWAY = ResourcesUtil.getIcon("networkStatusAway"); +// private static final Icon NETWORKSTATUSONLINE = ResourcesUtil.getIcon("networkStatusOnline"); +// private static final Icon NETWORKSTATUSOFFLINE = ResourcesUtil.getIcon("networkStatusOffline"); +// private JTextField newFileNameField; +// +//} diff --git a/src/eu/engys/util/filechooser/depot/SftpUserAuthenticator.java b/src/eu/engys/util/filechooser/depot/SftpUserAuthenticator.java new file mode 100644 index 0000000..f81f133 --- /dev/null +++ b/src/eu/engys/util/filechooser/depot/SftpUserAuthenticator.java @@ -0,0 +1,140 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.depot; +///* +// * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package eu.engys.util.otrosfilechooser.authentication.authenticator; +// +//import java.awt.event.ActionEvent; +//import java.awt.event.ActionListener; +//import java.io.File; +// +//import javax.swing.JButton; +//import javax.swing.JFileChooser; +//import javax.swing.JLabel; +//import javax.swing.JTextField; +// +//import net.java.dev.designgridlayout.Componentizer; +// +//import org.apache.commons.lang.StringUtils; +//import org.apache.commons.vfs2.FileSystemException; +//import org.apache.commons.vfs2.FileSystemOptions; +//import org.apache.commons.vfs2.UserAuthenticationData; +//import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; +// +//import eu.engys.util.otrosfilechooser.authentication.UserAuthenticationDataWrapper; +//import eu.engys.util.ui.ResourcesUtil; +//import eu.engys.util.ui.builder.PanelBuilder; +// +//public class SftpUserAuthenticator extends FTPUserAuthenticator { +// +// private JTextField sshKeyFileField; +// private static JFileChooser chooser; +// +// public SftpUserAuthenticator(String url, FileSystemOptions fileSystemOptions) { +// super(url, fileSystemOptions); +// } +// +// @Override +// protected void updateAuthenticationData(UserAuthenticationData authenticationData) { +// super.updateAuthenticationData(authenticationData); +// authenticationData.setData(UserAuthenticationDataWrapper.SSH_KEY, sshKeyFileField.getText().trim().toCharArray()); +// +// if (StringUtils.isNotBlank(sshKeyFileField.getText())) { +// try { +// SftpFileSystemConfigBuilder.getInstance().setIdentities(getFileSystemOptions(), new File[] { new File(sshKeyFileField.getText()) }); +// // TODO set user auth data file path +// } catch (FileSystemException e) { +// e.printStackTrace(); +// } +// } +// +// } +// +// @Override +// protected PanelBuilder getOptionsPanelBuilder() { +// if (sshKeyFileField == null) { +// sshKeyFileField = new JTextField(15); +// } +// if (chooser == null) { +// chooser = new JFileChooser(); +// } +// PanelBuilder builder = super.getOptionsPanelBuilder(); +// +// JButton browseButton = new JButton("..."); +// browseButton.addActionListener(new ActionListener() { +// +// @Override +// public void actionPerformed(ActionEvent e) { +// chooser.setMultiSelectionEnabled(false); +// chooser.setDialogTitle(AUTHENTICATOR_SELECTSSHKEY); +// int showOpenDialog = chooser.showOpenDialog(null); +// if (showOpenDialog == JFileChooser.APPROVE_OPTION) { +// sshKeyFileField.setText(chooser.getSelectedFile().getAbsolutePath()); +// } +// } +// }); +// builder.addComponent(AUTHENTICATOR_SSHKEYFILE, Componentizer.create().prefAndMore(sshKeyFileField).minToPref(browseButton).component()); +// builder.addComponent(new JLabel(AUTHENTICATOR_SSHKEYFILEDESCRIPTION)); +// +// return builder; +// } +// +// @Override +// protected void userSelectedHook(UserAuthenticationData userAuthenticationData) { +// if (userAuthenticationData != null) { +// char[] sshKeyPath = userAuthenticationData.getData(UserAuthenticationDataWrapper.SSH_KEY); +// String path = ""; +// if (sshKeyPath != null && sshKeyPath.length > 0) { +// path = new String(sshKeyPath); +// } +// sshKeyFileField.setText(path); +// } +// } +// +// /** +// * Resources +// */ +// +// private static final String AUTHENTICATOR_SSHKEYFILE = ResourcesUtil.getString("authenticator.sshKeyFile"); +// private static final String AUTHENTICATOR_SELECTSSHKEY = ResourcesUtil.getString("authenticator.selectSshKey"); +// private static final String AUTHENTICATOR_SSHKEYFILEDESCRIPTION = ResourcesUtil.getString("authenticator.sshKeyFileDescription"); +// +//} diff --git a/src/eu/engys/util/filechooser/depot/SmbUserAuthenticator.java b/src/eu/engys/util/filechooser/depot/SmbUserAuthenticator.java new file mode 100644 index 0000000..9f8bfdf --- /dev/null +++ b/src/eu/engys/util/filechooser/depot/SmbUserAuthenticator.java @@ -0,0 +1,111 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.depot; +///* +// * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package eu.engys.util.otrosfilechooser.depot; +// +//import javax.swing.JLabel; +//import javax.swing.JPanel; +//import javax.swing.JTextField; +// +//import org.apache.commons.vfs2.FileSystemOptions; +//import org.apache.commons.vfs2.UserAuthenticationData; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import eu.engys.util.otrosfilechooser.authentication.AuthStore; +//import eu.engys.util.ui.ResourcesUtil; +//import eu.engys.util.ui.builder.PanelBuilder; +// +//public class SmbUserAuthenticator extends FTPUserAuthenticator { +// +// private static final Logger LOGGER = LoggerFactory.getLogger(SmbUserAuthenticator.class); +// +// private JTextField fieldTextField; +// +// public SmbUserAuthenticator(AuthStore authStore, String url, FileSystemOptions fileSystemOptions) { +// super(authStore, url, fileSystemOptions); +// } +// +// @Override +// public UserAuthenticationData requestAuthentication(UserAuthenticationData.Type[] types) { +// LOGGER.debug("Requested for authentication"); +// for (UserAuthenticationData.Type type : types) { +// LOGGER.debug("Requested for authentication: %s", type); +// } +// if (data == null) { +// return super.requestAuthentication(types); +// } else { +// return data; +// } +// } +// +// @Override +// protected void updateAuthenticationData(UserAuthenticationData authenticationData) { +// super.updateAuthenticationData(authenticationData); +// authenticationData.setData(UserAuthenticationData.DOMAIN, fieldTextField.getText().toCharArray()); +// } +// +// @Override +// protected void userSelectedHook(UserAuthenticationData userAuthenticationData) { +// char[] domain = new char[0]; +// if (userAuthenticationData != null) { +// domain = userAuthenticationData.getData(UserAuthenticationData.DOMAIN); +// } +// fieldTextField.setText(new String(domain)); +// +// } +// +// @Override +// protected PanelBuilder getOptionsPanelBuilder() { +// PanelBuilder panel = super.getOptionsPanelBuilder(); +// fieldTextField = new JTextField(15); +// panel.addComponent(AUTHENTICATOR_DOMAIN, fieldTextField); +// return panel; +// } +// +// /** +// * Resources +// */ +// +// private static final String AUTHENTICATOR_DOMAIN = ResourcesUtil.getString("authenticator.domain"); +// +//} diff --git a/src/eu/engys/util/filechooser/favorites/Favorite.java b/src/eu/engys/util/filechooser/favorites/Favorite.java new file mode 100644 index 0000000..4d208af --- /dev/null +++ b/src/eu/engys/util/filechooser/favorites/Favorite.java @@ -0,0 +1,100 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.favorites; + +public class Favorite { + + public enum Type { + USER, SYSTEM, JVFSFILECHOOSER; + + public boolean isSystem() { + return equals(SYSTEM); + } + + public boolean isUser() { + return equals(USER); + } + } + + private String name; + + private Type type = Type.USER; + + private String url; + + public Favorite(String name, String url, Type type) { + this.name = name; + this.type = type; + this.url = url; + + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + @Override + public String toString() { + return name + " [" + url + "]"; + } + +} diff --git a/src/eu/engys/util/filechooser/favorites/FavoritesUtils.java b/src/eu/engys/util/filechooser/favorites/FavoritesUtils.java new file mode 100644 index 0000000..ff15206 --- /dev/null +++ b/src/eu/engys/util/filechooser/favorites/FavoritesUtils.java @@ -0,0 +1,135 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.favorites; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.filechooser.FileSystemView; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.filechooser.favorites.Favorite.Type; + +public class FavoritesUtils { + + private static final Logger logger = LoggerFactory.getLogger(FavoritesUtils.class); + + public static final String HOME = "Home"; + public static final String DESKTOP = "Desktop"; + public static final String DOCUMENTS = "Documents"; + private static final String FAVORITES_PREFERENCE_DELIMITER = "@@@"; + private static final String FAVORITE_NAME_URL_DELIMITER = "##"; + + public static final File HOME_DIRECTORY = new File(System.getProperty("user.home")); + + public static final File VFS_JFC_CONFIG_DIRECTORY = new File(HOME_DIRECTORY, ".vfsjfilechooser"); + public static final File VFS_JFC_BOOKMARKS_FILE = new File(VFS_JFC_CONFIG_DIRECTORY, "favorites.xml"); + + public List loadFavorite() { + return new ArrayList(); + } + + public static List loadFavorites() { + List list = new ArrayList(); + String favoritesString = PrefUtil.getString(PrefUtil.FAVORITES_KEY); + if (!favoritesString.isEmpty()) { + String[] favorites = favoritesString.split(FAVORITES_PREFERENCE_DELIMITER); + for (int i = 0; i < favorites.length; i++) { + String fav = favorites[i]; + if (!fav.isEmpty()) { + String[] nameAndURL = fav.split(FAVORITE_NAME_URL_DELIMITER); + if (nameAndURL.length == 2) { + String name = nameAndURL[0]; + String url = nameAndURL[1]; + list.add(new Favorite(name, url, Type.USER)); + } + } + } + } + return list; + } + + public static void saveFavorites(List favoriteList) { + StringBuffer favoritesString = new StringBuffer(); + for (Favorite favorite : favoriteList) { + if (favorite.getType().equals(Type.USER)) { + favoritesString.append(favorite.getName()); + favoritesString.append(FAVORITE_NAME_URL_DELIMITER); + favoritesString.append(favorite.getUrl()); + favoritesString.append(FAVORITES_PREFERENCE_DELIMITER); + } + } + PrefUtil.putString(PrefUtil.FAVORITES_KEY, favoritesString.toString()); + } + + public static List loadSystemLocations() { + List list = new ArrayList(); + File[] listRoots = File.listRoots(); + for (File file : listRoots) { + list.add(new Favorite(file.getAbsolutePath(), file.getAbsolutePath(), Favorite.Type.SYSTEM)); + } + File userHome = new File(System.getProperty("user.home")); + File desktop = null; + File documents = null; + if (Util.isWindows()) { + desktop = FileSystemView.getFileSystemView().getHomeDirectory(); + documents = FileSystemView.getFileSystemView().getDefaultDirectory(); + } else { + desktop = new File(userHome, "Desktop"); + documents = new File(userHome, "Documents"); + } + + list.add(new Favorite(HOME, userHome.getAbsolutePath(), Favorite.Type.SYSTEM)); + if (desktop.exists()) { + list.add(new Favorite(DESKTOP, desktop.getAbsolutePath(), Favorite.Type.SYSTEM)); + } + if (documents.exists()) { + list.add(new Favorite(DOCUMENTS, documents.getAbsolutePath(), Favorite.Type.SYSTEM)); + } + return list; + } +} diff --git a/src/eu/engys/util/filechooser/favorites/PopupListener.java b/src/eu/engys/util/filechooser/favorites/PopupListener.java new file mode 100644 index 0000000..945a4e8 --- /dev/null +++ b/src/eu/engys/util/filechooser/favorites/PopupListener.java @@ -0,0 +1,116 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.favorites; + +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.JList; +import javax.swing.JPopupMenu; +import javax.swing.JTable; + +public class PopupListener extends MouseAdapter implements KeyListener { + + private JPopupMenu popupMenu; + + public PopupListener(JPopupMenu popupMenu) { + super(); + this.popupMenu = popupMenu; + } + + public void mousePressed(MouseEvent e) { + checkPopup(e); + } + + public void mouseClicked(MouseEvent e) { + checkPopup(e); + } + + public void mouseReleased(MouseEvent e) { + checkPopup(e); + } + + private void checkPopup(MouseEvent e) { + if (e.isPopupTrigger()) { + show((Component) e.getSource(), e.getX(), e.getY()); + } + } + + public void show(Component invoker, int x, int y) { + popupMenu.show(invoker, x, y); + } + + @Override + public void keyTyped(KeyEvent e) { + + } + + @Override + public void keyPressed(KeyEvent e) { + Point p = new Point(e.getComponent().getLocation()); + + if (e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU) { + if (e.getComponent() instanceof JTable) { + JTable table = (JTable) e.getComponent(); + int selectedRow = table.getSelectedRow(); + Rectangle cellRect = table.getCellRect(selectedRow, 0, true); + p.setLocation(cellRect.getCenterX(), cellRect.getCenterY()); + } else if (e.getComponent() instanceof JList) { + JList list = (JList) e.getComponent(); + int selectedIndex = list.getSelectedIndex(); + Rectangle cellRect = list.getCellBounds(selectedIndex, selectedIndex); + p.setLocation(cellRect.getCenterX(), cellRect.getCenterY()); + } + show(e.getComponent(), (int) p.getX(), (int) p.getY()); + } + } + + @Override + public void keyReleased(KeyEvent e) { + + } +} diff --git a/src/eu/engys/util/filechooser/favorites/list/MutableListDragListener.java b/src/eu/engys/util/filechooser/favorites/list/MutableListDragListener.java new file mode 100644 index 0000000..6ee854d --- /dev/null +++ b/src/eu/engys/util/filechooser/favorites/list/MutableListDragListener.java @@ -0,0 +1,87 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.favorites.list; + +import java.awt.datatransfer.StringSelection; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; + +import javax.swing.JList; + +public class MutableListDragListener implements DragSourceListener, DragGestureListener { + private JList list; + + private DragSource ds = new DragSource(); + + public MutableListDragListener(final JList list) { + this.list = list; + ds.createDefaultDragGestureRecognizer(list, DnDConstants.ACTION_MOVE, this); + + } + + public void dragGestureRecognized(final DragGestureEvent dge) { + final StringSelection transferable = new StringSelection(Integer.toString(list.getSelectedIndex())); + ds.startDrag(dge, DragSource.DefaultCopyDrop, transferable, this); + } + + public void dragEnter(final DragSourceDragEvent dsde) { + } + + public void dragExit(final DragSourceEvent dse) { + } + + public void dragOver(final DragSourceDragEvent dsde) { + } + + public void dragDropEnd(final DragSourceDropEvent dsde) { + + } + + public void dropActionChanged(final DragSourceDragEvent dsde) { + } +} diff --git a/src/eu/engys/util/filechooser/favorites/list/MutableListDropHandler.java b/src/eu/engys/util/filechooser/favorites/list/MutableListDropHandler.java new file mode 100644 index 0000000..da82ed3 --- /dev/null +++ b/src/eu/engys/util/filechooser/favorites/list/MutableListDropHandler.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.favorites.list; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; + +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.TransferHandler; + +import eu.engys.util.ui.UiUtil; + +public class MutableListDropHandler extends TransferHandler { + private JList list; + + public MutableListDropHandler(final JList list) { + this.list = list; + } + + public boolean canImport(final TransferHandler.TransferSupport support) { + if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) { + return false; + } + final JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); + if (dl.getIndex() == -1) { + return false; + } else { + return true; + } + } + + public boolean importData(final TransferHandler.TransferSupport support) { + if (!canImport(support)) { + return false; + } + + final Transferable transferable = support.getTransferable(); + String indexString; + try { + indexString = (String) transferable.getTransferData(DataFlavor.stringFlavor); + } catch (final Exception e) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), e.getMessage(), "File Chooser Error", JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + return false; + } + + int index = Integer.parseInt(indexString); + final JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); + final int dropTargetIndex = dl.getIndex(); + + final MutableListModel model = (MutableListModel) list.getModel(); + model.move(index, dropTargetIndex); + return true; + } +} diff --git a/src/eu/engys/util/filechooser/favorites/list/MutableListModel.java b/src/eu/engys/util/filechooser/favorites/list/MutableListModel.java new file mode 100644 index 0000000..6887c21 --- /dev/null +++ b/src/eu/engys/util/filechooser/favorites/list/MutableListModel.java @@ -0,0 +1,98 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.favorites.list; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractListModel; + +/** + */ +public class MutableListModel extends AbstractListModel { + + private ArrayList list; + + public MutableListModel() { + list = new ArrayList(); + } + + @Override + public int getSize() { + return list.size(); + } + + @Override + public T getElementAt(int index) { + return list.get(index); + } + + public void add(T favorite) { + list.add(favorite); + fireIntervalAdded(this, list.size() - 1, list.size() - 1); + } + + public void remove(int index) { + list.remove(index); + fireIntervalRemoved(this, index, index); + } + + public void change(int index, T favorite) { + list.set(index, favorite); + fireContentsChanged(this, index, index); + } + + public void move(int from, int to) { + list.add(to, list.get(from)); + if (to < from) { + from++; + } + list.remove(from); + fireContentsChanged(this, Math.min(from, to), Math.max(from, to)); + + } + + public List getList() { + return new ArrayList(list); + } + +} diff --git a/src/eu/engys/util/filechooser/favorites/list/SelectFirstElementFocusAdapter.java b/src/eu/engys/util/filechooser/favorites/list/SelectFirstElementFocusAdapter.java new file mode 100644 index 0000000..a61ecdb --- /dev/null +++ b/src/eu/engys/util/filechooser/favorites/list/SelectFirstElementFocusAdapter.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.favorites.list; + +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; + +import javax.swing.JList; + +/** + * When component gained focus is list without selection, first element is + * selected. + */ +public class SelectFirstElementFocusAdapter extends FocusAdapter { + @Override + public void focusGained(FocusEvent e) { + if (e.getSource() instanceof JList) { + JList list = (JList) e.getSource(); + if (list.getSelectedIndex() < 0 && list.getModel().getSize() > 0) { + list.setSelectedIndex(0); + } + } + } +} diff --git a/src/eu/engys/util/filechooser/favorites/renderer/FavoriteListCellRenderer.java b/src/eu/engys/util/filechooser/favorites/renderer/FavoriteListCellRenderer.java new file mode 100644 index 0000000..76d1074 --- /dev/null +++ b/src/eu/engys/util/filechooser/favorites/renderer/FavoriteListCellRenderer.java @@ -0,0 +1,93 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.favorites.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JList; + +import eu.engys.util.filechooser.favorites.Favorite; +import eu.engys.util.filechooser.favorites.FavoritesUtils; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; + + +/** + */ +public class FavoriteListCellRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component component = super.getListCellRendererComponent(list, value, index, isSelected & cellHasFocus, cellHasFocus); + if (component instanceof JLabel) { + JLabel label = (JLabel) component; + Favorite f = (Favorite) value; + label.setText(f.getName()); + label.setToolTipText(VFSUtils.getFriendlyName(f.getUrl())); + + if(f.getType().isSystem()){ + if(FavoritesUtils.HOME.equals(f.getName())){ + label.setIcon(HOME_ICON); + } else if(FavoritesUtils.DESKTOP.equals(f.getName())){ + label.setIcon(DESKTOP_ICON); + } else if(FavoritesUtils.DOCUMENTS.equals(f.getName())){ + label.setIcon(DOCUMENTS_ICON); + } else { + label.setIcon(VFSUtils.getIconForFileSystem(f.getUrl())); + } + } else { + label.setIcon(VFSUtils.getIconForFileSystem(f.getUrl())); + } + } + + return component; + } + + /* + * RESOURCES + */ + private static final Icon HOME_ICON = ResourcesUtil.getIcon("home"); + private static final Icon DESKTOP_ICON = ResourcesUtil.getIcon("desktop"); + private static final Icon DOCUMENTS_ICON = ResourcesUtil.getIcon("documents"); +} diff --git a/src/eu/engys/util/filechooser/gui/Accessory.java b/src/eu/engys/util/filechooser/gui/Accessory.java new file mode 100644 index 0000000..976bb31 --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/Accessory.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import javax.swing.JPanel; + +public interface Accessory { + + void onSelectionChanged(); + + JPanel getPanel(); + +} diff --git a/src/eu/engys/util/filechooser/gui/BreadCrumbsPanel.java b/src/eu/engys/util/filechooser/gui/BreadCrumbsPanel.java new file mode 100644 index 0000000..1416717 --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/BreadCrumbsPanel.java @@ -0,0 +1,159 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; + +public class BreadCrumbsPanel extends JPanel { + + public static final String NAME = "chooser.breadcrumbspanel"; + + private FileChooserController controller; + private JPanel mainPanel; + private JScrollPane scrollPanel; + private MoveToTheEndListener listener; + private JScrollBar horizontalScrollBar; + + private List buttons = new ArrayList<>(); + + public BreadCrumbsPanel(FileChooserController controller) { + super(new BorderLayout()); + this.controller = controller; + setName(NAME); + layoutComponents(); + } + + private void layoutComponents() { + this.mainPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + this.mainPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); + this.scrollPanel = createScrollPanel(); + this.horizontalScrollBar = scrollPanel.getHorizontalScrollBar(); + scrollPanel.getHorizontalScrollBar().setPreferredSize(new Dimension(0, 8)); + this.listener = new MoveToTheEndListener(); + add(scrollPanel, BorderLayout.CENTER); + } + + private JScrollPane createScrollPanel() { + JScrollPane scrollPanel = new JScrollPane(mainPanel); + scrollPanel.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); + scrollPanel.setBorder(BorderFactory.createEmptyBorder()); + return scrollPanel; + } + + public void updatePanel(FileObject fileObject) { + horizontalScrollBar.addAdjustmentListener(listener); + + buttons.clear(); + mainPanel.removeAll(); + addButtons(fileObject); + + revalidate(); + repaint(); + } + + private void addButtons(FileObject fileObject) { + try { + addButtonFor(fileObject); + } catch (FileSystemException e) { + e.printStackTrace(); + } + } + + private void addButtonFor(final FileObject fo) throws FileSystemException { + if (fo != null) { + FileObject parent = fo.getParent(); + if (parent != null) { + addButtonFor(parent); + } + if (isRoot(fo)) { + _add(fo, "/"); + } else { + String baseName = fo.getName().getBaseName(); + if (!baseName.isEmpty()) { + _add(fo, baseName); + } + } + } + } + + private void _add(final FileObject fo, String name) { + JButton button = new JButton(new AbstractAction(name) { + @Override + public void actionPerformed(ActionEvent arg0) { + controller.goToURL(fo); + } + }); + button.setName(name); + mainPanel.add(button); + buttons.add(button); + } + + private boolean isRoot(FileObject fo) throws FileSystemException { + return fo.getName().getBaseName().isEmpty() && fo.getParent() == null; + } + + public List getButtons() { + return buttons; + } + + public List getPath() { + List path = new ArrayList<>(); + for (JButton b : buttons) { + path.add((String) b.getAction().getValue(Action.NAME)); + } + return path; + } + + private class MoveToTheEndListener implements AdjustmentListener { + + @Override + public void adjustmentValueChanged(AdjustmentEvent e) { + if (!e.getValueIsAdjusting()) { + horizontalScrollBar.setValue(horizontalScrollBar.getMaximum()); + horizontalScrollBar.removeAdjustmentListener(this); + } + } + } + +} diff --git a/src/eu/engys/util/filechooser/gui/BrowserFactory.java b/src/eu/engys/util/filechooser/gui/BrowserFactory.java new file mode 100644 index 0000000..16a21d0 --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/BrowserFactory.java @@ -0,0 +1,65 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import eu.engys.util.connection.SshParameters; +import eu.engys.util.filechooser.AbstractFileChooser; +import eu.engys.util.filechooser.util.HelyxFileFilter; + +public class BrowserFactory { + + public static FileChooserPanel createOpenBrowser(AbstractFileChooser chooser) { + return new FileChooserPanel(chooser, null, null, null, false); + } + + public static FileChooserPanel createOpenBrowser(AbstractFileChooser chooser, HelyxFileFilter... filters) { + return new FileChooserPanel(chooser, null, null, null, false, filters); + } + + public static FileChooserPanel createOpenBrowser(AbstractFileChooser chooser, Accessory accessory) { + return new FileChooserPanel(chooser, accessory, null, null, false); + } + + public static FileChooserPanel createOpenBrowser(AbstractFileChooser chooser, Options options) { + return new FileChooserPanel(chooser, null, options, null, false); + } + + public static FileChooserPanel createOpenBrowser(AbstractFileChooser chooser, Accessory accessory, HelyxFileFilter... filters) { + return new FileChooserPanel(chooser, accessory, null, null, false, filters); + } + + public static FileChooserPanel createSaveAsBrowser(AbstractFileChooser chooser) { + return new FileChooserPanel(chooser, null, null, null, true); + } + + public static FileChooserPanel createSaveAsBrowser(AbstractFileChooser chooser, HelyxFileFilter... filters) { + return new FileChooserPanel(chooser, null, null, null, true, filters); + } + + public static FileChooserPanel createOpenRemoteBrowser(AbstractFileChooser chooser, SshParameters sshParameters) { + return new FileChooserPanel(chooser, null, null, sshParameters, false); + } +} diff --git a/src/eu/engys/util/filechooser/gui/ButtonsPanel.java b/src/eu/engys/util/filechooser/gui/ButtonsPanel.java new file mode 100644 index 0000000..a4e93de --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/ButtonsPanel.java @@ -0,0 +1,208 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; + +import net.java.dev.designgridlayout.Componentizer; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; + +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.builder.PanelBuilder; + +public class ButtonsPanel extends JPanel { + + public static final String NAME = "chooser.buttonspanel"; + public static final String FILTER_COMBO = "filter.combo"; + + private FileChooserController controller; + private HelyxFileFilter[] filters; + private JComboBox filterCombo; + private JButton okButton; + + public ButtonsPanel(FileChooserController controller, HelyxFileFilter[] filters) { + super(new BorderLayout()); + this.filters = filters; + setName(NAME); + this.controller = controller; + layoutComponents(); + } + + private void layoutComponents() { + PanelBuilder pb = new PanelBuilder(); + okButton = new JButton(new OkAction()); + okButton.setName("OK"); + okButton.setEnabled(false); + JButton cancelButton = new JButton(new CancelAction()); + cancelButton.setName("Cancel"); + if (filters != null) { + filterCombo = createFilterCombo(); + pb.addComponent("Type", Componentizer.create().prefAndMore(filterCombo).minToPref(okButton, cancelButton).component()); + } else { + pb.addComponent(Componentizer.create().prefAndMore(new JLabel()).minToPref(okButton, cancelButton).component()); + } + add(pb.getPanel(), BorderLayout.CENTER); + } + + public void updateOkButton() { + ExecUtil.invokeAndWait(new Runnable() { + + @Override + public void run() { + _updateOkButton_OnEDT(); + } + }); + } + + private void _updateOkButton_OnEDT() { + FileObject fileSystemPanelFileObject = controller.getFileSystemPanel().getSelectedFileObject(); + FileObject uriPanelFileObject = controller.getUriPanel().getFileObject(); + + if (controller.isSaveAs()) { + String uriPanelNewFileName = controller.getUriPanel().getNewFileName(); + okButton.setEnabled(uriPanelFileObject != null && !uriPanelNewFileName.isEmpty()); + } else { + if (fileSystemPanelFileObject == null) { + if (controller.getSelectionMode().isDirsOnly() || controller.getSelectionMode().isDirsAndArchives()) { + okButton.setEnabled(uriPanelFileObject != null); + } else { + okButton.setEnabled(false); + } + } else { + okButton.setEnabled(checkTypeAndExtension(fileSystemPanelFileObject)); + } + } + } + + private boolean checkTypeAndExtension(FileObject selectedFileObject) { + try { + boolean rightType1 = (selectedFileObject.getType() == FileType.FILE) && controller.getSelectionMode().isFilesOnly(); + boolean rightType2 = (selectedFileObject.getType() == FileType.FOLDER) && controller.getSelectionMode().isDirsOnly(); + boolean rightType3 = (selectedFileObject.getType() == FileType.FOLDER) && controller.getSelectionMode().isDirsAndArchives(); + boolean rightType4 = controller.getSelectionMode().isDirsAndFiles(); + boolean rightType = rightType1 || rightType2 || rightType3 || rightType4; + + boolean rightExtension = true; + HelyxFileFilter filter = getSelectedFilter(); + if (filter != null && !filter.isAllFilesFilter()) { + String fileName = selectedFileObject.getName().getBaseName(); + String fileExtension = selectedFileObject.getName().getExtension(); + rightExtension = fileExtension.isEmpty() ? filter.isValidExtension(fileName) : filter.isValidExtension(fileExtension); + } + return rightExtension && (rightType); + } catch (FileSystemException e) { + return false; + } + } + + private JComboBox createFilterCombo() { + JComboBox filterCombo = new JComboBox(); + filterCombo.setName(FILTER_COMBO); + filterCombo.addItem(HelyxFileFilter.getAllFilesFilter()); + for (HelyxFileFilter filter : filters) { + filterCombo.addItem(filter); + } + filterCombo.setSelectedIndex(filterCombo.getItemCount() > 1 ? 1 : 0); + final ListCellRenderer renderer = filterCombo.getRenderer(); + filterCombo.setRenderer(new ListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, HelyxFileFilter value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (c instanceof JLabel && value instanceof HelyxFileFilter) { + HelyxFileFilter model = (HelyxFileFilter) value; + ((JLabel) c).setText(model.getDescription()); + } + return c; + } + }); + filterCombo.addItemListener(new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getSource() instanceof JComboBox && e.getStateChange() == ItemEvent.SELECTED) { + controller.applyFilter(); + } + } + }); + return filterCombo; + } + + public void resetFileFilter() { + filterCombo.setSelectedItem(HelyxFileFilter.getAllFilesFilter()); + controller.applyFilter(); + } + + public HelyxFileFilter getSelectedFilter() { + if (filterCombo != null) { + return (HelyxFileFilter) filterCombo.getSelectedItem(); + } + return null; + } + + public JButton getOkButton() { + return okButton; + } + + private class OkAction extends AbstractAction { + public OkAction() { + super(controller.isSaveAs() ? "Save" : filters != null ? "Open" : "Select"); + } + + @Override + public void actionPerformed(ActionEvent e) { + controller.closeAndReturn(ReturnValue.Approve); + } + } + + private class CancelAction extends AbstractAction { + public CancelAction() { + super("Cancel"); + } + + @Override + public void actionPerformed(ActionEvent e) { + controller.closeAndReturn(ReturnValue.Cancelled); + } + } + +} diff --git a/src/eu/engys/util/filechooser/gui/FavoritesPanel.java b/src/eu/engys/util/filechooser/gui/FavoritesPanel.java new file mode 100644 index 0000000..ff8eeee --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/FavoritesPanel.java @@ -0,0 +1,294 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; + +import eu.engys.util.filechooser.actions.favorite.EditFavorite; +import eu.engys.util.filechooser.actions.favorite.OpenFavorite; +import eu.engys.util.filechooser.favorites.Favorite; +import eu.engys.util.filechooser.favorites.FavoritesUtils; +import eu.engys.util.filechooser.favorites.PopupListener; +import eu.engys.util.filechooser.favorites.list.MutableListDragListener; +import eu.engys.util.filechooser.favorites.list.MutableListDropHandler; +import eu.engys.util.filechooser.favorites.list.MutableListModel; +import eu.engys.util.filechooser.favorites.list.SelectFirstElementFocusAdapter; +import eu.engys.util.filechooser.favorites.renderer.FavoriteListCellRenderer; +import eu.engys.util.filechooser.util.VFSUtils.LocationType; +import eu.engys.util.ui.FileChooserUtils; +import eu.engys.util.ui.ResourcesUtil; + +public class FavoritesPanel extends JPanel { + + public static final String NAME = "chooser.favoritespanel"; + public static final String FAVORITES_PANEL = "favoritesPanel"; + public static final String SYSTEM_PANEL = "systemPanel"; + public static final String FAVORITES_USER_LIST = "favoritesUserList"; + public static final String FAVORITES_SYSTEM_LIST = "favoriteSystemList"; + + private static final Color BG_COLOR = new Color(250, 250, 250); + + private static final String ACTION_OPEN = "OPEN"; + private static final String ACTION_DELETE = "DELETE"; + private static final String ACTION_EDIT = "EDIT"; + + private final FileChooserController controller; + + private List userFavorites; + + private MutableListModel systemListModel; + private MutableListModel userListModel; + + public FavoritesPanel(FileChooserController controller) { + super(new GridLayout(controller.isRemote() ? 1 : 2, 1, 0, 10)); + setName(NAME); + this.controller = controller; + + layoutComponents(); + load(); + } + + + private void layoutComponents() { + addSystemLocationPanel(); + addUserFavoritesPanel(); + } + + private void load() { + loadSystemLocations(); + loadFavorites(); + } + + @SuppressWarnings("unchecked") + private void addSystemLocationPanel() { + systemListModel = new MutableListModel(); + + JList favoriteSystemList = new JList(systemListModel); + favoriteSystemList.setName(FAVORITES_SYSTEM_LIST); + favoriteSystemList.setCellRenderer(new FavoriteListCellRenderer()); + favoriteSystemList.addFocusListener(new SelectFirstElementFocusAdapter()); + + addOpenActionToList(favoriteSystemList); + addPopupMenu(favoriteSystemList, ACTION_OPEN); + + JLabel systemLocationLabel = createLabelWithIcon(FAVORITES_SYSTEMLOCATIONS, COMPUTER_ICON); + + if (!controller.isRemote()) { + JPanel systemPanel = new JPanel(new BorderLayout()); + systemPanel.setName(SYSTEM_PANEL); + systemPanel.add(systemLocationLabel, BorderLayout.NORTH); + systemPanel.add(favoriteSystemList, BorderLayout.CENTER); + JScrollPane comp = new JScrollPane(systemPanel); + add(comp); + } + } + + private void addUserFavoritesPanel() { + userListModel = createListModel(); + + JList favoritesUserList = createList(); + favoritesUserList.setName(FAVORITES_USER_LIST); + favoritesUserList.setCellRenderer(new FavoriteListCellRenderer()); + favoritesUserList.addFocusListener(new SelectFirstElementFocusAdapter()); + + addOpenActionToList(favoritesUserList); + addEditActionToList(favoritesUserList, userListModel); + addPopupMenu(favoritesUserList, ACTION_OPEN, ACTION_EDIT, ACTION_DELETE); + + JLabel userFavouritesLabel = createLabelWithIcon(FAVORITES_FAVORITES, STAR); + + JPanel favoritesPanel = new JPanel(new BorderLayout()); + favoritesPanel.setName(FAVORITES_PANEL); + favoritesPanel.add(userFavouritesLabel, BorderLayout.NORTH); + favoritesPanel.add(favoritesUserList, BorderLayout.CENTER); + + add(new JScrollPane(favoritesPanel)); + } + + private void loadSystemLocations() { + List systemLocations = FavoritesUtils.loadSystemLocations(); + for (Favorite favorite : systemLocations) { + systemListModel.add(favorite); + } + } + + private void loadFavorites() { + this.userFavorites = FavoritesUtils.loadFavorites(); + for (Favorite favorite : userFavorites) { + if (isValidFavorite(favorite.getUrl(), controller)) { + userListModel.add(favorite); + } + } + } + + private boolean isValidFavorite(String url, FileChooserController controller) { + if (controller.isRemote()) { + String host = controller.getSshParameters().getHost(); + String port = String.valueOf(controller.getSshParameters().getPort()); + String typePrefix = LocationType.sftp.toString(); + if(port.equals(FileChooserUtils.DEFAULT_SSH_PORT)){ + return url.startsWith(typePrefix + host); + } else { + return url.startsWith(typePrefix + host + ":" + port); + } + } else { + return url.startsWith(LocationType.file.toString()); + } + } + + public void addFavorite(Favorite favorite) { + userFavorites.add(favorite); + userListModel.add(favorite); + } + + @SuppressWarnings("unchecked") + private JList createList() { + final JList favoritesUserList = new JList(userListModel); + favoritesUserList.setTransferHandler(new MutableListDropHandler(favoritesUserList)); + new MutableListDragListener(favoritesUserList); + favoritesUserList.getActionMap().put(ACTION_DELETE, new AbstractAction("Delete", MINUSBUTTON) { + + @Override + public void actionPerformed(ActionEvent e) { + Favorite favorite = userListModel.getElementAt(favoritesUserList.getSelectedIndex()); + if (!Favorite.Type.USER.equals(favorite.getType())) { + return; + } + userFavorites.remove(favoritesUserList.getSelectedValue()); + userListModel.remove(favoritesUserList.getSelectedIndex()); + } + }); + InputMap favoritesListInputMap = favoritesUserList.getInputMap(JComponent.WHEN_FOCUSED); + favoritesListInputMap.put(KeyStroke.getKeyStroke("DELETE"), ACTION_DELETE); + return favoritesUserList; + } + + private MutableListModel createListModel() { + final MutableListModel favoritesUserListModel = new MutableListModel(); + favoritesUserListModel.addListDataListener(new ListDataListener() { + @Override + public void intervalAdded(ListDataEvent e) { + saveFavorites(); + } + + @Override + public void intervalRemoved(ListDataEvent e) { + saveFavorites(); + } + + @Override + public void contentsChanged(ListDataEvent e) { + saveFavorites(); + } + + protected void saveFavorites() { + FavoritesUtils.saveFavorites(userFavorites); + } + }); + return favoritesUserListModel; + } + + private JPopupMenu addPopupMenu(JList list, String... actions) { + JPopupMenu favoritesPopupMenu = new JPopupMenu(); + for (String action : actions) { + JMenuItem item = favoritesPopupMenu.add(list.getActionMap().get(action)); + item.setName(action); + } + list.addKeyListener(new PopupListener(favoritesPopupMenu)); + list.addMouseListener(new PopupListener(favoritesPopupMenu)); + return favoritesPopupMenu; + } + + private JLabel createLabelWithIcon(String text, Icon icon) { + JLabel label = new JLabel(text, icon, SwingConstants.CENTER); + Font font = label.getFont(); + label.setFont(font.deriveFont(Font.BOLD)); + Border lineBorder = BorderFactory.createMatteBorder(0, 0, 1, 0, BG_COLOR.darker()); + Border emptyBorder = BorderFactory.createEmptyBorder(2, 0, 2, 0); + CompoundBorder compoundBorder = BorderFactory.createCompoundBorder(lineBorder, emptyBorder); + + label.setBorder(compoundBorder); + return label; + } + + private void addOpenActionToList(final JList favoritesList) { + favoritesList.getActionMap().put(ACTION_OPEN, new OpenFavorite(controller, favoritesList)); + favoritesList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + boolean isLeftButton = e.getButton() == MouseEvent.BUTTON1; + boolean isSingleClick = e.getClickCount() == 1; + if (isSingleClick && isLeftButton) { + favoritesList.getActionMap().get(ACTION_OPEN).actionPerformed(null); + } + } + }); + InputMap favoritesListInputMap = favoritesList.getInputMap(JComponent.WHEN_FOCUSED); + favoritesListInputMap.put(KeyStroke.getKeyStroke("ENTER"), ACTION_OPEN); + } + + private void addEditActionToList(JList favoritesList, MutableListModel listModel) { + favoritesList.getActionMap().put(ACTION_EDIT, new EditFavorite(controller, favoritesList, listModel)); + + InputMap favoritesListInputMap = favoritesList.getInputMap(JComponent.WHEN_FOCUSED); + favoritesListInputMap.put(KeyStroke.getKeyStroke("F2"), ACTION_EDIT); + } + + /** + * Resources + */ + + private static final String FAVORITES_SYSTEMLOCATIONS = ResourcesUtil.getString("favorites.systemLocations"); + private static final String FAVORITES_FAVORITES = ResourcesUtil.getString("favorites.favorites"); + + private static final Icon COMPUTER_ICON = ResourcesUtil.getIcon("computer"); + private static final Icon STAR = ResourcesUtil.getIcon("star"); + private static final Icon MINUSBUTTON = ResourcesUtil.getIcon("minusButton"); +} diff --git a/src/eu/engys/util/filechooser/gui/FileChooserController.java b/src/eu/engys/util/filechooser/gui/FileChooserController.java new file mode 100644 index 0000000..1dc5158 --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/FileChooserController.java @@ -0,0 +1,234 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.connection.SshParameters; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.favorites.Favorite; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.filechooser.util.TaskContext; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; + +public class FileChooserController { + + private static final Logger logger = LoggerFactory.getLogger(FileChooserController.class); + public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = "MultiSelectionEnabledChangedProperty"; + public static final String MULTI_SELECTION_MODE_CHANGED_PROPERTY = "SelectionModeChangedProperty"; + + private URIPanel uriPanel; + private FavoritesPanel favoritesPanel; + private FileSystemPanel fileSystemPanel; + + private TaskContext taskContext; + + private FileChooserPanel chooserPanel; + private SelectionMode selectionMode = SelectionMode.DIRS_AND_FILES; + private SshParameters sshParameters; + private boolean saveAs; + private ButtonsPanel buttonsPanel; + + public FileChooserController(SshParameters sshParameters) { + this.sshParameters = sshParameters; + } + + public void setBrowser(FileChooserPanel vfsBrowser) { + this.chooserPanel = vfsBrowser; + this.uriPanel = chooserPanel.getUriPanel(); + this.favoritesPanel = chooserPanel.getFavoritesPanel(); + this.fileSystemPanel = chooserPanel.getFileSystemPanel(); + this.buttonsPanel = chooserPanel.getButtonsPanel(); + // this.breadCrumbsPanel = chooserPanel.getBreadCrumbsPanel(); + } + + public void goToURL(final String url, boolean encoded) { + String encodedURL = encoded ? url : VFSUtils.encode(url, sshParameters); + try { + FileObject resolveFileObject = VFSUtils.resolveFileObject(encodedURL, sshParameters); + goToURL(resolveFileObject); + } catch (FileSystemException e) { + VFSUtils.showErrorMessage(chooserPanel, encodedURL, e); + } + } + + public void goToURL(final FileObject fileObject) { + try { + fileObject.refresh(); + } catch (FileSystemException e) { + logger.error("Could not refresh " + fileObject.getName().getFriendlyURI()); + } + if (taskContext != null) { + taskContext.setStop(true); + } + final FileObject[] files = VFSUtils.getFiles(chooserPanel, fileObject); + taskContext = new TaskContext(BROWSER_CHECKINGSFTPLINKSTASK, files.length); + taskContext.setIndeterminate(false); + VFSUtils.checkForSftpLinks(files, taskContext); + taskContext.setStop(true); + + ExecUtil.invokeLater(new Runnable() { + + @Override + public void run() { + FileObject[] fileObjectsWithParent = files; + if (fileSystemPanel != null) { + fileSystemPanel.setContent(fileObjectsWithParent); + } + if (uriPanel != null) { + uriPanel.setFileObject(fileObject); + } + if (fileSystemPanel != null) { + fileSystemPanel.resetFilter(); + } + } + }); + updateOkButton(); + } + + public void addFavorite(Favorite favorite) { + favoritesPanel.addFavorite(favorite); + } + + public FileObject getSelectedFileObject() { + FileObject[] fos = getSelectedFileObjects(); + if (fos != null && fos.length > 0) { + return fos[0]; + } else { + return null; + } + } + + public FileObject[] getSelectedFileObjects() { + return chooserPanel.getSelectedFileObjects(); + } + + public FileSystemPanel getFileSystemPanel() { + return fileSystemPanel; + } + + public void resetFileFilter() { + buttonsPanel.resetFileFilter(); + } + + public URIPanel getUriPanel() { + return uriPanel; + } + + public static Throwable getRootCause(Throwable t) { + while (t.getCause() != null) { + t = t.getCause(); + } + return t; + } + + public void applyFilter() { + HelyxFileFilter filter = buttonsPanel.getSelectedFilter(); + if (filter != null) { + fileSystemPanel.applyFilter(filter); + } + } + + public SelectionMode getSelectionMode() { + return selectionMode; + } + + public void setSelectionMode(SelectionMode mode) { + this.selectionMode = mode; + } + + public void showTable() { + if (chooserPanel != null) { + chooserPanel.showTable(); + } + } + + public void showLoading() { + if (chooserPanel != null) { + chooserPanel.showLoading(); + } + } + + public void updateNewFileName() { + uriPanel.updateFileName(); + } + + public void updateOkButton() { + buttonsPanel.updateOkButton(); + } + + public void closeAndReturn(ReturnValue retVal) { + chooserPanel.closeAndReturn(retVal); + } + + public HelyxFileFilter getFilter() { + return buttonsPanel.getSelectedFilter(); + } + + public void fixSelection() { + // fileSystemPanel.fixSelection(); + } + + public SshParameters getSshParameters() { + return sshParameters; + } + + public boolean isRemote() { + return getSshParameters() != null; + } + + public boolean isSaveAs() { + return saveAs; + } + + public void setSaveAs(boolean saveAs) { + this.saveAs = saveAs; + } + + /* + * For tests purposes only + */ + public void setFavoritesPanel(FavoritesPanel favoritesPanel) { + this.favoritesPanel = favoritesPanel; + } + + public void setUriPanel(URIPanel uriPanel) { + this.uriPanel = uriPanel; + } + + /* + * Resources + */ + + private static final String BROWSER_CHECKINGSFTPLINKSTASK = ResourcesUtil.getString("browser.checkingSFtpLinksTask"); + +} diff --git a/src/eu/engys/util/filechooser/gui/FileChooserPanel.java b/src/eu/engys/util/filechooser/gui/FileChooserPanel.java new file mode 100644 index 0000000..eda5b10 --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/FileChooserPanel.java @@ -0,0 +1,337 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.gui; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.io.File; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.cache.SoftRefFilesCache; +import org.apache.log4j.Level; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.connection.SshParameters; +import eu.engys.util.filechooser.AbstractFileChooser; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.authentication.MemoryAuthStore; +import eu.engys.util.filechooser.authentication.UserAuthenticatorFactory; +import eu.engys.util.filechooser.authentication.authenticator.UseCentralsFromSessionUserAuthenticator; +import eu.engys.util.filechooser.util.EngysFileSystemManager; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ExecUtil; + +public class FileChooserPanel extends JPanel { + + private static final Logger logger = LoggerFactory.getLogger(FileChooserPanel.class); + public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = "MultiSelectionEnabledChangedProperty"; + public static final String MULTI_SELECTION_MODE_CHANGED_PROPERTY = "SelectionModeChangedProperty"; + + private static final String TABLE_KEY = "TABLE"; + private static final String LOADING_KEY = "LOADING"; + + private CardLayout cardLayout; + + private JPanel cardLayoutPanel; + private URIPanel uriPanel; + private FileSystemPanel fileSystemPanel; + private FavoritesPanel favoritesPanel; + private LoadingPanel loadingPanel; + private ButtonsPanel buttonsPanel; + + private FileChooserController controller; + private final AbstractFileChooser chooser; + + private Accessory accessory; + private Options options; + private SshParameters sshParameters; + private HelyxFileFilter[] filters; + private boolean enableSaveAs; + private File fileToSelect; + + FileChooserPanel(AbstractFileChooser chooser, Accessory accessory, Options options, SshParameters sshParameters, boolean enableSaveAs, HelyxFileFilter... filters) { + super(new BorderLayout()); + setName("filechooser.panel"); + this.chooser = chooser; + this.accessory = accessory; + this.options = options; + this.sshParameters = sshParameters; + this.enableSaveAs = enableSaveAs; + this.filters = filters; + + setLogLevelToWarning(SoftRefFilesCache.class); + setLogLevelToWarning(EngysFileSystemManager.class); + setLogLevelToWarning(MemoryAuthStore.class); + setLogLevelToWarning(UseCentralsFromSessionUserAuthenticator.class); + setLogLevelToWarning(UserAuthenticatorFactory.class); + } + + public void layoutComponents() { + this.controller = new FileChooserController(sshParameters); + this.controller.setSaveAs(enableSaveAs); + this.uriPanel = new URIPanel(controller); + this.favoritesPanel = new FavoritesPanel(controller); + this.fileSystemPanel = new FileSystemPanel(controller, accessory); + this.loadingPanel = new LoadingPanel(); + this.buttonsPanel = new ButtonsPanel(controller, filters); + this.controller.setBrowser(this); + + this.cardLayoutPanel = new JPanel(cardLayout = new CardLayout()); + cardLayoutPanel.add(new JScrollPane(loadingPanel), LOADING_KEY); + + if (accessory != null) { + JSplitPane fileSystemAndPreviewPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, fileSystemPanel, accessory.getPanel()); + fileSystemAndPreviewPane.setOneTouchExpandable(false); + fileSystemAndPreviewPane.setDividerLocation(450); + cardLayoutPanel.add(fileSystemAndPreviewPane, TABLE_KEY); + } else { + cardLayoutPanel.add(fileSystemPanel, TABLE_KEY); + } + + JPanel centralPanel = new JPanel(new BorderLayout()); + centralPanel.add(cardLayoutPanel, BorderLayout.CENTER); + + if (options != null) { + centralPanel.add(options.getPanel(), BorderLayout.SOUTH); + } + + JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, favoritesPanel, centralPanel); + mainSplitPane.setOneTouchExpandable(false); + mainSplitPane.setDividerLocation(180); + + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.add(uriPanel, BorderLayout.NORTH); + mainPanel.add(mainSplitPane, BorderLayout.CENTER); + mainPanel.add(buttonsPanel, BorderLayout.SOUTH); + mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + add(mainPanel, BorderLayout.CENTER); + } + + public void initialize(final String initialPath) { + new Thread(new Runnable() { + @Override + public void run() { + showLoading(); + initializeInAThread(initialPath); + } + }).start(); + } + + private void initializeInAThread(final String initialPath) { + try { + boolean thereIsAValidFileToSelect = fileToSelect != null && fileToSelect.getParent() != null; + if (thereIsAValidFileToSelect) { + goToURL(fileToSelect.getParent()); + } else { + goToURL(initialPath); + } + + showTable(); + + controller.applyFilter(); + + if (thereIsAValidFileToSelect) { + selectFileOnTable(); + } + + } catch (FileSystemException e1) { + logger.error("Can't initialize default location", e1.getMessage()); + } + } + + private void goToURL(final String initialPath) throws FileSystemException { + if (initialPath != null && !initialPath.isEmpty()) { + controller.goToURL(initialPath, false); + } else { + if (controller.isRemote()) { + controller.goToURL(VFSUtils.getRemoteUserHome(sshParameters), false); + } else { + controller.goToURL(VFSUtils.getUserHome()); + } + } + } + + private void selectFileOnTable() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + fileSystemPanel.selectFileByName(fileToSelect.getName()); + } + }); + } + + public void showTable() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + loadingPanel.stop(); + fileSystemPanel.resetScroll(); + cardLayout.show(cardLayoutPanel, TABLE_KEY); + } + }); + } + + public void showLoading() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + cardLayout.show(cardLayoutPanel, LOADING_KEY); + loadingPanel.start(); + } + }); + } + + // Called from outside + public FileObject[] getFileObjects() { + if (controller.isSaveAs()) { + FileObject[] fos = new FileObject[1]; + try { + String newFileName = uriPanel.getNewFileName(); + boolean hasFilter = controller.getFilter() != null && !controller.getFilter().isAllFilesFilter(); + if (hasFilter) { + newFileName = fixFileExtension(newFileName); + } + fos[0] = uriPanel.getFileObject().resolveFile(newFileName); + return fos; + } catch (FileSystemException e) { + return null; + } + } else { + FileObject[] selectedFileObjects = getSelectedFileObjects(); + if (selectedFileObjects == null) { + selectedFileObjects = new FileObject[] { uriPanel.getFileObject() }; + } + return selectedFileObjects; + } + } + + private String fixFileExtension(String newFileName) { + String extension = FilenameUtils.getExtension(newFileName); + if (!controller.getFilter().isValidExtension(extension)) { + return newFileName += "." + controller.getFilter().getExtensions()[0]; + } + return newFileName; + } + + FileObject[] getSelectedFileObjects() { + FileObject[] selectedFileObjects = fileSystemPanel.getSelectedFileObjects(); + if (selectedFileObjects != null && selectedFileObjects.length > 0) { + return selectedFileObjects; + } else { + return null; + } + } + + public static void setLogLevelToWarning(Class klass) { + org.apache.log4j.Logger.getLogger(klass).setLevel(Level.WARN); + } + + public void setSelectionMode(SelectionMode selectionMode) { + controller.setSelectionMode(selectionMode); + } + + public void setMultiSelectionEnabled(boolean b) { + fileSystemPanel.setMultiSelection(b); + } + + public void setSelectedFile(File fileToSelect) { + this.fileToSelect = fileToSelect; + } + + public FileChooserController getController() { + return controller; + } + + public URIPanel getUriPanel() { + return uriPanel; + } + + public FavoritesPanel getFavoritesPanel() { + return favoritesPanel; + } + + public ButtonsPanel getButtonsPanel() { + return buttonsPanel; + } + + public FileSystemPanel getFileSystemPanel() { + return fileSystemPanel; + } + + public LoadingPanel getLoadingPanel() { + return loadingPanel; + } + + public ButtonsPanel getStatusPanel() { + return buttonsPanel; + } + + public JButton getOkButton() { + return buttonsPanel.getOkButton(); + } + + public HelyxFileFilter getSelectedFilter() { + return buttonsPanel.getSelectedFilter(); + } + + public Accessory getAccessory() { + return accessory; + } + + public void closeAndReturn(ReturnValue retVal) { + chooser.setReturnValue(retVal); + chooser.disposeDialog(); + } + +} diff --git a/src/eu/engys/util/filechooser/gui/FileSystemPanel.java b/src/eu/engys/util/filechooser/gui/FileSystemPanel.java new file mode 100644 index 0000000..3d72b65 --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/FileSystemPanel.java @@ -0,0 +1,416 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.swing.ActionMap; +import javax.swing.BorderFactory; +import javax.swing.InputMap; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.JToolBar; +import javax.swing.KeyStroke; +import javax.swing.ListSelectionModel; +import javax.swing.RowSorter; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.RowSorterEvent; +import javax.swing.event.RowSorterListener; +import javax.swing.table.TableColumnModel; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; + +import eu.engys.util.ArchiveUtils; +import eu.engys.util.filechooser.actions.DeleteFileAction; +import eu.engys.util.filechooser.actions.ExtractArchiveAction; +import eu.engys.util.filechooser.actions.NewFolderAction; +import eu.engys.util.filechooser.actions.pathnavigation.BaseNavigateActionGoUp; +import eu.engys.util.filechooser.actions.pathnavigation.BaseNavigateActionOpen; +import eu.engys.util.filechooser.actions.pathnavigation.BaseNavigateActionRefresh; +import eu.engys.util.filechooser.table.FileNameWithType; +import eu.engys.util.filechooser.table.FileNameWithTypeComparator; +import eu.engys.util.filechooser.table.FileSize; +import eu.engys.util.filechooser.table.FileSystemTableModel; +import eu.engys.util.filechooser.table.QuickSearchKeyAdapter; +import eu.engys.util.filechooser.table.renderer.FileNameWithTypeTableCellRenderer; +import eu.engys.util.filechooser.table.renderer.FileSizeTableCellRenderer; +import eu.engys.util.filechooser.table.renderer.FileTypeTableCellRenderer; +import eu.engys.util.filechooser.table.renderer.MixedDateTableCellRenderer; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.textfields.PromptTextField; +import eu.engys.util.ui.treetable.TableFilter; + +public class FileSystemPanel extends JPanel { + + private static final String ACTION_OPEN = "OPEN"; + private static final String ACTION_GO_UP = "GO_UP"; + private static final String ACTION_REFRESH = "REFRESH"; + private static final String ACTION_DELETE = "DELETE"; + private static final String ACTION_APPROVE = "ACTION APPROVE"; + + public static final String NAME = "chooser.filesystempanel"; + public static final String CREATE_FOLDER = "create.folder"; + public static final String DELETE_FILE = "delete.file"; + public static final String EXTRACT_ARCHIVE = "extract.archive"; + + private JTable table; + private FileChooserController controller; + private JScrollPane scrollPane; + private HelyxFileFilter appliedFilter; + private final Accessory accessory; + private TableFilter tableFilter; + private TableRowSorter sorter; + private JTextField searchField; + + public FileSystemPanel(FileChooserController controller, Accessory accessory) { + super(new BorderLayout(0, 5)); + setName(NAME); + this.controller = controller; + this.accessory = accessory; + this.appliedFilter = HelyxFileFilter.getAllFilesFilter(); + layoutComponents(); + } + + private void layoutComponents() { + createTable(); + scrollPane = new JScrollPane(table); + scrollPane.setPreferredSize(new Dimension(scrollPane.getPreferredSize().width, 300)); + add(createFileSystemBar(), BorderLayout.NORTH); + add(scrollPane, BorderLayout.CENTER); + } + + private void createTable() { + FileSystemTableModel model = new FileSystemTableModel(); + this.table = new JTable(model); + populateActionMap(); + populateInputMap(); + setColumnSize(); + + sorter = createSorter(); + table.setRowSorter(sorter); + + tableFilter = new TableFilter(""); + tableFilter.setColumnsWhereToSearch(0); + sorter.setRowFilter(tableFilter); + + table.setFillsViewportHeight(true); + table.setShowGrid(false); + table.setColumnSelectionAllowed(false); + + setRenderer(); + addListeners(); + } + + private JComponent createFileSystemBar() { + JButton createFolderButton = new JButton(new NewFolderAction(controller)); + createFolderButton.setName(CREATE_FOLDER); + + JButton deleteFileButton = new JButton(new DeleteFileAction(controller)); + deleteFileButton.setName(DELETE_FILE); + + JButton extractArchiveButton = new JButton(new ExtractArchiveAction(controller)); + extractArchiveButton.setName(EXTRACT_ARCHIVE); + + JToolBar bar = UiUtil.getToolbar("filesystem.toolbar"); + bar.add(searchField = createSearchField()); + bar.add(createFolderButton); + bar.add(deleteFileButton); + bar.add(extractArchiveButton); + + bar.setBorder(BorderFactory.createEmptyBorder()); + + return bar; + } + + private JTextField createSearchField() { + final PromptTextField filterField = new PromptTextField(); + filterField.setPrompt("Search (* = any string, ? = any character)"); + filterField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + filter(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + filter(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + filter(); + } + + }); + return filterField; + } + + private void filter() { + tableFilter.setFilterText(searchField.getText()); + sorter.sort(); + } + + public void resetFilter() { + searchField.setText(""); + filter(); + } + + private void setColumnSize() { + TableColumnModel columnModel = table.getColumnModel(); + columnModel.getColumn(0).setMinWidth(140); + columnModel.getColumn(1).setMaxWidth(80); + columnModel.getColumn(2).setMaxWidth(80); + columnModel.getColumn(3).setMaxWidth(180); + columnModel.getColumn(3).setMinWidth(120); + } + + private void setRenderer() { + table.setDefaultRenderer(FileSize.class, new FileSizeTableCellRenderer()); + table.setDefaultRenderer(FileNameWithType.class, new FileNameWithTypeTableCellRenderer()); + table.setDefaultRenderer(Date.class, new MixedDateTableCellRenderer()); + table.setDefaultRenderer(FileType.class, new FileTypeTableCellRenderer()); + } + + private void addListeners() { + addMouseListener(); + addSelectionListener(); + addKeyListener(); + addAccessoryListener(); + } + + private void addMouseListener() { + table.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + boolean isLeftButton = e.getButton() == MouseEvent.BUTTON1; + boolean isDoubleClick = e.getClickCount() == 2; + boolean isSomethingSelected = table.getSelectedRows().length > 0; + if (isLeftButton && isDoubleClick && isSomethingSelected) { + table.getActionMap().get(ACTION_OPEN).actionPerformed(null); + } + } + }); + } + + private void addKeyListener() { + table.addKeyListener(new QuickSearchKeyAdapter(table)); + } + + private void addSelectionListener() { + table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + + @Override + public void valueChanged(ListSelectionEvent e) { + controller.updateNewFileName(); + controller.updateOkButton(); + } + }); + } + + private void addAccessoryListener() { + if (accessory != null) { + table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + + @Override + public void valueChanged(ListSelectionEvent e) { + accessory.onSelectionChanged(); + } + }); + } + } + + private void populateInputMap() { + InputMap inputMap = table.getInputMap(JComponent.WHEN_FOCUSED); + inputMap.put(KeyStroke.getKeyStroke("ENTER"), ACTION_OPEN); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_MASK), ACTION_APPROVE); + + inputMap.put(KeyStroke.getKeyStroke("BACK_SPACE"), ACTION_GO_UP); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), ACTION_GO_UP); + + inputMap.put(KeyStroke.getKeyStroke("F5"), ACTION_REFRESH); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0), ACTION_REFRESH); + + inputMap.put(KeyStroke.getKeyStroke("DELETE"), ACTION_DELETE); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_CANCEL, 0), ACTION_DELETE); + + } + + private void populateActionMap() { + ActionMap actionMap = table.getActionMap(); + actionMap.put(ACTION_OPEN, new BaseNavigateActionOpen(controller)); + actionMap.put(ACTION_GO_UP, new BaseNavigateActionGoUp(controller)); + actionMap.put(ACTION_REFRESH, new BaseNavigateActionRefresh(controller)); + actionMap.put(ACTION_DELETE, new DeleteFileAction(controller)); + } + + public FileObject getSelectedFileObject() { + int selectedRow = table.getSelectedRow(); + if (selectedRow > -1) { + int convertedRowIndex = table.convertRowIndexToModel(selectedRow); + return ((FileSystemTableModel) table.getModel()).get(convertedRowIndex); + } + return null; + } + + public FileObject[] getSelectedFileObjects() { + int[] selectedRows = table.getSelectedRows(); + FileObject[] fileObjects = new FileObject[selectedRows.length]; + for (int i = 0; i < selectedRows.length; i++) { + fileObjects[i] = ((FileSystemTableModel) table.getModel()).get(table.convertRowIndexToModel(selectedRows[i])); + } + return fileObjects; + } + + public void applyFilter(HelyxFileFilter selectedFilter) { + this.appliedFilter = selectedFilter; + if (controller.getUriPanel().getFileObject() != null) { + controller.goToURL(controller.getUriPanel().getFileObject()); + } + } + + public void setContent(FileObject[] fileObjects) { + try { + _setContent(fileObjects); + table.clearSelection(); + } catch (FileSystemException e) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), e.getMessage(), "File Chooser Error", JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + private void _setContent(FileObject[] fileObjectsWithParent) throws FileSystemException { + List filteredObjects = new ArrayList<>(); + for (FileObject fileObject : fileObjectsWithParent) { + if (!VFSUtils.isHiddenFile(fileObject)) { + if (fileObject.getType() == FileType.FILE) { + manageFiles(filteredObjects, fileObject); + } else if (fileObject.getType() == FileType.FOLDER) { + filteredObjects.add(fileObject); + } + } + + } + ((FileSystemTableModel) table.getModel()).setContent(filteredObjects.toArray(new FileObject[0])); + } + + private void manageFiles(List filteredObjects, FileObject fileObject) throws FileSystemException { + boolean showOnlyFolders = controller.getSelectionMode().isDirsOnly(); + boolean showOnlyFoldersAndArchives = controller.getSelectionMode().isDirsAndArchives(); + if (showOnlyFolders) { + return; + } else { + if (showOnlyFoldersAndArchives) { + File file = new File(VFSUtils.decode(fileObject.getName().getURI(), controller.getSshParameters())); + if (ArchiveUtils.isArchive(file)) { + filteredObjects.add(fileObject); + } + } else { + filter(filteredObjects, fileObject); + } + } + } + + private void filter(List filteredObjects, FileObject fileObject) { + String fileName = fileObject.getName().getBaseName(); + String fileExtension = fileObject.getName().getExtension(); + for (String ext : appliedFilter.getExtensions()) { + boolean filterIsAllFiles = ext.equals("*"); + boolean extensionMatchesExtension = fileExtension.equalsIgnoreCase(ext); + boolean extensionMatchesName = fileExtension.isEmpty() && fileName.equalsIgnoreCase(ext); + + if (filterIsAllFiles || extensionMatchesExtension || extensionMatchesName) { + filteredObjects.add(fileObject); + } + } + } + + public void resetScroll() { + scrollPane.getVerticalScrollBar().setValue(0); + } + + private TableRowSorter createSorter() { + TableRowSorter sorter = new TableRowSorter(table.getModel()); + final FileNameWithTypeComparator fileNameWithTypeComparator = new FileNameWithTypeComparator(); + sorter.addRowSorterListener(new RowSorterListener() { + @SuppressWarnings("unchecked") + @Override + public void sorterChanged(RowSorterEvent e) { + RowSorterEvent.Type type = e.getType(); + if (type.equals(RowSorterEvent.Type.SORT_ORDER_CHANGED)) { + List sortKeys = e.getSource().getSortKeys(); + for (RowSorter.SortKey sortKey : sortKeys) { + if (sortKey.getColumn() == FileSystemTableModel.COLUMN_NAME) { + fileNameWithTypeComparator.setSortOrder(sortKey.getSortOrder()); + } + } + } + } + }); + sorter.setComparator(FileSystemTableModel.COLUMN_NAME, fileNameWithTypeComparator); + return sorter; + } + + public void setMultiSelection(boolean b) { + int selectionMode = b ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION; + table.getSelectionModel().setSelectionMode(selectionMode); + } + + public void selectFileByName(String selectedFileName) { + if (selectedFileName != null) { + FileSystemTableModel model = (FileSystemTableModel) table.getModel(); + int index = model.getIndexByName(selectedFileName); + if (index != -1) { + table.getSelectionModel().setSelectionInterval(index, index); + table.scrollRectToVisible(table.getCellRect(index, 0, false)); + } + } + + } + +} diff --git a/src/eu/engys/util/filechooser/gui/LoadingPanel.java b/src/eu/engys/util/filechooser/gui/LoadingPanel.java new file mode 100644 index 0000000..e74547a --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/LoadingPanel.java @@ -0,0 +1,94 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Font; +import java.util.Timer; +import java.util.TimerTask; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +import eu.engys.util.ui.ExecUtil; + +public class LoadingPanel extends JPanel { + + private static final String LOADING = "Loading..."; + private static final String LOADING_FULL = "Loading.............."; + private JLabel loadingLabel; + private Timer timer; + + public LoadingPanel() { + super(new BorderLayout()); + setName("chooser.loadingpanel"); + setOpaque(true); + setBackground(Color.WHITE); + layoutComponents(); + } + + private void layoutComponents() { + loadingLabel = new JLabel(LOADING); + loadingLabel.setForeground(Color.LIGHT_GRAY); + loadingLabel.setFont(new Font("Monotype Corsiva", 1, 28)); + add(loadingLabel); + } + + public void start() { + timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + updateLabel(); + } + + }, 0, 800); + } + + private void updateLabel() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + String current = loadingLabel.getText(); + if (LOADING_FULL.equals(current)) { + loadingLabel.setText(LOADING); + } else { + loadingLabel.setText(current + "."); + } + } + }); + } + + public void stop() { + if (timer != null) { + timer.cancel(); + timer = null; + } + loadingLabel.setText(LOADING); + } + +} diff --git a/src/eu/engys/util/filechooser/gui/Options.java b/src/eu/engys/util/filechooser/gui/Options.java new file mode 100644 index 0000000..fd69107 --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/Options.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import javax.swing.JPanel; + +public interface Options { + + void onSelectionChanged(); + + JPanel getPanel(); + +} diff --git a/src/eu/engys/util/filechooser/gui/URIPanel.java b/src/eu/engys/util/filechooser/gui/URIPanel.java new file mode 100644 index 0000000..d53fc7f --- /dev/null +++ b/src/eu/engys/util/filechooser/gui/URIPanel.java @@ -0,0 +1,219 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.gui; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractAction; +import javax.swing.InputMap; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.JToolBar; +import javax.swing.KeyStroke; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import net.java.dev.designgridlayout.Componentizer; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.filechooser.actions.favorite.AddFavorite; +import eu.engys.util.filechooser.actions.pathnavigation.BaseNavigateAction; +import eu.engys.util.filechooser.actions.pathnavigation.BaseNavigateActionGoUp; +import eu.engys.util.filechooser.actions.pathnavigation.BaseNavigateActionRefresh; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.builder.PanelBuilder; + +public class URIPanel extends JPanel { + + private static final Logger LOGGER = LoggerFactory.getLogger(URIPanel.class); + + public static final String NAME = "chooser.uripanel"; + public static final String NAME_LABEL = "Name:"; + public static final String LOOK_IN = "Look in:"; + public static final String SAVE_IN = "Save in:"; + private static final String ACTION_FOCUS_ON_TABLE = "FOCUS ON TABLE"; + + public static final String ADD_FAVORITE = "add.favorite"; + public static final String UP_FOLDER = "up.folder"; + public static final String REFRESH = "refresh"; + + private JTextField pathField; + + private FileChooserController controller; + private FileObject fileObject; + private JTextField newFileNameField; + private BreadCrumbsPanel breadCrumbs; + + public URIPanel(FileChooserController controller) { + super(new BorderLayout()); + setName(NAME); + this.controller = controller; + layoutComponents(); + } + + private void layoutComponents() { + pathField = createPathField(); + breadCrumbs = new BreadCrumbsPanel(controller); + + PanelBuilder pb = new PanelBuilder(); + + String pathLabel = controller.isSaveAs() ? SAVE_IN : LOOK_IN; + pb.addComponent(pathLabel, Componentizer.create().prefAndMore(pathField).minToPref(createURIActionsBar()).component()); + pathField.setName(pathLabel); + + if (controller.isSaveAs()) { + newFileNameField = new JTextField(15); + newFileNameField.getDocument().addDocumentListener(new NotEmptyListener()); + newFileNameField.setText(""); + pb.addComponent(NAME_LABEL, newFileNameField); + } + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(pb.removeMargins().getPanel(), BorderLayout.NORTH); + panel.add(breadCrumbs, BorderLayout.CENTER); + + add(panel, BorderLayout.CENTER); + } + + public String getNewFileName() { + return newFileNameField == null ? null : newFileNameField.getText(); + } + + private JTextField createPathField() { + final JTextField field = new JTextField(30); + field.setToolTipText(NAV_PATHTOOLTIP); + + InputMap inputMapPath = field.getInputMap(JComponent.WHEN_FOCUSED); + inputMapPath.put(KeyStroke.getKeyStroke("ENTER"), "OPEN_PATH"); + inputMapPath.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), ACTION_FOCUS_ON_TABLE); + + field.getActionMap().put("OPEN_PATH", new BaseNavigateAction(controller) { + + @Override + protected void performLongOperation(CheckBeforeActionResult actionResult) { + controller.goToURL(field.getText().trim(), false); + controller.updateOkButton(); + } + + @Override + protected boolean canGoUrl() { + return true; + } + + @Override + protected boolean canExecuteDefaultAction() { + return false; + } + + }); + + field.getActionMap().put(ACTION_FOCUS_ON_TABLE, new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + controller.fixSelection(); + } + }); + return field; + } + + private JComponent createURIActionsBar() { + JButton goUpButton = new JButton(new BaseNavigateActionGoUp(controller)); + goUpButton.setName(UP_FOLDER); + + JButton refreshButton = new JButton(new BaseNavigateActionRefresh(controller)); + refreshButton.setName(REFRESH); + + JButton addCurrentLocationToFavoriteButton = new JButton(new AddFavorite(controller)); + addCurrentLocationToFavoriteButton.setName(ADD_FAVORITE); + addCurrentLocationToFavoriteButton.setText(""); + + JToolBar bar = UiUtil.getToolbar("uri.panel.toolbar"); + + bar.add(goUpButton); + bar.add(refreshButton); + bar.add(addCurrentLocationToFavoriteButton); + + return bar; + } + + public void setFileObject(FileObject fileObject) { + try { + this.fileObject = fileObject; + pathField.setText(VFSUtils.decode(fileObject.getURL().toString(), controller.getSshParameters())); + breadCrumbs.updatePanel(fileObject); + } catch (FileSystemException e) { + LOGGER.error("Can't get URL", e); + } + } + + public void updateFileName() { + FileObject fo = controller.getSelectedFileObject(); + if (controller.isSaveAs() && fo != null) { + newFileNameField.setText(fo.getName().getBaseName()); + } + } + + public FileObject getFileObject() { + return fileObject; + } + + private class NotEmptyListener implements DocumentListener { + @Override + public void removeUpdate(DocumentEvent e) { + checkNotEmpty(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + checkNotEmpty(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + checkNotEmpty(); + } + + private void checkNotEmpty() { + controller.updateOkButton(); + } + } + + /** + * Resources + */ + + private static final String NAV_PATHTOOLTIP = ResourcesUtil.getString("nav.pathTooltip"); +} diff --git a/src/eu/engys/util/filechooser/table/FileNameWithType.java b/src/eu/engys/util/filechooser/table/FileNameWithType.java new file mode 100644 index 0000000..7ccc1f9 --- /dev/null +++ b/src/eu/engys/util/filechooser/table/FileNameWithType.java @@ -0,0 +1,79 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table; + +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileType; + +public class FileNameWithType { + + private FileName fileName; + private FileType fileType; + + public FileNameWithType(FileName fileName, FileType fileType) { + super(); + this.fileName = fileName; + this.fileType = fileType; + } + + public FileName getFileName() { + return fileName; + } + + public void setFileName(FileName fileName) { + this.fileName = fileName; + } + + public FileType getFileType() { + return fileType; + } + + public void setFileType(FileType fileType) { + this.fileType = fileType; + } + + @Override + public String toString() { + return fileName.getBaseName(); + } + +} diff --git a/src/eu/engys/util/filechooser/table/FileNameWithTypeComparator.java b/src/eu/engys/util/filechooser/table/FileNameWithTypeComparator.java new file mode 100644 index 0000000..ec78b8b --- /dev/null +++ b/src/eu/engys/util/filechooser/table/FileNameWithTypeComparator.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table; + +import java.util.Comparator; + +import javax.swing.SortOrder; + +import org.apache.commons.vfs2.FileType; + +import eu.engys.util.filechooser.ParentFileObject; + +public class FileNameWithTypeComparator implements Comparator { + private SortOrder sortOrder = SortOrder.ASCENDING; + + @Override + public int compare(FileNameWithType o1, FileNameWithType o2) { + return compareTo(o1, o2); + } + + public int compareTo(FileNameWithType o1, FileNameWithType o2) { + if (o1 == null || o1.getFileType() == null || o1.getFileName() == null) { + return -1; + } + if (o2 == null || o2.getFileType() == null || o2.getFileName() == null) { + return 1; + } + // folders first first + boolean folder1 = FileType.FOLDER.equals(o1.getFileType()); + boolean folder2 = FileType.FOLDER.equals(o2.getFileType()); + int result = 0; + + int sortOrderSign = SortOrder.ASCENDING.equals(sortOrder) ? 1 : -1; + String o1BaseName = o1.getFileName().getBaseName(); + String o2BaseName = o2.getFileName().getBaseName(); + + if (o1BaseName.equalsIgnoreCase(ParentFileObject.PARENT_NAME)) { + result = -1 * sortOrderSign; + } else { + if (o2BaseName.equalsIgnoreCase(ParentFileObject.PARENT_NAME)) { + result = 1 * sortOrderSign; + } else if (folder1 & !folder2) { + result = -1 * sortOrderSign; + } else if (!folder1 & folder2) { + result = 1 * sortOrderSign; + } else { + result = o1BaseName.compareToIgnoreCase(o2BaseName); + } + } + + return result; + } + + public void setSortOrder(SortOrder sortOrder) { + this.sortOrder = sortOrder; + } +} diff --git a/src/eu/engys/util/filechooser/table/FileObjectComparator.java b/src/eu/engys/util/filechooser/table/FileObjectComparator.java new file mode 100644 index 0000000..bb59ed0 --- /dev/null +++ b/src/eu/engys/util/filechooser/table/FileObjectComparator.java @@ -0,0 +1,78 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table; + +import java.util.Comparator; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FileObjectComparator implements Comparator { + + private static final Logger LOGGER = LoggerFactory.getLogger(FileObjectComparator.class); + private FileNameWithTypeComparator fileNameWithTypeComparator = new FileNameWithTypeComparator(); + + @Override + public int compare(FileObject o1, FileObject o2) { + if (o1 != null && o2 != null) { + try { + return fileNameWithTypeComparator.compare(new FileNameWithType(o1.getName(), o1.getType()), new FileNameWithType(o2.getName(), o2.getType())); + } catch (FileSystemException e) { + return 0; + } + } + return 0; + } + + private int compareTypes(FileType type1, FileType type2) { + if (type1.equals(FileType.FILE) && !type2.equals(FileType.FILE)) { + return 1; + } else if (!type1.equals(FileType.FILE) && type2.equals(FileType.FILE)) { + return -1; + } + return 0; + } + +} diff --git a/src/eu/engys/util/filechooser/table/FileSize.java b/src/eu/engys/util/filechooser/table/FileSize.java new file mode 100644 index 0000000..cd80ac7 --- /dev/null +++ b/src/eu/engys/util/filechooser/table/FileSize.java @@ -0,0 +1,166 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table; + +import java.text.DecimalFormat; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; + +public class FileSize implements Comparable { + + private static final long K = 1024; + private static final long M = K * K; + private static final long G = M * K; + private static final long T = G * K; + + private long bytes; + + public FileSize(String string) { + Pattern p = Pattern.compile("([\\d,.]+)\\s?([kKmMgGtT]{1})[Bb]{1}"); + Matcher matcher = p.matcher(string); + if (matcher.matches()) { + double count = Double.parseDouble(matcher.group(1).replace(',', '.')); + long multiplier = 1; + if (StringUtils.isNotBlank(matcher.group(2))) { + multiplier = getMultiplier(matcher.group(2).charAt(0)); + } + bytes = (long) (count * multiplier); + } + } + + public FileSize(long bytes) { + super(); + this.bytes = bytes; + } + + public long getBytes() { + return bytes; + } + + public void setBytes(long bytes) { + this.bytes = bytes; + } + + @Override + public String toString() { + return convertToStringRepresentation(bytes); + } + + public long getMultiplier(char multiplierChar) { + long multiplier = 1; + multiplierChar = Character.toLowerCase(multiplierChar); + switch (multiplierChar) { + case 't': + multiplier = multiplier * 1024; + case 'g': + multiplier = multiplier * 1024; + case 'm': + multiplier = multiplier * 1024; + case 'k': + multiplier = multiplier * 1024; + break; + } + return multiplier; + } + + public static String convertToStringRepresentation(final long value) { + final long[] dividers = new long[] { T, G, M, K, 1 }; + final String[] units = new String[] { "TB", "GB", "MB", "KB", "B" }; + if (value == 0) { + return format(0, 1, "B"); + } else if (value < 1) { + return "Folder"; + } + String result = null; + for (int i = 0; i < dividers.length; i++) { + final long divider = dividers[i]; + if (value >= divider) { + result = format(value, divider, units[i]); + break; + } + } + return result; + } + + private static String format(final long value, final long divider, final String unit) { + final double result = divider > 1 ? (double) value / (double) divider : (double) value; + DecimalFormat decimalFormat = new DecimalFormat(); + decimalFormat.setMaximumFractionDigits(1); + decimalFormat.setMinimumFractionDigits(0); + decimalFormat.setGroupingUsed(false); + decimalFormat.setDecimalSeparatorAlwaysShown(false); + return decimalFormat.format(result) + " " + unit; + } + + @Override + public int compareTo(FileSize o) { + int result; + if (o == null || bytes > o.bytes) { + result = 1; + } else if (bytes < o.bytes) { + result = -1; + } else { + result = 0; + } + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + FileSize fileSize = (FileSize) o; + + return bytes == fileSize.bytes; + + } + + @Override + public int hashCode() { + return (int) (bytes ^ (bytes >>> 32)); + } +} diff --git a/src/eu/engys/util/filechooser/table/FileSystemTableModel.java b/src/eu/engys/util/filechooser/table/FileSystemTableModel.java new file mode 100644 index 0000000..d7d9e64 --- /dev/null +++ b/src/eu/engys/util/filechooser/table/FileSystemTableModel.java @@ -0,0 +1,173 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table; + +import java.util.Arrays; +import java.util.Date; + +import javax.swing.table.AbstractTableModel; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.ui.ResourcesUtil; + +public class FileSystemTableModel extends AbstractTableModel { + + private static final String MODEL_NAME = ResourcesUtil.getString("model.name"); + private static final String MODEL_SIZE = ResourcesUtil.getString("model.size"); + private static final String MODEL_TYPE = ResourcesUtil.getString("model.type"); + private static final String MODEL_DATELASTMOD = ResourcesUtil.getString("model.dateLastMod"); + + public static final int COLUMN_NAME = 0; + protected static final int COLUMN_SIZE = 1; + protected static final int COLUMN_TYPE = 2; + protected static final int COLUMN_LAST_MOD_DATE = 3; + private static final String[] COLUMN_NAMES = new String[] { MODEL_NAME, MODEL_SIZE, MODEL_TYPE, MODEL_DATELASTMOD }; + private static final Logger LOGGER = LoggerFactory.getLogger(FileSystemTableModel.class); + + private FileObject[] fileObjects = new FileObject[0]; + private FileObjectComparator fileObjectComparator = new FileObjectComparator(); + + @Override + public int getColumnCount() { + return 4; + } + + @Override + public int getRowCount() { + return fileObjects.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + FileObject fileObject = fileObjects[rowIndex]; + boolean isFile = false; + try { + isFile = FileType.FILE.equals(fileObject.getType()); + } catch (FileSystemException e1) { + LOGGER.warn("Can't check file type " + fileObject.getName().getBaseName(), e1); + } + if (columnIndex == COLUMN_NAME) { + try { + return new FileNameWithType(fileObject.getName(), fileObject.getType()); + } catch (FileSystemException e) { + return new FileNameWithType(fileObject.getName(), null); + } + } else if (columnIndex == COLUMN_TYPE) { + try { + return fileObject.getType().getName(); + } catch (FileSystemException e) { + LOGGER.warn("Can't get file type " + fileObject.getName().getBaseName(), e); + return "?"; + } + } else if (columnIndex == COLUMN_SIZE) { + try { + long size = -1; + if (isFile) { + size = fileObject.getContent().getSize(); + } + return new FileSize(size); + } catch (FileSystemException e) { + LOGGER.warn("Can't get size " + fileObject.getName().getBaseName(), e); + return new FileSize(-1); + } + } else if (columnIndex == COLUMN_LAST_MOD_DATE) { + try { + + long lastModifiedTime = fileObject.getContent().getLastModifiedTime(); + return new Date(lastModifiedTime); + } catch (FileSystemException e) { + LOGGER.warn("Can't get last mod date " + fileObject.getName().getBaseName(), e); + return null; + } + } + return "?"; + } + + @Override + public Class getColumnClass(int columnIndex) { + if (columnIndex == COLUMN_NAME) { + return FileNameWithType.class; + } else if (columnIndex == COLUMN_TYPE) { + return FileType.class; + } else if (columnIndex == COLUMN_SIZE) { + return FileSize.class; + } else if (columnIndex == COLUMN_LAST_MOD_DATE) { + return Date.class; + } + return super.getColumnClass(columnIndex); + } + + @Override + public String getColumnName(int column) { + return COLUMN_NAMES[column]; + } + + public void setContent(FileObject... fileObjects) { + this.fileObjects = fileObjects; + Arrays.sort(fileObjects, fileObjectComparator); + fireTableDataChanged(); + } + + public FileObject[] getContent() { + return fileObjects; + } + + public FileObject get(int row) { + return fileObjects[row]; + } + + public int getIndexByName(String nameToSelect) { + for (int i = 0; i < fileObjects.length; i++) { + String foName = fileObjects[i].getName().getBaseName(); + if (nameToSelect.equals(foName)) { + return i; + } + } + return -1; + } + +} diff --git a/src/eu/engys/util/filechooser/table/QuickSearchKeyAdapter.java b/src/eu/engys/util/filechooser/table/QuickSearchKeyAdapter.java new file mode 100644 index 0000000..0a6c91e --- /dev/null +++ b/src/eu/engys/util/filechooser/table/QuickSearchKeyAdapter.java @@ -0,0 +1,93 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.table; + +import java.awt.Rectangle; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +import javax.swing.JTable; + +import org.apache.commons.vfs2.FileObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QuickSearchKeyAdapter extends KeyAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(QuickSearchKeyAdapter.class); + + private long lastTimeTyped = 0; + private long typeTimeout = 500; + private static final String LETTERS = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"; + private static final String DIGITS = "0123456789"; + private static final String OTHER_CHARS = "!@#$%^&*()()-_=+[];:'\",./ "; + private static final String ALLOWED_CHARS = LETTERS + DIGITS + OTHER_CHARS; + private StringBuilder sb; + private final JTable table; + + public QuickSearchKeyAdapter(JTable table) { + this.table = table; + sb = new StringBuilder(); + } + + @Override + public void keyTyped(KeyEvent e) { + char keyChar = e.getKeyChar(); + if (ALLOWED_CHARS.indexOf(keyChar) > -1) { + if (System.currentTimeMillis() > lastTimeTyped + typeTimeout) { + sb.setLength(0); + } + sb.append(keyChar); + selectNextFileStarting(sb.toString()); + lastTimeTyped = System.currentTimeMillis(); + } + + } + + private void selectNextFileStarting(String string) { + LOGGER.debug("Looking for file starting with {}", string); + int selectedRow = table.getSelectedRow(); + selectedRow = selectedRow < 0 ? 0 : selectedRow; + LOGGER.debug("Starting search with row {}", selectedRow); + boolean fullLoop; + int started = selectedRow; + do { + LOGGER.debug("Checking table row {}", selectedRow); + int convertRowIndexToModel = table.convertRowIndexToModel(selectedRow); + LOGGER.debug("Table row {} is row {} from model", selectedRow, convertRowIndexToModel); + FileObject fileObject = ((FileSystemTableModel) table.getModel()).get(convertRowIndexToModel); + LOGGER.debug("Checking {} if begins with {}", fileObject.getName().getBaseName(), string); + if (fileObject.getName().getBaseName().toLowerCase().startsWith(string.toLowerCase())) { + table.getSelectionModel().setSelectionInterval(selectedRow, selectedRow); + table.scrollRectToVisible(new Rectangle(table.getCellRect(selectedRow, 0, true))); + break; + } + selectedRow++; + selectedRow = selectedRow >= table.getRowCount() ? 0 : selectedRow; + fullLoop = selectedRow == started; + } while (!fullLoop); + } +} diff --git a/src/eu/engys/util/filechooser/table/renderer/DateTableCellRenderer.java b/src/eu/engys/util/filechooser/table/renderer/DateTableCellRenderer.java new file mode 100644 index 0000000..8e764f0 --- /dev/null +++ b/src/eu/engys/util/filechooser/table/renderer/DateTableCellRenderer.java @@ -0,0 +1,83 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table.renderer; + +import java.awt.Component; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.SwingConstants; +import javax.swing.table.DefaultTableCellRenderer; + +public class DateTableCellRenderer extends DefaultTableCellRenderer { + + private DateFormat dateFormatFull = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private DateFormat dateFormatHourOnly = new SimpleDateFormat("HH:mm:ss"); + private DateFormat dateOnly = new SimpleDateFormat("yyyy-MM-dd"); + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + Date d = (Date) value; + String s = "-"; + if (d != null) { + s = d.toString(); + DateFormat df = dateOnly; + if (dateOnly.format(d).equals(dateOnly.format(new Date()))) { + df = dateFormatHourOnly; + l.setToolTipText(dateFormatFull.format(d)); + } + l.setToolTipText(dateFormatFull.format(d)); + s = df.format(d); + + } + l.setText(s); + l.setHorizontalAlignment(SwingConstants.RIGHT); + + return l; + + } + +} diff --git a/src/eu/engys/util/filechooser/table/renderer/FileNameWithTypeTableCellRenderer.java b/src/eu/engys/util/filechooser/table/renderer/FileNameWithTypeTableCellRenderer.java new file mode 100644 index 0000000..5d1a94c --- /dev/null +++ b/src/eu/engys/util/filechooser/table/renderer/FileNameWithTypeTableCellRenderer.java @@ -0,0 +1,134 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table.renderer; + +import static eu.engys.util.ui.FileChooserUtils.EXCEL_EXTENSION_NEW; +import static eu.engys.util.ui.FileChooserUtils.EXCEL_EXTENSION_OLD; +import static eu.engys.util.ui.FileChooserUtils.PDF_EXTENSION; + +import java.awt.Component; +import java.io.File; + +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileType; + +import eu.engys.util.ApplicationInfo; +import eu.engys.util.filechooser.table.FileNameWithType; +import eu.engys.util.filechooser.util.VFSUtils; +import eu.engys.util.ui.ResourcesUtil; + +public class FileNameWithTypeTableCellRenderer extends DefaultTableCellRenderer { + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + FileNameWithType fileNameWithType = (FileNameWithType) value; + FileName fileName = fileNameWithType.getFileName(); + label.setText(fileName.getBaseName()); + label.setToolTipText(fileName.getPath()); + + FileType fileType = fileNameWithType.getFileType(); + Icon icon = null; + if (FileType.FOLDER.equals(fileType)) { + String decodePath = VFSUtils.decode(fileName.getURI(), null); + File file = decodePath == null ? null : new File(decodePath); + if (isSuitable(file)) { + label.setText(label.getText()); + if (ApplicationInfo.getVendor() != null) { + icon = ResourcesUtil.getIcon(ApplicationInfo.getVendor().toLowerCase() + ".case"); + } + } else { + icon = FOLDEROPEN; + } + } else if (VFSUtils.isArchive(fileName)) { + if ("jar".equalsIgnoreCase(fileName.getExtension())) { + icon = JARICON; + } else { + icon = FOLDERZIPPER; + } + } else if (FileType.FILE.equals(fileType)) { + if (PDF_EXTENSION.equalsIgnoreCase(fileName.getExtension())) { + icon = PDF_ICON; + } else if (EXCEL_EXTENSION_OLD.equalsIgnoreCase(fileName.getExtension()) || EXCEL_EXTENSION_NEW.equalsIgnoreCase(fileName.getExtension())) { + icon = EXCEL_ICON; + } else { + icon = FILE; + } + } else if (FileType.IMAGINARY.equals(fileType)) { + icon = SHORTCUT; + } + label.setIcon(icon); + return label; + } + + private boolean isSuitable(File file) { + if (file != null && file.exists() && file.isDirectory()) { + File constant = new File(file, "constant"); + File system = new File(file, "system"); + if (constant.exists() && constant.isDirectory() && system.exists() && system.isDirectory()) { + File controlDict = new File(system, "controlDict"); + return controlDict.exists(); + } + return false; + } + return false; + } + + /** + * Resources + */ + + private static final Icon FILE = ResourcesUtil.getIcon("file"); + private static final Icon JARICON = ResourcesUtil.getIcon("jarIcon"); + private static final Icon SHORTCUT = ResourcesUtil.getIcon("shortCut"); + private static final Icon FOLDEROPEN = ResourcesUtil.getIcon("folderOpen"); + private static final Icon FOLDERZIPPER = ResourcesUtil.getIcon("folderZipper"); + + private static final Icon PDF_ICON = ResourcesUtil.getIcon("file.pdf"); + private static final Icon EXCEL_ICON = ResourcesUtil.getIcon("file.excel"); + +} diff --git a/src/eu/engys/util/filechooser/table/renderer/FileSizeTableCellRenderer.java b/src/eu/engys/util/filechooser/table/renderer/FileSizeTableCellRenderer.java new file mode 100644 index 0000000..a5e0ecf --- /dev/null +++ b/src/eu/engys/util/filechooser/table/renderer/FileSizeTableCellRenderer.java @@ -0,0 +1,65 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table.renderer; + +import java.awt.Component; + +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.SwingConstants; +import javax.swing.table.DefaultTableCellRenderer; + +import eu.engys.util.filechooser.table.FileSize; + +public class FileSizeTableCellRenderer extends DefaultTableCellRenderer { + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + FileSize valueAt = (FileSize) table.getValueAt(row, column); + label.setText(valueAt.toString() + " "); + label.setHorizontalAlignment(SwingConstants.RIGHT); + + return label; + } + +} diff --git a/src/eu/engys/util/filechooser/table/renderer/FileTypeTableCellRenderer.java b/src/eu/engys/util/filechooser/table/renderer/FileTypeTableCellRenderer.java new file mode 100644 index 0000000..74b243d --- /dev/null +++ b/src/eu/engys/util/filechooser/table/renderer/FileTypeTableCellRenderer.java @@ -0,0 +1,63 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table.renderer; + +import java.awt.Component; + +import javax.swing.JTable; +import javax.swing.SwingConstants; +import javax.swing.table.DefaultTableCellRenderer; + +public class FileTypeTableCellRenderer extends DefaultTableCellRenderer { + + public FileTypeTableCellRenderer() { + super(); + setHorizontalAlignment(SwingConstants.RIGHT); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setText(value + " "); + return this; + } +} diff --git a/src/eu/engys/util/filechooser/table/renderer/MixedDateTableCellRenderer.java b/src/eu/engys/util/filechooser/table/renderer/MixedDateTableCellRenderer.java new file mode 100644 index 0000000..5359902 --- /dev/null +++ b/src/eu/engys/util/filechooser/table/renderer/MixedDateTableCellRenderer.java @@ -0,0 +1,66 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table.renderer; + +import java.awt.Component; +import java.util.Date; + +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +public class MixedDateTableCellRenderer extends DefaultTableCellRenderer { + + private static final long DURATION_THRESHOLD = 1000l * 60 * 60 * 24 * 60; + + private RelativeDateTableCellRenderer relativeDateTableCellRenderer = new RelativeDateTableCellRenderer(); + private DateTableCellRenderer dateTableCellRenderer = new DateTableCellRenderer(); + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (value != null && value instanceof Date && ((Date) value).getTime() > System.currentTimeMillis() - DURATION_THRESHOLD) { + return relativeDateTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } + return dateTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + } + +} diff --git a/src/eu/engys/util/filechooser/table/renderer/RelativeDateTableCellRenderer.java b/src/eu/engys/util/filechooser/table/renderer/RelativeDateTableCellRenderer.java new file mode 100644 index 0000000..1e6e916 --- /dev/null +++ b/src/eu/engys/util/filechooser/table/renderer/RelativeDateTableCellRenderer.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.table.renderer; + +import java.awt.Component; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.SwingConstants; +import javax.swing.table.DefaultTableCellRenderer; + +import org.ocpsoft.prettytime.PrettyTime; + +public class RelativeDateTableCellRenderer extends DefaultTableCellRenderer { + + private PrettyTime prettyTime = new PrettyTime(); + private DateFormat dateFormatFull = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + Date d = (Date) value; + String s = "-"; + String tooltip = ""; + + if (d != null) { + String formattedTime = prettyTime.format(d); + s = formattedTime; + tooltip = dateFormatFull.format(d); + } + l.setToolTipText(tooltip); + l.setText(s); + l.setHorizontalAlignment(SwingConstants.RIGHT); + + return l; + + } + +} diff --git a/src/eu/engys/util/filechooser/uri/Protocol.java b/src/eu/engys/util/filechooser/uri/Protocol.java new file mode 100644 index 0000000..3d4f31e --- /dev/null +++ b/src/eu/engys/util/filechooser/uri/Protocol.java @@ -0,0 +1,113 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package eu.engys.util.filechooser.uri; + +/** + *

+ * T1ODO Disable the SSL port option when not supported in the connection dialog + * It's probably better/faster than removing the SSL member For the file + * protocol no port will be associated, need to handle that case using a -1 + * value in the connection dialog + *

+ * Enumeration holding protocol constants + * + * @author Yves Zoundi + * @version 0.0.1 + */ +public enum Protocol { // Protocol constants + SMB("SMB", 445, "Connect to windows LAN or SAMBA"), + SFTP("SFTP", 22, "Connect to a SSH server"), + FTP("FTP", 21, "Connect to a FTP server"), + WEBDAV("WEBDAV", 9800, "Connect to a WEBDAV server"), + HTTP("HTTP", 80, "Connect to a HTTP server"), + HTTPS("HTTPS", 443, "HTTP connection over SSL"), + FILE("FILE", -1, "Local files"); + + private final String name; // displayed name + private final Integer port; // port number + private final String description; // protocol description + + /** + * Create a new protocol + * + * @param name + * The name of the protocol + * @param port + * The port used by the protocol + */ + Protocol(final String name, final int port, final String description) { + this.name = name; + this.port = port; + this.description = description; + } + + /** + * Returns the protocol name + * + * @return the protocol name + */ + public final String getName() { + return name; + } + + /** + * Returns the protocol port number + * + * @return the protocol port number + */ + public final int getPort() { + return port; + } + + /** + * Returns the protocol description + * + * @return the protocol description + */ + public String getDescription() { + return description; + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/src/eu/engys/util/filechooser/uri/VFSURIParser.java b/src/eu/engys/util/filechooser/uri/VFSURIParser.java new file mode 100644 index 0000000..847d83a --- /dev/null +++ b/src/eu/engys/util/filechooser/uri/VFSURIParser.java @@ -0,0 +1,157 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package eu.engys.util.filechooser.uri; + + +/** + * VFSURIParser class for bookmarks URIs + * + * @author Yves Zoundi + * @author Stan Love + * @version 0.0.6 + */ +public final class VFSURIParser { + private static final char PATH_SEPARATOR = '/'; + private String username; + private String password; + private String path; + private String hostname; + private String portnumber; + private Protocol protocol; + + /** + * Create a new instance of VFSURIParser + * + * @param fileURI + * The VFS file URI to parse + */ + public VFSURIParser(final String fileURI) { + this(fileURI, true); + } + + public VFSURIParser(final String fileURI, boolean assignDefaultPort) { + if (fileURI == null) { + throw new NullPointerException("file URI is null"); + } + + VFSURIValidator v = new VFSURIValidator(); + boolean valid = v.isValid(fileURI); + if (valid) { + hostname = v.getHostname(); + username = v.getUser(); + password = v.getPassword(); + path = v.getFile(); + portnumber = v.getPort(); + String p = v.getProtocol(); + + // fix up parsing results + protocol = Protocol.valueOf(p.toUpperCase()); + if ((portnumber == null) && (!p.equalsIgnoreCase("file"))) { + portnumber = String.valueOf(protocol.getPort()); + } + if (path == null) { + path = String.valueOf(PATH_SEPARATOR); + } + } else { + hostname = null; + username = null; + password = null; + path = fileURI; + portnumber = null; + protocol = null; + } + + } + + /** + * Returns the VFS hostname + * + * @return the VFS hostname + */ + public String getHostname() { + return hostname; + } + + /** + * Returns the VFS password + * + * @return the VFS password + */ + public String getPassword() { + return password; + } + + /** + * Returns the VFS path + * + * @return the VFS path + */ + public String getPath() { + return path; + } + + /** + * Returns the VFS port number + * + * @return the VFS port number + */ + public String getPortnumber() { + return portnumber; + } + + /** + * Returns the VFS protocol + * + * @return the VFS protocol + */ + public Protocol getProtocol() { + return protocol; + } + + /** + * Returns the VFS username + * + * @return the VFS username + */ + public String getUsername() { + return username; + } +} diff --git a/src/eu/engys/util/filechooser/uri/VFSURIValidator.java b/src/eu/engys/util/filechooser/uri/VFSURIValidator.java new file mode 100644 index 0000000..25d32c9 --- /dev/null +++ b/src/eu/engys/util/filechooser/uri/VFSURIValidator.java @@ -0,0 +1,2854 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package eu.engys.util.filechooser.uri; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * VFS URIs validator + * + * @author Stan Love + * @version 0.0.4 + */ +public class VFSURIValidator { + private String local_uri, local_protocol, local_user, local_pass; + private String local_hostname, local_port, local_file; + + public boolean assertEquals(String _s1, String _s2) { + if ((_s1 == null) || (_s2 == null)) { + System.out.println("FATAL assertEquals -- _s1 || _s2 == null"); + System.out.println("_s1=" + _s1 + "="); + System.out.println("_s2=" + _s2 + "="); + Exception e = new Exception(""); + e.printStackTrace(); + System.exit(10); + } + if (_s1.equals(_s2)) { + } else { + System.out.println("FATAL assertEquals -- _s1 != _s2 "); + System.out.println("_s1=" + _s1 + "="); + System.out.println("_s2=" + _s2 + "="); + Exception e = new Exception(""); + e.printStackTrace(); + System.exit(10); + } + return false; + } + + public boolean assertNull(String _s1) { + if (_s1 != null) { + System.out.println("FATAL assertNull -- _s1 != null"); + Exception e = new Exception(""); + e.printStackTrace(); + System.exit(10); + } + return false; + } + + public boolean assertnotNull(String _s1) { + if (_s1 == null) { + System.out.println("FATAL assertnoNull -- _s1 != null"); + Exception e = new Exception(""); + e.printStackTrace(); + System.exit(10); + } + return false; + } + + public String getUri() { + if (local_uri.equals("")) + local_uri = null; + return local_uri; + } + + public String getProtocol() { + if ((local_protocol != null) && (local_protocol.equals(""))) + local_protocol = null; + return local_protocol; + } + + public String getUser() { + if ((local_user != null) && (local_user.equals(""))) + local_user = null; + return local_user; + } + + public String getPassword() { + if ((local_pass != null) && (local_pass.equals(""))) + local_pass = null; + return local_pass; + } + + public String getHostname() { + if ((local_hostname != null) && (local_hostname.equals(""))) + local_hostname = null; + return local_hostname; + } + + public String getPort() { + if (local_port == null) { + return local_port; + } + if (local_port.startsWith(":")) { + local_port = local_port.substring(1); + } + if ((local_port != null) && (local_port.equals(""))) + local_port = null; + return local_port; + } + + public String getFile() { + if ((local_file != null) && (local_file.equals(""))) + local_file = null; + return local_file; + } + + public boolean isValid(String _uri) { + boolean ret = false; + boolean ends_with_slash = false; + + String protocol = null; + String user_pass = null; + String hostname = null; + String port = null; + String bad_port = null; + String drive = null; + String file = null; + + /* + * System.out.println(); System.out.println(); System.out.println(); + */ + + local_uri = null; + local_protocol = null; + local_user = null; + local_pass = null; + local_hostname = null; + local_port = null; + local_file = null; + // file://(drive_letter:)/ + // file://(drive_letter:)/file_path + // Pattern p_file1 = + // Pattern.compile("(file|FILE)://([a-z][ ]*:)*?(/.*)"); + Pattern p_file1 = Pattern.compile("(file|FILE)://(/*)([a-zA-Z][ ]*:)*(.*)"); + Matcher m_file1 = p_file1.matcher(_uri); + + if (m_file1.matches()) { + // System.out.println("file matcher"); + protocol = m_file1.group(1); + String path_start = m_file1.group(2); + drive = m_file1.group(3); + file = m_file1.group(4); + + /* + * System.out.println("uri="+_uri+"="); + * System.out.println("drive="+drive+"="); + * System.out.println("file="+file+"="); + * System.out.println("path_start="+path_start+"="); + */ + local_uri = _uri; + local_protocol = protocol; + local_user = null; + local_pass = null; + local_hostname = null; + local_port = null; + if ((drive != null) && (file != null)) { + local_file = drive + file; + } else if ((path_start != null) && (drive == null) && (file != null)) { + local_file = path_start + file; + } else if ((drive != null) && (file == null)) { + local_file = drive; + } else { + local_file = file; + } + return true; + } + + /* + * //look for a bad port number + * //ftp://(username:pass)*?@hostname(:[0-9]+)*?/.* Pattern p_ftp1 = + * Pattern.compile( + * "(ftp|FTP|sftp|SFTP|http|HTTP|https|HTTPS|webdav|WEBDAV|smb|SMB)://(.*?:.*?@)*(.*?)?([ ]*:[^0-9]+)*?[ ]*[^:]/.*" + * ); Matcher m_ftp1 = p_ftp1.matcher(_uri); if(m_ftp1.matches())return + * false; + * + * if (m_file1.matches()) { //System.out.println("file matcher"); + * protocol = m_file1.group(1); drive = m_file1.group(2); file = + * m_file1.group(3); + * + * //System.out.println("uri="+_uri+"="); + * //System.out.println("file="+file+"="); + * //System.out.println("drive="+drive+"="); local_uri = _uri; + * local_protocol = protocol; local_user = null; local_pass = null; + * local_hostname = null; local_port = null; if ((drive != null) && + * (file != null)) { local_file = drive + file; } else { local_file = + * file; } return true; } + * + * /* //look for a bad port number + * //ftp://(username:pass)*?@hostname(:[0-9]+)*?/.* Pattern p_ftp1 = + * Pattern.compile( + * "(ftp|FTP|sftp|SFTP|http|HTTP|https|HTTPS|webdav|WEBDAV|smb|SMB)://(.*?:.*?@)*(.*?)?([ ]*:[^0-9]+)*?[ ]*[^:]/.*" + * ); Matcher m_ftp1 = p_ftp1.matcher(_uri); if(m_ftp1.matches())return + * false; + */ + + // remove trailing slash if present + if (_uri.endsWith("/")) { + int iend = _uri.length(); + _uri = _uri.substring(0, iend - 1); + ends_with_slash = true; + } + // ftp://(username:pass)*?@hostname(:[0-9]+)*?/.* + // "(ftp|FTP|sftp|SFTP|http|HTTP|https|HTTPS|webdav|WEBDAV|smb|SMB)://(.*?:.*?@)*([^:]+)([ ]*:[0-9]+)*([ ]*:)*(/.*)"); + // "(ftp|FTP|sftp|SFTP|http|HTTP|https|HTTPS|webdav|WEBDAV|smb|SMB)://(.+:.+@)*([^:]+)([ ]*:[0-9]+)*([ ]*:)*(/.*)"); + Pattern p_ftp2 = Pattern.compile("(ftp|FTP|sftp|SFTP|http|HTTP|https|HTTPS|webdav|WEBDAV|smb|SMB)://(.+:.+@)*([^:]+?/*)([ ]*:[0-9]+)*([ ]*:)*(/.*)"); + Matcher m_ftp2 = p_ftp2.matcher(_uri); + + Pattern p_ftp3 = Pattern.compile("(ftp|FTP|sftp|SFTP|http|HTTP|https|HTTPS|webdav|WEBDAV|smb|SMB)://(.+:.+@)*([^:]+)([ ]*:[0-9]+)*([ ]*:)*(/*?.*)"); + Matcher m_ftp3 = p_ftp3.matcher(_uri); + + if (m_ftp2.matches()) { + // System.out.println("ftp2 matcher"); + ret = true; + protocol = m_ftp2.group(1); + user_pass = m_ftp2.group(2); + hostname = m_ftp2.group(3); + + port = m_ftp2.group(4); + bad_port = m_ftp2.group(5); // this should be null on all valid port + // inputs + file = m_ftp2.group(6); + if (ends_with_slash) { + file = file + "/"; + } + if (hostname == null) { + protocol = null; + user_pass = null; + port = null; + bad_port = null; + file = null; + ret = false; + } + + } else if (m_ftp3.matches()) { + // System.out.println("ftp3 matcher"); + ret = true; + protocol = m_ftp3.group(1); + user_pass = m_ftp3.group(2); + hostname = m_ftp3.group(3); + + port = m_ftp3.group(4); + bad_port = m_ftp3.group(5); // this should be null on all valid port + // inputs + file = m_ftp3.group(6); + if (ends_with_slash) { + file = file + "/"; + } + if (hostname == null) { + protocol = null; + user_pass = null; + port = null; + bad_port = null; + file = null; + ret = false; + } + } else { + // System.out.println("did not match"); + } + + if (ret == true) { + // leave the various regex parts of the string here in case we want + // to do more validation/debugging in the future + } + + if ((hostname != null) && hostname.contains("@")) { + user_pass = hostname.substring(0, hostname.indexOf('@')); + hostname = hostname.substring(hostname.indexOf('@') + 1); + } + // System.out.println("uri="+_uri+"="); + // System.out.println("protocol="+protocol+"="); + // System.out.println("user_pass="+user_pass+"="); + // System.out.println("hostname="+hostname+"="); + // System.out.println("port="+port+"="); + // System.out.println("bad_port="+bad_port+"="); + // System.out.println("file="+file+"="); + + if ((hostname != null) && (hostname.startsWith(":") || hostname.endsWith(":") || hostname.contains(":"))) { + // System.out.println("bad hostname="+hostname+"="); + ret = false; + } + + if (bad_port != null) { + // System.out.println("bad_port found="+bad_port+"="); + ret = false; + } + + if (ret == false) { // don't parse any bad inputs + return ret; + } + local_uri = _uri; + local_protocol = protocol; + int colon_position = -1; + if ((user_pass == null) || (user_pass.equals(""))) { + colon_position = -1; + } else { + colon_position = user_pass.indexOf(':'); + } + if ((user_pass == null) || (user_pass.equals(""))) { + local_user = null; + local_pass = null; + } else if (colon_position == -1) { + local_user = user_pass; + local_pass = null; + } else { + local_user = user_pass.substring(0, colon_position); + local_pass = user_pass.substring(colon_position); + } + // System.out.println("raw local_pass="+local_pass+"="); + if (local_pass != null) { + if (local_pass.endsWith("@")) { + local_pass = local_pass.substring(0, local_pass.length() - 1); + } + if (local_pass.startsWith(":")) { + local_pass = local_pass.substring(1); + } + } + local_hostname = hostname; + local_port = port; + local_file = file; + + return ret; + } + + public void error_msg(String _s) { + System.out.println("Error in test=" + _s + "="); + Exception e = new Exception(""); + e.printStackTrace(); + System.exit(10); + } + + /** + * @param args + */ + public static void main(String[] args) { + // test code + String s; + + /* + * v.assertEquals(v.getProtocol(),"files"); v.assertNull(v.getUser()); + * v.assertNull(v.getHostname()); v.assertNull(v.getPassword()); + * v.assertNull(v.getPort()); v.assertEquals(v.getFile(),"c:"); + */ + // unknown protocol names + s = "files://c:"; + + VFSURIValidator v = new VFSURIValidator(); + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "files://c:"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "FTPS://c:"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "ftps://c:"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "files123://c:"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "fiLE://c:"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + // file tests + s = "file://c:"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "c:"); + + s = "file://d:"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "d:"); + + s = "file://e:"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "e:"); + + s = "file://z:"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "z:"); + + s = "file://c:/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "c:/"); + + s = "file://d:/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "d:/"); + + s = "file://e:/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "e:/"); + + s = "file://z:/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "z:/"); + + s = "file://c:/a"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "c:/a"); + + s = "file://d:/a"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "d:/a"); + + s = "file://e:/b"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "e:/b"); + + s = "file://z:/b"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "z:/b"); + + s = "FILE://c:"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "c:"); + + s = "FILE://d:"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "d:"); + + s = "FILE://e:"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "e:"); + + s = "FILE://z:"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "z:"); + + s = "FILE://c:/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "c:/"); + + s = "FILE://d:/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "d:/"); + + s = "FILE://e:/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "e:/"); + + s = "FILE://z:/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "z:/"); + + s = "FILE://c:/a"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "c:/a"); + + s = "FILE://d:/a"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "d:/a"); + + s = "FILE://e:/b"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "e:/b"); + + s = "FILE://z:/b"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FILE"); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "z:/b"); + + // ftp tests + s = "ftp://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "ftp"); + v.assertNull(v.getUser()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "ftp://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "ftp"); + v.assertNull(v.getUser()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPassword()); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "ftp://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "ftp"); + v.assertNull(v.getUser()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPassword()); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "ftp://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "ftp://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "ftp"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "ftp://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "ftp"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "ftp://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "ftp://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "ftp"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "ftp://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "ftp"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "ftp: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "ftp:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "ftp:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "ftp://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "ftp://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + // System.exit(10); + s = "FTP://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "FTP://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "FTP://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "FTP://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "FTP://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "FTP://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "FTP://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "FTP://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "FTP://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "FTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "FTP: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "FTP:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "FTP:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "FTP://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "FTP://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + // sftp tests + s = "sftp://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "sftp://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "sftp://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "sftp://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "sftp://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "sftp://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "sftp://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "sftp://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "sftp://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "sftp: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "sftp:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "sftp:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "sftp://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "sftp://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SFTP://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SFTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SFTP://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SFTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SFTP://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SFTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SFTP://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SFTP://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SFTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SFTP://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SFTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SFTP://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SFTP://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SFTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SFTP://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SFTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "SFTP: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SFTP:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + + s = "SFTP:/ /user:pass:@machine"; + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SFTP://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SFTP://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + // http tests + s = "http://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "http"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "http://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "http"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "http://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "http"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "http://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "http://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "http"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "http://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "http"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "http://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "http://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "http"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "http://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "http"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "http: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "http:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "http:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "http://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "http://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTP://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTP://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTP://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTP"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTP://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTP://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTP://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTP://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTP://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTP://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTP"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "HTTP: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTP:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTP:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTP://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTP://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + // https tests + s = "https://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "https"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "https://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "https"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "https://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "https"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "https://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "https://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "https"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "https://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "https"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "https://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "https://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "https"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "https://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "https"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "https: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "https:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "https:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "https://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "https://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTPS://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTPS"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTPS://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTPS"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTPS://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTPS"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTPS://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTPS://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTPS"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTPS://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTPS"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTPS://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTPS://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTPS"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "HTTPS://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "HTTPS"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "HTTPS: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTPS:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTPS:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTPS://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "HTTPS://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + // webdav tests + s = "webdav://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "webdav"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "webdav://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "webdav"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "webdav://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "webdav"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "webdav://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "webdav://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "webdav"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "webdav://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "webdav"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "webdav://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "webdav://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "webdav"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "webdav://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + + s = "webdav: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "webdav:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "webdav:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "webdav://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "webdav://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "WEBDAV://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "WEBDAV"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "WEBDAV://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "WEBDAV"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "WEBDAV://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "WEBDAV"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "WEBDAV://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "WEBDAV://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "WEBDAV"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "WEBDAV://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "WEBDAV"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "WEBDAV://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "WEBDAV://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "WEBDAV"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "WEBDAV://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "WEBDAV"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "WEBDAV: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "WEBDAV:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "WEBDAV:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "WEBDAV://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "WEBDAV://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + // smb tests + s = "smb://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "smb"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "smb://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "smb"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "smb://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "smb"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "smb://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "smb://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "smb"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "smb://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "smb"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "smb://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "smb://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "smb"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "smb://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "smb"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "smb: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "smb:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "smb:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "smb://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "smb://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SMB://machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SMB"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SMB://machine:1/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SMB"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "1"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SMB://machine:12345/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SMB"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "12345"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SMB://machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SMB://user:pass@machine/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SMB"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SMB://user:pass@machine:123/the_file"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SMB"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass"); + v.assertEquals(v.getHostname(), "machine"); + v.assertEquals(v.getPort(), "123"); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SMB://user:pass@machine:/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SMB://user:pass:@machine/the_file"; // can ":" be part of a + // password? + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SMB"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_file"); + + s = "SMB://user:pass:@machine/the_dir/"; + + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "SMB"); + v.assertEquals(v.getUser(), "user"); + v.assertEquals(v.getPassword(), "pass:"); + v.assertEquals(v.getHostname(), "machine"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/the_dir/"); + + s = "SMB: //user:pass:@machine/the_file"; // failure tests + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SMB:/ /user:pass:@machine/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SMB:/ /user:pass:@machine"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SMB://user:pass:@:123/a"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "SMB://user:pass:@machine:a/the_file"; + + if (v.isValid(s)) { + v.error_msg(s); + } + v.assertNull(v.getProtocol()); + v.assertNull(v.getUser()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPassword()); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + // add tests from Yves + s = "sftp://shell.sf.net"; + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "shell.sf.net"); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "file:///C:/home/birdman"; + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "C:/home/birdman"); + + s = "file:///home/birdman"; + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/home/birdman"); + + s = "file://home/birdman"; + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "file"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertNull(v.getHostname()); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "home/birdman"); + + s = "webdav://myserver.net/home/yves"; + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "webdav"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "myserver.net"); + v.assertNull(v.getPort()); + v.assertEquals(v.getFile(), "/home/yves"); + + s = "ftp://ftp.ca.freebsd.org"; + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "ftp"); + v.assertNull(v.getUser()); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "ftp.ca.freebsd.org"); + v.assertNull(v.getPort()); + v.assertNull(v.getFile()); + + s = "sftp://yves@shell.sf.net:28"; + if (!v.isValid(s)) { + v.error_msg(s); + } + v.assertEquals(v.getProtocol(), "sftp"); + v.assertEquals(v.getUser(), "yves"); + v.assertNull(v.getPassword()); + v.assertEquals(v.getHostname(), "shell.sf.net"); + v.assertEquals(v.getPort(), "28"); + v.assertNull(v.getFile()); + + System.out.println("all done"); + } +} diff --git a/src/eu/engys/util/filechooser/util/CompositeTaskContext.java b/src/eu/engys/util/filechooser/util/CompositeTaskContext.java new file mode 100644 index 0000000..0307794 --- /dev/null +++ b/src/eu/engys/util/filechooser/util/CompositeTaskContext.java @@ -0,0 +1,79 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.util; + +/** + */ +public class CompositeTaskContext extends TaskContext { + + private TaskContext[] taskContext; + + public CompositeTaskContext(String name, TaskContext[] taskContext) { + super(name, 0); + this.taskContext = taskContext; + } + + @Override + public void setStop(boolean stop) { + for (TaskContext context : taskContext) { + context.setStop(stop); + } + } + + @Override + public int getMax() { + int max = 0; + for (TaskContext context : taskContext) { + max += context.getMax(); + } + return max; + } + + @Override + public int getCurrentProgress() { + int progress = 0; + for (TaskContext context : taskContext) { + progress += context.getMax(); + } + return progress; + } +} diff --git a/src/eu/engys/util/filechooser/util/EngysFileSystemManager.java b/src/eu/engys/util/filechooser/util/EngysFileSystemManager.java new file mode 100644 index 0000000..c5b4c0f --- /dev/null +++ b/src/eu/engys/util/filechooser/util/EngysFileSystemManager.java @@ -0,0 +1,48 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.util; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.NameScope; +import org.apache.commons.vfs2.impl.StandardFileSystemManager; + +public class EngysFileSystemManager extends StandardFileSystemManager { + + @Override + public FileName resolveName(FileName base, String name, NameScope scope) { + FileName fileName; + try { + fileName = super.resolveName(base, name, scope); + } catch (Exception e) { + String scheme = StringUtils.removeEnd(base.getRootURI(), "/"); + fileName = new InvalidFileName(name, scheme, "invalid", FileType.FILE); + } + return fileName; + } + +} diff --git a/src/eu/engys/util/filechooser/util/FileNameWrapper.java b/src/eu/engys/util/filechooser/util/FileNameWrapper.java new file mode 100644 index 0000000..f0e1cef --- /dev/null +++ b/src/eu/engys/util/filechooser/util/FileNameWrapper.java @@ -0,0 +1,153 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.util; + +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.NameScope; +import org.apache.commons.vfs2.provider.AbstractFileName; + +public class FileNameWrapper extends AbstractFileName { + + protected FileName fileName; + + public FileNameWrapper(FileName fileName) { + super(fileName.getScheme(), fileName.getPath(), fileName.getType()); + this.fileName = fileName; + } + + @Override + public String getBaseName() { + return fileName.getBaseName(); + } + + @Override + public int getDepth() { + return fileName.getDepth(); + } + + @Override + public String getExtension() { + return fileName.getExtension(); + } + + @Override + public String getFriendlyURI() { + return fileName.getFriendlyURI(); + } + + @Override + public FileName getParent() { + return fileName.getParent(); + } + + @Override + public String getPath() { + return fileName.getPath(); + } + + @Override + public String getPathDecoded() throws FileSystemException { + return fileName.getPathDecoded(); + } + + @Override + public String getRelativeName(FileName name) throws FileSystemException { + return fileName.getRelativeName(name); + } + + @Override + public FileName getRoot() { + return fileName.getRoot(); + } + + @Override + public String getRootURI() { + return fileName.getRootURI(); + } + + @Override + public String getScheme() { + return fileName.getScheme(); + } + + @Override + public FileType getType() { + return fileName.getType(); + } + + @Override + public String getURI() { + return fileName.getURI(); + } + + @Override + public boolean isAncestor(FileName ancestor) { + return fileName.isAncestor(ancestor); + } + + @Override + public boolean isDescendent(FileName descendent) { + return fileName.isDescendent(descendent); + } + + @Override + public boolean isDescendent(FileName descendent, NameScope nameScope) { + return fileName.isDescendent(descendent, nameScope); + } + + @Override + public int compareTo(FileName o) { + return fileName.compareTo(o); + } + + @Override + public FileName createName(String absPath, FileType type) { + return ((AbstractFileName) fileName).createName(absPath, type); + } + + @Override + protected void appendRootUri(StringBuilder buffer, boolean addPassword) { + + } +} diff --git a/src/eu/engys/util/filechooser/util/FileObjectWrapper.java b/src/eu/engys/util/filechooser/util/FileObjectWrapper.java new file mode 100644 index 0000000..a773e91 --- /dev/null +++ b/src/eu/engys/util/filechooser/util/FileObjectWrapper.java @@ -0,0 +1,176 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.util; + +import java.net.URL; +import java.util.List; + +import org.apache.commons.vfs2.FileContent; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSelector; +import org.apache.commons.vfs2.FileSystem; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.NameScope; +import org.apache.commons.vfs2.operations.FileOperations; + +public class FileObjectWrapper implements FileObject { + protected FileObject parent; + + public FileObjectWrapper(FileObject parent) { + super(); + this.parent = parent; + } + + public FileName getName() { + return parent.getName(); + } + + public URL getURL() throws FileSystemException { + return parent.getURL(); + } + + public boolean exists() throws FileSystemException { + return parent.exists(); + } + + public boolean isHidden() throws FileSystemException { + return parent.isHidden(); + } + + public boolean isReadable() throws FileSystemException { + return parent.isReadable(); + } + + public boolean isWriteable() throws FileSystemException { + return parent.isWriteable(); + } + + public FileType getType() throws FileSystemException { + return parent.getType(); + } + + public FileObject getParent() throws FileSystemException { + return parent.getParent(); + } + + public FileSystem getFileSystem() { + return parent.getFileSystem(); + } + + public FileObject[] getChildren() throws FileSystemException { + return parent.getChildren(); + } + + public FileObject getChild(String name) throws FileSystemException { + return parent.getChild(name); + } + + public FileObject resolveFile(String name, NameScope scope) throws FileSystemException { + return parent.resolveFile(name, scope); + } + + public FileObject resolveFile(String path) throws FileSystemException { + return parent.resolveFile(path); + } + + public FileObject[] findFiles(FileSelector selector) throws FileSystemException { + return parent.findFiles(selector); + } + + public void findFiles(FileSelector selector, boolean depthwise, List selected) throws FileSystemException { + parent.findFiles(selector, depthwise, selected); + } + + public boolean delete() throws FileSystemException { + return parent.delete(); + } + + public int delete(FileSelector selector) throws FileSystemException { + return parent.delete(selector); + } + + public void createFolder() throws FileSystemException { + parent.createFolder(); + } + + public void createFile() throws FileSystemException { + parent.createFile(); + } + + public void copyFrom(FileObject srcFile, FileSelector selector) throws FileSystemException { + parent.copyFrom(srcFile, selector); + } + + public void moveTo(FileObject destFile) throws FileSystemException { + parent.moveTo(destFile); + } + + public boolean canRenameTo(FileObject newfile) { + return parent.canRenameTo(newfile); + } + + public FileContent getContent() throws FileSystemException { + return parent.getContent(); + } + + public void close() throws FileSystemException { + parent.close(); + } + + public void refresh() throws FileSystemException { + parent.refresh(); + } + + public boolean isAttached() { + return parent.isAttached(); + } + + public boolean isContentOpen() { + return parent.isContentOpen(); + } + + public FileOperations getFileOperations() throws FileSystemException { + return parent.getFileOperations(); + } +} diff --git a/src/eu/engys/util/filechooser/util/HelyxFileFilter.java b/src/eu/engys/util/filechooser/util/HelyxFileFilter.java new file mode 100644 index 0000000..19d4d4f --- /dev/null +++ b/src/eu/engys/util/filechooser/util/HelyxFileFilter.java @@ -0,0 +1,84 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.util; + +import java.io.File; + +import org.apache.commons.io.FilenameUtils; + +public class HelyxFileFilter { + + private static final String[] ALL_FILES_FILTER_EXTENSIONS = new String[] { "*" }; + public static final String ALL_FILES_FILTER_DESCRIPTION = "All Files (*.*)"; + private final String description; + private String[] extensions; + private static HelyxFileFilter allFilesFilter = new HelyxFileFilter(ALL_FILES_FILTER_DESCRIPTION, ALL_FILES_FILTER_EXTENSIONS); + + /** + * Example: Fluent File (*.msh, *.cas)", "msh", "cas" + */ + public HelyxFileFilter(String description, String... extensions) { + this.description = description; + this.extensions = extensions; + } + + public static HelyxFileFilter getAllFilesFilter() { + return allFilesFilter; + } + + public boolean isAllFilesFilter() { + return ALL_FILES_FILTER_DESCRIPTION.equals(description) && ALL_FILES_FILTER_EXTENSIONS.equals(extensions); + } + + public String getDescription() { + return description; + } + + public String[] getExtensions() { + return extensions; + } + + public boolean isValidExtension(String extensionToCheck) { + for (String ext : extensions) { + if (ext.equalsIgnoreCase(extensionToCheck)) { + return true; + } + } + return false; + } + + public boolean accepts(File file) { + if (extensions == null) { + return false; + } + if (isAllFilesFilter()) { + return true; + } + String fileExtension = FilenameUtils.getExtension(file.getName()); + return isValidExtension(fileExtension); + } + +} diff --git a/src/eu/engys/util/filechooser/util/InvalidFileName.java b/src/eu/engys/util/filechooser/util/InvalidFileName.java new file mode 100644 index 0000000..e8495fa --- /dev/null +++ b/src/eu/engys/util/filechooser/util/InvalidFileName.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.filechooser.util; + +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.provider.AbstractFileName; + +public class InvalidFileName extends AbstractFileName { + + private String originalName; + + public InvalidFileName(String originalName, String scheme, String absPath, FileType type) { + super(scheme, absPath, type); + this.originalName = originalName; + } + + @Override + public FileName createName(String absPath, FileType type) { + return new InvalidFileName("", getScheme(), absPath, type); + } + + @Override + protected void appendRootUri(StringBuilder buffer, boolean addPassword) { + buffer.append(getScheme()); + } + + public String getOriginalName() { + return originalName; + } + +} diff --git a/src/eu/engys/util/filechooser/util/SelectionMode.java b/src/eu/engys/util/filechooser/util/SelectionMode.java new file mode 100644 index 0000000..45f459a --- /dev/null +++ b/src/eu/engys/util/filechooser/util/SelectionMode.java @@ -0,0 +1,79 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.util; + +/** + */ +public enum SelectionMode { + + FILES_ONLY("Files only"), + DIRS_ONLY("Dirs only"), + DIRS_AND_FILES("Dirs and files"), + DIRS_AND_ARCHIVES("Dirs and archives"); + + private String name; + + private SelectionMode(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean isDirsOnly() { + return this.equals(DIRS_ONLY); + } + + public boolean isFilesOnly() { + return this.equals(FILES_ONLY); + } + + public boolean isDirsAndFiles() { + return this.equals(DIRS_AND_FILES); + } + + public boolean isDirsAndArchives() { + return this.equals(DIRS_AND_ARCHIVES); + } + +} diff --git a/src/eu/engys/util/filechooser/util/TaskContext.java b/src/eu/engys/util/filechooser/util/TaskContext.java new file mode 100644 index 0000000..39e3d57 --- /dev/null +++ b/src/eu/engys/util/filechooser/util/TaskContext.java @@ -0,0 +1,94 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.engys.util.filechooser.util; + +/** + */ +public class TaskContext { + private int max; + private volatile int currentProgress; + private volatile boolean stop; + private String name; + + private boolean indeterminate; + + public TaskContext(String name, int max) { + this.max = max; + this.name = name; + } + + public void setIndeterminate(boolean indeterminate) { + this.indeterminate = indeterminate; + } + + public boolean isIndeterminate() { + return indeterminate; + } + + public String getName() { + return name; + } + + public boolean isStop() { + return stop; + } + + public void setStop(boolean stop) { + this.stop = stop; + } + + public int getCurrentProgress() { + return currentProgress; + } + + public void setCurrentProgress(int currentProgress) { + this.currentProgress = currentProgress; + } + + public int getMax() { + return max; + } + + public void setMax(int max) { + this.max = max; + } +} diff --git a/src/eu/engys/util/filechooser/util/VFSUtils.java b/src/eu/engys/util/filechooser/util/VFSUtils.java new file mode 100644 index 0000000..b022dba --- /dev/null +++ b/src/eu/engys/util/filechooser/util/VFSUtils.java @@ -0,0 +1,547 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +/* + * Copyright 2012 Krzysztof Otrebski (krzysztof.otrebski@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package eu.engys.util.filechooser.util; + +import static eu.engys.util.ui.FileChooserUtils.DEFAULT_SSH_PORT; + +import java.awt.Component; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.swing.Icon; +import javax.swing.JOptionPane; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.vfs2.CacheStrategy; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileSystemManager; +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.UserAuthenticationData; +import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder; +import org.apache.commons.vfs2.impl.StandardFileSystemManager; +import org.apache.commons.vfs2.provider.UriParser; +import org.apache.commons.vfs2.provider.sftp.SftpFileObject; +import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Joiner; + +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.connection.SshParameters; +import eu.engys.util.filechooser.LinkFileObject; +import eu.engys.util.filechooser.authentication.AuthStore; +import eu.engys.util.filechooser.authentication.MemoryAuthStore; +import eu.engys.util.filechooser.authentication.UserAuthenticationDataWrapper; +import eu.engys.util.filechooser.authentication.UserAuthenticationInfo; +import eu.engys.util.filechooser.authentication.UserAuthenticatorFactory; +import eu.engys.util.filechooser.authentication.authenticator.OtrosUserAuthenticator; +import eu.engys.util.filechooser.uri.Protocol; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.ResourcesUtil; + +/** + * A helper class to deal with commons-vfs file abstractions + * + * @author Yves Zoundi + * @author Jojada Tirtowidjojo + * @author Stephan Schuster + * @version 0.0.5 + */ +public final class VFSUtils { + + private static final Logger logger = LoggerFactory.getLogger(VFSUtils.class); + + public enum LocationType { + file, sftp; + + public String toString() { + if (Util.isWindows() && equals(file)) { + return super.toString() + WIN_PROTOCOL_PREFIX; + } + return super.toString() + UNIX_PROTOCOL_PREFIX; + }; + + public static String[] toStringArray() { + return new String[] { file.toString(), sftp.toString() }; + }; + } + + private static final int SYMBOLIC_LINK_MAX_SIZE = 128; + + private static FileSystemManager fileSystemManager; + private static FileSystemOptions fileSystemOptions = new FileSystemOptions(); + public static final String UNIX_PROTOCOL_PREFIX = "://"; + public static final String WIN_PROTOCOL_PREFIX = ":///"; + private static final File HOME_DIRECTORY = new File(System.getProperty("user.home")); + + public static final File CONFIG_DIRECTORY = new File(HOME_DIRECTORY, ".otrosvfsbrowser"); + public static final File USER_AUTH_FILE = new File(CONFIG_DIRECTORY, "auth.xml"); + public static final File USER_AUTH_FILE_BAK = new File(CONFIG_DIRECTORY, "auth.xml.bak"); + private static ReadWriteLock aLock = new ReentrantReadWriteLock(true); + + // File size localized strings + + private static final Map schemeIconMap = new HashMap(); + private static final Set archivesSuffixes = new HashSet(); + + static { + schemeIconMap.put("file", ResourcesUtil.getIcon("drive")); + schemeIconMap.put("sftp", ResourcesUtil.getIcon("networkCloud")); + schemeIconMap.put("ftp", ResourcesUtil.getIcon("networkCloud")); + schemeIconMap.put("smb", ResourcesUtil.getIcon("sambaShare")); + schemeIconMap.put("http", ResourcesUtil.getIcon("networkCloud")); + schemeIconMap.put("https", ResourcesUtil.getIcon("networkCloud")); + schemeIconMap.put("zip", ResourcesUtil.getIcon("folderZipper")); + schemeIconMap.put("tar", ResourcesUtil.getIcon("folderZipper")); + schemeIconMap.put("jar", ResourcesUtil.getIcon("jarIcon")); + schemeIconMap.put("tgz", ResourcesUtil.getIcon("folderZipper")); + schemeIconMap.put("tbz", ResourcesUtil.getIcon("folderZipper")); + + archivesSuffixes.add("zip"); + archivesSuffixes.add("tar"); + archivesSuffixes.add("jar"); + archivesSuffixes.add("tgz"); + archivesSuffixes.add("gz"); + archivesSuffixes.add("bz2"); + archivesSuffixes.add("tar"); + archivesSuffixes.add("tbz"); + archivesSuffixes.add("tgz"); + + } + + public static FileSystemManager getFileSystemManager() { + aLock.readLock().lock(); + + try { + if (fileSystemManager == null) { + try { + EngysFileSystemManager fm = new EngysFileSystemManager(); + // fm.setClassLoader(StandardFileSystemManager.class.getClassLoader()); + fm.setConfiguration(StandardFileSystemManager.class.getResource("providers.xml")); + fm.setCacheStrategy(CacheStrategy.MANUAL); + fm.init(); + logger.trace("Supported schemes: {} ", Joiner.on(", ").join(fm.getSchemes())); + fileSystemManager = fm; + } catch (Exception exc) { + throw new RuntimeException(exc); + } + } + + return fileSystemManager; + } finally { + aLock.readLock().unlock(); + } + } + + public static String getFriendlyName(String fileName) { + return getFriendlyName(fileName, true); + } + + public static String getFriendlyName(String fileName, boolean excludeLocalFilePrefix) { + if (fileName == null) { + return ""; + } + StringBuilder filePath = new StringBuilder(); + + int pos = fileName.lastIndexOf('@'); + + if (pos == -1) { + filePath.append(fileName); + } else { + int pos2 = fileName.indexOf(UNIX_PROTOCOL_PREFIX); + + if (pos2 == -1) { + filePath.append(fileName); + } else { + String protocol = fileName.substring(0, pos2); + + filePath.append(protocol).append(UNIX_PROTOCOL_PREFIX).append(fileName.substring(pos + 1, fileName.length())); + } + } + + String returnedString = filePath.toString(); + + if (excludeLocalFilePrefix && returnedString.startsWith(LocationType.file.toString())) { + return filePath.substring(LocationType.file.toString().length()); + } + + return returnedString; + } + + public static FileObject createFileSystemRoot(FileObject fileObject) { + try { + return fileObject.getFileSystem().getRoot(); + } catch (FileSystemException ex) { + return null; + } + } + + public static FileObject[] getFiles(Component parent, FileObject folder) { + try { + return getChildren(folder); + } catch (FileSystemException ex) { + String url = folder == null ? "non existing file" : folder.getName().getPath(); + VFSUtils.showErrorMessage(parent, url, ex); + return new FileObject[0]; + } + } + + public static FileObject getRootFileSystem(FileObject fileObject) { + try { + if ((fileObject == null) || !fileObject.exists()) { + return null; + } + + return fileObject.getFileSystem().getRoot(); + } catch (FileSystemException ex) { + return null; + } + } + + public static boolean isHiddenFile(FileObject fileObject) { + try { + return fileObject.getName().getBaseName().charAt(0) == '.'; + } catch (Exception ex) { + return false; + } + } + + public static boolean isRoot(FileObject fileObject) { + try { + return fileObject.getParent() == null; + } catch (FileSystemException ex) { + return false; + } + } + + public static FileObject resolveFileObject(String filePath) throws FileSystemException { + return resolveFileObject(filePath, null); + } + + public static FileObject resolveFileObject(String filePath, SshParameters sshParameters) throws FileSystemException { + logger.trace("Resolving file: {}", filePath); + if (filePath.startsWith(LocationType.sftp.toString())) { + SftpFileSystemConfigBuilder builder = SftpFileSystemConfigBuilder.getInstance(); + builder.setStrictHostKeyChecking(fileSystemOptions, "no"); + builder.setUserDirIsRoot(fileSystemOptions, false); + builder.setCompression(fileSystemOptions, "zlib,none"); + } + + AuthStore sessionAuthStore = new MemoryAuthStore(); + if (sshParameters != null) { + String host = sshParameters.getHost(); + String user = sshParameters.getUser(); + String pwd = sshParameters.getSshpwd(); + String key = sshParameters.getSshkey(); + int port = sshParameters.getPort(); + if (host != null && user != null && pwd != null && key != null) { + setAuthenticationFromSSHParameters(sessionAuthStore, host, user, pwd, key); + } + } + return resolveFileObject(sessionAuthStore, filePath); + } + + private static void setAuthenticationFromSSHParameters(AuthStore sessionAuthStore, String host, String user, String pwd, String key) { + UserAuthenticationInfo auInfo = new UserAuthenticationInfo(Protocol.SFTP.getName(), host, user); + UserAuthenticationDataWrapper authenticationData = new UserAuthenticationDataWrapper(); + authenticationData.setData(UserAuthenticationData.USERNAME, user.toCharArray()); + authenticationData.setData(UserAuthenticationData.PASSWORD, pwd.toCharArray()); + authenticationData.setData(UserAuthenticationDataWrapper.SSH_KEY, key.toCharArray()); + sessionAuthStore.add(auInfo, authenticationData); + } + + private static FileObject resolveFileObject(AuthStore sessionAuthStore, String filePath) throws FileSystemException { + UserAuthenticatorFactory factory = new UserAuthenticatorFactory(); + OtrosUserAuthenticator authenticator = factory.getUiUserAuthenticator(sessionAuthStore, filePath, fileSystemOptions); + if (filePath.startsWith(LocationType.sftp.toString())) { + SftpFileSystemConfigBuilder builder = SftpFileSystemConfigBuilder.getInstance(); + builder.setStrictHostKeyChecking(fileSystemOptions, "no"); + builder.setUserDirIsRoot(fileSystemOptions, false); + builder.setCompression(fileSystemOptions, "zlib,none"); + + } + + DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(fileSystemOptions, authenticator); + FileObject resolveFile; + try { + resolveFile = getFileSystemManager().resolveFile(filePath, fileSystemOptions);// SLOW ACTION (circa 120ms) + resolveFile.getType(); + } catch (FileSystemException e) { + logger.error("Error resolving file " + filePath, e.getMessage()); + e.printStackTrace(); + throw e; + } + return resolveFile; + } + + public static boolean exists(FileObject fileObject) { + if (fileObject == null) { + return false; + } + + try { + return fileObject.exists(); + } catch (FileSystemException ex) { + return false; + } + } + + public static boolean isDirectory(FileObject fileObject) { + try { + return fileObject.getType().equals(FileType.FOLDER); + } catch (FileSystemException ex) { + logger.info("Exception when checking if fileobject is folder", ex); + return false; + } + } + + public static boolean isLocalFile(FileObject fileObject) { + try { + return fileObject.getURL().getProtocol().equalsIgnoreCase("file") && FileType.FILE.equals(fileObject.getType()); + } catch (FileSystemException e) { + logger.info("Exception when checking if fileobject is local file", e); + return false; + } + } + + public static boolean isFileSystemRoot(FileObject folder) { + return isRoot(folder); + } + + public static boolean isParent(FileObject folder, FileObject file) { + try { + FileObject parent = file.getParent(); + + return parent != null && parent.equals(folder); + + } catch (FileSystemException ex) { + return false; + } + } + + public static String getRemoteUserHome(SshParameters sshParameters) throws FileSystemException { + return "/home/" + sshParameters.getUser(); + } + + public static FileObject getUserHome() throws FileSystemException { + return resolveFileObject(Util.isUnix() ? PrefUtil.USER_DIR : PrefUtil.USER_HOME); + } + + public static void checkForSftpLinks(FileObject[] files, TaskContext taskContext) { + logger.trace("Checking for SFTP links"); + taskContext.setMax(files.length); + long ts = System.currentTimeMillis(); + for (int i = 0; i < files.length && !taskContext.isStop(); i++) { + FileObject fileObject = files[i]; + try { + if (fileObject instanceof SftpFileObject) { + SftpFileObject sftpFileObject = (SftpFileObject) fileObject; + long size = sftpFileObject.getContent().getSize(); + if (sftpFileObject.getType() == FileType.FILE && size < SYMBOLIC_LINK_MAX_SIZE && size != 0) { + if (!pointToItself(sftpFileObject)) { + files[i] = new LinkFileObject(sftpFileObject); + } + } + + } + taskContext.setCurrentProgress(i); + } catch (Exception e) { + + } + + } + long checkDuration = System.currentTimeMillis() - ts; + logger.trace("Checking SFTP links took {} ms [{}ms/file]", checkDuration, (float) checkDuration / files.length); + } + + public static boolean pointToItself(FileObject fileObject) throws FileSystemException { + if (!fileObject.getURL().getProtocol().equalsIgnoreCase("file") && FileType.FILE.equals(fileObject.getType())) { + logger.trace("Checking if {} is pointing to itself", fileObject.getName().getFriendlyURI()); + FileObject[] children = VFSUtils.getChildren(fileObject); + logger.trace("Children number of {} is {}", fileObject.getName().getFriendlyURI(), children.length); + if (children.length == 1) { + FileObject child = children[0]; + if (child.getContent().getSize() != child.getContent().getSize()) { + return false; + } + if (child.getName().getBaseName().equals(fileObject.getName().getBaseName())) { + return true; + } + } + } + return false; + } + + public static FileObject[] getChildren(FileObject fileObject) throws FileSystemException { + FileObject[] result; + if (isLocalFileSystem(fileObject) && isArchive(fileObject)) { + String extension = fileObject.getName().getExtension(); + result = VFSUtils.resolveFileObject(extension + ":" + fileObject.getURL().toString() + "!/").getChildren(); + } else { + result = fileObject.getChildren(); + } + return filterInvalidFiles(result); + } + + private static FileObject[] filterInvalidFiles(FileObject[] result) { + List validFileObjects = new ArrayList<>(); + for (FileObject fo : result) { + if (fo.getName() instanceof InvalidFileName) { + logger.warn("Invalid filename filtered: {}", ((InvalidFileName) fo.getName()).getOriginalName()); + } else { + if (isLocalFileSystem(fo) && isInvalidFolder(fo)) { + logger.warn("Invalid folder filtered: {}", fo.getName()); + } else { + validFileObjects.add(fo); + } + } + } + return validFileObjects.toArray(new FileObject[0]); + } + + private static boolean isInvalidFolder(FileObject folder) { + try { + if (folder.getType() != FileType.FOLDER) { + return false; + } + + File file = new File(decode(folder.getName().getURI(), null)); + String[] files = UriParser.encode(file.list()); + + return files == null; + } catch (Exception e) { + return true; + } + } + + public static boolean isArchive(FileObject fileObject) { + return isArchive(fileObject.getName()); + } + + public static boolean isArchive(FileName fileName) { + String extension = fileName.getExtension(); + return archivesSuffixes.contains(extension.toLowerCase()); + } + + private static boolean isLocalFileSystem(FileObject fileObject) { + return fileObject.getName().getScheme().equalsIgnoreCase("file"); + } + + public static Icon getIconForFileSystem(String url) { + String schema = "file"; + if (null != url) { + int indexOf = url.indexOf(UNIX_PROTOCOL_PREFIX); + if (indexOf > 0) { + schema = url.substring(0, indexOf); + } + } + return schemeIconMap.get(schema); + } + + public static boolean canGoUrl(FileObject fileObject) throws FileSystemException { + if (VFSUtils.pointToItself(fileObject)) { + return false; + } + if (VFSUtils.isLocalFile(fileObject)) { + return false; + } + return true; + + } + + public static String encode(String url, SshParameters sshParameters) { + String fixedUrl = url.replace("\\", "/"); + if (sshParameters != null) { + String host = sshParameters.getHost(); + String port = String.valueOf(sshParameters.getPort()); + String typePrefix = LocationType.sftp.toString(); + if (port.equals(DEFAULT_SSH_PORT)) { + return typePrefix + host + fixedUrl; + } else { + return typePrefix + host + ":" + port + fixedUrl; + } + } else { + String typePrefix = LocationType.file.toString(); + return typePrefix + fixedUrl; + } + } + + public static String decode(String path, SshParameters sshParameters) { + if (path.startsWith(LocationType.file.toString())) { + return StringUtils.removeStart(path, LocationType.file.toString()); + } else if (path.startsWith(LocationType.sftp.toString()) && sshParameters != null) { + String noType = StringUtils.removeStart(path, LocationType.sftp.toString()); + String noHost = StringUtils.removeStart(noType, sshParameters.getHost()); + String noPort = StringUtils.removeStart(noHost, ":" + sshParameters.getPort()); + return noPort; + } + return null; + } + + public static void showErrorMessage(final Component parent, final String url, final Exception e) { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + String message = "Error opening " + url; + if (e != null) { + message += "\n" + e.getMessage(); + if (message.contains("descendent")) { + message = message.replace("descendent", ""); + } + } + logger.error(message); + JOptionPane.showMessageDialog(parent, message, "File System Error", JOptionPane.ERROR_MESSAGE); + } + }); + } +} diff --git a/src/eu/engys/util/plaf/HelyxOSLookAndFeel.java b/src/eu/engys/util/plaf/HelyxOSLookAndFeel.java new file mode 100644 index 0000000..5b1b433 --- /dev/null +++ b/src/eu/engys/util/plaf/HelyxOSLookAndFeel.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.plaf; + +import javax.swing.UIManager; + +import com.pagosoft.plaf.PgsLookAndFeel; +import com.pagosoft.plaf.PlafOptions; + +public class HelyxOSLookAndFeel implements ILookAndFeel { + + private final double[] BG_COLOR = { 0.8, 0.8, 0.8 }; + private final double[] BG2_COLOR = { 0.2, 0.2, 0.2 }; + private final double[] SELECT_COLOR = { 1.0, 1.0, 1.0 }; + + @Override + public double[] get3DColor1() { + return BG_COLOR; + } + + @Override + public double[] get3DColor2() { + return BG2_COLOR; + } + + @Override + public double[] get3DSelectionColor() { + return SELECT_COLOR; + } + + @Override + public int getMainWidth() { + return 650; + } + + @Override + public int getSecondaryWidth() { + return 180; + } + + @Override + public void init() { + initPgsLAF(); + } + + private void initPgsLAF() { + try { + PlafOptions.setClearBorderEnabled(true); + PlafOptions.useExtraMargin(false); + PlafOptions.useShadowBorder(false); + PlafOptions.setOfficeScrollBarEnabled(true); + UIManager.setLookAndFeel(new PgsLookAndFeel()); + } catch (Exception e) { + } + + } +} diff --git a/src/eu/engys/util/plaf/ILookAndFeel.java b/src/eu/engys/util/plaf/ILookAndFeel.java new file mode 100644 index 0000000..32dbe88 --- /dev/null +++ b/src/eu/engys/util/plaf/ILookAndFeel.java @@ -0,0 +1,42 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.plaf; + + +public interface ILookAndFeel { + + public void init(); + + public double[] get3DColor1(); + public double[] get3DColor2(); + + public double[] get3DSelectionColor(); + + public int getMainWidth(); + public int getSecondaryWidth(); + +} diff --git a/src/eu/engys/util/plaf/TestLookAndFeel.java b/src/eu/engys/util/plaf/TestLookAndFeel.java new file mode 100644 index 0000000..a3e7d23 --- /dev/null +++ b/src/eu/engys/util/plaf/TestLookAndFeel.java @@ -0,0 +1,66 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.plaf; + + +public class TestLookAndFeel implements ILookAndFeel { + + private static final double[] BG_COLOR = {0.3, 0.6, 0.9}; + private static final double[] BG2_COLOR = {0.1, 0.2, 0.4}; + private static final double[] SELECT_COLOR = {1.0, 1.0, 1.0}; + + @Override + public double[] get3DColor1() { + return BG_COLOR; + } + + @Override + public double[] get3DColor2() { + return BG2_COLOR; + } + + @Override + public double[] get3DSelectionColor() { + return SELECT_COLOR; + } + + @Override + public int getMainWidth() { + return 550; + } + + @Override + public int getSecondaryWidth() { + return 180; + } + + @Override + public void init() { + } + +} + diff --git a/src/eu/engys/util/progress/ConsoleMonitor.java b/src/eu/engys/util/progress/ConsoleMonitor.java new file mode 100644 index 0000000..0ea2e2d --- /dev/null +++ b/src/eu/engys/util/progress/ConsoleMonitor.java @@ -0,0 +1,181 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.progress; + +import java.awt.Window; +import java.util.List; +import java.util.concurrent.Callable; + +import javax.swing.JDialog; + +public class ConsoleMonitor implements ProgressMonitor { + + @Override + public void setTotal(int i) { + } + + @Override + public int getTotal() { + return 0; + } + + @Override + public void setParent(Window parent) { + } + + @Override + public void start(String message, boolean canStop, Runnable r) { + System.out.println("START " + message); + r.run(); + } + + @Override + public void start(String message) { + System.out.println("START " + message); + } + + @Override + public void end() { + System.out.println("END"); + } + + @Override + public void error(String message) { + System.err.println("ERROR: " + message); + } + + @Override + public void error(String message, int indentLevel) { + System.err.println("ERROR: " + message); + } + + @Override + public void info(String message) { + System.out.println("INFO: " + message); + } + + @Override + public void infoN(String message) { + System.out.print("INFO: " + message); + } + + @Override + public void info(String message, int indentLevel) { + System.out.println("INFO: " + message); + } + + @Override + public void infoN(String message, int indentLevel) { + System.out.println("INFO: " + message); + } + + @Override + public void debug(String message) { + System.out.print(message); + } + + @Override + public void warning(String message) { + System.out.println("WARNING: " + message); + } + + @Override + public void warning(String message, int indentLevel) { + System.out.println("WARNING: " + message); + } + + @Override + public void warning(List invalidFiles) { + System.out.println("WARNING: " + invalidFiles); + } + + @Override + public int getCurrent() { + return 0; + } + + @Override + public void setCurrent(String string, int i) { + } + + @Override + public void setCurrent(String string, int i, int indentLevel) { + } + + @Override + public void setCurrent(String string, int min, int max, int indentLevel) { + } + + @Override + public String getMessages() { + return null; + } + + @Override + public boolean hasErrors() { + return false; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isIndeterminate() { + return false; + } + + @Override + public void setIndeterminate(boolean b) { + } + + @Override + public Boolean start(String message, boolean canStop, Callable c) { + System.out.println("START " + message); + try { + return c.call(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + @Override + public JDialog getDialog() { + return null; + } + + @Override + public boolean canStop() { + return false; + } + + @Override + public void stop() { + } +} diff --git a/src/eu/engys/util/progress/ProgressBar.java b/src/eu/engys/util/progress/ProgressBar.java new file mode 100644 index 0000000..18800b8 --- /dev/null +++ b/src/eu/engys/util/progress/ProgressBar.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ +package eu.engys.util.progress; + +import javax.swing.JProgressBar; + +import eu.engys.util.ui.ExecUtil; + +public class ProgressBar extends JProgressBar { + + private int value; + + public ProgressBar(int min, int max) { + super(min, max); + } + + @Override + public void setValue(final int value) { + this.value = value; + ExecUtil.invokeLater(new Runnable() { + public void run() { + ProgressBar.super.setValue(value); + } + }); + } + + @Override + public int getValue() { + return value; + } + + @Override + public void setIndeterminate(final boolean b) { + ExecUtil.invokeLater(new Runnable() { + public void run() { + ProgressBar.super.setIndeterminate(b); + } + }); + } +} diff --git a/src/eu/engys/util/progress/ProgressDialog.java b/src/eu/engys/util/progress/ProgressDialog.java new file mode 100644 index 0000000..7512df6 --- /dev/null +++ b/src/eu/engys/util/progress/ProgressDialog.java @@ -0,0 +1,261 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.progress; + +import java.awt.BorderLayout; +import java.awt.HeadlessException; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BoundedRangeModel; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JEditorPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public class ProgressDialog extends JDialog { + + private final Action CLOSE_ACTION = new AbstractAction("Close") { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }; + + private final Action STOP_ACTION = new AbstractAction("Stop") { + @Override + public void actionPerformed(ActionEvent e) { + monitor.stop(); + } + }; + + private JEditorPane statusArea = new JEditorPane("text/html", null); + private ProgressBar progressBar; + private JCheckBox keepOpen; + private ProgressMonitor monitor; + + private JButton closeButton; + private JButton stopButton; + + public ProgressDialog(Window window) throws HeadlessException { + super(window, "Progress", JDialog.DEFAULT_MODALITY_TYPE); + setSize(500, 300); + setLocationRelativeTo(null); + } + + public void init(ProgressMonitor monitor) { + this.monitor = monitor; + + progressBar = new ProgressBar(0, monitor.getTotal()); + + if (monitor.isIndeterminate()) { + progressBar.setIndeterminate(true); + progressBar.setStringPainted(false); + } else { + progressBar.setStringPainted(monitor.getTotal() > 0); + progressBar.setValue(monitor.getCurrent() < 0 ? 0 : monitor.getCurrent()); + } + + keepOpen = new JCheckBox("Keep dialog open on errors", true); + + statusArea.setText(monitor.getMessages()); + + final JScrollPane statusScrollPane = new JScrollPane(statusArea); + statusScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { + + BoundedRangeModel brm = statusScrollPane.getVerticalScrollBar().getModel(); + boolean wasAtBottom = true; + + public void adjustmentValueChanged(AdjustmentEvent e) { + if (!brm.getValueIsAdjusting()) { + if (wasAtBottom) + brm.setValue(brm.getMaximum()); + } else + wasAtBottom = ((brm.getValue() + brm.getExtent()) == brm.getMaximum()); + + } + }); + + JPanel centerPanel = new JPanel(new BorderLayout()); + centerPanel.add(statusScrollPane, BorderLayout.CENTER); + centerPanel.add(keepOpen, BorderLayout.SOUTH); + + closeButton = new JButton(CLOSE_ACTION); + stopButton = new JButton(STOP_ACTION); + + List buttons = new ArrayList(); + buttons.add(closeButton); + buttons.add(stopButton); + JComponent buttonsPanel = UiUtil.getCommandRow(buttons); + + JPanel contents = (JPanel) getContentPane(); + contents.setLayout(new BorderLayout(UiUtil.STANDARD_BORDER, UiUtil.STANDARD_BORDER)); + contents.setBorder(UiUtil.getStandardBorder()); + contents.add(progressBar, BorderLayout.NORTH); + contents.add(centerPanel, BorderLayout.CENTER); + contents.add(buttonsPanel, BorderLayout.SOUTH); + + setDefaultCloseOperation(HIDE_ON_CLOSE); + closeButton.setVisible(false); + stopButton.setVisible(false); + } + + public void start() { + ExecUtil.invokeLater(new Runnable() { + public void run() { + _start(); + } + }); + } + + public void startImmediately() { + ExecUtil.invokeAndWait(new Runnable() { + public void run() { + _start(); + } + }); + } + + private void _start() { + _update(); + + stopButton.setVisible(monitor.canStop()); + + if (!monitor.isFinished()) { + setVisible(true); + } + } + + public void end() { + if (isVisible()) { + ExecUtil.invokeAndWait(new Runnable() { + public void run() { + _end(); + } + }); + } else { + ExecUtil.invokeLater(new Runnable() { + public void run() { + _end(); + } + }); + } + } + + private void _end() { + if (monitor.isFinished()) { + progressBar.setIndeterminate(false); + progressBar.setValue(progressBar.getMaximum()); + String messages = monitor.getMessages(); + statusArea.setText(messages); + + if (!(keepOpen.isSelected() && monitor.hasErrors())) { + if (isVisible()) { + setVisible(false); + } + } + closeButton.setVisible(isVisible()); + stopButton.setVisible(false); + } else { + } + } + + public void update() { + ExecUtil.invokeLater(new Runnable() { + public void run() { + _update(); + } + }); + } + + private void _update() { + if (monitor.getCurrent() != monitor.getTotal()) { + String messages = monitor.getMessages(); + statusArea.setText(messages); + + if (monitor.isIndeterminate() != progressBar.isIndeterminate()) { + progressBar.setIndeterminate(monitor.isIndeterminate()); + progressBar.setStringPainted(false); + } + + if (!monitor.isIndeterminate()) { + if (monitor.getTotal() != progressBar.getMaximum()) + progressBar.setMaximum(monitor.getTotal()); + + if (monitor.getTotal() > 0) { + progressBar.setStringPainted(true); + progressBar.setValue(monitor.getCurrent()); + } else { + progressBar.setStringPainted(false); + } + } + + } else { + progressBar.setStringPainted(true); + progressBar.setValue(progressBar.getMaximum()); +// CLOSE_ACTION.setEnabled(true); + } + } + + public static void runOnEDT(final Runnable runnable) { + if (SwingUtilities.isEventDispatchThread()) { + // System.out.println("ProgressDialog.runOnEDT() is EDT"); + // Thread.dumpStack(); + runnable.run(); + } else { + SwingUtilities.invokeLater(runnable); + } + } + + public static void waitOnEDT(final Runnable runnable) { + if (SwingUtilities.isEventDispatchThread()) { + // System.out.println("ProgressDialog.runOnEDT() is EDT"); + // Thread.dumpStack(); + runnable.run(); + } else { + try { + SwingUtilities.invokeAndWait(runnable); + } catch (InvocationTargetException | InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/eu/engys/util/progress/ProgressMonitor.java b/src/eu/engys/util/progress/ProgressMonitor.java new file mode 100644 index 0000000..78ddbd1 --- /dev/null +++ b/src/eu/engys/util/progress/ProgressMonitor.java @@ -0,0 +1,79 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.progress; + +import java.awt.Window; +import java.util.List; +import java.util.concurrent.Callable; + +import javax.swing.JDialog; + +public interface ProgressMonitor { + + void setTotal(int i); + int getTotal(); + + + void start(String string, boolean canStop, Runnable r); + Boolean start(String string, boolean canStop, Callable c); + + void start(String string); + void end(); + + void debug(String message); + void error(String message); + void error(String message, int indentLevel); + void info(String message); + void info(String message, int indentLevel); + void infoN(String message); + void infoN(String message, int indentLevel); + void warning(String message); + void warning(String message, int indentLevel); + void warning(List invalidFiles); + + int getCurrent(); + void setCurrent(String string, int i); + void setCurrent(String string, int i, int indentLevel); + void setCurrent(String string, int min, int max, int indentLevel); + + + String getMessages(); + + boolean hasErrors(); + + boolean isFinished(); + + boolean isIndeterminate(); + void setIndeterminate(boolean b); + public JDialog getDialog(); + + void setParent(Window parent); + + boolean canStop(); + void stop(); + +} diff --git a/src/eu/engys/util/progress/ProgressMonitorImpl.java b/src/eu/engys/util/progress/ProgressMonitorImpl.java new file mode 100644 index 0000000..45c1c43 --- /dev/null +++ b/src/eu/engys/util/progress/ProgressMonitorImpl.java @@ -0,0 +1,358 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.progress; + +import java.awt.Window; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import javax.inject.Inject; + +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; + +public class ProgressMonitorImpl implements ProgressMonitor { + + // private static final Logger logger = + // LoggerFactory.getLogger(ProgressMonitorImpl.class); + + private static final String INDENT = " "; + + private static final String START = "
";
+	private static final String END = "
"; + + private static final String START_INFO = ""; + private static final String END_INFO = "\n"; + private static final String END_INFO_N = ""; + + private static final String START_B = ""; + private static final String END_B = " currentTask = null; + private boolean stoppable = false; + + @Override + public void start(String status, boolean canStop, Runnable r) { + final ExecutorService executor = Executors.newSingleThreadExecutor(); + this.currentTask = executor.submit(r); + prepareStart(status, canStop); + dialog().start(); + try { + currentTask.get(); + } catch (ExecutionException | InterruptedException e) { + error(e); + executor.shutdownNow(); + end(); + e.printStackTrace(); + } + } + + @Override + public Boolean start(String status, boolean canStop, final Callable c) { + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future task = executor.submit(c); + prepareStart(status, canStop); + dialog().start(); + try { + return task.get(); + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + } + return false; + } + + @Override + public void start(String status) { + prepareStart(status, false); + dialog().start(); + } + + private void prepareStart(String status, boolean canStop) { + stoppable = canStop; + finished = false; + hasErrors = false; + if (current != -1) { + current = -1; + } + sb.append(START); + if (status != null) + info(START_B + status + END_B); + current = 0; + } + + @Override + public boolean canStop() { + return stoppable; + } + + @Override + public void stop() { + if (stoppable) { + if (currentTask != null) { + currentTask.cancel(true); + } + } + } + + @Override + public void end() { + finished = true; + if (current != total) + current = total; + dialog().end(); + } + + @Override + public int getCurrent() { + return current; + } + + @Override + public String getMessages() { + return sb.toString() + END; + } + + @Override + public boolean isIndeterminate() { + return indeterminate; + } + + @Override + public void setIndeterminate(boolean indeterminate) { + this.indeterminate = indeterminate; + dialog().update(); + } + + @Override + public void setCurrent(String msg, int current) { + if (current == -1) + throw new IllegalStateException("not started yet"); + this.current = current; + if (msg != null) + info(msg); + dialog().update(); + } + + @Override + public void setCurrent(String msg, int current, int indentLevel) { + if (current == -1) + throw new IllegalStateException("not started yet"); + this.current = current; + if (msg != null) + info(msg, indentLevel); + dialog().update(); + } + + @Override + public void setCurrent(String msg, int min, int max, int indentLevel) { + if (current == -1) + throw new IllegalStateException("not started yet"); + this.total = max; + this.current = min; + if (msg != null) { + sb.append(START_INFO); + sb.append(addIndentation(msg, indentLevel)); + sb.append(END_INFO); + } + dialog().update(); + } + + @Override + public boolean isFinished() { + return finished; + } + + @Override + public void info(String message, int indentLevel) { + info(addIndentation(message, indentLevel)); + } + + @Override + public void infoN(String message, int indentLevel) { + infoN(addIndentation(message, indentLevel)); + } + + @Override + public void info(String message) { + sb.append(START_INFO); + sb.append(message); + sb.append(END_INFO); + dialog().update(); + } + + @Override + public void infoN(String message) { + sb.append(START_INFO); + sb.append(message); + sb.append(END_INFO_N); + dialog().update(); + } + + @Override + public void warning(String message, int indentLevel) { + warning(addIndentation(message, indentLevel)); + } + + private static String addIndentation(String message, int indentLevel) { + String toAppend = ""; + for (int i = 0; i < indentLevel; i++) { + toAppend += INDENT; + } + toAppend += message; + return toAppend; + } + + @Override + public void debug(String message) { +// logger.info(message); +// sb.append(START_INFO); + sb.append(message); +// sb.append(END_INFO); + dialog().update(); + } + + @Override + public void warning(String message) { + // logger.warn(message); + sb.append(START_WARING); + sb.append(message); + sb.append(END_WARNING); + dialog().update(); + } + + @Override + public void warning(List list) { + StringBuilder sb = new StringBuilder(); + for (String name : list) { + sb.append("\n"); + sb.append("\t"); + sb.append(name); + } + warning(sb.toString()); + } + + @Override + public void error(String message, int indentLevel) { + error(addIndentation(message, indentLevel)); + } + + @Override + public void error(String message) { + // logger.error(message); + hasErrors = true; + sb.append(START_ERROR); + sb.append(message); + sb.append(END_ERROR); + dialog().update(); + } + + private void error(Throwable t) { + StackTraceElement[] stackTrace = t.getStackTrace(); + StringBuilder sb = new StringBuilder(); + for (StackTraceElement el : stackTrace) { + sb.append(START_ERROR); + sb.append(" "); + sb.append(el.toString()); + sb.append(END_ERROR); + } + } + + @Override + public boolean hasErrors() { + return hasErrors; + } + +} diff --git a/src/eu/engys/util/progress/SilentMonitor.java b/src/eu/engys/util/progress/SilentMonitor.java new file mode 100644 index 0000000..532c028 --- /dev/null +++ b/src/eu/engys/util/progress/SilentMonitor.java @@ -0,0 +1,162 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.progress; + +import java.awt.Window; +import java.util.List; +import java.util.concurrent.Callable; + +import javax.swing.JDialog; + +public class SilentMonitor implements ProgressMonitor { + + @Override + public void setTotal(int i) { + } + + @Override + public int getTotal() { + return 0; + } + + @Override + public void setParent(Window parent) { + } + + @Override + public void start(String string, boolean canStop, Runnable r) { + r.run(); + } + + @Override + public void start(String message) { + } + + @Override + public void end() { + } + + @Override + public void error(String message) { + } + + @Override + public void error(String message, int indentLevel) { + } + + @Override + public void info(String message) { + } + + @Override + public void infoN(String message) { + } + + @Override + public void info(String message, int indentLevel) { + } + + @Override + public void infoN(String message, int indentLevel) { + } + + @Override + public void debug(String message) { + } + + @Override + public void warning(String message) { + } + + @Override + public void warning(String message, int indentLevel) { + } + + @Override + public void warning(List invalidFiles) { + } + + @Override + public int getCurrent() { + return 0; + } + + @Override + public void setCurrent(String string, int i) { + } + + @Override + public void setCurrent(String string, int i, int indentLevel) { + } + + @Override + public void setCurrent(String string, int min, int max, int indentLevel) { + + } + + @Override + public String getMessages() { + return null; + } + + @Override + public boolean hasErrors() { + return false; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isIndeterminate() { + return false; + } + + @Override + public void setIndeterminate(boolean b) { + } + + @Override + public Boolean start(String string, boolean canStop, Callable c) { + return false; + } + + @Override + public JDialog getDialog() { + return null; + } + @Override + public boolean canStop() { + return false; + } + @Override + public void stop() { + } + +} diff --git a/src/eu/engys/util/progress/VTKProgressConsoleWrapper.java b/src/eu/engys/util/progress/VTKProgressConsoleWrapper.java new file mode 100644 index 0000000..ccc62dc --- /dev/null +++ b/src/eu/engys/util/progress/VTKProgressConsoleWrapper.java @@ -0,0 +1,52 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.progress; + +import vtk.vtkAlgorithm; + +public class VTKProgressConsoleWrapper { + + private vtkAlgorithm algo; + private String title; + + public VTKProgressConsoleWrapper(String title, vtkAlgorithm algo, ProgressMonitor monitor) { + this.title = title; + this.algo = algo; + } + + public void onProgress() { + System.err.println( (int) (algo.GetProgress() * 100)); + } + + public void onStart() { + System.err.println("Loading " + title + "... "); + } + + public void onEnd() { + System.out.println("done"); + } + +} diff --git a/src/eu/engys/util/progress/VTKProgressMonitorWrapper.java b/src/eu/engys/util/progress/VTKProgressMonitorWrapper.java new file mode 100644 index 0000000..2fcf39a --- /dev/null +++ b/src/eu/engys/util/progress/VTKProgressMonitorWrapper.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.progress; + +import vtk.vtkAlgorithm; + +public class VTKProgressMonitorWrapper { + + private vtkAlgorithm algo; + private ProgressMonitor monitor; + private String title; + + public VTKProgressMonitorWrapper(String title, vtkAlgorithm algo, ProgressMonitor monitor) { + this.title = title; + this.algo = algo; + this.monitor = monitor; + } + + public void onProgress() { + monitor.setCurrent(null, (int) (algo.GetProgress() * 100)); + } + + public void onStart() { + monitor.infoN("Loading " + title + "... ", 1); + } + + public void onEnd() { + monitor.info("done"); + } + +} diff --git a/src/eu/engys/util/ui/ASCIIArt.java b/src/eu/engys/util/ui/ASCIIArt.java new file mode 100644 index 0000000..8ddee27 --- /dev/null +++ b/src/eu/engys/util/ui/ASCIIArt.java @@ -0,0 +1,65 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +public class ASCIIArt { + + private static final int VOID = -16777216; + + public static String toAA(String text) { + int width = 200; + int height = 30; + + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics g = image.getGraphics(); + g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 12)); + + Graphics2D graphics = (Graphics2D) g; +// graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + graphics.drawString(text, 0, 20); + + StringBuilder sb = new StringBuilder(); + for (int y = 0; y < height; y++) { + StringBuilder row = new StringBuilder(); + for (int x = 0; x < width; x++) { + int rgb = image.getRGB(x, y); + row.append(rgb == VOID ? " " : "#" ); + } + + if (!row.toString().trim().isEmpty()) { + sb.append(row); + sb.append("\n"); + } + } + + return sb.toString(); + } +} diff --git a/src/eu/engys/util/ui/BigButton.java b/src/eu/engys/util/ui/BigButton.java new file mode 100644 index 0000000..171ff25 --- /dev/null +++ b/src/eu/engys/util/ui/BigButton.java @@ -0,0 +1,40 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.awt.Dimension; + +import javax.swing.Action; +import javax.swing.JButton; + +public class BigButton extends JButton { + public BigButton(Action action) { + super(action); + setName((String) action.getValue(Action.NAME)); + setPreferredSize(new Dimension(120, 60)); + } +} diff --git a/src/eu/engys/util/ui/ButtonBar.java b/src/eu/engys/util/ui/ButtonBar.java new file mode 100644 index 0000000..4fc0816 --- /dev/null +++ b/src/eu/engys/util/ui/ButtonBar.java @@ -0,0 +1,207 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.AbstractButton; +import javax.swing.BoxLayout; +import javax.swing.JComponent; + +public class ButtonBar extends JComponent { + private class ButtonBarLayout extends BoxLayout { + + public void layoutContainer(Container container) { + super.layoutContainer(container); + Rectangle rectangle = new Rectangle(); + Component acomponent[]; + int k = (acomponent = container.getComponents()).length; + for (int i = 0; i < k; i++) { + Component component = acomponent[i]; + Rectangle rectangle1 = component.getBounds(); + if (getOrientation() == 0) + rectangle = rectangle1.height <= rectangle.height ? rectangle : rectangle1; + else + rectangle = rectangle1.width <= rectangle.width ? rectangle : rectangle1; + } + + k = (acomponent = container.getComponents()).length; + for (int j = 0; j < k; j++) { + Component component1 = acomponent[j]; + Rectangle rectangle2 = component1.getBounds(); + if (getOrientation() == 0) { + rectangle2.y = rectangle.y; + rectangle2.height = rectangle.height; + } else { + rectangle2.x = rectangle.x; + rectangle2.width = rectangle.width; + } + component1.setBounds(rectangle2); + } + + } + + public ButtonBarLayout(Container container, int i) { + super(container, i); + } + } + + public static final String uiClassID = "ButtonBarUI"; + + public static final int HORIZONTAL = 0; + public static final int VERTICAL = 1; + + private static final String POS_KEY = "JButton.segmentPosition"; + private static final String ONLY = "only"; + private static final String FIRST = "first"; + private static final String MIDDLE = "middle"; + private static final String LAST = "last"; + private int orientation; + + public ButtonBar() { + this(HORIZONTAL); + } + + public String getUIClassID() { + return uiClassID; + } + + public ButtonBar(int orientation) { + this.orientation = orientation; + if (orientation == HORIZONTAL) + setLayout(new ButtonBarLayout(this, ButtonBarLayout.LINE_AXIS)); + else + setLayout(new ButtonBarLayout(this, ButtonBarLayout.PAGE_AXIS)); + setName("ButtonBar"); + } + + public Component add(Component component) { + return addButton((AbstractButton) component); + } + + public AbstractButton addButton(AbstractButton abstractbutton) { + abstractbutton.getMaximumSize(); + Component acomponent[] = getComponents(); + int i = acomponent.length; + String s = null; + if (i == 0) + s = ONLY; + else if (i >= 1) { + s = LAST; + AbstractButton abstractbutton1 = (AbstractButton) acomponent[i - 1]; + if (i == 1) + abstractbutton1.putClientProperty(POS_KEY, FIRST); + else + abstractbutton1.putClientProperty(POS_KEY, MIDDLE); + } + abstractbutton.putClientProperty(POS_KEY, s); + abstractbutton.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent propertychangeevent) { + if ("componentOrientation".equals(propertychangeevent.getPropertyName())) { + JComponent jcomponent = (JComponent) propertychangeevent.getSource(); + String s1 = (String) jcomponent.getClientProperty(POS_KEY); + if (s1.equals(FIRST) || s1.equals(LAST)) + jcomponent.putClientProperty(POS_KEY, s1.equals(FIRST) ? LAST : FIRST); + } + } + + }); + super.add(abstractbutton); + return abstractbutton; + } + + public void remove(Component component) { + removeButton((AbstractButton) component); + } + + public void removeButton(AbstractButton abstractbutton) { + Component acomponent[] = getComponents(); + int i = acomponent.length; + int j = 0; + Component acomponent1[]; + int l = (acomponent1 = acomponent).length; + for (int k = 0; k < l; k++) { + Component component = acomponent1[k]; + if (component == abstractbutton) + break; + j++; + } + + if (i == j) + return; + String s = null; + AbstractButton abstractbutton1 = null; + if (i == 2) { + s = ONLY; + abstractbutton1 = j != 0 ? (AbstractButton) acomponent[0] : (AbstractButton) acomponent[1]; + } else if (i > 2) + if (j == 0) { + s = FIRST; + abstractbutton1 = (AbstractButton) acomponent[j + 1]; + } else if (j == i - 1) { + s = LAST; + abstractbutton1 = (AbstractButton) acomponent[j - 1]; + } + if (abstractbutton1 != null) + abstractbutton1.putClientProperty(POS_KEY, s); + super.remove(abstractbutton); + } + + public int getOrientation() { + return orientation; + } + + // public static void main(String[] args) { + // SwingUtilities.invokeLater(new Runnable() { + // + // @Override + // public void run() { + // new HelyxLookAndFeel().init(); + // + // ButtonBar bar = new ButtonBar(); + // bar.add(new JButton("pippo")); + // bar.add(new JButton("3")); + // + // JToolBar toolBar = new JToolBar(JToolBar.HORIZONTAL); + // toolBar.add(new JButton("pippo1")); + // toolBar.add(new JButton("pippo2")); + // toolBar.add(bar); + // toolBar.setRollover(true); + // + // JPanel panel = new JPanel(new BorderLayout()); + // panel.add(toolBar, BorderLayout.NORTH); + // panel.add(new JLabel(""), BorderLayout.CENTER); + // + // UiUtil.show("prova", panel); + // } + // }); + // } +} diff --git a/src/eu/engys/util/ui/CheckBoxPanel.java b/src/eu/engys/util/ui/CheckBoxPanel.java new file mode 100644 index 0000000..ef03fb1 --- /dev/null +++ b/src/eu/engys/util/ui/CheckBoxPanel.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Font; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.UIManager; + +import eu.engys.util.ui.builder.PanelBuilder; + +public class CheckBoxPanel extends JPanel { + + private JCheckBox titleComponent; // displayed in the titled border + + private PanelBuilder builder; + + public CheckBoxPanel(PanelBuilder builder, JCheckBox checkBox) { + this.builder = builder; + this.titleComponent = checkBox; + + layoutComponents(); + } + + private void layoutComponents() { + setLayout(new BorderLayout()); + + add(titleComponent, BorderLayout.CENTER); + add(builder.getPanel(), BorderLayout.CENTER); + + setBorder(new ComponentTitledBorder(null, titleComponent)); + + setupTitleComponent(); + placeTitleComponent(); + } + + private void placeTitleComponent() { + Insets insets = this.getInsets(); + Rectangle containerRectangle = this.getBounds(); + Rectangle componentRectangle = ((ComponentTitledBorder) getBorder()).getComponentRect(containerRectangle, insets); + titleComponent.setBounds(componentRectangle); + } + + private void setupTitleComponent() { + Font font = BorderFactory.createTitledBorder("").getTitleFont(); + Color color = BorderFactory.createTitledBorder("").getTitleColor(); + color = UIManager.getColor("TitledBorder.titleColor"); + + titleComponent.setFont(font); + titleComponent.setForeground(color); + titleComponent.setFocusable(false); + titleComponent.setContentAreaFilled(false); + + titleComponent.addActionListener(new CheckBoxPanel.EnableDisableAction()); + } + + private class EnableDisableAction implements ActionListener { + public void actionPerformed(ActionEvent e) { + builder.setEnabled(titleComponent.isSelected()); + } + } + +} diff --git a/src/eu/engys/util/ui/ChooseFileAction.java b/src/eu/engys/util/ui/ChooseFileAction.java new file mode 100644 index 0000000..2491123 --- /dev/null +++ b/src/eu/engys/util/ui/ChooseFileAction.java @@ -0,0 +1,80 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.event.ActionEvent; +import java.io.File; + +import javax.swing.AbstractAction; +import javax.swing.SwingUtilities; + +import eu.engys.util.Symbols; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.textfields.FileTextField; + +public class ChooseFileAction extends AbstractAction { + + private final FileTextField textField; + private final SelectionMode mode; + private boolean selectFile; + + ChooseFileAction(boolean selectFile, FileTextField textField, SelectionMode mode) { + super(Symbols.DOTS); + this.selectFile = selectFile; + this.textField = textField; + this.mode = mode; + } + + @Override + public void actionPerformed(ActionEvent e) { + File file = textField.getValue(); + HelyxFileChooser chooser = null; + if (selectFile) { + chooser = new HelyxFileChooser(); + chooser.selectFile(file); + } else { + if (file != null) { + chooser = new HelyxFileChooser(file.getAbsolutePath()); + } else { + chooser = new HelyxFileChooser(); + } + } + chooser.setParent(SwingUtilities.getWindowAncestor(textField)); + + if (mode != null) { + chooser.setSelectionMode(mode); + } + + ReturnValue retVal = chooser.showOpenDialog(); + if (retVal.isApprove()) { + textField.setValue(chooser.getSelectedFile()); + } + + } + +} diff --git a/src/eu/engys/util/ui/ChooserPanel.java b/src/eu/engys/util/ui/ChooserPanel.java new file mode 100644 index 0000000..d93b898 --- /dev/null +++ b/src/eu/engys/util/ui/ChooserPanel.java @@ -0,0 +1,168 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.Transient; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.AbstractButton; +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JPanel; +import javax.swing.JRadioButton; + +public class ChooserPanel extends JPanel implements ActionListener { + + public static final String NONE = "NONE"; + + private ButtonGroup buttonGroup = new ButtonGroup(); + private Map buttons = new HashMap(); + boolean propagateEnable; + + public ChooserPanel(String title, boolean propagateEnable) { + super(new GridLayout(0, 1, 2, 2)); + this.propagateEnable = propagateEnable; + if (title != null && !title.isEmpty()) { + setBorder(BorderFactory.createTitledBorder(title)); + } + } + + public ChooserPanel(String title) { + this(title, true); + } + + @Override + @Transient + public Dimension getPreferredSize() { + if (buttons.isEmpty()) { + return new Dimension(4, 4); + } + return super.getPreferredSize(); + } + + public String getSelectedState() { + if (buttonGroup.getSelection() != null) + return buttonGroup.getSelection().getActionCommand(); + else + return NONE; + } + + public boolean hasSelection() { + return buttonGroup.getSelection() != null; + } + + public void selectFirst() { + if (!buttons.isEmpty()) { + buttonGroup.getElements().nextElement().setSelected(true); + } + } + + public void select(String targetField) { + if (buttons.containsKey(targetField)) { + buttons.get(targetField).setSelected(true); + } + } + + public void unselect(String targetField) { + if (!buttons.isEmpty()) { + for (String key : buttons.keySet()) { + if (!key.equals(targetField)) { + buttons.get(key).setSelected(true); + return; + } + } + } + } + + public void selectNone() { + if (!buttons.isEmpty()) { + buttonGroup.clearSelection(); + } + } + + public void reset() { + buttonGroup.clearSelection(); + setEnabled(true); + } + + private JRadioButton createChoice(String choice, int offset) { + JRadioButton radio = new JRadioButton(choice); + radio.setName(choice); + radio.setActionCommand(choice); + radio.addActionListener(this); + radio.setBorder(BorderFactory.createEmptyBorder(0, offset, 0, 0)); + return radio; + } + + public void addChoice(String choice, int offset) { + JRadioButton radio = createChoice(choice, offset); + add(radio); + buttonGroup.add(radio); + buttons.put(choice, radio); + } + + public void addChoice(String choice) { + addChoice(choice, UiUtil.ONE_SPACE); + } + + public void addChoices(int offset, String... choices) { + JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT)); + for (String choice : choices) { + JRadioButton radio = createChoice(choice, offset); + p.add(radio); + buttonGroup.add(radio); + buttons.put(choice, radio); + } + add(p); + } + + public AbstractButton getButton(String key) { + return buttons.get(key); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() instanceof AbstractButton) { + firePropertyChange("selection", false, true); + } + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + if (propagateEnable) { + for (String key : buttons.keySet()) { + buttons.get(key).setEnabled(enabled); + } + } + } +} diff --git a/src/eu/engys/util/ui/ComponentTitledBorder.java b/src/eu/engys/util/ui/ComponentTitledBorder.java new file mode 100644 index 0000000..9f8b7ab --- /dev/null +++ b/src/eu/engys/util/ui/ComponentTitledBorder.java @@ -0,0 +1,202 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JRadioButton; +import javax.swing.border.Border; +import javax.swing.border.TitledBorder; + +/** + * Special titled border that includes a component in the title area + */ +public class ComponentTitledBorder extends TitledBorder { + JComponent component; + //Border border; + + public ComponentTitledBorder(Border border, JComponent component) { + this(border, component, LEFT, TOP); + } + + public ComponentTitledBorder(Border border, JComponent component, int titleJustification, int titlePosition) { + //TitledBorder needs border, title, justification, position, font, and color + super(border, null, titleJustification, titlePosition, null, null); + this.component = component; + if (border == null) { + this.border = super.getBorder(); + } + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + Rectangle borderR = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING, width - (EDGE_SPACING * 2), height - (EDGE_SPACING * 2)); + Insets borderInsets; + if (border != null) { + borderInsets = border.getBorderInsets(c); + } else { + borderInsets = new Insets(0, 0, 0, 0); + } + + Rectangle rect = new Rectangle(x, y, width, height); + Insets insets = getBorderInsets(c); + Rectangle compR = getComponentRect(rect, insets); + int diff; + switch (titlePosition) { + case ABOVE_TOP: + diff = compR.height + TEXT_SPACING; + borderR.y += diff; + borderR.height -= diff; + break; + case TOP: + case DEFAULT_POSITION: + diff = insets.top / 2 - borderInsets.top - EDGE_SPACING; + borderR.y += diff; + borderR.height -= diff; + break; + case BELOW_TOP: + case ABOVE_BOTTOM: + break; + case BOTTOM: + diff = insets.bottom / 2 - borderInsets.bottom - EDGE_SPACING; + borderR.height -= diff; + break; + case BELOW_BOTTOM: + diff = compR.height + TEXT_SPACING; + borderR.height -= diff; + break; + } + border.paintBorder(c, g, borderR.x, borderR.y, borderR.width, borderR.height); + Color col = g.getColor(); + g.setColor(new Color(255, 255, 255, 0)); + g.fillRect(compR.x, compR.y, compR.width, compR.height); + g.setColor(col); + } + + public Insets getBorderInsets(Component c, Insets insets) { + Insets borderInsets; + if (border != null) { + borderInsets = border.getBorderInsets(c); + } else { + borderInsets = new Insets(0, 0, 0, 0); + } + insets.top = EDGE_SPACING + TEXT_SPACING + borderInsets.top; + insets.right = EDGE_SPACING + TEXT_SPACING + borderInsets.right; + insets.bottom = EDGE_SPACING + TEXT_SPACING + borderInsets.bottom; + insets.left = EDGE_SPACING + TEXT_SPACING + borderInsets.left; + + if (c == null || component == null) { + return insets; + } + + int compHeight = component.getPreferredSize().height; + + switch (titlePosition) { + case ABOVE_TOP: + insets.top += compHeight + TEXT_SPACING; + break; + case TOP: + case DEFAULT_POSITION: + insets.top += Math.max(compHeight, borderInsets.top) - borderInsets.top; + break; + case BELOW_TOP: + insets.top += compHeight + TEXT_SPACING; + break; + case ABOVE_BOTTOM: + insets.bottom += compHeight + TEXT_SPACING; + break; + case BOTTOM: + insets.bottom += Math.max(compHeight, borderInsets.bottom) - borderInsets.bottom; + break; + case BELOW_BOTTOM: + insets.bottom += compHeight + TEXT_SPACING; + break; + } + return insets; + } + + public JComponent getTitleComponent() { + return component; + } + + public void setTitleComponent(JComponent component) { + this.component = component; + } + + public Rectangle getComponentRect(Rectangle rect, Insets borderInsets) { + Dimension compD = component.getPreferredSize(); + Rectangle compR = new Rectangle(0, 0, compD.width, compD.height); + switch (titlePosition) { + case ABOVE_TOP: + compR.y = EDGE_SPACING; + break; + case TOP: + case DEFAULT_POSITION: + if (component instanceof JButton) { + compR.y = EDGE_SPACING + (borderInsets.top - EDGE_SPACING - TEXT_SPACING - compD.height) / 2; + } else if (component instanceof JRadioButton) { + compR.y = (borderInsets.top - EDGE_SPACING - TEXT_SPACING - compD.height) / 2; + } else if (component instanceof JCheckBox) { + compR.y = (borderInsets.top - EDGE_SPACING - TEXT_SPACING - compD.height) / 2; + } + break; + case BELOW_TOP: + compR.y = borderInsets.top - compD.height - TEXT_SPACING; + break; + case ABOVE_BOTTOM: + compR.y = rect.height - borderInsets.bottom + TEXT_SPACING; + break; + case BOTTOM: + compR.y = rect.height - borderInsets.bottom + TEXT_SPACING + (borderInsets.bottom - EDGE_SPACING - TEXT_SPACING - compD.height) / 2; + break; + case BELOW_BOTTOM: + compR.y = rect.height - compD.height - EDGE_SPACING; + break; + } + switch (titleJustification) { + case LEFT: + case DEFAULT_JUSTIFICATION: + //compR.x = TEXT_INSET_H + borderInsets.left; + compR.x = TEXT_INSET_H + borderInsets.left - EDGE_SPACING; + break; + case RIGHT: + compR.x = rect.width - borderInsets.right - TEXT_INSET_H - compR.width; + break; + case CENTER: + compR.x = (rect.width - compR.width) / 2; + break; + } + return compR; + } +} diff --git a/src/eu/engys/util/ui/ComponentsFactory.java b/src/eu/engys/util/ui/ComponentsFactory.java new file mode 100644 index 0000000..095b0d4 --- /dev/null +++ b/src/eu/engys/util/ui/ComponentsFactory.java @@ -0,0 +1,445 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.util.HashMap; + +import javax.swing.ComboBoxModel; +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPasswordField; +import javax.swing.JTextArea; +import javax.swing.ListCellRenderer; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.event.ListDataListener; + +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.builder.JCheckBoxController; +import eu.engys.util.ui.builder.JComboBoxController; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.util.ui.textfields.IntegerField; +import eu.engys.util.ui.textfields.SpinnerField; +import eu.engys.util.ui.textfields.StringField; + +public class ComponentsFactory { + + public static JLabel labelField(String text) { + return new JLabel(text); + } + + public static JTextArea labelArea() { + return new JTextArea(); + } + + public static JLabel[] labelArrayField(String... strings) { + JLabel[] value = new JLabel[strings.length]; + for (int i = 0; i < value.length; i++) { + value[i] = labelField(strings[i]); + } + return value; + } + + public static JCheckBox checkField() { + JCheckBox checkBox = new JCheckBox(); + checkBox.setOpaque(false); + return checkBox; + } + + public static JCheckBox checkField(String string) { + JCheckBox checkBox = new JCheckBox(string); + checkBox.setOpaque(false); + return checkBox; + } + + public static JCheckBox checkField(boolean def) { + JCheckBox checkBox = new JCheckBox(); + checkBox.setSelected(def); + checkBox.setOpaque(false); + return checkBox; + } + + public static JCheckBox checkField(String string, boolean def) { + JCheckBox checkBox = new JCheckBox(string); + checkBox.setSelected(def); + checkBox.setOpaque(false); + return checkBox; + } + + public static JCheckBox checkField(String string, boolean def, Color color) { + JCheckBox checkBox = new JCheckBox(string); + checkBox.setSelected(def); + checkBox.setOpaque(false); + checkBox.putClientProperty("Synthetica.background", color); + checkBox.putClientProperty("Synthetica.background.alpha", UIManager.get("Synthetica.checkbox.background.alpha")); + return checkBox; + } + + public static StringField stringField() { + return new StringField(); + } + + public static StringField stringField(boolean checkEmptyStrings, boolean checkForbidden) { + return new StringField(checkEmptyStrings, checkForbidden); + } + + public static StringField stringField(String text, Integer columns) { + return new StringField(text, columns, true, true); + } + + public static StringField stringField(String text) { + return new StringField(text); + } + + public static JPasswordField passwordField() { + return new JPasswordField(20); + } + + public static SpinnerField spinnerField() { + return new SpinnerField(0, Integer.MAX_VALUE, 0); + } + + public static SpinnerField spinnerField(Integer lb, Integer ub) { + return new SpinnerField(lb, ub, Math.max(0, lb)); + } + + public static IntegerField intField() { + return new IntegerField(0, Integer.MAX_VALUE, 0); + } + + public static IntegerField intField(Integer lb, Integer ub) { + return new IntegerField(lb, ub, Math.max(0, lb)); + } + + public static IntegerField intField(Integer def) { + return new IntegerField(0, Integer.MAX_VALUE, def); + } + + public static IntegerField[] intArrayField(Integer dimensions) { + IntegerField[] value = new IntegerField[dimensions]; + for (int i = 0; i < value.length; i++) { + value[i] = intField(); + } + return value; + } + + public static DoubleField doubleField() { + return new DoubleField(-Double.MAX_VALUE, Double.MAX_VALUE, 0.0); + } + + public static DoubleField doubleField(Double def) { + return new DoubleField(-Double.MAX_VALUE, Double.MAX_VALUE, def); + } + + public static DoubleField doubleField(Integer places) { + return new DoubleField(-Double.MAX_VALUE, Double.MAX_VALUE, 0.0, places); + } + + public static DoubleField doubleField(Integer places, Double d) { + return new DoubleField(-Double.MAX_VALUE, Double.MAX_VALUE, d, places); + } + + public static DoubleField doubleField(Double lb, Double ub) { + return new DoubleField(lb, ub, lb); + } + + public static DoubleField doubleField(Double def, Double lb, Double ub) { + return new DoubleField(lb, ub, def); + } + + public static DoubleField[] doublePointField() { + return new DoubleField[] { doubleField(), doubleField(), doubleField() }; + } + + public static DoubleField[] doublePointField(Integer places) { + return new DoubleField[] { doubleField(places), doubleField(places), doubleField(places) }; + } + + public static DoubleField[] doublePointField(Double d1, Double d2, Double d3) { + return new DoubleField[] { doubleField(d1), doubleField(d2), doubleField(d3) }; + } + + public static DoubleField[] doublePointField(Double d1, Double d2, Double d3, Double lb, Double ub ) { + return new DoubleField[] { doubleField(d1, lb, ub), doubleField(d2,lb, ub), doubleField(d3, lb, ub) }; + } + + public static DoubleField[] doublePointField(Integer places, Double d) { + return new DoubleField[] { doubleField(places, d), doubleField(places, d), doubleField(places, d) }; + } + + public static DoubleField[] doubleArrayField(Integer dimensions) { + DoubleField[] value = new DoubleField[dimensions]; + for (int i = 0; i < value.length; i++) { + value[i] = doubleField(); + } + return value; + } + + public static DoubleField[] doubleArrayField(Integer dimensions, Integer places) { + DoubleField[] value = new DoubleField[dimensions]; + for (int i = 0; i < value.length; i++) { + value[i] = doubleField(places); + } + return value; + } + + public static class SelectField extends JComboBox { + + private final class SelectFieldCellRenderer implements ListCellRenderer { + + private ListCellRenderer delegate; + + private HashMap iconFromKey = new HashMap<>(); + private HashMap labelFromKey = new HashMap<>(); + + private SelectFieldCellRenderer(ListCellRenderer renderer) { + this.delegate = renderer; + } + + @Override + public Component getListCellRendererComponent(JList list, T value, int index, boolean isSelected, boolean cellHasFocus) { + delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + String text = labelFromKey.get(value); + Icon icon = iconFromKey.get(value); + + if (delegate instanceof JLabel) { + JLabel label = (JLabel) delegate; + label.setText(text); + label.setIcon(icon); + return label; + } else { + return new JLabel(text, icon, SwingConstants.LEFT); + } + } + + public void addItem(T key, String label, Icon icon) { + labelFromKey.put(key, label); + iconFromKey.put(key, icon); + } + + public void removeAllItems() { + labelFromKey.clear(); + iconFromKey.clear(); + } + } + + private SelectFieldCellRenderer renderer; + + public SelectField(T[] keys) { + this(); + for (T string : keys) { + addItem(string); + } + } + + public SelectField(T[] keys, final String[] labels, final Icon[] icons) { + this(); + for (int i = 0; i < keys.length; i++) { + addItem(keys[i], labels[i], icons[i]); + } + } + + public SelectField() { + super(); + } + + @Override + protected void fireActionEvent() { + super.fireActionEvent(); + firePropertyChange("value", null, getSelectedItem()); + } + + @Override + public void addItem(T item) { + super.addItem(item); + setMaximumRowCount(getItemCount()); + } + + public void addItem(T key, String label, Icon icon) { + addItem(key); + if (renderer == null) { + renderer = new SelectFieldCellRenderer(getRenderer()); + setRenderer(renderer); + } + renderer.addItem(key, label, icon); + } + + @Override + public void removeAllItems() { + super.removeAllItems(); + if (renderer != null) { + renderer.removeAllItems(); + } + } + } + + public static SelectField selectField() { + SelectField combo = new SelectField(); + return combo; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static JComboBox selectField(final ListBuilder builder) { + final JComboBox combo = selectField(); + combo.setModel(new ComboBoxModel() { + + private Object selected; + + @Override + public void removeListDataListener(ListDataListener l) { + } + + @Override + public int getSize() { + return builder.getSourceElements().length; + } + + @Override + public Object getElementAt(int index) { + return builder.getSourceElements()[index]; + } + + @Override + public void addListDataListener(ListDataListener l) { + } + + @Override + public void setSelectedItem(Object anItem) { + this.selected = anItem; + combo.revalidate(); + combo.repaint(); + } + + @Override + public Object getSelectedItem() { + return selected; + } + }); + return combo; + } + + public static JComboBox selectField(String... items) { + JComboBox combo = new SelectField<>(items); + return combo; + } + + public static JComboBox selectField(final String[] keys, final String[] labels) { + return selectField(keys, labels, new Icon[keys.length]); + } + + public static SelectField selectField(final String[] keys, final String[] labels, final Icon[] icons) { + SelectField combo = new SelectField<>(keys, labels, icons); + return combo; + } + + private static JComboBoxWithItemsSupport selectFieldWithItemSupport() { + JComboBoxWithItemsSupport combo = new JComboBoxWithItemsSupport() { + @Override + protected void fireActionEvent() { + super.fireActionEvent(); + firePropertyChange("value", null, getSelectedItem()); + } + }; + return combo; + } + + public static JComboBoxWithItemsSupport selectFieldWithItemSupport(final String[] items) { + JComboBoxWithItemsSupport combo = selectFieldWithItemSupport(); + for (String string : items) { + combo.addItem(string); + } + return combo; + } + + public static JComboBoxWithItemsSupport selectFieldWithItemSupport(final String[] keys, final String[] items) { + JComboBoxWithItemsSupport combo = selectFieldWithItemSupport(keys); + combo.setLabels(items); + return combo; + } + + public static JComboBoxController comboBoxControllerField() { + JComboBoxController combo = new JComboBoxController() { + @Override + protected void fireActionEvent() { + super.fireActionEvent(); + firePropertyChange("value", null, getSelectedItem()); + } + }; + return combo; + } + + public static JCheckBoxController checkBoxControllerField(String name) { + JCheckBoxController combo = new JCheckBoxController(name) { + @Override + protected void fireActionPerformed(ActionEvent event) { + super.fireActionPerformed(event); + firePropertyChange("value", null, isSelected()); + } + }; + return combo; + } + + public static RadioFieldPanel radioField(final String[] keys, final String[] items) { + RadioFieldPanel panel = new RadioFieldPanel(); + for (int i = 0; i < keys.length; i++) { + panel.addButton(items[i], keys[i]); + } + if (keys.length == 1) { + panel.select(keys[0]); + } + return panel; + } + + public static RadioFieldPanel radioField(String... items) { + RadioFieldPanel panel = new RadioFieldPanel(); + for (String string : items) { + panel.addButton(string); + } + if (items.length == 1) { + panel.select(items[0]); + } + return panel; + } + + public static ListFieldPanel listField(ListBuilder listBuilder) { + return new ListFieldPanel(listBuilder); + } + + public static FileFieldPanel fileField(SelectionMode mode, String tooltip, boolean selectFile) { + return fileField(mode, tooltip, "", selectFile); + } + + public static FileFieldPanel fileField(SelectionMode mode, String tooltip, String prompt, boolean selectFile) { + return new FileFieldPanel(mode, tooltip, prompt, selectFile); + } + +} diff --git a/src/eu/engys/util/ui/CopyPasteSupport.java b/src/eu/engys/util/ui/CopyPasteSupport.java new file mode 100644 index 0000000..a6cd33f --- /dev/null +++ b/src/eu/engys/util/ui/CopyPasteSupport.java @@ -0,0 +1,224 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.util.StringTokenizer; + +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JTable; +import javax.swing.KeyStroke; + +public class CopyPasteSupport { + + public static void addSupportTo(JTable table) { + KeyStroke copy = KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK, false); + // Identifying the copy KeyStroke user can modify this + // to copy on some other Key combination. + KeyStroke paste = KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK, false); + // Identifying the Paste KeyStroke user can modify this + // to copy on some other Key combination. + + CopyPasteListener cpl = new CopyPasteListener(table); + + table.registerKeyboardAction(cpl, "Copy", copy, JComponent.WHEN_FOCUSED); + table.registerKeyboardAction(cpl, "Paste", paste, JComponent.WHEN_FOCUSED); + + table.setColumnSelectionAllowed(true); + table.setRowSelectionAllowed(true); + } + + static class CopyPasteListener implements ActionListener { + + private JTable table; + + public CopyPasteListener(JTable table) { + this.table = table; + } + + @Override + public void actionPerformed(ActionEvent e) { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + + if (e.getActionCommand().equals("Copy")) { + StringBuffer sbf = new StringBuffer(); + // Check to ensure we have selected only a contiguous block of + // cells + int numcols = table.getSelectedColumnCount(); + int numrows = table.getSelectedRowCount(); + + int[] rowsselected = table.getSelectedRows(); + int[] colsselected = table.getSelectedColumns(); + if (!((numrows - 1 == rowsselected[rowsselected.length - 1] - rowsselected[0] && numrows == rowsselected.length) && (numcols - 1 == colsselected[colsselected.length - 1] + - colsselected[0] && numcols == colsselected.length))) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Invalid Copy Selection", "Invalid Copy Selection", JOptionPane.ERROR_MESSAGE); + return; + } + for (int i = 0; i < numrows; i++) { + for (int j = 0; j < numcols; j++) { + sbf.append(table.getValueAt(rowsselected[i], colsselected[j])); + if (j < numcols - 1) + sbf.append("\t"); + } + sbf.append("\n"); + } + StringSelection stsel = new StringSelection(sbf.toString()); + + clipboard.setContents(stsel, stsel); + } + if (e.getActionCommand().equals("Paste")) { + System.out.println("Trying to Paste"); + int[] selRows = table.getSelectedRows(); + int[] selCols = table.getSelectedColumns(); + + int startRow = selRows[0]; + int startCol = selCols[0]; + + try { + String copiedString = (String) clipboard.getContents(this).getTransferData(DataFlavor.stringFlavor); + System.out.println("String is:" + copiedString); + + String[][] data = stringToArray(copiedString); + TypeOfCopy type = decodeTypeOfCopy(data, selRows, selCols); + + if (type == TypeOfCopy.ERROR) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Invalid Paste Selection", "Invalid Paste Selection", JOptionPane.ERROR_MESSAGE); + } else { + System.out.println(String.format("Paste %d x %d -> %d x %d", data.length, data[0].length, selRows.length, selCols.length)); + switch (type) { + case CELL: + for (int i = 0; i < selRows.length; i++) { + for (int j = 0; j < selCols.length; j++) { + table.setValueAt(getEditedValue(data[0][0]), selRows[i], selCols[j]); + } + } + break; + + case ROW: + for (int i = 0; i < selRows.length; i++) { + for (int j = 0; j < selCols.length; j++) { + table.setValueAt(getEditedValue(data[0][j]), selRows[i], selCols[j]); + } + } + break; + + case COLUMN: + for (int i = 0; i < selRows.length; i++) { + for (int j = 0; j < selCols.length; j++) { + table.setValueAt(getEditedValue(data[j][0]), selRows[i], selCols[j]); + } + } + break; + + case MATRIX: + for (int i = 0; i < selRows.length; i++) { + for (int j = 0; j < selCols.length; j++) { + table.setValueAt(getEditedValue(data[i][j]), selRows[i], selCols[j]); + } + } + break; + + default: + break; + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + private Object getEditedValue(String string) { + // Class klass = table.getModel().getColumnClass(col); + // System.out.println("CopyPasteSupport.CopyPasteListener.getEditedValue() "+klass); + try { + return Double.valueOf(string); + } catch (NumberFormatException e) { + return 0; + } + // Object value; + + // if (klass.isInstance(Double.class)) { + // value = Double.valueOf(string); + // } else { + // value = string; + // } + } + + enum TypeOfCopy { + CELL, ROW, COLUMN, MATRIX, ERROR + } + + private TypeOfCopy decodeTypeOfCopy(String[][] data, int[] selRows, int[] selCols) { + if (data != null) { + if (data.length == 1) { + if (data[0].length == 1) { + return TypeOfCopy.CELL; + } else if (data[0].length == selCols.length) { + return TypeOfCopy.ROW; + } else { + return TypeOfCopy.ERROR; + } + } else if (data.length == selRows.length) { + if (data[0].length == 1) { + return TypeOfCopy.COLUMN; + } else if (data[0].length == selCols.length) { + return TypeOfCopy.MATRIX; + } else { + return TypeOfCopy.ERROR; + } + } else { + return TypeOfCopy.ERROR; + } + } else { + return TypeOfCopy.ERROR; + } + } + + private String[][] stringToArray(String copiedString) { + StringTokenizer rowTokenizer = new StringTokenizer(copiedString, "\n"); + String[][] data = new String[rowTokenizer.countTokens()][]; + for (int i = 0; rowTokenizer.hasMoreTokens(); i++) { + String rowstring = rowTokenizer.nextToken(); + StringTokenizer colTokenizer = new StringTokenizer(rowstring, "\t"); + data[i] = new String[colTokenizer.countTokens()]; + for (int j = 0; colTokenizer.hasMoreTokens(); j++) { + String value = (String) colTokenizer.nextToken(); + data[i][j] = value; + } + } + return data; + } + } +} diff --git a/src/eu/engys/util/ui/DoubleListAction.java b/src/eu/engys/util/ui/DoubleListAction.java new file mode 100644 index 0000000..3189e17 --- /dev/null +++ b/src/eu/engys/util/ui/DoubleListAction.java @@ -0,0 +1,116 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import eu.engys.util.Symbols; + +public class DoubleListAction extends AbstractAction { + + private final ListFieldPanel listField; + private final ListBuilder listBuilder; + + private JDialog dialog; + private DualList dual; + + DoubleListAction(ListFieldPanel listField, ListBuilder listBuilder) { + super(Symbols.DOTS); + this.listField = listField; + this.listBuilder = listBuilder; + } + + public void actionPerformed(ActionEvent e) { + if (dialog == null) { + dialog = new JDialog(SwingUtilities.getWindowAncestor(listField), listBuilder.getTitle()); + dialog.setName("dual.list.dialog"); + dialog.setModal(true); + dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); + dialog.setSize(400, 300); + dialog.setLocationRelativeTo(listField); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.setBorder(UiUtil.getStandardBorder()); + + dual = new DualList(); + + ArrayList buttons = new ArrayList(); + JButton okButton = new JButton(new AbstractAction("OK") { + @Override + public void actionPerformed(ActionEvent e) { + listField.setValues(dual.getDestinationElements()); + dialog.setVisible(false); + } + }); + okButton.setName("OK"); + buttons.add(okButton); + + JButton cancelButton = new JButton(new AbstractAction("Cancel") { + @Override + public void actionPerformed(ActionEvent e) { + dialog.setVisible(false); + } + }); + cancelButton.setName("Cancel"); + buttons.add(cancelButton); + + JComponent buttonsPanel = UiUtil.getCommandRow(buttons); + + mainPanel.add(dual, BorderLayout.CENTER); + mainPanel.add(buttonsPanel, BorderLayout.SOUTH); + + dialog.getContentPane().add(mainPanel); + dialog.getRootPane().setDefaultButton(okButton); + } + + String[] destination = listField.getValues(); + String[] source = listBuilder.getSourceElements(); + + String[] sourceMinusAlreadyPresent = new String[source.length - destination.length]; + int j = 0; + List destinationList = Arrays.asList(destination); + for (int i = 0; i < source.length; i++) { + if (!destinationList.contains(source[i])) { + sourceMinusAlreadyPresent[j++] = source[i]; + } + } + dual.setSourceElements(sourceMinusAlreadyPresent); + dual.setDestinationElements(destination); + + dialog.setVisible(true); + } +} diff --git a/src/eu/engys/util/ui/DualList.java b/src/eu/engys/util/ui/DualList.java new file mode 100644 index 0000000..63dfe22 --- /dev/null +++ b/src/eu/engys/util/ui/DualList.java @@ -0,0 +1,258 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.swing.AbstractListModel; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ListModel; + +public class DualList extends JPanel { + private JList sourceList; + private SortedListModel sourceListModel; + + private JList destList; + private SortedListModel destListModel; + + private JButton addButton; + private JButton removeButton; + + public DualList() { + layoutComponents(); + } + + private void layoutComponents() { + setLayout(new GridBagLayout()); + sourceListModel = new SortedListModel(); + sourceList = new JList<>(sourceListModel); + sourceList.setName("source.list"); + + addButton = new JButton(">>"); + addButton.setName(">>"); + addButton.addActionListener(new AddListener()); + removeButton = new JButton("<<"); + removeButton.setName("<<"); + removeButton.addActionListener(new RemoveListener()); + + destListModel = new SortedListModel(); + destList = new JList<>(destListModel); + destList.setName("dest.list"); + + JPanel leftPanel = new JPanel(new BorderLayout()); + leftPanel.add(new JLabel("Available Elements:"), BorderLayout.NORTH); + leftPanel.add(new JScrollPane(sourceList), BorderLayout.CENTER); + + JPanel rightPanel = new JPanel(new BorderLayout()); + rightPanel.add(new JLabel("Selected Elements:"), BorderLayout.NORTH); + rightPanel.add(new JScrollPane(destList), BorderLayout.CENTER); + + JPanel centerPanel = new JPanel(); + centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); + centerPanel.add(Box.createVerticalGlue()); + centerPanel.add(addButton); + centerPanel.add(removeButton); + centerPanel.add(Box.createVerticalGlue()); + + add(leftPanel, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + add(centerPanel, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 4, 0, 4), 0, 0)); + add(rightPanel, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + } + + /* + * SOURCE + */ + + public void setSourceElements(Object newValue[]) { + sourceListModel.clear(); + sourceListModel.addAll(newValue); + } + + private void addSourceElements(ListModel newValue) { + int size = newValue.getSize(); + for (int i = 0; i < size; i++) { + System.out.println("DualList.addSourceElements(): " + newValue.getElementAt(i)); + sourceListModel.add(newValue.getElementAt(i)); + } + } + + @SuppressWarnings("deprecation") + private void clearSourceSelected() { + Object selected[] = sourceList.getSelectedValues(); + for (int i = selected.length - 1; i >= 0; --i) { + sourceListModel.removeElement(selected[i]); + } + sourceList.getSelectionModel().clearSelection(); + } + + /* + * DESTINATION + */ + + public void setDestinationElements(Object newValue[]) { + destListModel.clear(); + destListModel.addAll(newValue); + } + + public String[] getDestinationElements() { + String[] elements = new String[destListModel.model.size()]; + int i = 0; + for (Iterator it = destListModel.iterator(); it.hasNext();) { + elements[i++] = (String) it.next(); + } + return elements; + } + + @SuppressWarnings("deprecation") + private void clearDestinationSelected() { + Object selected[] = destList.getSelectedValues(); + for (int i = selected.length - 1; i >= 0; --i) { + destListModel.removeElement(selected[i]); + } + destList.getSelectionModel().clearSelection(); + } + + /* + * OTHER + */ + + @SuppressWarnings("deprecation") + private class AddListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + Object selected[] = sourceList.getSelectedValues(); + destListModel.addAll(selected); + clearSourceSelected(); + } + } + + @SuppressWarnings("deprecation") + private class RemoveListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + Object selected[] = destList.getSelectedValues(); + sourceListModel.addAll(selected); + clearDestinationSelected(); + } + } + + public static void main(String args[]) { + JFrame frame = new JFrame("Dual List Box Tester"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + DualList dual = new DualList(); + List model = new ArrayList<>(); + model.add("One"); + model.add("Two"); + model.add("Three"); + model.add("Four"); + model.add("Five"); + model.add("Six"); + model.add("Seven"); + model.add("Eight"); + model.add("Nine"); + model.add("Ten"); + dual.setSourceElements(model.toArray(new String[0])); + frame.add(dual, BorderLayout.CENTER); + frame.setSize(400, 300); + frame.setVisible(true); + } + + private class SortedListModel extends AbstractListModel { + SortedSet model; + + public SortedListModel() { + model = new TreeSet(); + } + + public int getSize() { + return model.size(); + } + + public Object getElementAt(int index) { + return model.toArray()[index]; + } + + public void add(Object element) { + if (model.add(element)) { + fireContentsChanged(this, 0, getSize()); + } + } + + public void addAll(Object elements[]) { + Collection c = Arrays.asList(elements); + model.addAll(c); + fireContentsChanged(this, 0, getSize()); + } + + public void clear() { + model.clear(); + fireContentsChanged(this, 0, getSize()); + } + + public boolean contains(Object element) { + return model.contains(element); + } + + public Object firstElement() { + return model.first(); + } + + public Iterator iterator() { + return model.iterator(); + } + + public Object lastElement() { + return model.last(); + } + + public boolean removeElement(Object element) { + boolean removed = model.remove(element); + if (removed) { + fireContentsChanged(this, 0, getSize()); + } + return removed; + } + } + +} diff --git a/src/eu/engys/util/ui/ExecUtil.java b/src/eu/engys/util/ui/ExecUtil.java new file mode 100644 index 0000000..bbecce6 --- /dev/null +++ b/src/eu/engys/util/ui/ExecUtil.java @@ -0,0 +1,91 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.swing.SwingUtilities; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExecUtil { + + private static final Logger logger = LoggerFactory.getLogger(ExecUtil.class); + + public static void invokeLater(Runnable runnable) { + if (SwingUtilities.isEventDispatchThread()) { + runnable.run(); + } else { + SwingUtilities.invokeLater(runnable); + } + } + + public static void invokeAndWait(Runnable runnable) { + if (SwingUtilities.isEventDispatchThread()) { + runnable.run(); + } else { + try { + SwingUtilities.invokeAndWait(runnable); + } catch (InvocationTargetException | InterruptedException e) { + e.printStackTrace(); + } + } + } + + public static void execSerial(Runnable... runnables) { + for (Runnable runnable : runnables) { + runnable.run(); + } + } + + public static void execParallelAndWait(Runnable... runnables) { + if (runnables.length > 0) { + ExecutorService service = createParallelExecutor(runnables.length); + for (Runnable runnable : runnables) { + service.submit(runnable); + } + awaitTermination(service); + } + } + + public static ExecutorService createParallelExecutor(int np) { + return Executors.newFixedThreadPool(np); + } + + public static void awaitTermination(ExecutorService service) { + service.shutdown(); + try { + service.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); + } catch (InterruptedException e) { + logger.error("Thread interrupted", e); + } + } + +} diff --git a/src/eu/engys/util/ui/FileChooserUtils.java b/src/eu/engys/util/ui/FileChooserUtils.java new file mode 100644 index 0000000..2817a9e --- /dev/null +++ b/src/eu/engys/util/ui/FileChooserUtils.java @@ -0,0 +1,134 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.io.File; + +import javax.swing.JOptionPane; + +import org.apache.commons.io.FilenameUtils; + +import eu.engys.util.PrefUtil; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.util.HelyxFileFilter; +import eu.engys.util.filechooser.util.SelectionMode; + +public class FileChooserUtils { + + public static final String PDF_EXTENSION = "pdf"; + public static final String PNG_EXTENSION = "png"; + public static final String CSV_EXTENSION = "csv"; + public static final String EXCEL_EXTENSION_OLD = "xls"; + public static final String EXCEL_EXTENSION_NEW = "xlsx"; + + public static final String DEFAULT_SSH_PORT = "22"; + + public static File getPNGFile() { + File lastDir = PrefUtil.getWorkDir(PrefUtil.LAST_OPEN_EXPORT_DIR); + + HelyxFileChooser fc = new HelyxFileChooser(lastDir.getAbsolutePath()); + fc.setSelectionMode(SelectionMode.FILES_ONLY); + HelyxFileFilter filter = new HelyxFileFilter("PNG File (*.png)", PNG_EXTENSION); + File file = null; + ReturnValue retVal = fc.showSaveAsDialog(filter); + + if (retVal.isApprove()) { + file = fc.getSelectedFile(); + String extension = FilenameUtils.getExtension(file.getAbsolutePath()); + + if (!extension.equalsIgnoreCase(PNG_EXTENSION)) { + file = new File(file.getParent(), file.getName() + "." + PNG_EXTENSION); + } + + if (file.exists()) { + int confirm = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "File already exists. Overwrite?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (confirm == JOptionPane.NO_OPTION) { + return getPNGFile(); + } + } + PrefUtil.putFile(PrefUtil.LAST_OPEN_EXPORT_DIR, file.getParentFile()); + } + return file; + } + + public static File getExcelFile() { + File lastDir = PrefUtil.getWorkDir(PrefUtil.LAST_OPEN_EXPORT_DIR); + + HelyxFileChooser fc = new HelyxFileChooser(lastDir.getAbsolutePath()); + fc.setSelectionMode(SelectionMode.FILES_ONLY); + HelyxFileFilter filter = new HelyxFileFilter("Excel File (*.xls, *.xlsx)", EXCEL_EXTENSION_OLD, EXCEL_EXTENSION_NEW); + File file = null; + ReturnValue retVal = fc.showSaveAsDialog(filter); + + if (retVal.isApprove()) { + file = fc.getSelectedFile(); + String extension = FilenameUtils.getExtension(file.getAbsolutePath()); + + if (!extension.equalsIgnoreCase(EXCEL_EXTENSION_OLD) && !extension.equalsIgnoreCase(EXCEL_EXTENSION_NEW)) { + file = new File(file.getParent(), file.getName() + "." + EXCEL_EXTENSION_OLD); + } + + if (file.exists()) { + int confirm = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "File already exists. Overwrite?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (confirm == JOptionPane.NO_OPTION) { + return getPNGFile(); + } + } + PrefUtil.putFile(PrefUtil.LAST_OPEN_EXPORT_DIR, file.getParentFile()); + } + return file; + } + + public static File getCSVFile() { + File lastDir = PrefUtil.getWorkDir(PrefUtil.LAST_OPEN_EXPORT_DIR); + + HelyxFileChooser fc = new HelyxFileChooser(lastDir.getAbsolutePath()); + fc.setSelectionMode(SelectionMode.FILES_ONLY); + HelyxFileFilter filter = new HelyxFileFilter("CSV File (*.csv)", CSV_EXTENSION); + File file = null; + ReturnValue retVal = fc.showSaveAsDialog(filter); + + if (retVal.isApprove()) { + file = fc.getSelectedFile(); + String extension = FilenameUtils.getExtension(file.getAbsolutePath()); + + if (!extension.equalsIgnoreCase(CSV_EXTENSION)) { + file = new File(file.getParent(), file.getName() + "." + CSV_EXTENSION); + } + + if (file.exists()) { + int confirm = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "File already exists. Overwrite?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (confirm == JOptionPane.NO_OPTION) { + return getPNGFile(); + } + } + PrefUtil.putFile(PrefUtil.LAST_OPEN_EXPORT_DIR, file.getParentFile()); + } + return file; + } + +} diff --git a/src/eu/engys/util/ui/FileFieldPanel.java b/src/eu/engys/util/ui/FileFieldPanel.java new file mode 100644 index 0000000..0bc2d08 --- /dev/null +++ b/src/eu/engys/util/ui/FileFieldPanel.java @@ -0,0 +1,108 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.beans.PropertyChangeListener; +import java.io.File; + +import javax.swing.JButton; +import javax.swing.JPanel; + +import eu.engys.util.filechooser.util.SelectionMode; +import eu.engys.util.ui.textfields.FileTextField; + +public class FileFieldPanel extends JPanel { + private FileTextField textField; + private JButton button; + + public FileFieldPanel(SelectionMode mode, String tooltip, String prompt, boolean selectFile) { + super(new BorderLayout(4, 4)); + setOpaque(false); + + textField = new FileTextField(); + textField.setEditable(false); + textField.setFocusable(false); + textField.setToolTipText(tooltip); + textField.setPrompt(prompt); + + button = createButtonFileChooser(selectFile, textField, mode); + add(textField, BorderLayout.CENTER); + add(button, BorderLayout.EAST); + } + + @Override + public void setName(String name) { + super.setName(name); + textField.setName(name + ".text"); + button.setName(name + ".button"); + } + + public boolean hasExistingFile() { + return textField.getText().isEmpty() || textField.hasValidFile(); + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + if (textField != null) + textField.addPropertyChangeListener(listener); + } + + public String getFilePath() { + File file = textField.getValue(); + return file != null ? file.getPath() : ""; + } + + public void setFilePath(String path) { + textField.setValue(new File(path == null ? "" : path)); + } + + public File getFile() { + return textField.getValue(); + } + + public void setFile(File file) { + textField.setValue(file); + } + + private JButton createButtonFileChooser(boolean selectFile, FileTextField textField, SelectionMode mode) { + JButton button = new JButton(new ChooseFileAction(selectFile, textField, mode)); + Dimension prefSize = button.getPreferredSize(); + button.setPreferredSize(new Dimension(24, prefSize.height)); + return button; + } + + public FileTextField getTextField() { + return textField; + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + button.setEnabled(enabled); + } +} diff --git a/src/eu/engys/util/ui/JComboBoxWithItemsSupport.java b/src/eu/engys/util/ui/JComboBoxWithItemsSupport.java new file mode 100644 index 0000000..8609844 --- /dev/null +++ b/src/eu/engys/util/ui/JComboBoxWithItemsSupport.java @@ -0,0 +1,121 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.awt.Component; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +public class JComboBoxWithItemsSupport extends JComboBox implements ItemListener { + + private Map itemFromKey = new HashMap(); + private List disabledIndexes = new ArrayList(); + + public JComboBoxWithItemsSupport() { + super(); + final ListCellRenderer renderer = getRenderer(); + setRenderer(new ListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, String value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + + if (c instanceof JLabel) { + JLabel label = (JLabel) c; + String key = value; + label.setText(itemFromKey.containsKey(key) ? itemFromKey.get(key) : key); + + if (disabledIndexes.contains(index)) { + label.setFocusable(false); + label.setEnabled(false); + if (isSelected) + label.setBackground(list.getBackground()); + } else { + label.setFocusable(true); + label.setEnabled(true); + } + } + + return c; + } + }); + addItemListener(this); + } + + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getSource() instanceof JComboBox && e.getStateChange() == ItemEvent.SELECTED) { + JComboBox combo = (JComboBox) e.getSource(); + int index = combo.getSelectedIndex(); + if (disabledIndexes.contains(index)) { + combo.setSelectedIndex(-1); + } + } + } + + @Override + public void setSelectedIndex(int index) { + if (disabledIndexes.contains(index)) { + super.setSelectedIndex(-1); + } else { + super.setSelectedIndex(index); + } + } + + public boolean isDisabledAt(int index){ + return disabledIndexes.contains(index); + } + +// private void addDisabledIndex(int index) { +// disabledIndexes.add(index); +// } + + public void addDisabledItem(String item) { + int itemIndex = ((DefaultComboBoxModel) getModel()).getIndexOf(item); + disabledIndexes.add(itemIndex); + } + + public void clearDisabledIndexes() { + disabledIndexes.clear(); + } + + public void setLabels(String[] labels) { + for (int i = 0; i < getItemCount(); i++) { + itemFromKey.put(getItemAt(i), labels[i]); + } + } + +} diff --git a/src/eu/engys/util/ui/ListBuilder.java b/src/eu/engys/util/ui/ListBuilder.java new file mode 100644 index 0000000..c357c40 --- /dev/null +++ b/src/eu/engys/util/ui/ListBuilder.java @@ -0,0 +1,37 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +public interface ListBuilder { + public static int SINGLE_SELECTION = 0; + public static int MULTIPLE_SELECTION = 0; + + public int getSelectionMode(); + + public String[] getSourceElements(); + + public String getTitle(); +} diff --git a/src/eu/engys/util/ui/ListFieldPanel.java b/src/eu/engys/util/ui/ListFieldPanel.java new file mode 100644 index 0000000..a84f701 --- /dev/null +++ b/src/eu/engys/util/ui/ListFieldPanel.java @@ -0,0 +1,99 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.beans.PropertyChangeListener; + +import javax.swing.JButton; +import javax.swing.JPanel; + +import eu.engys.util.ui.textfields.StringField; + +public class ListFieldPanel extends JPanel { + private StringField textField; + private JButton button; + + public ListFieldPanel(ListBuilder listBuilder) { + super(new BorderLayout(4, 4)); + setName("list.field.panel"); + + textField = new StringField(); + textField.setName("field"); + textField.setColumns(20); + textField.setEnabled(false); + + button = createButtonDoubleList(listBuilder); + button.setName("button"); + add(textField, BorderLayout.CENTER); + add(button, BorderLayout.EAST); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + // textField.setEnabled(enabled); + button.setEnabled(enabled); + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + if (textField != null) + textField.addPropertyChangeListener(listener); + } + + private JButton createButtonDoubleList(ListBuilder listBuilder) { + JButton button = new JButton(new DoubleListAction(this, listBuilder)); + Dimension prefSize = button.getPreferredSize(); + button.setPreferredSize(new Dimension(24, prefSize.height)); + return button; + } + + public String[] getValues() { + String text = textField.getText().trim(); + if (text.length() == 0) + return new String[0]; + else + return text.split("\\s+"); + } + + public void setValues(String[] values) { + StringBuilder sb = new StringBuilder(); + for (String string : values) { + sb.append(string + " "); + } + textField.setValue(sb.toString()); + } + + @Override + public void setToolTipText(String text) { + super.setToolTipText(text); + button.setToolTipText(text); + textField.setToolTipText(text); + } + +} diff --git a/src/eu/engys/util/ui/NoneSelectedButtonGroup.java b/src/eu/engys/util/ui/NoneSelectedButtonGroup.java new file mode 100644 index 0000000..17da3a7 --- /dev/null +++ b/src/eu/engys/util/ui/NoneSelectedButtonGroup.java @@ -0,0 +1,40 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import javax.swing.ButtonGroup; +import javax.swing.ButtonModel; + +public class NoneSelectedButtonGroup extends ButtonGroup { + @Override + public void setSelected(ButtonModel model, boolean selected) { + if (selected) { + super.setSelected(model, selected); + } else { + clearSelection(); + } + } + } diff --git a/src/eu/engys/util/ui/RadioFieldPanel.java b/src/eu/engys/util/ui/RadioFieldPanel.java new file mode 100644 index 0000000..0634bbb --- /dev/null +++ b/src/eu/engys/util/ui/RadioFieldPanel.java @@ -0,0 +1,113 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Enumeration; + +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; +import javax.swing.ButtonModel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; + +public class RadioFieldPanel extends JPanel implements ActionListener { + + public static final String PROPERTY_NAME = "value"; + private ButtonGroup bg = new ButtonGroup(); + + public RadioFieldPanel() { + super(new GridLayout(0, 1)); + setOpaque(false); + } + + public void addButton(String string) { + JRadioButton button = new JRadioButton(string); + button.setName(string); + button.setActionCommand(string); + button.addActionListener(this); + bg.add(button); + add(button); + } + + public void addButton(String string, String actionCommand) { + JRadioButton button = new JRadioButton(string); + button.setName(string); + button.setActionCommand(actionCommand); + button.addActionListener(this); + bg.add(button); + add(button); + } + + @Override + public void actionPerformed(ActionEvent e) { + firePropertyChange(PROPERTY_NAME, "", e.getActionCommand()); + } + + public String getSelectedKey() { + return bg.getSelection() != null ? bg.getSelection().getActionCommand() : null; + } + + public String getSelectedItem() { + return bg.getSelection() != null ? getButton(bg.getSelection()).getText() : null; + } + + private AbstractButton getButton(ButtonModel bm) { + for (Enumeration e = bg.getElements(); e.hasMoreElements();) { + AbstractButton b = e.nextElement(); + if (b.getModel().equals(bm)) { + return b; + } + } + return null; + } + + public void select(String actionCommand) { + for (Enumeration e = bg.getElements(); e.hasMoreElements();) { + AbstractButton b = e.nextElement(); + if (b.getActionCommand().equals(actionCommand)) { + bg.setSelected(b.getModel(), true); + return; + } + } + } + + public int getButtonCount() { + return bg.getButtonCount(); + } + + public void doClick(String actionCommand) { + for (Enumeration e = bg.getElements(); e.hasMoreElements();) { + AbstractButton b = e.nextElement(); + if (b.getActionCommand().equals(actionCommand)) { + b.doClick(); + return; + } + } + } +} diff --git a/src/eu/engys/util/ui/ResourcesUtil.java b/src/eu/engys/util/ui/ResourcesUtil.java new file mode 100644 index 0000000..c055067 --- /dev/null +++ b/src/eu/engys/util/ui/ResourcesUtil.java @@ -0,0 +1,113 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.net.URL; +import java.util.Enumeration; +import java.util.ResourceBundle; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import org.slf4j.LoggerFactory; + +public final class ResourcesUtil { + + private static final ResourceBundle bundle = getBundle("eu/engys/resources/bundle"); + private static final ClassLoader loader = ResourcesUtil.class.getClassLoader(); + + private static final Icon EMPTY_ICON = new ImageIcon(new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB) { + { + Graphics2D g = createGraphics(); + g.setColor(Color.RED); + g.fillRect(0, 0, 16, 16); + } + }); + + public static String getString(String key) { + try { + return bundle.getString(key); + } catch (Exception e) { + LoggerFactory.getLogger(ResourcesUtil.class).warn(e.getMessage()); + return "MISSING"; + } + } + + private static ResourceBundle getBundle(String string) { + try { + return ResourceBundle.getBundle(string); + } catch (Exception e) { + return new ResourceBundle() { + + @Override + protected Object handleGetObject(String key) { + return null; + } + + @Override + public Enumeration getKeys() { + return null; + } + + }; + } + } + + public static Icon getResourceIcon(String path) { + URL resource = ResourcesUtil.class.getClassLoader().getResource(path); + if (resource == null) { + return EMPTY_ICON; + } else { + return new ImageIcon(resource); + } + } + + public static Icon getIcon(String key) { + try { + String path = bundle.getString(key); + URL res = loader.getResource(path); + return new ImageIcon(res); + } catch (Exception e) { + LoggerFactory.getLogger(ResourcesUtil.class).warn(e.getMessage()); + return EMPTY_ICON; + } + } + + public static URL getIconURL(String key) { + try { + String path = bundle.getString(key); + URL res = loader.getResource(path); + return res; + } catch (Exception e) { + LoggerFactory.getLogger(ResourcesUtil.class).warn(e.getMessage()); + return null; + } + } +} diff --git a/src/eu/engys/util/ui/ScriptEditor.java b/src/eu/engys/util/ui/ScriptEditor.java new file mode 100644 index 0000000..44097c7 --- /dev/null +++ b/src/eu/engys/util/ui/ScriptEditor.java @@ -0,0 +1,367 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dialog.ModalityType; +import java.awt.FlowLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.SwingConstants; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.DefaultEditorKit; + +import org.apache.commons.io.FileUtils; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.fife.ui.rtextarea.RTextScrollPane; + +import eu.engys.util.IOUtils; +import eu.engys.util.PrefUtil; +import eu.engys.util.Util; +import eu.engys.util.filechooser.AbstractFileChooser.ReturnValue; +import eu.engys.util.filechooser.HelyxFileChooser; +import eu.engys.util.filechooser.util.SelectionMode; + +public class ScriptEditor { + + public enum Syntax { + BASH, BATCH, PYTHON, JAVA, C + }; + + public static final String BAT_COMMENT = "rem "; + public static final String SHELL_COMMENT = "# "; + + private static ScriptEditor instance; + + private JDialog dialog; + private RSyntaxTextArea editor; + private DocumentListener documentListener; + + private File file; + private List defaultScript; + private boolean modified; + private JButton okButton; + + public static ScriptEditor getInstance() { + if (instance == null) + instance = new ScriptEditor(); + return instance; + } + + private ScriptEditor() { + initEditor(); + initListeners(); + } + + private void initEditor() { + this.editor = new RSyntaxTextArea(); + // End of line is changed in save method + // This is used to split text in lines + editor.getDocument().putProperty(DefaultEditorKit.EndOfLineStringProperty, IOUtils.EOL); + editor.setCodeFoldingEnabled(true); + editor.setAntiAliasingEnabled(true); + editor.setBackground(new Color(240, 240, 240)); + editor.setName("codeEditor"); + } + + private void initListeners() { + documentListener = new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + documentModified(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + documentModified(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + documentModified(); + } + }; + } + + private void documentModified() { + if (!modified) { + if (dialog != null) { + dialog.setTitle("*" + dialog.getTitle()); + this.modified = true; + } + } + } + + public void show(Syntax syntax, Path scriptPath, List defaultScript) { + String style = ""; + switch (syntax) { + case BASH: + style = SyntaxConstants.SYNTAX_STYLE_UNIX_SHELL; + break; + case BATCH: + style = SyntaxConstants.SYNTAX_STYLE_WINDOWS_BATCH; + break; + case PYTHON: + style = SyntaxConstants.SYNTAX_STYLE_PYTHON; + break; + case C: + style = SyntaxConstants.SYNTAX_STYLE_C; + break; + case JAVA: + style = SyntaxConstants.SYNTAX_STYLE_JAVA; + break; + + default: + break; + } + editor.setSyntaxEditingStyle(style); + show(scriptPath, defaultScript); + } + + public void show(Path scriptPath, List defaultScript) { + this.defaultScript = defaultScript; + this.file = scriptPath != null ? scriptPath.toFile() : null; + this.editor.setSyntaxEditingStyle(Util.isWindowsScriptStyle() ? SyntaxConstants.SYNTAX_STYLE_WINDOWS_BATCH : SyntaxConstants.SYNTAX_STYLE_UNIX_SHELL); + ExecUtil.invokeAndWait(new Runnable() { + + @Override + public void run() { + initDialog(); + load(); + dialog.setVisible(true); + } + }); + } + + private void initDialog() { + dialog = new JDialog(UiUtil.getActiveWindow(), ModalityType.MODELESS); + dialog.setName("script.editor.dialog"); + dialog.getContentPane().setLayout(new BorderLayout()); + dialog.getContentPane().add(createMainPanel(), BorderLayout.CENTER); + dialog.getContentPane().add(createButtonsPanel(), BorderLayout.SOUTH); + dialog.getContentPane().doLayout(); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + closeDialog(); + } + }); + + dialog.setSize(800, 600); + dialog.setLocationRelativeTo(null); + dialog.getRootPane().setDefaultButton(okButton); + } + + private JPanel createMainPanel() { + RTextScrollPane sp = new RTextScrollPane(editor); + sp.setFoldIndicatorEnabled(true); + sp.setBorder(BorderFactory.createEmptyBorder()); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(sp); + return mainPanel; + } + + private JPanel createButtonsPanel() { + JPanel panel = new JPanel(new GridLayout(1, 2)); + JPanel leftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JButton resetButton = new JButton(new ResetAction()); + resetButton.setName("reset"); + leftPanel.add(resetButton); + JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + okButton = new JButton(new OKAction()); + okButton.setName("OK"); + rightPanel.add(okButton); + + JButton cancelButton = new JButton(new CancelAction()); + cancelButton.setName("cancel"); + rightPanel.add(cancelButton); + + panel.add(leftPanel); + panel.add(rightPanel); + + JPanel buttonsPanel = new JPanel(new BorderLayout()); + buttonsPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.NORTH); + buttonsPanel.add(panel, BorderLayout.CENTER); + + return buttonsPanel; + } + + private void closeDialog() { + dialog.setVisible(false); + dialog.dispose(); + dialog = null; + } + + private void load() { + editor.getDocument().removeDocumentListener(documentListener); + if (file != null && file.exists()) { + try { + // IOUtils.loadFromFile(editor, file, null, Charset.defaultCharset()); + editor.setText(IOUtils.readStringFromFile(file)); + editor.setCaretPosition(0); + } catch (Exception e) { + e.printStackTrace(); + } + dialog.setTitle(file.getAbsolutePath()); + } else { + editor.setText(""); + dialog.setTitle("newScript"); + } + editor.getDocument().addDocumentListener(documentListener); + this.modified = false; + } + + private void save() { + if (file != null && file.exists()) { + try { + IOUtils.writeStringToFile(file, editor.getText()); + } catch (Exception e) { + e.printStackTrace(); + } + dialog.setTitle(file.getAbsolutePath()); + } else { + saveAs(); + } + } + + private void saveAs() { + File lastDir = PrefUtil.getWorkDir(PrefUtil.WORK_DIR); + HelyxFileChooser fc = new HelyxFileChooser(lastDir.getAbsolutePath()); + fc.setParent(dialog); + fc.setSelectionMode(SelectionMode.FILES_ONLY); + ReturnValue retVal = fc.showSaveAsDialog(); + if (retVal.isApprove()) { + File file = fc.getSelectedFile(); + if (file != null) { + if (file.exists()) { + int answer = JOptionPane.showConfirmDialog(UiUtil.getActiveWindow(), "File already exists. Overwrite?", "File Overwrite", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (answer == JOptionPane.YES_OPTION) { + setFile(file); + save(); + } + } else { + try { + file.createNewFile(); + setFile(file); + save(); + } catch (IOException e) { + e.printStackTrace(); + } + } + PrefUtil.putFile(PrefUtil.WORK_DIR, file.getParentFile()); + } + } + } + + private void setFile(File file) { + this.file = file; + } + + private class OKAction extends AbstractAction { + public OKAction() { + super("OK"); + } + + @Override + public void actionPerformed(ActionEvent e) { + save(); + closeDialog(); + } + } + + private class CancelAction extends AbstractAction { + public CancelAction() { + super("Cancel"); + } + + @Override + public void actionPerformed(ActionEvent e) { + closeDialog(); + } + + } + + private class ResetAction extends AbstractAction { + public ResetAction() { + super("Reset"); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (file != null) { + try { + File defaultFile = File.createTempFile("xxx", null); + IOUtils.writeLinesToFile(defaultFile, getDefaultFileLinesAndOldOnesCommented()); + editor.setText(IOUtils.readStringFromFile(defaultFile)); + editor.setCaretPosition(0); + FileUtils.deleteQuietly(defaultFile); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + private List getDefaultFileLinesAndOldOnesCommented() throws IOException { + List commentedLines = getCurrentFileCommentedLines(); + + List newLines = new ArrayList<>(); + newLines.addAll(defaultScript); + newLines.add(""); + newLines.addAll(commentedLines); + return newLines; + } + + private List getCurrentFileCommentedLines() throws IOException { + String comment = Util.isWindowsScriptStyle() ? BAT_COMMENT : SHELL_COMMENT; + List commentedLines = new ArrayList<>(); + for (String line : FileUtils.readLines(file)) { + commentedLines.add(new StringBuilder(comment).append(line).toString()); + } + return commentedLines; + } + } +} diff --git a/src/eu/engys/util/ui/SelectionValueConfigurator.java b/src/eu/engys/util/ui/SelectionValueConfigurator.java new file mode 100644 index 0000000..3018f4b --- /dev/null +++ b/src/eu/engys/util/ui/SelectionValueConfigurator.java @@ -0,0 +1,32 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +public interface SelectionValueConfigurator { + public String write(String value); + + public String read(String value); +} diff --git a/src/eu/engys/util/ui/TableUtil.java b/src/eu/engys/util/ui/TableUtil.java new file mode 100644 index 0000000..885e16c --- /dev/null +++ b/src/eu/engys/util/ui/TableUtil.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import javax.swing.JTable; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; + +public class TableUtil { + + public static void disableSorting(JTable table) { + TableRowSorter sorter = (TableRowSorter) table.getRowSorter(); + if (sorter != null) { + for (int i = 0; i < table.getColumnCount(); i++) { + sorter.setSortable(i, false); + } + } + } + +} diff --git a/src/eu/engys/util/ui/TreeUtil.java b/src/eu/engys/util/ui/TreeUtil.java new file mode 100644 index 0000000..be8cc6f --- /dev/null +++ b/src/eu/engys/util/ui/TreeUtil.java @@ -0,0 +1,154 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreePath; + +public class TreeUtil { + + public static boolean areSiblings(TreePath[] selectionPath) { + if (selectionPath.length == 0) + return true; + return areSiblings(selectionPath, selectionPath[0].getParentPath()); + } + + public static boolean areSiblings(TreePath[] selectionPath, TreePath parent) { + if (selectionPath.length == 0) + return true; + for (TreePath path : selectionPath) { + if (!parent.isDescendant(path)) { + return false; + } + } + return true; + } + + public static boolean isConsistent(List selection, Class klass) { + return isConsistent(selection.toArray(), klass); + } + + public static boolean isConsistent(Object[] selection, Class klass) { + if (selection == null || selection.length == 0) + return false; + for (Object object : selection) { + if (!(klass.isInstance(object))) { + return false; + } + } + return true; + } + + public static List toUserObjects(TreePath[] selectionPath) { + List selection = new ArrayList<>(); + for (TreePath treePath : selectionPath) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent(); + Object userObject = node.getUserObject(); + selection.add(userObject); + } + return selection; + } + + public static Object[] toUserObjectsArray(TreePath[] selectionPath) { + return toUserObjects(selectionPath).toArray(); + } + + public static TreePath[] getAConsistentSelection(TreePath[] selectionPath) { + List consistentPath = new ArrayList<>(); + Object[] selection = TreeUtil.toUserObjectsArray(selectionPath); + Class firstClass = selection[0].getClass(); + + for (int i = 0; i < selection.length; i++) { + if (firstClass.isInstance(selection[i])) { + // System.out.println("TreeUtil.getAConsistentSelection() "+firstClass+" == "+selection[i].getClass()); + consistentPath.add(selectionPath[i]); + } else { + // System.out.println("TreeUtil.getAConsistentSelection() "+firstClass+" != "+selection[i].getClass()); + + } + } + + return consistentPath.toArray(new TreePath[0]); + } + + public static DefaultMutableTreeNode getFirstLevelParent(DefaultMutableTreeNode node) { + if (node.getLevel() == 1) { + return node; + } + DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent(); + if (parent != null && parent.getLevel() == 1) + return parent; + else + return getFirstLevelParent(parent); + } + + private static TreeNodeComparator tnc = new TreeNodeComparator(); + + public static void sortTree(DefaultMutableTreeNode root) { + Enumeration e = root.depthFirstEnumeration(); + while (e.hasMoreElements()) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement(); + if (!node.isLeaf()) { + sortChildren(node); + } + } + } + + public static void sortChildren(DefaultMutableTreeNode parent) { + @SuppressWarnings("unchecked") + Enumeration e = parent.children(); + List children = Collections.list(e); + + Collections.sort(children, tnc); + parent.removeAllChildren(); + for (MutableTreeNode node : children) { + parent.add(node); + } + } + + private static class TreeNodeComparator implements Comparator { + @Override + public int compare(DefaultMutableTreeNode a, DefaultMutableTreeNode b) { + if (a.getLevel() > b.getLevel()) { + return 1; + } else if (a.getLevel() < b.getLevel()) { + return -1; + } else { + String sa = a.getUserObject().toString(); + String sb = b.getUserObject().toString(); + return sa.compareToIgnoreCase(sb); + } + } + } +} diff --git a/src/eu/engys/util/ui/UiUtil.java b/src/eu/engys/util/ui/UiUtil.java new file mode 100644 index 0000000..73acd63 --- /dev/null +++ b/src/eu/engys/util/ui/UiUtil.java @@ -0,0 +1,891 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.FontMetrics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.File; +import java.lang.Thread.UncaughtExceptionHandler; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JTabbedPane; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.JTree; +import javax.swing.ListCellRenderer; +import javax.swing.LookAndFeel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.TabbedPaneUI; +import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.plaf.metal.MetalTabbedPaneUI; +import javax.swing.plaf.synth.SynthLookAndFeel; +import javax.swing.plaf.synth.SynthTabbedPaneUI; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import org.apache.commons.io.FileUtils; + +import eu.engys.util.ApplicationInfo; +import eu.engys.util.connection.SshParameters; +import eu.engys.util.connection.SshUtils; +import eu.engys.util.progress.ProgressMonitor; + +/** Static convenience methods for GUIs which eliminate code duplication. */ +public final class UiUtil { + + public static Window getActiveWindow() { + for (Window window : Window.getWindows()) { + if (window.isShowing() && window.isActive()) + return (Window) window; + } + return null; + } + + public static void debugPreferredSize(JComponent component) { + UiUtil.debugPreferredSize(component, 0, 0); + } + + public static void debugPreferredSize(JComponent component, int limitWidth, int limitHeight) { + double width = component.getPreferredSize().getWidth(); + double height = component.getPreferredSize().getHeight(); + if (component.getComponentCount() == 0) { + StringBuffer out = new StringBuffer("-> LEAF [" + component.getName() + "] - [" + component.getClass().getCanonicalName() + "]"); + if (width >= limitWidth && height >= limitHeight) { + out.append(" - W:[" + width + "] - H:[" + height + "]"); + } + System.out.println(out.toString()); + } else { + StringBuffer out = new StringBuffer("| PARENT [" + component.getName() + "] - [" + component.getClass().getCanonicalName() + "]"); + if (width >= limitWidth && height >= limitHeight) { + out.append(" - W:[" + width + "] - H:[" + height + "]"); + } + System.out.println(out.toString()); + for (Component c : component.getComponents()) { + if (c instanceof JComponent) { + debugPreferredSize((JComponent) c, limitWidth, limitHeight); + } + } + } + } + + public static void showDocumentationNotLoadedWarning(boolean emptyDocumentation) { + if (emptyDocumentation) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Missing file.", ApplicationInfo.getName() + " Documentation error", JOptionPane.ERROR_MESSAGE); + } else { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Ambiguous file name.", ApplicationInfo.getName() + " Documentation error", JOptionPane.ERROR_MESSAGE); + } + } + + public static void showEnvironmentNotLoadedWarning(String application) { + String message = String.format("%s cannot be launched because:\n\t1) %s is not installed on your system.\n\t2) The path to the executable does not exists.\n\t3) The path to the executable is broken.\nPlease, enter %s executable path under: Edit > Preferences.", application, application, application); + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), message, application + " executable error", JOptionPane.WARNING_MESSAGE); + } + + public static void showCoreEnvironmentNotLoadedWarning() { + showCoreEnvironmentNotLoadedWarning(UiUtil.getActiveWindow()); + } + + public static void showCoreEnvironmentNotLoadedWarning(Component parent) { + String token = ApplicationInfo.getName() + " Core"; + String message = String.format("%s cannot be launched because:\n\t1) %s is not installed on your system.\n\t2) The path to the executable does not exists.\n\t3) The path to the executable is broken.\nPlease, enter %s executable path under: Edit > Preferences.", token, token, token); + JOptionPane.showMessageDialog(parent, message, token + " executable error", JOptionPane.WARNING_MESSAGE); + } + + public static void showDemoMessage() { + String message = "The feature requested is not available in this demo version of " + ApplicationInfo.getName() + ".\nPlease contact " + ApplicationInfo.getVendor() + " at " + ApplicationInfo.getMail(); + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), message, "Demo", JOptionPane.INFORMATION_MESSAGE); + } + + public static void show(String title, Component panel, int w, int h) { + UiUtil.centerAndShow(defaultTestFrame(title, panel, w, h)); + } + + public static void show(String title, Component panel) { + UiUtil.centerAndShow(defaultTestFrame(title, panel)); + } + + public static JFrame defaultTestFrame(String title, Component panel, int w, int h) { + JFrame frame = defaultTestFrame(title, panel); + frame.setSize(w, h); + frame.setPreferredSize(new Dimension(w, h)); + return frame; + } + + public static JFrame defaultTestFrame(String title, Component panel) { + JFrame frame = defaultEmptyTestFrame(title); + frame.getContentPane().add(panel, BorderLayout.CENTER); + return frame; + } + + public static JFrame defaultEmptyTestFrame(String title) { + JFrame frame = new JFrame(title); + frame.getContentPane().setLayout(new BorderLayout()); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + return frame; + } + + public static void center(Window aWindow) { + Dimension screen = getScreenSize(); + Dimension window = aWindow.getSize(); + // ensure that no parts of aWindow will be off-screen + if (window.height > screen.height) { + window.height = screen.height; + } + if (window.width > screen.width) { + window.width = screen.width; + } + int xCoord = (screen.width / 2 - window.width / 2); + int yCoord = (screen.height / 2 - window.height / 2); + aWindow.setLocation(xCoord, yCoord); + } + + public static void centerAndShow(Window aWindow) { + aWindow.pack(); + /* + * If called from outside the event dispatch thread (as is the case upon startup, in the launch thread), + * then in principle this code is not thread-safe: once pack has been called, the component is realized, + * and (most) further work on the component should take place in the event-dispatch thread. + * + * In practice, it is exceedingly unlikely that this will lead to an error, since invisible components cannot receive events. + */ + center(aWindow); + aWindow.setVisible(true); + } + + public static Border getStandardBorder() { + return BorderFactory.createEmptyBorder(UiUtil.STANDARD_BORDER, UiUtil.STANDARD_BORDER, UiUtil.STANDARD_BORDER, UiUtil.STANDARD_BORDER); + } + + public static JComponent getCommandRow(JComponent... aButtons) { + List list = Arrays.asList(aButtons); + return getCommandRow(list); + } + + public static JComponent getCommandRow(java.util.List aButtons) { + equalizeSizes(aButtons); + JPanel panel = new JPanel(); + LayoutManager layout = new BoxLayout(panel, BoxLayout.X_AXIS); + panel.setLayout(layout); + panel.setOpaque(false); + panel.setBorder(BorderFactory.createEmptyBorder(UiUtil.TWO_SPACES, 0, 0, 0)); + panel.add(Box.createHorizontalGlue()); + Iterator buttonsIter = aButtons.iterator(); + while (buttonsIter.hasNext()) { + panel.add(buttonsIter.next()); + if (buttonsIter.hasNext()) { + panel.add(Box.createHorizontalStrut(UiUtil.ONE_SPACE)); + } + } + return panel; + } + + public static JComponent getCommandColumn(java.util.List aButtons) { + equalizeSizes(aButtons); + JPanel panel = new JPanel(); + LayoutManager layout = new BoxLayout(panel, BoxLayout.Y_AXIS); + panel.setLayout(layout); + panel.setOpaque(false); + panel.setBorder(BorderFactory.createEmptyBorder(0, UiUtil.TWO_SPACES, 0, 0)); + // (no for-each is used here, because of the 'not-yet-last' check) + Iterator buttonsIter = aButtons.iterator(); + while (buttonsIter.hasNext()) { + panel.add(buttonsIter.next()); + if (buttonsIter.hasNext()) { + panel.add(Box.createVerticalStrut(UiUtil.ONE_SPACE)); + } + } + panel.add(Box.createVerticalGlue()); + return panel; + } + + public static JComponent getCommandColumnToolbar(java.util.List aButtons) { + equalizeSizes(aButtons); + JToolBar panel = getToolbar("command.column.toolbar"); + LayoutManager layout = new BoxLayout(panel, BoxLayout.Y_AXIS); + panel.setLayout(layout); + panel.setOpaque(false); + panel.setFloatable(false); + panel.setBorder(BorderFactory.createEmptyBorder(0, UiUtil.TWO_SPACES, 0, 0)); + + // (no for-each is used here, because of the 'not-yet-last' check) + Iterator buttonsIter = aButtons.iterator(); + while (buttonsIter.hasNext()) { + AbstractButton next = (AbstractButton) buttonsIter.next(); + next.setAlignmentX(Component.LEFT_ALIGNMENT); + next.setHorizontalAlignment(SwingConstants.LEFT); + panel.add(next); + if (buttonsIter.hasNext()) { + panel.add(Box.createVerticalStrut(UiUtil.ONE_SPACE)); + } + } + panel.add(Box.createVerticalGlue()); + return panel; + } + + public static JMenuItem createMenuItem(Action a) { + Icon icon = (Icon) a.getValue(Action.SMALL_ICON); + String text = (String) a.getValue(Action.NAME); + String desc = (String) a.getValue(Action.SHORT_DESCRIPTION); + + JMenuItem item = new JMenuItem(a); + item.setName(text != null ? text : desc); + item.setText(text != null ? text : desc); + item.setIcon(icon); + item.setToolTipText(desc); + + return item; + } + + public static AbstractButton createButton(Action a) { + Icon icon = (Icon) a.getValue(Action.SMALL_ICON); + String text = (String) a.getValue(Action.NAME); + String desc = (String) a.getValue(Action.SHORT_DESCRIPTION); + + JButton b = new JButton(a); + b.setName(text != null ? text : desc); + b.setText(((text != null && text.equals("MISSING")) ? null : text)); + b.setIcon(icon); + b.setToolTipText(desc); + + return b; + } + + public static AbstractButton createToolBarIconButton(Action a) { + return _createToolBarButton(a, false); + } + + public static AbstractButton createToolBarButton(Action a) { + return _createToolBarButton(a, true); + } + + private static AbstractButton _createToolBarButton(Action a, boolean showLabel) { + Icon icon = (Icon) a.getValue(Action.SMALL_ICON); + String text = (String) a.getValue(Action.NAME); + String desc = (String) a.getValue(Action.SHORT_DESCRIPTION); + + JButton b = new JButton(a) { + public Insets getMargin() { + if (super.getMargin() != null) + return new Insets(super.getMargin().top, 2, super.getMargin().bottom, 2); + else + return null; + } + }; + b.setName(text != null ? text : desc); + b.setText(showLabel ? ((text != null && text.equals("MISSING")) ? null : text) : null); + b.setIcon(icon); + b.setToolTipText(desc); + // b.setEnabled(a.isEnabled()); + b.setFocusable(false); + return b; + } + + public static AbstractButton createToolBarMultiButtonBar(String name, Icon icon, String tooltip, final Action... actions) { + final JButton button = new JButton() { + public Insets getMargin() { + if (super.getMargin() != null) + return new Insets(super.getMargin().top, 2, super.getMargin().bottom, 2); + else + return null; + } + }; + button.setName(name); + button.setToolTipText(tooltip); + button.setFocusable(false); + + final JPopupMenu popup = new JPopupMenu(); + for (Action action : actions) { + JMenuItem item = new JMenuItem(action); + item.setName((String) action.getValue(Action.NAME)); + item.setToolTipText(String.valueOf(action.getValue(Action.SHORT_DESCRIPTION))); + popup.add(item); + } + + button.setAction(new ViewAction(name, icon, tooltip) { + + @Override + public void actionPerformed(ActionEvent e) { + popup.show(button, 0, button.getPreferredSize().height); + } + }); + + return button; + } + + public static ButtonBar createToolBarButtonBar(Action... actions) { + ButtonBar bar = new ButtonBar(); + for (Action action : actions) { + AbstractButton button = createButtonBarButton(action); + button.setName((String) action.getValue(Action.NAME)); + bar.add(button); + } + return bar; + } + + public static void clearToolbar(JToolBar toolbar) { + for (Component c : toolbar.getComponents()) { + if (c instanceof AbstractButton) { + ((AbstractButton) c).setSelected(false); + } else if (c instanceof JComboBox) { + ((JComboBox) c).setSelectedIndex(-1); + } + } + } + + public static ButtonBar createToolBarToggleButtonBar(Action... actions) { + ButtonGroup viewGroup = new ButtonGroup(); + ButtonBar bar = new ButtonBar(); + for (Action action : actions) { + bar.add(createButtonBarToggleButton(action, viewGroup)); + } + return bar; + } + + public static AbstractButton createToolBarToggleButton(Action a) { + return createToolBarToggleButton(a, false); + } + + public static JToggleButton createToolBarToggleButton(Action a, final boolean tooltipOver) { + Icon icon = (Icon) a.getValue(Action.SMALL_ICON); + Icon sel_icon = (Icon) a.getValue(Action.SMALL_ICON + Action.SELECTED_KEY); + String text = (String) a.getValue(Action.NAME); + + final JToggleButton b = new JToggleButton(a) { + public Insets getMargin() { + if (super.getMargin() != null) + return new Insets(super.getMargin().top, 2, super.getMargin().bottom, 2); + else + return null; + } + }; + b.getModel().addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + b.getAction().putValue(Action.SELECTED_KEY, b.getModel().isSelected()); + } + }); + b.setName(text); + b.setText((text != null && text.equals("MISSING")) ? null : text); + b.setHorizontalTextPosition(0); + b.setVerticalTextPosition(3); + b.setIcon(icon); + b.setRolloverIcon(icon); + b.setRolloverSelectedIcon(sel_icon); + b.setSelectedIcon(sel_icon); + b.setEnabled(a.isEnabled()); + b.setFocusable(false); + return b; + } + + public static AbstractButton createButtonBarButton(Action a) { + JButton b = new JButton(a) { + public Insets getMargin() { + if (super.getMargin() != null) + return new Insets(super.getMargin().top, 0, super.getMargin().bottom, 0); + else + return null; + } + }; + b.setHorizontalTextPosition(SwingConstants.RIGHT); + // b.setVerticalTextPosition(3); + b.setName((String) a.getValue(Action.NAME)); + b.setFocusable(false); + return b; + } + + public static AbstractButton createButtonBarToggleButton(Action a, ButtonGroup group) { + Icon icon = (Icon) a.getValue(Action.SMALL_ICON); + String text = (String) a.getValue(Action.SHORT_DESCRIPTION); + + JToggleButton b = new JToggleButton(a) { + public Insets getMargin() { + if (super.getMargin() != null) + return new Insets(super.getMargin().top, 0, super.getMargin().bottom, 0); + else + return null; + } + }; + b.setHorizontalTextPosition(0); + b.setVerticalTextPosition(3); + b.setText(""); + b.setIcon(icon); + b.setToolTipText(text); + b.setFocusable(false); + group.add(b); + return b; + } + + public static void updateToolBarComboButton(final JComboBox combo, final List actions) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + _updateToolBarComboButton(combo, actions); + } + }); + } + + private static void _updateToolBarComboButton(JComboBox combo, List actions) { + int selectedIndex = -1; + ActionListener[] actionListeners = combo.getActionListeners(); + for (ActionListener l : actionListeners) { + combo.removeActionListener(l); + } + ItemListener[] itemListeners = combo.getItemListeners(); + for (ItemListener l : itemListeners) { + combo.removeItemListener(l); + } + combo.removeAllItems(); + combo.setPrototypeDisplayValue(getPrototype(actions, combo.getPrototypeDisplayValue())); + for (int j = 0; j < actions.size(); j++) { + combo.addItem(actions.get(j)); + if (actions.get(j).getValue("default") != null) { + selectedIndex = j; + } + } + combo.setSelectedIndex(selectedIndex); + for (ActionListener l : actionListeners) { + combo.addActionListener(l); + } + for (ItemListener l : itemListeners) { + combo.addItemListener(l); + } + } + + public static JComboBox createToolBarComboButton(List actions, String tooltip, String prototype, boolean enabled, final boolean tooltipOver) { + int selectedIndex = -1; + final JComboBox c = new JComboBox(); + c.setPrototypeDisplayValue(getPrototype(prototype)); + for (int j = 0; j < actions.size(); j++) { + c.addItem(actions.get(j)); + if (actions.get(j).getValue("default") != null) { + selectedIndex = j; + } + } + c.setSelectedIndex(selectedIndex); + c.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + if (c.getSelectedIndex() > -1) { + c.getItemAt(c.getSelectedIndex()).actionPerformed(null); + } + } + } + }); + c.setMaximumSize(c.getPreferredSize()); + c.setEnabled(enabled); + c.setToolTipText(tooltip); + c.setRenderer(new ActionsComboBoxRenderer(c.getRenderer())); + return c; + } + + private static Action getPrototype(List actions, Action actualPrototype) { + Action proto = actualPrototype; + for (Action action : actions) { + String actionName = (String) action.getValue(Action.NAME); + String prototypeName = (String) proto.getValue(Action.NAME); + if (actionName.length() > prototypeName.length()) { + proto = action; + } + } + return proto; + } + + private static Action getPrototype(String actionName) { + return new AbstractAction(actionName) { + @Override + public void actionPerformed(ActionEvent arg0) { + } + }; + } + + private static class ActionsComboBoxRenderer extends JLabel implements ListCellRenderer { + + private ListCellRenderer renderer; + + public ActionsComboBoxRenderer(ListCellRenderer renderer) { + this.renderer = renderer; + } + + @SuppressWarnings("unchecked") + public Component getListCellRendererComponent(JList list, Action value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + + if (c instanceof JLabel && value != null) { + String text = (String) value.getValue(Action.NAME); + Icon icon = (Icon) value.getValue(Action.SMALL_ICON); + + JLabel label = (JLabel) renderer; + label.setIcon(icon); + label.setText(text); + } + + return c; + } + + } + + public static void equalizeSizes(java.util.List aComponents) { + Dimension targetSize = new Dimension(0, 0); + for (JComponent comp : aComponents) { + Dimension compSize = comp.getPreferredSize(); + double width = Math.max(targetSize.getWidth(), compSize.getWidth()); + double height = Math.max(targetSize.getHeight(), compSize.getHeight()); + targetSize.setSize(width, height); + } + setSizes(aComponents, targetSize); + } + + private static void setSizes(java.util.List aComponents, Dimension aDimension) { + Iterator compsIter = aComponents.iterator(); + while (compsIter.hasNext()) { + JComponent comp = (JComponent) compsIter.next(); + comp.setPreferredSize((Dimension) aDimension.clone()); + comp.setMaximumSize((Dimension) aDimension.clone()); + } + } + + private static List getDescendantsOfType(Class clazz, Container container, boolean nested) { + List tList = new ArrayList(); + + for (Component component : container.getComponents()) { + if (clazz.isAssignableFrom(component.getClass())) { + tList.add(clazz.cast(component)); + } + if (nested || !clazz.isAssignableFrom(component.getClass())) { + if (component instanceof Container) { + tList.addAll(getDescendantsOfType(clazz, (Container) component, nested)); + } + } + } + + return tList; + } + + private static Map> containers = new HashMap>(); + + public static void enable(Container container) { + List enabledComponents = containers.get(container); + if (enabledComponents != null) { + for (JComponent component : enabledComponents) { + if (component instanceof AbstractButton) { + AbstractButton b = (AbstractButton) component; + if (b.getAction() != null) { + b.getAction().setEnabled(true); + } else { + component.setEnabled(true); + } + } else { + component.setEnabled(true); + } + + } + containers.remove(container); + } + } + + public static void disable(Container container) { + List components = getDescendantsOfType(JComponent.class, container, true); + List enabledComponents = new ArrayList(); + if (!containers.containsKey(container)) { + containers.put(container, enabledComponents); + for (JComponent component : components) { + if (component.isEnabled()) { + enabledComponents.add(component); + if (component instanceof AbstractButton) { + AbstractButton b = (AbstractButton) component; + if (b.getAction() != null) { + b.getAction().setEnabled(false); + } else { + component.setEnabled(false); + } + } else { + component.setEnabled(false); + } + } + } + } + } + + + public static void expandAll(JTree tree, boolean expand) { + TreeNode root = (TreeNode) tree.getModel().getRoot(); + + // Traverse tree from root + expandAll(tree, new TreePath(root), expand); + } + + public static void expandAll(JTree tree, TreePath parent, boolean expand) { + // Traverse children + TreeNode node = (TreeNode) parent.getLastPathComponent(); + if (node.getChildCount() >= 0) { + for (Enumeration e = node.children(); e.hasMoreElements();) { + TreeNode n = (TreeNode) e.nextElement(); + TreePath path = parent.pathByAddingChild(n); + expandAll(tree, path, expand); + } + } + + // Expansion or collapse must be done bottom-up + if (expand) { + tree.expandPath(parent); + } else { + tree.collapsePath(parent); + } + } + + public static Boolean testConnection(final SshParameters sshParameters, final ProgressMonitor progressMonitor) { + progressMonitor.setIndeterminate(true); + Boolean retVal = progressMonitor.start("Testing connection...", false, new Callable() { + @Override + public Boolean call() throws Exception { + boolean retVal = SshUtils.testConnection(sshParameters); + progressMonitor.end(); + return retVal; + } + }); + return retVal; + } + + public static boolean isMainScreen(GraphicsDevice currentScreen) { + GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice def = g.getDefaultScreenDevice(); + return def.equals(currentScreen); + } + + public static boolean isSecondaryScreen(GraphicsDevice currentScreen) { + return !isMainScreen(currentScreen); + } + + public static Rectangle getCurrentScreenSize(JFrame frame) { + GraphicsConfiguration config = frame.getGraphicsConfiguration(); + GraphicsDevice currentScreen = config.getDevice(); + return new Rectangle(currentScreen.getDisplayMode().getWidth(), currentScreen.getDisplayMode().getHeight()); + } + + public static JToolBar getToolbar(String name) { + JToolBar toolbar = new JToolBar(); + toolbar.setLayout(new WrappedFlowLayout(FlowLayout.LEFT, 0, 0)); + toolbar.putClientProperty("Synthetica.toolBar.buttons.paintBorder", Boolean.TRUE); + toolbar.putClientProperty("Synthetica.opaque", Boolean.FALSE); + toolbar.setName(name); + toolbar.setFloatable(false); + toolbar.setRollover(false); + toolbar.setOpaque(false); + toolbar.setBorder(BorderFactory.createEmptyBorder()); + + return toolbar; + } + + public static void setOneTabHide(final JTabbedPane tabbedPane) { + try { + LookAndFeel laf = UIManager.getLookAndFeel(); + TabbedPaneUI ui = null; + + if (laf != null && laf instanceof SynthLookAndFeel) { + ui = new SynthTabbedPaneUI() { + @Override + protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount, int maxTabHeight) { + if (tabbedPane.getTabCount() > 1) { + return super.calculateTabAreaHeight(tabPlacement, horizRunCount, maxTabHeight); + } else { + return 0; + } + } + + @Override + protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics) { + if (tabbedPane.getTabCount() > 1) { + return super.calculateTabWidth(tabPlacement, tabIndex, metrics); + } else { + return 0; + } + } + + }; + + } else if (laf != null && laf instanceof MetalLookAndFeel) { + ui = new MetalTabbedPaneUI() { + @Override + protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount, int maxTabHeight) { + if (tabbedPane.getTabCount() > 1) { + return super.calculateTabAreaHeight(tabPlacement, horizRunCount, maxTabHeight); + } else { + return 0; + } + } + + @Override + protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics) { + if (tabbedPane.getTabCount() > 1) { + return super.calculateTabWidth(tabPlacement, tabIndex, metrics); + } else { + return 0; + } + } + + }; + } + tabbedPane.setUI(ui); + } catch (Exception e) { + // e.printStackTrace(); + } + } + + public static void installExceptionHandler() { + Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + if (GraphicsEnvironment.isHeadless()) { + } else { + e.printStackTrace(); +// StringOutputStream stream = new StringOutputStream(); +// e.printStackTrace(new PrintStream(stream)); +// String msg = stream.toString(); +// System.err.println(msg); +// JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), msg, "An error occurred", JOptionPane.ERROR_MESSAGE); + } + } + }); + } + + public static void renameUIThread() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + if (SwingUtilities.isEventDispatchThread()) { + Thread.currentThread().setName("GUI Dispatch Queue"); + } + } + }); + } + + public static Dimension getScreenSize() { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] screenDevices = ge.getScreenDevices(); + // System.out.println("UiUtil.getPreferredDimension() screenDevices.length: "+screenDevices.length); + if (screenDevices.length > 1) { + int width = screenSize.width; + int height = screenSize.height; + for (int i = 0; i < screenDevices.length; i++) { + GraphicsDevice gd = screenDevices[i]; + width = Math.min(width, gd.getDisplayMode().getWidth()); + height = Math.min(height, gd.getDisplayMode().getHeight()); + } + + // System.out.println("UiUtil.getPreferredDimension() width: "+width+" height: "+height); + return new Dimension(width, height); + } else { + return screenSize; + } + } + + public static Dimension getPreferredScreenSize() { + Dimension screenSize = getScreenSize(); + int W = screenSize.width * 8 / 10; + int H = screenSize.height * 8 / 10; + + return new Dimension(W, H); + } + + public static void printLogOnDesktopFile(String log) { + printLogOnDesktopFile(log, true); + } + + public static void printLogOnDesktopFile(String log, boolean append) { + try { + File desktopFolder = Paths.get(System.getProperty("user.home"), "Desktop").toFile(); + if (desktopFolder.exists()) { + File logFile = new File(desktopFolder, "log.txt"); + if (!logFile.exists()) { + logFile.createNewFile(); + } + String date = new SimpleDateFormat("'['HH:mm:ss']'").format(new Date()); + FileUtils.writeStringToFile(logFile, date + " - " + log + "\n", append); + } + } catch (Exception e) { + + } + + } + + public static final int ONE_SPACE = 5; + public static final int TWO_SPACES = 11; + public static final int THREE_SPACES = 17; + public static final int STANDARD_BORDER = TWO_SPACES; + +} diff --git a/src/eu/engys/util/ui/ViewAction.java b/src/eu/engys/util/ui/ViewAction.java new file mode 100644 index 0000000..65362ce --- /dev/null +++ b/src/eu/engys/util/ui/ViewAction.java @@ -0,0 +1,90 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui; + +import java.awt.event.InputEvent; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.KeyStroke; + +public abstract class ViewAction extends AbstractAction { + + public ViewAction(String text, String tooltip) { + super(text, null); + putValue(SHORT_DESCRIPTION, tooltip); + } + + public ViewAction(Icon icon, String tooltip) { + super(null, icon); + putValue(SHORT_DESCRIPTION, tooltip); + } + + public ViewAction(String text, Icon icon, boolean enabled) { + super(text, icon); + setEnabled(enabled); + } + + public ViewAction(String text, Icon icon, String tooltip) { + super(text, icon); + putValue(SHORT_DESCRIPTION, tooltip); + } + + public ViewAction(String text, Icon icon, String tooltip, boolean enabled) { + super(text, icon); + putValue(SHORT_DESCRIPTION, tooltip); + setEnabled(enabled); + } + + public ViewAction(String text, Icon icon, String tooltip, int mnemonic) { + super(text, icon); + putValue(SHORT_DESCRIPTION, tooltip); + putValue(MNEMONIC_KEY, mnemonic); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(mnemonic, InputEvent.CTRL_DOWN_MASK)); + } + + public boolean isSelected() { + return Boolean.TRUE.equals(getValue(Action.SELECTED_KEY)); + } + + public void setSelected(boolean b) { + putValue(Action.SELECTED_KEY, Boolean.valueOf(b)); + } + + public String getText() { + return (String) getValue(NAME); + } + + public String getTooltip() { + return (String) getValue(SHORT_DESCRIPTION); + } + + public Icon getIcon() { + return (Icon) getValue(SMALL_ICON); + } +} diff --git a/src/eu/engys/util/ui/WrappedFlowLayout.java b/src/eu/engys/util/ui/WrappedFlowLayout.java new file mode 100644 index 0000000..2350477 --- /dev/null +++ b/src/eu/engys/util/ui/WrappedFlowLayout.java @@ -0,0 +1,131 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; + +public class WrappedFlowLayout extends FlowLayout { + public WrappedFlowLayout() { + super(); + } + + public WrappedFlowLayout(int align) { + super(align); + } + + public WrappedFlowLayout(int align, int hgap, int vgap) { + super(align, hgap, vgap); + } + + public Dimension minimumLayoutSize(Container target) { + // Size of largest component, so we can resize it in + // either direction with something like a split-pane. + return computeMinSize(target); + } + + public Dimension preferredLayoutSize(Container target) { + return computeSize(target); + } + + private Dimension computeSize(Container target) { + synchronized (target.getTreeLock()) { + int hgap = getHgap(); + int vgap = getVgap(); + int w = target.getWidth(); + + // Let this behave like a regular FlowLayout (single row) + // if the container hasn't been assigned any size yet + if (w == 0) { + w = Integer.MAX_VALUE; + } + + Insets insets = target.getInsets(); + if (insets == null) { + insets = new Insets(0, 0, 0, 0); + } + int reqdWidth = 0; + + int maxwidth = w - (insets.left + insets.right + hgap * 2); + int n = target.getComponentCount(); + int x = 0; + int y = insets.top + vgap; // FlowLayout starts by adding vgap, + // so do that here too. + int rowHeight = 0; + + for (int i = 0; i < n; i++) { + Component c = target.getComponent(i); + if (c.isVisible()) { + Dimension d = c.getPreferredSize(); + if ((x == 0) || ((x + d.width) <= maxwidth)) { + // fits in current row. + if (x > 0) { + x += hgap; + } + x += d.width; + rowHeight = Math.max(rowHeight, d.height); + } else { + // Start of new row + x = d.width; + y += vgap + rowHeight; + rowHeight = d.height; + } + reqdWidth = Math.max(reqdWidth, x); + } + } + y += rowHeight; + y += insets.bottom; + return new Dimension(reqdWidth + insets.left + insets.right, y); + } + } + + private Dimension computeMinSize(Container target) { + synchronized (target.getTreeLock()) { + int minx = Integer.MAX_VALUE; + int miny = Integer.MIN_VALUE; + boolean found_one = false; + int n = target.getComponentCount(); + + for (int i = 0; i < n; i++) { + Component c = target.getComponent(i); + if (c.isVisible()) { + found_one = true; + Dimension d = c.getPreferredSize(); + minx = Math.min(minx, d.width); + miny = Math.min(miny, d.height); + } + } + if (found_one) { + return new Dimension(minx, miny); + } + return new Dimension(0, 0); + } + } + +} diff --git a/src/eu/engys/util/ui/builder/GroupController.java b/src/eu/engys/util/ui/builder/GroupController.java new file mode 100644 index 0000000..682020d --- /dev/null +++ b/src/eu/engys/util/ui/builder/GroupController.java @@ -0,0 +1,51 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.builder; + +import java.awt.event.ActionListener; + +import javax.swing.JComponent; + +public interface GroupController { + void addActionListener(ActionListener pop); + + String getSelectedKey(); + + void setSelectedIndex(int i); + + void setSelectedItem(String groupName); + + void setSelectedKey(String key); + + void addGroup(String groupKey, String groupName); + + void addChildController(GroupController controller); + + GroupController getChildController(String selectedKey); + + JComponent getComponent(); +} diff --git a/src/eu/engys/util/ui/builder/HideController.java b/src/eu/engys/util/ui/builder/HideController.java new file mode 100644 index 0000000..a5fbcb9 --- /dev/null +++ b/src/eu/engys/util/ui/builder/HideController.java @@ -0,0 +1,101 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.builder; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JComponent; +import javax.swing.JLabel; + + +public class HideController implements GroupController { + private ActionListener action; + private JLabel label = new JLabel(); + private List groups = new ArrayList(); + private List keys = new ArrayList(); + private Map childControllers = new HashMap(); + + private String selectedKey = null; + + @Override + public void setSelectedIndex(int i) { + setSelectedItem(groups.get(i)); + } + + @Override + public void setSelectedItem(String item) { + selectedKey = item != null ? keys.get(groups.indexOf(item)) : null; + action.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, selectedKey)); + label.setText(item); + } + + @Override + public void setSelectedKey(String key) { + setSelectedIndex(keys.indexOf(key)); + } + + @Override + public String getSelectedKey() { + return selectedKey; + } + + public String getSelectedItem() { + return groups.get(keys.indexOf(selectedKey)); + } + + @Override + public void addChildController(GroupController controller) { + childControllers.put(keys.get(keys.size()-1), controller); + } + + @Override + public GroupController getChildController(String key) { + return childControllers.get(key); + } + + @Override + public JComponent getComponent() { + return label; + } + + @Override + public void addGroup(String groupKey, String groupName) { + groups.add(groupName); + keys.add(groupKey); + } + + @Override + public void addActionListener(ActionListener showHideAction) { + this.action = showHideAction; + } + +} diff --git a/src/eu/engys/util/ui/builder/JCheckBoxController.java b/src/eu/engys/util/ui/builder/JCheckBoxController.java new file mode 100644 index 0000000..214789f --- /dev/null +++ b/src/eu/engys/util/ui/builder/JCheckBoxController.java @@ -0,0 +1,103 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.builder; + +import java.awt.Color; +import java.awt.Font; +import java.awt.event.ActionListener; + +import javax.swing.JCheckBox; +import javax.swing.JComponent; + + +public class JCheckBoxController extends JCheckBox implements GroupController { + + private String selectedKey; + + public JCheckBoxController(String name) { + super(name); + setName(name); + setOpaque(false); + setFocusable(false); + } + + @Override + public void addActionListener(ActionListener action) { + super.addActionListener(action); + } + + @Override + public void addGroup(String groupKey, String groupName) { + this.selectedKey = groupKey; + } + + @Override + public JComponent getComponent() { + return this; + } + + @Override + public void setSelectedIndex(int i) { + super.doClick(); + } + + @Override + public void setSelectedItem(String groupName) { + super.doClick(); + } + + @Override + public void setSelectedKey(String key) { + super.doClick(); + } + + @Override + public String getSelectedKey() { + return isSelected() ? selectedKey : null; + } + + @Override + public void addChildController(GroupController controller) { + } + + @Override + public GroupController getChildController(String selectedKey) { + return null; + } + + @Override + public Font getFont() { + Font font = super.getFont(); + return font != null ? font.deriveFont(Font.BOLD) : font; + } + + @Override + public Color getForeground() { + // if (isEnabled()) return Color.BLUE; + return super.getForeground(); + } +} diff --git a/src/eu/engys/util/ui/builder/JComboBoxController.java b/src/eu/engys/util/ui/builder/JComboBoxController.java new file mode 100644 index 0000000..be9608e --- /dev/null +++ b/src/eu/engys/util/ui/builder/JComboBoxController.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.builder; + +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JComponent; + +import eu.engys.util.ui.JComboBoxWithItemsSupport; + +public class JComboBoxController extends JComboBoxWithItemsSupport implements GroupController { + + private List keys = new ArrayList(); + private Map childControllers = new HashMap(); + + public JComboBoxController() { + super(); + } + + @Override + public void addActionListener(ActionListener action) { + super.addActionListener(action); + } + + @Override + public void addGroup(String groupKey, String groupName) { + if (!keys.contains(groupKey)) { + keys.add(groupKey); + super.addItem(groupName); + } + } + + @Override + public void addChildController(GroupController controller) { + childControllers.put(keys.get(keys.size()-1), controller); + } + + @Override + public GroupController getChildController(String key) { + return childControllers.get(key); + } + + @Override + public JComponent getComponent() { + return this; + } + + @Override + public void setSelectedItem(String groupName) { + super.setSelectedItem(groupName); + } + + @Override + public void setSelectedKey(String key) { + super.setSelectedIndex(keys.indexOf(key)); + } + + @Override + public String getSelectedKey() { + int index = getSelectedIndex(); + return index < 0 ? null : keys.get(index); + } + + public boolean containsKey(String key) { + return keys.contains(key); + } +} diff --git a/src/eu/engys/util/ui/builder/PanelBuilder.java b/src/eu/engys/util/ui/builder/PanelBuilder.java new file mode 100644 index 0000000..e707729 --- /dev/null +++ b/src/eu/engys/util/ui/builder/PanelBuilder.java @@ -0,0 +1,628 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui.builder; + +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import net.java.dev.designgridlayout.DesignGridLayout; +import net.java.dev.designgridlayout.INonGridRow; +import net.java.dev.designgridlayout.IRowCreator; +import net.java.dev.designgridlayout.ISpannableGridRow; +import net.java.dev.designgridlayout.RowGroup; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.util.TooltipUtils; +import eu.engys.util.ui.UiUtil; + +/** + *
+ * startChoice("Autore");
+ * startGroup("Disney");
+ *   startChoice("Citta");
+ *       startGroup("Topolinia");
+ *           startChoice("Personaggi");
+ *               startGroup("Topolino");
+ *                   newRow().grid(label("topolino")).add(label("TOPOLINO"));
+ *                   newRow().grid(label("minnie")).add(label("MINNIE"));
+ *                  newRow().grid(label("pluto")).add(label("PLUTO"));
+ *               endGroup();
+ *              startGroup("Pippo");
+ *                   newRow().grid(label("pippo")).add(label("PIPPO"));
+ *                   newRow().grid(label("orazio")).add(label("ORAZIO"));
+ *                   newRow().grid(label("clarabella")).add(label("CLARABELLA"));
+ *               endGroup();
+ *               startGroup("Commissariato");
+ *                   newRow().grid(label("basettoni")).add(label("BASETTONI"));
+ *                   newRow().grid(label("manetta")).add(label("MANETTA"));
+ *              endGroup();
+ *          endChoice();//personaggi
+ *       endGroup();//topolinia
+ *       startGroup("Paperopoli");
+ *           startChoice("Personaggi");
+ *               startGroup("Paperino");
+ *                   newRow().grid(label("paperino")).add(label("PAPERINO"));
+ *                   newRow().grid(label("paperina")).add(label("PAPERINA"));
+ *                   newRow().grid(label("qui")).add(label("QUI"));
+ *                   newRow().grid(label("quo")).add(label("QUO"));
+ *                   newRow().grid(label("qua")).add(label("QUA"));
+ *               endGroup();
+ *               startGroup("NonnaPapera");
+ *                  newRow().grid(label("nonna")).add(label("NONNA"));
+ *                   newRow().grid(label("ciccio")).add(label("CICCIO"));
+ *               endGroup();
+ *           endChoice();//personaggi
+ *       endGroup();//paperopoli
+ *   evndChoice();//citta
+ * endGroup();//disney
+ * startGroup("Marvel");
+ *   startChoice("Gotham City");
+ *       startGroup("Batman");
+ *           newRow().grid(label("batman")).add(label("BATMAN"));
+ *           newRow().grid(label("robin")).add(label("ROBIN"));
+ *           newRow().grid(label("qui")).add(label("QUI"));
+ *           newRow().grid(label("quo")).add(label("QUO"));
+ *       endGroup();
+ *       startGroup("Cattivi");
+ *           newRow().grid(label("penguin")).add(label("PENGUIN"));
+ *           newRow().grid(label("poisonivy")).add(label("POISONIVY"));
+ *       endGroup();
+ *   endChoice();//gotham city
+ * endGroup();//marvel
+ * endChoice();//autore
+ * 
+ * + */ +public class PanelBuilder { + + private static final Logger logger = LoggerFactory.getLogger(PanelBuilder.class); + + private DesignGridLayout layout; + private final JPanel parent; + private int level = 0; + private int indent = 0; + + protected Stack groups = new Stack(); + protected Stack controllers = new Stack(); + protected Stack actions = new Stack(); + + private HashMap hideables = new HashMap(); + + private String prefix = ""; + + public PanelBuilder() { + super(); + this.parent = new JPanel(); + this.parent.setOpaque(false); + this.layout = new DesignGridLayout(parent); + // layout.labelAlignment(LabelAlignment.RIGHT); + layout.withoutConsistentWidthAcrossNonGridRows(); + layout.emptyRow(); + } + + public PanelBuilder(String name) { + this(); + this.parent.setName(name); + } + + public JPanel getPanel() { + return (JPanel) parent; + } + + public PanelBuilder removeMargins() { + layout.margins(0, 0, 0, 0); + return this; + } + + public PanelBuilder margins(double top, double left, double bottom, double right) { + layout.margins(top, left, bottom, right); + return this; + } + + private IRowCreator newRow() { + // System.out.println("ChoicePanelBuilder.newRow() level: "+level+", groups: "+groups.size() + // ); + if (level == 0) + return layout.row(); + else if (level == 1) + return layout.row().group(groups.get(0).group); + else if (level == 2) + return layout.row().group(groups.get(0).group).group(groups.get(1).group); + else if (level == 3) + return layout.row().group(groups.get(0).group).group(groups.get(1).group).group(groups.get(2).group); + else if (level == 4) + return layout.row().group(groups.get(0).group).group(groups.get(1).group).group(groups.get(2).group).group(groups.get(3).group); + else if (level == 5) + return layout.row().group(groups.get(0).group).group(groups.get(1).group).group(groups.get(2).group).group(groups.get(3).group).group(groups.get(4).group); + else + throw new IllegalStateException("Level > 5"); + } + + private ISpannableGridRow newGridRow() { + return newRow().grid().indent(indent); + } + + private ISpannableGridRow newGridRow(String string, String tooltip) { + JLabel l = label(string); + l.setToolTipText(TooltipUtils.format(tooltip)); + return newRow().grid(l).indent(indent); + } + + private ISpannableGridRow newGridRow(JLabel label, String tooltip) { + label.setToolTipText(tooltip); + return newRow().grid(label).indent(indent); + } + + private INonGridRow newLeftRow() { + return newRow().left().indent(indent); + } + + public void addSeparator(JComponent c) { + newLeftRow().add(c).fill(); + } + + public void addSeparator(String string) { + addSeparator(boldlabel(string)); + } + + public void addButtons(JComponent... components) { + addLeft(components); + } + + public void addLeft(JComponent... components) { + newRow().bar().left(components); + } + + public void addRight(JComponent... components) { + newRow().bar().right(components); + } + + public void addCenter(JComponent... components) { + newRow().center().add(components); + } + + public void addFill(JComponent... components) { + newRow().center().add(components).fill(); + } + + public void addComponentToGroup(RowGroup group, JComponent c) { + layout.row().group(group).grid().add(c); + } + + public void addComponentToGroup(RowGroup group, String s, JComponent c) { + layout.row().group(group).grid(new JLabel(s)).add(c); + } + + public JComponent addComponent(JComponent c) { + newGridRow().add(c); + return c; + } + + public JComponent addComponent(JLabel label, JComponent c) { + newGridRow(label, null).add(c); + c.setName(prefix + label.getName()); + return c; + } + + public JComponent addComponent(String label, JComponent c) { + newGridRow(label, null).add(c); + c.setName(prefix + label); + return c; + } + + public JComponent addComponent(String label, JComponent c, String tooltip) { + newGridRow(label, tooltip).add(c); + c.setName(prefix + label); + c.setToolTipText(TooltipUtils.format(tooltip)); + return c; + } + + public JComponent addComponentAndSpan(String label, JComponent c) { + newGridRow(label, null).add(c).spanRow(); + c.setName(prefix + label); + return c; + } + + public JComponent addComponentAndSpan(String label, JComponent c, int span) { + newGridRow(label, null).add(c,span).spanRow(); + c.setName(prefix + label); + return c; + } + + public JComponent addSubComponent(String label, JComponent c) { + newGridRow().grid(label(label)).add(c); + return c; + } + + public JComponent[] addComponent(JComponent... c) { + newGridRow().add(c); + return c; + } + + public JComponent[] addComponent(int spanRows, JComponent... c) { + newGridRow().addMulti(spanRows, c); + return c; + } + + public JComponent[] addComponent(String label, JComponent... c) { + newGridRow(label, null).add(c); + setNames(label, c); + return c; + } + + public JComponent[] addComponent(JLabel label, JComponent... c) { + newGridRow(label, null).add(c); + setNames(prefix + label.getName()); + return c; + } + + public JComponent[] addComponent(String label, int spanCol, JComponent spanComponent, JComponent... c) { + newGridRow(label, null).add(spanComponent, 3).add(c); + setNames(label, c); + return c; + } + + public JComponent[] addComponentAndSpan(String label, JComponent... c) { + newGridRow(label, null).add(c).spanRow(); + setNames(label, c); + return c; + } + + public void addComponent(List> comps) { + ISpannableGridRow row = newGridRow(); + for (List list : comps) { + if (list.size() == 1) { + row.add(list.get(0)); + } else if (list.size() > 1) { + row.addMulti(list.toArray(new JComponent[0])); + } + } + row.spanRow(); + } + + public void addSpanRow() { + newGridRow().spanRow(); + } + + private void setNames(String label, JComponent... c) { + if (c.length == 1) { + c[0].setName(prefix + label); + } else { + for (int i = 0; i < c.length; i++) { + c[i].setName(prefix + label + "." + i); + } + } + } + + public JPanel addComponentsAsOne(String label, JComponent... c) { + PanelBuilder pb = new PanelBuilder(); + pb.addComponent(c); + setNames(label, c); + JPanel panel = pb.removeMargins().getPanel(); + addComponent(label, panel); + return panel; + } + + public void indent() { + indent++; + } + + public void outdent() { + indent--; + } + + public void clear() { + getPanel().setLayout(null); + getPanel().removeAll(); + this.layout = new DesignGridLayout(parent); + layout.withoutConsistentWidthAcrossNonGridRows(); + layout.emptyRow(); + } + + public GroupController startChoice(String choiceName, GroupController groupController) { + + ShowHideAction action = new ShowHideAction(); + + actions.push(action); + controllers.push(groupController); + + addComponent(choiceName, controllers.peek().getComponent()); + + level++; + + return groupController; + } + + public GroupController startChoice(String choiceName) { + return startChoice(choiceName, (String) null); + } + + public GroupController startChoice(String choiceName, String tooltip) { + ShowHideAction action = new ShowHideAction(); + + GroupController comboBox = comboBox(); + + actions.push(action); + controllers.push(comboBox); + + addComponent(choiceName, controllers.peek().getComponent()); + + level++; + + ((JComboBoxController) comboBox).setToolTipText(TooltipUtils.format(tooltip)); + + return comboBox; + } + + public void endChoice() { + level--; + GroupController combo = controllers.pop(); + combo.addActionListener(actions.pop()); + combo.setSelectedIndex(0); + } + + public void startHidable(String key) { + ShowHideAction action = new ShowHideAction(); + + GroupController hider = hider(); + hideables.put(key, (HideController) hider); + actions.push(action); + controllers.push(hider); + + level++; + } + + public void endHidable() { + level--; + // indent--; + GroupController check = controllers.pop(); + check.addActionListener(actions.pop()); + check.setSelectedIndex(0); + } + + public void setShowing(String hideable, String group) { + // ci sono casi in cui non ci sono delle chiavi ad es turbulence + // openings non ha timevarying + if (hideables.containsKey(hideable)) { + hideables.get(hideable).setSelectedItem(group); + } + } + + public GroupController startCheck(String checkName) { + return startCheck(checkName, (String) null); + } + + public GroupController startCheck(String checkName, String tooltip) { + ShowHideAction action = new ShowHideAction(); + + GroupController checkBox = checkBox(checkName); + + actions.push(action); + controllers.push(checkBox); + + addSeparator(controllers.peek().getComponent()); + + level++; + indent(); + startGroup(checkName); + + ((JCheckBoxController) checkBox).setToolTipText(TooltipUtils.format(tooltip)); + + return checkBox; + } + + public GroupController startCheck(String checkName, JCheckBoxController checkBox) { + return startCheck(checkName, checkBox, null); + } + + public GroupController startCheck(String checkName, JCheckBoxController checkBox, String tooltip) { + ShowHideAction action = new ShowHideAction(); + + actions.push(action); + controllers.push(checkBox); + + addSeparator(controllers.peek().getComponent()); + + level++; + indent(); + startGroup(checkName); + + checkBox.setToolTipText(TooltipUtils.format(tooltip)); + + return checkBox; + } + + public void endCheck() { + endCheck(true); + } + + public void endCheck(boolean enable) { + endGroup(); + level--; + outdent(); + GroupController check = controllers.pop(); + check.addActionListener(actions.pop()); + check.setSelectedIndex(0); + if (enable) + return; // questo significa che se voglio inizialmente deselezionato + // devo fare click due volte + check.setSelectedIndex(0); + } + + public RowGroup startGroup(String groupName) { + return startGroup(groupName, groupName); + } + + public RowGroup startGroup(String groupKey, String groupName) { + RowGroup group = new RowGroup(); + actions.peek().addItem(groupKey, group); // prima questo altrimenti + // scassa + controllers.peek().addGroup(groupKey, groupName); + groups.push(new KeydRowGroup(groupKey, group)); + + return group; + } + + public void endGroup() { + groups.pop().group.hide(); + } + + protected void checkForParent() { + GroupController controller = controllers.pop(); + if (!controllers.isEmpty()) { // sto mettendo un choice dentro un choice + GroupController parentController = controllers.pop(); + parentController.addChildController(controller); + + if (!controllers.isEmpty()) { // sto mettendo un choice dentro un choice dentro un choice + GroupController grandParentController = controllers.peek(); + grandParentController.addChildController(parentController); + } else { + + } + controllers.push(parentController); + } else { + } + controllers.push(controller); + } + + public void setEnabled(boolean enabled) { + if (enabled) + UiUtil.enable(parent); + else + UiUtil.disable(parent); + } + + private JLabel label(String string) { + return new JLabel(string); + } + + private JLabel boldlabel(String string) { + JLabel boldlabel = label(string); + boldlabel.setFont(boldlabel.getFont().deriveFont(Font.BOLD)); + return boldlabel; + } + + // private JLabel bluelabel(String string) { + // JLabel bluelabel = label(string); + // bluelabel.setForeground(Color.BLUE); + // return bluelabel; + // } + + private GroupController checkBox(String name) { + return new JCheckBoxController(name); + } + + private GroupController comboBox() { + return new JComboBoxController(); + } + + private GroupController hider() { + return new HideController(); + } + + class ShowHideAction implements ActionListener { + Map groups = new HashMap(); + String previousKey = null; + + public void addItem(String groupKey, RowGroup group) { + groups.put(groupKey, group); + } + + @Override + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + if (source instanceof GroupController) { + GroupController controller = (GroupController) e.getSource(); + String selectedKey = controller.getSelectedKey(); + handleSelection(selectedKey); + GroupController childController = controller.getChildController(selectedKey); + if (childController != null) { + String childSelectedKey = childController.getSelectedKey(); + childController.setSelectedKey(childSelectedKey); + // GroupController grandChildController = childController.getChildController(childSelectedKey); + // if (grandChildController != null) { + // String grandChildSelectedKey = childController.getSelectedKey(); + // grandChildController.setSelectedKey(grandChildSelectedKey); + // } + } + } else { + if (previousKey != null) { + groups.get(previousKey).hide(); + previousKey = null; + } else { + String selectedKey = groups.keySet().iterator().next(); + groups.get(selectedKey).show(); + previousKey = selectedKey; + } + } + } + + private void handleSelection(String selectedKey) { + beforeSelection(selectedKey); + if (previousKey != null) + groups.get(previousKey).hide(); + if (selectedKey != null) + groups.get(selectedKey).show(); + + previousKey = selectedKey; + afterSelection(selectedKey); + } + } + + protected void beforeSelection(String selectedKey) { + + } + + protected void afterSelection(String selectedKey) { + + } + + protected class KeydRowGroup { + public String groupKey; + public RowGroup group; + + public KeydRowGroup(String groupKey, RowGroup group) { + this.group = group; + this.groupKey = groupKey; + } + } + + /* set a prefix for naming component */ + public void prefix(String name) { + this.prefix = name; + } +} diff --git a/src/eu/engys/util/ui/checkboxtree/AddCheckBoxToTree.java b/src/eu/engys/util/ui/checkboxtree/AddCheckBoxToTree.java new file mode 100644 index 0000000..3d2d757 --- /dev/null +++ b/src/eu/engys/util/ui/checkboxtree/AddCheckBoxToTree.java @@ -0,0 +1,646 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui.checkboxtree; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.MouseInfo; +import java.awt.Point; +import java.awt.PointerInfo; +import java.awt.event.MouseAdapter; +import java.beans.Transient; +import java.util.ArrayList; +import java.util.Stack; + +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; + +import eu.engys.util.ui.checkboxtree.TristateCheckBox.State; +import eu.engys.util.ui.treetable.tree.TreeTableTreeModel; + +public class AddCheckBoxToTree { + + public interface CheckBoxSelectionListener { + void selectionAdded(DefaultMutableTreeNode userObject); + + void selectionRemoved(DefaultMutableTreeNode userObject); + } + + public static CheckTreeManager toTree(JTree tree) { + return new CheckTreeManager(tree); + } + + public static class CheckTreeManager extends MouseAdapter { + + private final CheckTreeSelectionModel checkSelectionModel; + private final CheckTreeCellRenderer checkCellRenderer; + private final SelectionModelProxy selectionModel; + private final JTree tree; + + public CheckTreeManager(final JTree tree) { + this.tree = tree; + this.checkSelectionModel = new CheckTreeSelectionModel(tree.getModel()); + this.checkCellRenderer = new CheckTreeCellRenderer(tree.getCellRenderer(), checkSelectionModel); + this.selectionModel = new SelectionModelProxy(tree, checkSelectionModel); + + tree.setCellRenderer(checkCellRenderer); + tree.setSelectionModel(selectionModel); + + tree.getModel().addTreeModelListener(new CheckTreeModelListener(selectionModel)); + } + + public CheckTreeManager withListener(CheckBoxSelectionListener l) { + checkSelectionModel.setListener(l); + return this; + } + + public void selectNode(DefaultMutableTreeNode node) { + CheckBoxSelectionListener listener = checkSelectionModel.removeListener(); + if (tree.getModel() instanceof DefaultTreeModel) { + DefaultTreeModel treeModel = (DefaultTreeModel) tree.getModel(); + checkSelectionModel.addSelectionPath(new TreePath(treeModel.getPathToRoot(node))); + } else if (tree.getModel() instanceof TreeTableTreeModel) { + TreeTableTreeModel treeModel = (TreeTableTreeModel) tree.getModel(); + checkSelectionModel.addSelectionPath(new TreePath(treeModel.getPathToRoot(node))); + } + checkSelectionModel.setListener(listener); + } + + public void deselectNode(DefaultMutableTreeNode node) { + CheckBoxSelectionListener listener = checkSelectionModel.removeListener(); + if (tree.getModel() instanceof DefaultTreeModel) { + DefaultTreeModel treeModel = (DefaultTreeModel) tree.getModel(); + checkSelectionModel.removeSelectionPath(new TreePath(treeModel.getPathToRoot(node))); + } else if (tree.getModel() instanceof TreeTableTreeModel) { + TreeTableTreeModel treeModel = (TreeTableTreeModel) tree.getModel(); + checkSelectionModel.removeSelectionPath(new TreePath(treeModel.getPathToRoot(node))); + } + checkSelectionModel.setListener(listener); + } + + public void clearSelection() { + checkSelectionModel.clearSelection(); + } + } + + private static class CheckTreeModelListener implements TreeModelListener { + + private SelectionModelProxy selectionModel; + + public CheckTreeModelListener(SelectionModelProxy selectionModel) { + this.selectionModel = selectionModel; + } + + @Override + public void treeNodesChanged(TreeModelEvent e) { + } + + @Override + public void treeNodesInserted(TreeModelEvent e) { + } + + @Override + public void treeNodesRemoved(TreeModelEvent e) { + } + + @Override + public void treeStructureChanged(TreeModelEvent e) { + // System.out.println("AddCheckBoxToTree.CheckTreeModelListener.treeStructureChanged()"); + selectionModel.adjustSelection((DefaultMutableTreeNode) new TreePath(e.getPath()).getLastPathComponent()); + } + + } + + private static class SelectionModelProxy extends DefaultTreeSelectionModel { + private final int hotspot = new JCheckBox().getPreferredSize().width; + private final TreeSelectionModel delegate; + private final JTree tree; + private final CheckTreeSelectionModel checkSelectionModel; + + private SelectionModelProxy(JTree tree, CheckTreeSelectionModel checkSelectionModel) { + this.tree = tree; + this.checkSelectionModel = checkSelectionModel; + this.delegate = tree.getSelectionModel(); + } + + public void adjustSelection(DefaultMutableTreeNode node) { + if (node.isLeaf()) { + if (checkBoxIsVisible(node) && nodeToVisibleItm(node).isVisible()) { + // System.out.println("AddCheckBoxToTree.SelectionModelProxy.adjustSelection() -> "+nodeToVisibleItm(node)); + if (tree.getModel() instanceof DefaultTreeModel) { + checkSelectionModel.addSelectionPath(new TreePath(((DefaultTreeModel) tree.getModel()).getPathToRoot(node))); + } else { + + } + } + } else { + for (int i = 0; i < node.getChildCount(); i++) { + DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i); + adjustSelection(child); + } + } + } + + @Override + public void addSelectionPaths(TreePath[] paths) { + // System.out.println("AddCheckBoxToTree.SelectionModelProxy.addSelectionPaths()"); + Point mousePosition = tree.getMousePosition(); + if (mousePosition != null && paths != null && paths.length > 0) { + if (checkBoxIsVisible(paths[0]) && clickIsInsideCheckBox(mousePosition.x, paths[0])) { + if (isAMultipleSelection(paths[0])) { + setCheckSelectionPaths(paths[0], delegate.getSelectionPaths()); + } else { + setCheckSelectionPath(paths[0]); + } + } else { + delegate.addSelectionPaths(paths); + super.addSelectionPaths(delegate.getSelectionPaths()); + } + } else { + delegate.addSelectionPaths(paths); + super.addSelectionPaths(delegate.getSelectionPaths()); + } + } + + private boolean checkBoxIsVisible(TreePath path) { + return checkBoxIsVisible((DefaultMutableTreeNode) path.getLastPathComponent()); + } + + private boolean checkBoxIsVisible(DefaultMutableTreeNode node) { + return node.getUserObject() instanceof VisibleItem; + } + + private VisibleItem nodeToVisibleItm(DefaultMutableTreeNode node) { + return (VisibleItem) node.getUserObject(); + } + + @Override + public void setSelectionPaths(TreePath[] paths) { + Point mousePosition = getMousePosition(); + if (paths != null && paths.length > 0) { + if (mousePosition != null && checkBoxIsVisible(paths[0]) && clickIsInsideCheckBox(mousePosition.x, paths[0])) { + if (isAMultipleSelection(paths[0])) { + setCheckSelectionPaths(paths[0], delegate.getSelectionPaths()); + } else { + setCheckSelectionPath(paths[0]); + } + } else { + delegate.setSelectionPaths(paths); + super.setSelectionPaths(delegate.getSelectionPaths()); + } + } + } + + private Point getMousePosition() { + Point mousePosition = tree.getMousePosition(); + if (tree.getParent() != null && mousePosition != null) { + return mousePosition; + } else { + PointerInfo pointerInfo = MouseInfo.getPointerInfo(); + Point point = new Point(pointerInfo.getLocation()); + SwingUtilities.convertPointFromScreen(point, tree); + return point; + } + } + + private boolean isAMultipleSelection(TreePath treePath) { + TreePath[] selectionPaths = delegate.getSelectionPaths(); + if (selectionPaths != null && selectionPaths.length > 1) { + for (TreePath tp : selectionPaths) { + if (tp.equals(treePath)) + return true; + } + } + return false; + } + + public boolean clickIsInsideCheckBox(int x, TreePath path) { + return x < tree.getPathBounds(path).x + hotspot; + } + + public void setCheckSelectionPath(TreePath path) { + // System.out.println("AddCheckBoxToTree.SelectionModelProxy.setCheckSelectionPath() >>>>>>>>>>>>> "); + if (path == null) { + return; + } + + boolean selected = checkSelectionModel.isPathSelected(path, true); + + try { + if (selected) { + checkSelectionModel.removeSelectionPath(path); + } else { + checkSelectionModel.addSelectionPath(path); + } + } finally { + tree.treeDidChange(); + tree.getParent().revalidate(); + tree.getParent().repaint(); + } + } + + public void setCheckSelectionPaths(TreePath path, TreePath[] paths) { + if (paths == null || path == null) { + return; + } + + boolean selected = checkSelectionModel.isPathSelected(path, true); + + try { + if (selected) { + checkSelectionModel.removeSelectionPath(path); + for (TreePath treePath : paths) { + checkSelectionModel.removeSelectionPath(treePath); + } + } else { + checkSelectionModel.addSelectionPath(path); + for (TreePath treePath : paths) { + checkSelectionModel.addSelectionPath(treePath); + } + } + } finally { + tree.treeDidChange(); + } + } + } + + public static class CheckTreeSelectionModel extends DefaultTreeSelectionModel { + static final long serialVersionUID = 0; + private TreeModel model; + private CheckBoxSelectionListener listener; + + public CheckTreeSelectionModel(TreeModel model) { + this.model = model; + setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); + } + + public CheckBoxSelectionListener removeListener() { + CheckBoxSelectionListener l = this.listener; + this.listener = null; + return l; + } + + public void setListener(CheckBoxSelectionListener l) { + this.listener = l; + } + + @Override + public void addSelectionPath(TreePath path) { + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.addSelectionPath() "+path); + super.addSelectionPath(path); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent(); + if (listener != null) + listener.selectionAdded(node); + } + + @Override + public void removeSelectionPath(TreePath path) { + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.removeSelectionPath() "+path); + super.removeSelectionPath(path); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent(); + if (listener != null) + listener.selectionRemoved(node); + } + + // tests whether there is any unselected node in the subtree of given path (DONT_CARE) + public boolean isPartiallySelected(TreePath path) { + if (isPathSelected(path, true)) { + return false; + } + + TreePath[] selectionPaths = getSelectionPaths(); + + if (selectionPaths == null) { + return false; + } + + for (int j = 0; j < selectionPaths.length; j++) { + if (isDescendant(selectionPaths[j], path)) { + return true; + } + } + + return false; + } + + // tells whether given path is selected. + // if dig is true, then a path is assumed to be selected, if + // one of its ancestor is selected. + public boolean isPathSelected(TreePath path, boolean dig) { + if (!dig) { + return super.isPathSelected(path); + } + + while (path != null && !super.isPathSelected(path)) { + path = path.getParentPath(); + } + + return path != null; + } + + // is path1 descendant of path2 + private boolean isDescendant(TreePath path1, TreePath path2) { + return path1 != path2 && path2.isDescendant(path1); + } + + public void setSelectionPaths(TreePath[] pPaths) { + throw new UnsupportedOperationException("not implemented yet!!!"); + } + + public void addSelectionPaths(TreePath[] paths) { + + // unselect all descendants of paths[] + for (int i = 0; i < paths.length; i++) { + TreePath path = paths[i]; + + TreePath[] selectionPaths = getSelectionPaths(); + + if (selectionPaths == null) { + break; + } + + ArrayList toBeRemoved = new ArrayList(); + + for (int j = 0; j < selectionPaths.length; j++) { + if (isDescendant(selectionPaths[j], path)) { + toBeRemoved.add(selectionPaths[j]); + } + } + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.addSelectionPaths() -> removeSelectionPaths "+toBeRemoved); + super.removeSelectionPaths((TreePath[]) toBeRemoved.toArray(new TreePath[0])); + } + + // if all siblings are selected then unselect them and select parent + // recursively + // otherwise just select that path. + for (int i = 0; i < paths.length; i++) { + TreePath path = paths[i]; + + TreePath temp = null; + + while (areSiblingsSelected(path)) { + temp = path; + + if (path.getParentPath() == null) { + break; + } + + path = path.getParentPath(); + } + + if (temp != null) { + if (temp.getParentPath() != null) { + addSelectionPath(temp.getParentPath()); + } else { + if (!isSelectionEmpty()) { + removeSelectionPaths(getSelectionPaths()); + } + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.addSelectionPaths() -> addSelectionPaths temp: "+temp); + super.addSelectionPaths(new TreePath[] { temp }); + } + } else { + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.addSelectionPaths() -> addSelectionPaths path: "+path); + super.addSelectionPaths(new TreePath[] { path }); + } + } + } + + // tells whether all siblings of given path are selected. + private boolean areSiblingsSelected(TreePath path) { + TreePath parent = path.getParentPath(); + + if (parent == null) { + return true; + } + + Object node = path.getLastPathComponent(); + + Object parentNode = parent.getLastPathComponent(); + + int childCount = model.getChildCount(parentNode); + + for (int i = 0; i < childCount; i++) { + + Object childNode = model.getChild(parentNode, i); + + if (childNode == node) { + continue; + } + + if (!isPathSelected(parent.pathByAddingChild(childNode))) { + return false; + } + } + + return true; + } + + public void removeSelectionPaths(TreePath[] paths) { + for (int i = 0; i < paths.length; i++) { + TreePath path = paths[i]; + if (path.getPathCount() == 1) { + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.removeSelectionPaths() -> removeSelectionPaths "+path); + super.removeSelectionPaths(new TreePath[] { path }); + } else { + toggleRemoveSelection(path); + } + } + } + + /** + * if any ancestor node of given path is selected then unselect it and selection all its descendants except given path and descendants. otherwise just unselect the given path + */ + private void toggleRemoveSelection(TreePath path) { + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.toggleRemoveSelection() path: " + path); + Stack stack = new Stack(); + TreePath parent = path.getParentPath(); + + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.toggleRemoveSelection() parent: " + parent); + + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.toggleRemoveSelection() is parent selected: " + isPathSelected(parent)); + while (parent != null && !isPathSelected(parent)) { + stack.push(parent); + parent = parent.getParentPath(); + } + if (parent != null) + stack.push(parent); + else { + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.toggleRemoveSelection() -> removeSelectionPaths path: "+path); + super.removeSelectionPaths(new TreePath[] { path }); + return; + } + + while (!stack.isEmpty()) { + TreePath temp = (TreePath) stack.pop(); + + TreePath peekPath = stack.isEmpty() ? path : (TreePath) stack.peek(); + + Object node = temp.getLastPathComponent(); + Object peekNode = peekPath.getLastPathComponent(); + int childCount = model.getChildCount(node); + + for (int i = 0; i < childCount; i++) { + Object childNode = model.getChild(node, i); + + if (childNode != peekNode) { + TreePath pathByAddingChild = temp.pathByAddingChild(childNode); + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.toggleRemoveSelection() -> addSelectionPAth pathByAddingChild: "+pathByAddingChild); + super.addSelectionPaths(new TreePath[] { pathByAddingChild }); + } + } + } + + // System.out.println("AddCheckBoxToTree.CheckTreeSelectionModel.toggleRemoveSelection() -> removeSelectionPaths parent: "+parent); + super.removeSelectionPaths(new TreePath[] { parent }); + } + + public TreeModel getModel() { + return model; + } + } + + public static class CheckTreeCellRenderer extends JPanel implements TreeCellRenderer { + + static final long serialVersionUID = 0; + + CheckTreeSelectionModel selectionModel; + private TreeCellRenderer delegate; + private TristateCheckBox checkBox; + private JCheckBox fakeBox; + + public CheckTreeCellRenderer(TreeCellRenderer delegate, CheckTreeSelectionModel selectionModel) { + this.delegate = delegate; + this.selectionModel = selectionModel; + + setLayout(new BorderLayout()); + setOpaque(false); + + checkBox = new TristateCheckBox(); + checkBox.setOpaque(false); + + fakeBox = new JCheckBox() { + protected void paintComponent(java.awt.Graphics g) { + }; + }; + fakeBox.setOpaque(false); + } + + public void setBackgroundSelectionColor(Color c) { + if (delegate instanceof DefaultTreeCellRenderer) { + ((DefaultTreeCellRenderer) delegate).setBackgroundSelectionColor(c); + } + } + + public void setBackgroundNonSelectionColor(Color c) { + if (delegate instanceof DefaultTreeCellRenderer) { + ((DefaultTreeCellRenderer) delegate).setBackgroundNonSelectionColor(c); + } + } + + public void setTextSelectionColor(Color c) { + if (delegate instanceof DefaultTreeCellRenderer) { + ((DefaultTreeCellRenderer) delegate).setTextSelectionColor(c); + } + } + + public void setTextNonSelectionColor(Color c) { + if (delegate instanceof DefaultTreeCellRenderer) { + ((DefaultTreeCellRenderer) delegate).setTextNonSelectionColor(c); + } + } + + @Override + @Transient + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + d.width = d.width + 20; + return d; + } + + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + Component renderer = delegate.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + + TreePath path = tree.getPathForRow(row); + + if (path != null) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent(); + // int level = node.getLevel(); + + if (node.getLevel() == 1) { + setFont(tree.getFont().deriveFont(Font.BOLD)); + } else { + setFont(tree.getFont().deriveFont(Font.PLAIN)); + } + + if (node.isRoot() || !(node.getUserObject() instanceof VisibleItem)) { + removeAll(); + add(renderer, BorderLayout.CENTER); + return this; + } + + if ((node.getUserObject() instanceof LoadableItem && !((LoadableItem) node.getUserObject()).isLoaded())) { + removeAll(); + add(renderer, BorderLayout.CENTER); + return this; + } + + if (selectionModel.isPathSelected(path, true)) { + checkBox.setState(State.SELECTED); + // System.out.println(">>>>>> selected: " + path); + } else { + checkBox.setState(State.NOT_SELECTED); + // System.out.println(">>>>>> not selected: " + path); + } + + if (selectionModel.isPartiallySelected(path)) { + checkBox.setState(State.DONT_CARE); + } + } + + removeAll(); + + add(checkBox, BorderLayout.WEST); + add(renderer, BorderLayout.CENTER); + + return this; + } + } +} diff --git a/src/eu/engys/util/ui/checkboxtree/FileTreeViewer.java b/src/eu/engys/util/ui/checkboxtree/FileTreeViewer.java new file mode 100644 index 0000000..4c1192f --- /dev/null +++ b/src/eu/engys/util/ui/checkboxtree/FileTreeViewer.java @@ -0,0 +1,366 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.checkboxtree; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.File; +import java.util.Vector; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; +import javax.swing.UIManager; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; + +import eu.engys.util.ui.UiUtil; + +public class FileTreeViewer extends JFrame { + + private static final long serialVersionUID = 1L; + public static final ImageIcon ICON_COMPUTER = new ImageIcon(""); + public static final ImageIcon ICON_DISK = new ImageIcon("defaults1.png"); + public static final ImageIcon ICON_FOLDER = new ImageIcon("fol_orig.png"); + public static final ImageIcon ICON_EXPANDEDFOLDER = new ImageIcon("folder_open.png"); + + protected JTree m_tree; + protected DefaultTreeModel m_model; + + protected TreePath m_clickedPath; + + public FileTreeViewer() { + super("Demo tree check box"); + setSize(400, 300); + + DefaultMutableTreeNode top = new DefaultMutableTreeNode(new IconData(ICON_COMPUTER, null, "Computer")); + + DefaultMutableTreeNode node; + File[] roots = File.listRoots(); + for (int k = 0; k < roots.length; k++) { + node = new DefaultMutableTreeNode(new IconData(ICON_DISK, null, new FileNode(roots[k]))); + top.add(node); + node.add(new DefaultMutableTreeNode(new Boolean(true))); + } + + m_model = new DefaultTreeModel(top); + + m_tree = new JTree(m_model) { + public String getToolTipText(MouseEvent ev) { + if (ev == null) + return null; + TreePath path = m_tree.getPathForLocation(ev.getX(), ev.getY()); + if (path != null) { + FileNode fnode = getFileNode(getTreeNode(path)); + if (fnode == null) + return null; + File f = fnode.getFile(); + return (f == null ? null : f.getPath()); + } + return null; + } + }; + + ToolTipManager.sharedInstance().registerComponent(m_tree); + + m_tree.putClientProperty("JTree.lineStyle", "Angled"); + + TreeCellRenderer renderer = new IconCellRenderer(); + m_tree.setCellRenderer(renderer); + + m_tree.addTreeExpansionListener(new DirExpansionListener()); + + m_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + m_tree.setShowsRootHandles(true); + m_tree.setEditable(false); + + AddCheckBoxToTree.toTree(m_tree); + + JScrollPane s = new JScrollPane(); + s.getViewport().add(m_tree); + getContentPane().add(s, BorderLayout.CENTER); + + WindowListener wndCloser = new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }; + + addWindowListener(wndCloser); + + setVisible(true); + } + + DefaultMutableTreeNode getTreeNode(TreePath path) { + return (DefaultMutableTreeNode) (path.getLastPathComponent()); + } + + FileNode getFileNode(DefaultMutableTreeNode node) { + if (node == null) + return null; + Object obj = node.getUserObject(); + if (obj instanceof IconData) + obj = ((IconData) obj).getObject(); + if (obj instanceof FileNode) + return (FileNode) obj; + else + return null; + } + + // Make sure expansion is threaded and updating the tree model + // only occurs within the event dispatching thread. + class DirExpansionListener implements TreeExpansionListener { + public void treeExpanded(TreeExpansionEvent event) { + final DefaultMutableTreeNode node = getTreeNode(event.getPath()); + final FileNode fnode = getFileNode(node); + + Thread runner = new Thread() { + public void run() { + if (fnode != null && fnode.expand(node)) { + Runnable runnable = new Runnable() { + public void run() { + m_model.reload(node); + } + }; + SwingUtilities.invokeLater(runnable); + } + } + }; + runner.start(); + } + + public void treeCollapsed(TreeExpansionEvent event) { + } + } + +} + +class IconCellRenderer extends JLabel implements TreeCellRenderer { + protected Color m_textSelectionColor; + protected Color m_textNonSelectionColor; + protected Color m_bkSelectionColor; + protected Color m_bkNonSelectionColor; + protected Color m_borderSelectionColor; + + protected boolean m_selected; + + public IconCellRenderer() { + super(); + m_textSelectionColor = UIManager.getColor("Tree.selectionForeground"); + m_textNonSelectionColor = UIManager.getColor("Tree.textForeground"); + m_bkSelectionColor = UIManager.getColor("Tree.selectionBackground"); + m_bkNonSelectionColor = UIManager.getColor("Tree.textBackground"); + m_borderSelectionColor = UIManager.getColor("Tree.selectionBorderColor"); + setOpaque(false); + } + + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) + + { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + Object obj = node.getUserObject(); + setText(obj.toString()); + + if (obj instanceof Boolean) + setText("Retrieving data..."); + + if (obj instanceof IconData) { + IconData idata = (IconData) obj; + if (expanded) + setIcon(idata.getExpandedIcon()); + else + setIcon(idata.getIcon()); + } else + setIcon(null); + + setFont(tree.getFont()); + setForeground(sel ? m_textSelectionColor : m_textNonSelectionColor); + setBackground(sel ? m_bkSelectionColor : m_bkNonSelectionColor); + m_selected = sel; + return this; + } + + public void paintComponent(Graphics g) { + Color bColor = getBackground(); + Icon icon = getIcon(); + + g.setColor(bColor); + int offset = 0; + if (icon != null && getText() != null) + offset = (icon.getIconWidth() + getIconTextGap()); + g.fillRect(offset, 0, getWidth() - 1 - offset, getHeight() - 1); + + if (m_selected) { + g.setColor(m_borderSelectionColor); + g.drawRect(offset, 0, getWidth() - 1 - offset, getHeight() - 1); + } + + super.paintComponent(g); + } +} + +class IconData { + protected Icon m_icon; + protected Icon m_expandedIcon; + protected Object m_data; + + public IconData(Icon icon, Object data) { + m_icon = icon; + m_expandedIcon = null; + m_data = data; + } + + public IconData(Icon icon, Icon expandedIcon, Object data) { + m_icon = icon; + m_expandedIcon = expandedIcon; + m_data = data; + } + + public Icon getIcon() { + return m_icon; + } + + public Icon getExpandedIcon() { + return m_expandedIcon != null ? m_expandedIcon : m_icon; + } + + public Object getObject() { + return m_data; + } + + public String toString() { + return m_data.toString(); + } +} + +class FileNode { + protected File m_file; + + public FileNode(File file) { + m_file = file; + } + + public File getFile() { + return m_file; + } + + public String toString() { + return m_file.getName().length() > 0 ? m_file.getName() : m_file.getPath(); + } + + public boolean expand(DefaultMutableTreeNode parent) { + DefaultMutableTreeNode flag = (DefaultMutableTreeNode) parent.getFirstChild(); + if (flag == null) // No flag + return false; + Object obj = flag.getUserObject(); + if (!(obj instanceof Boolean)) + return false; // Already expanded + + parent.removeAllChildren(); // Remove Flag + + File[] files = listFiles(); + if (files == null) + return true; + + Vector v = new Vector(); + + for (int k = 0; k < files.length; k++) { + File f = files[k]; + if (!(f.isDirectory())) + continue; + + FileNode newNode = new FileNode(f); + + boolean isAdded = false; + for (int i = 0; i < v.size(); i++) { + FileNode nd = (FileNode) v.elementAt(i); + if (newNode.compareTo(nd) < 0) { + v.insertElementAt(newNode, i); + isAdded = true; + break; + } + } + if (!isAdded) + v.addElement(newNode); + } + + for (int i = 0; i < v.size(); i++) { + FileNode nd = (FileNode) v.elementAt(i); + IconData idata = new IconData(FileTreeViewer.ICON_FOLDER, FileTreeViewer.ICON_EXPANDEDFOLDER, nd); + DefaultMutableTreeNode node = new DefaultMutableTreeNode(idata); + parent.add(node); + + if (nd.hasSubDirs()) + node.add(new DefaultMutableTreeNode(new Boolean(true))); + } + + return true; + } + + public boolean hasSubDirs() { + File[] files = listFiles(); + if (files == null) + return false; + for (int k = 0; k < files.length; k++) { + if (files[k].isDirectory()) + return true; + } + return false; + } + + public int compareTo(FileNode toCompare) { + return m_file.getName().compareToIgnoreCase(toCompare.m_file.getName()); + } + + protected File[] listFiles() { + if (!m_file.isDirectory()) + return null; + try { + return m_file.listFiles(); + } catch (Exception ex) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "Error reading directory " + m_file.getAbsolutePath(), "Warning", JOptionPane.WARNING_MESSAGE); + return null; + } + } +} diff --git a/src/eu/engys/util/ui/checkboxtree/LoadableItem.java b/src/eu/engys/util/ui/checkboxtree/LoadableItem.java new file mode 100644 index 0000000..6d2d88f --- /dev/null +++ b/src/eu/engys/util/ui/checkboxtree/LoadableItem.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.checkboxtree; + +public interface LoadableItem { + + void setVisible(boolean b); + boolean isVisible(); + String getName(); + boolean isLoaded(); + void setLoaded(boolean b); +} diff --git a/src/eu/engys/util/ui/checkboxtree/RootVisibleItem.java b/src/eu/engys/util/ui/checkboxtree/RootVisibleItem.java new file mode 100644 index 0000000..505f40f --- /dev/null +++ b/src/eu/engys/util/ui/checkboxtree/RootVisibleItem.java @@ -0,0 +1,58 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.checkboxtree; + +public class RootVisibleItem implements VisibleItem { + + private final String name; + private boolean visible; + + public RootVisibleItem(String name) { + this.name = name; + } + + @Override + public void setVisible(boolean b) { + this.visible = b; + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } + +} diff --git a/src/eu/engys/util/ui/checkboxtree/RootVisibleLoadableItem.java b/src/eu/engys/util/ui/checkboxtree/RootVisibleLoadableItem.java new file mode 100644 index 0000000..5e185fd --- /dev/null +++ b/src/eu/engys/util/ui/checkboxtree/RootVisibleLoadableItem.java @@ -0,0 +1,46 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.checkboxtree; + +public class RootVisibleLoadableItem extends RootVisibleItem implements LoadableItem { + + private boolean loaded; + + public RootVisibleLoadableItem(String name) { + super(name); + } + + @Override + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } + + @Override + public boolean isLoaded() { + return loaded; + } +} diff --git a/src/eu/engys/util/ui/checkboxtree/RootVisibleLoadableTreeNode.java b/src/eu/engys/util/ui/checkboxtree/RootVisibleLoadableTreeNode.java new file mode 100644 index 0000000..f902785 --- /dev/null +++ b/src/eu/engys/util/ui/checkboxtree/RootVisibleLoadableTreeNode.java @@ -0,0 +1,62 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.checkboxtree; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; + +public class RootVisibleLoadableTreeNode extends DefaultMutableTreeNode { + + public RootVisibleLoadableTreeNode(String name) { + super(new RootVisibleLoadableItem(name)); + } + + private void checkForChanges() { + if (getChildCount() > 0) { + TreeNode child = getChildAt(0); + if (child instanceof DefaultMutableTreeNode) { + DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode) child; + Object obj = dmtn.getUserObject(); + if (obj instanceof LoadableItem) { + LoadableItem li = (LoadableItem) obj; + getVisibleLoadableUserObject().setLoaded(li.isLoaded()); + } + } + } + } + + public RootVisibleLoadableItem getVisibleLoadableUserObject() { + return (RootVisibleLoadableItem) userObject; + } + + @Override + public Object getUserObject() { + checkForChanges(); + return super.getUserObject(); + } + +} diff --git a/src/eu/engys/util/ui/checkboxtree/TristateCheckBox.java b/src/eu/engys/util/ui/checkboxtree/TristateCheckBox.java new file mode 100644 index 0000000..db1197a --- /dev/null +++ b/src/eu/engys/util/ui/checkboxtree/TristateCheckBox.java @@ -0,0 +1,295 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.checkboxtree; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.AbstractAction; +import javax.swing.ActionMap; +import javax.swing.ButtonGroup; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JCheckBox; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ActionMapUIResource; + +public class TristateCheckBox extends JCheckBox { + static final long serialVersionUID = 0; + + private static final Icon EYE_ICON = new ImageIcon(TristateCheckBox.class.getClassLoader().getResource("eu/engys/resources/images/eye16.png")); + private static final Icon EYE_NO_ICON = new ImageIcon(TristateCheckBox.class.getClassLoader().getResource("eu/engys/resources/images/eye_no16.png")); + + public enum State { NOT_SELECTED, SELECTED, DONT_CARE }; + + private final TristateDecorator model; + + public TristateCheckBox(String text, Icon icon, State initial) { + super(text, icon); +// setIcon(EYE_NO_ICON); +// setSelectedIcon(EYE_ICON); +// setPressedIcon(EYE_ICON); +// setRolloverIcon(EYE_ICON); +// setRolloverSelectedIcon(EYE_NO_ICON); + + // Add a listener for when the mouse is pressed + super.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + grabFocus(); + model.nextState(); + } + }); + + // Reset the keyboard action map + ActionMap map = new ActionMapUIResource(); + map.put("pressed", new AbstractAction() { + + private static final long serialVersionUID = 1L; + + public void actionPerformed(ActionEvent e) { + grabFocus(); + model.nextState(); + } + }); + + map.put("released", null); + + SwingUtilities.replaceUIActionMap(this, map); + + // set the model to the adapted model + model = new TristateDecorator(getModel()); + setModel(model); + setState(initial); + } + + // Constractor types: + public TristateCheckBox(String text, State initial) { + this(text, null, initial); + } + + public TristateCheckBox(String text) { + this(text, State.DONT_CARE); + } + + public TristateCheckBox() { + this(null); + } + + /** No one may add mouse listeners, not even Swing! */ + public void addMouseListener(MouseListener l) { + } + + /** + * Set the new state to either SELECTED, NOT_SELECTED or DONT_CARE. If state + * == null, it is treated as DONT_CARE. + */ + public void setState(State state) { + model.setState(state); + } + + /** + * Return the current state, which is determined by the selection status of + * the model. + */ + public State getState() { + return model.getState(); + } + + public void setSelected(boolean b) { + if (b) { + setState(State.SELECTED); + } else { + setState(State.NOT_SELECTED); + } + } + + /** + * Exactly which Design Pattern is this? Is it an Adapter, a Proxy or a + * Decorator? In this case, my vote lies with the Decorator, because we are + * extending functionality and "decorating" the original model with a more + * powerful model. + */ + private class TristateDecorator implements ButtonModel { + private final ButtonModel other; + + private TristateDecorator(ButtonModel other) { + this.other = other; + } + + private void setState(State state) { + if (state == State.NOT_SELECTED) { + other.setArmed(false); + setPressed(false); + setSelected(false); + } else if (state == State.SELECTED) { + other.setArmed(false); + setPressed(false); + setSelected(true); + } else { // either "null" or DONT_CARE + other.setArmed(true); + setPressed(true); + setSelected(false); + } + } + + /** + * The current state is embedded in the selection / armed state of the + * model. + * + * We return the SELECTED state when the checkbox is selected but not + * armed, DONT_CARE state when the checkbox is selected and armed (grey) + * and NOT_SELECTED when the checkbox is deselected. + */ + private State getState() { + if (isSelected() && !isArmed()) { + // normal black tick + return State.SELECTED; + } else if (isSelected() && isArmed()) { + // don't care grey tick + return State.DONT_CARE; + } else { + // normal deselected + return State.NOT_SELECTED; + } + } + + /** We rotate between NOT_SELECTED, SELECTED and DONT_CARE. */ + private void nextState() { + State current = getState(); + if (current == State.NOT_SELECTED) { + setState(State.SELECTED); + } else if (current == State.SELECTED) { + setState(State.DONT_CARE); + } else if (current == State.DONT_CARE) { + setState(State.NOT_SELECTED); + } + } + + /** Filter: No one may change the armed status except us. */ + public void setArmed(boolean b) { + } + + /** + * We disable focusing on the component when it is not enabled. + */ + public void setEnabled(boolean b) { + setFocusable(b); + other.setEnabled(b); + } + + /** + * All these methods simply delegate to the "other" model that is being + * decorated. + */ + public boolean isArmed() { + return other.isArmed(); + } + + public boolean isSelected() { + return other.isSelected(); + } + + public boolean isEnabled() { + return other.isEnabled(); + } + + public boolean isPressed() { + return other.isPressed(); + } + + public boolean isRollover() { + return other.isRollover(); + } + + public int getMnemonic() { + return other.getMnemonic(); + } + + public String getActionCommand() { + return other.getActionCommand(); + } + + public Object[] getSelectedObjects() { + return other.getSelectedObjects(); + } + + public void setSelected(boolean b) { + other.setSelected(b); + } + + public void setPressed(boolean b) { + other.setPressed(b); + } + + public void setRollover(boolean b) { + other.setRollover(b); + } + + public void setMnemonic(int key) { + other.setMnemonic(key); + } + + public void setActionCommand(String s) { + other.setActionCommand(s); + } + + public void setGroup(ButtonGroup group) { + other.setGroup(group); + } + + public void addActionListener(ActionListener l) { + other.addActionListener(l); + } + + public void removeActionListener(ActionListener l) { + other.removeActionListener(l); + } + + public void addItemListener(ItemListener l) { + other.addItemListener(l); + } + + public void removeItemListener(ItemListener l) { + other.removeItemListener(l); + } + + public void addChangeListener(ChangeListener l) { + other.addChangeListener(l); + } + + public void removeChangeListener(ChangeListener l) { + other.removeChangeListener(l); + } + + } +} diff --git a/src/eu/engys/util/ui/checkboxtree/VisibleItem.java b/src/eu/engys/util/ui/checkboxtree/VisibleItem.java new file mode 100644 index 0000000..346de42 --- /dev/null +++ b/src/eu/engys/util/ui/checkboxtree/VisibleItem.java @@ -0,0 +1,35 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui.checkboxtree; + +public interface VisibleItem { + + void setVisible(boolean b); + + boolean isVisible(); + + String getName(); +} diff --git a/src/eu/engys/util/ui/groupcolumnheader/ColumnGroup.java b/src/eu/engys/util/ui/groupcolumnheader/ColumnGroup.java new file mode 100644 index 0000000..a593645 --- /dev/null +++ b/src/eu/engys/util/ui/groupcolumnheader/ColumnGroup.java @@ -0,0 +1,143 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.groupcolumnheader; + +import java.awt.Component; +import java.awt.Dimension; +import java.util.Iterator; +import java.util.Vector; + +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.UIManager; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; + +public class ColumnGroup { + + protected TableCellRenderer renderer; + protected Vector v; + protected String text; + protected int margin = 0; + + public ColumnGroup(String text) { + this(null, text); + } + + public ColumnGroup(TableCellRenderer renderer, String text) { + if (renderer == null) { + this.renderer = new DefaultTableCellRenderer() { + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JTableHeader header = table.getTableHeader(); + if (header != null) { + setForeground(header.getForeground()); + setBackground(header.getBackground()); + setFont(header.getFont()); + } + setHorizontalAlignment(JLabel.CENTER); + setText((value == null) ? "" : value.toString()); + setBorder(UIManager.getBorder("TableHeader.cellBorder")); + return this; + } + }; + } else { + this.renderer = renderer; + } + this.text = text; + v = new Vector<>(); + } + + public void add(Object obj) { + if (obj == null) { + return; + } + v.addElement(obj); + } + + @SuppressWarnings("unchecked") + public Vector getColumnGroups(TableColumn c, Vector g) { + g.addElement(this); + if (v.contains(c)) + return g; + Iterator iter = v.iterator(); + while (iter.hasNext()) { + Object obj = iter.next(); + if (obj instanceof ColumnGroup) { + Vector groups = (Vector) ((ColumnGroup) obj).getColumnGroups(c, (Vector) g.clone()); + if (groups != null) + return groups; + } + } + return null; + } + + public TableCellRenderer getHeaderRenderer() { + return renderer; + } + + public void setHeaderRenderer(TableCellRenderer renderer) { + if (renderer != null) { + this.renderer = renderer; + } + } + + public Object getHeaderValue() { + return text; + } + + public Dimension getSize(JTable table) { + Component comp = renderer.getTableCellRendererComponent(table, getHeaderValue(), false, false, -1, -1); + int height = comp.getPreferredSize().height; + int width = 0; + Iterator iter = v.iterator(); + while (iter.hasNext()) { + Object obj = iter.next(); + if (obj instanceof TableColumn) { + TableColumn aColumn = (TableColumn) obj; + width += aColumn.getWidth(); + } else { + width += ((ColumnGroup) obj).getSize(table).width; + } + } + return new Dimension(width, height); + } + + public void setColumnMargin(int margin) { + this.margin = margin; + Iterator iter = v.iterator(); + while (iter.hasNext()) { + Object obj = iter.next(); + if (obj instanceof ColumnGroup) { + ((ColumnGroup) obj).setColumnMargin(margin); + } + } + } +} diff --git a/src/eu/engys/util/ui/groupcolumnheader/GroupableTableColumnModel.java b/src/eu/engys/util/ui/groupcolumnheader/GroupableTableColumnModel.java new file mode 100644 index 0000000..4ce29b7 --- /dev/null +++ b/src/eu/engys/util/ui/groupcolumnheader/GroupableTableColumnModel.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.groupcolumnheader; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Vector; + +import javax.swing.table.DefaultTableColumnModel; +import javax.swing.table.TableColumn; + +public class GroupableTableColumnModel extends DefaultTableColumnModel { + + protected ArrayList columnGroups = new ArrayList<>(); + + public void addColumnGroup(ColumnGroup columnGroup) { + columnGroups.add(columnGroup); + } + + public Iterator columnGroupIterator() { + return columnGroups.iterator(); + } + + public ColumnGroup getColumnGroup(int index) { + if (index >= 0 && index < columnGroups.size()) { + return (ColumnGroup) columnGroups.get(index); + } + return null; + } + + public Iterator getColumnGroups(TableColumn col) { + if (columnGroups.isEmpty()) + return null; + Iterator iter = columnGroups.iterator(); + while (iter.hasNext()) { + ColumnGroup cGroup = iter.next(); + Vector v_ret = cGroup.getColumnGroups(col, new Vector<>()); + if (v_ret != null) { + return v_ret.iterator(); + } + } + return null; + } +} diff --git a/src/eu/engys/util/ui/groupcolumnheader/GroupableTableHeader.java b/src/eu/engys/util/ui/groupcolumnheader/GroupableTableHeader.java new file mode 100644 index 0000000..3c2a2ee --- /dev/null +++ b/src/eu/engys/util/ui/groupcolumnheader/GroupableTableHeader.java @@ -0,0 +1,50 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.groupcolumnheader; + +import java.util.Iterator; + +import javax.swing.table.JTableHeader; + +public class GroupableTableHeader extends JTableHeader { + + public GroupableTableHeader(GroupableTableColumnModel model) { + super(model); + setUI(new GroupableTableHeaderUI()); + setReorderingAllowed(false); + } + + public void setColumnMargin() { + int columnMargin = getColumnModel().getColumnMargin(); + Iterator iter = ((GroupableTableColumnModel) columnModel).columnGroupIterator(); + while (iter.hasNext()) { + ColumnGroup cGroup = (ColumnGroup) iter.next(); + cGroup.setColumnMargin(columnMargin); + } + } + +} diff --git a/src/eu/engys/util/ui/groupcolumnheader/GroupableTableHeaderUI.java b/src/eu/engys/util/ui/groupcolumnheader/GroupableTableHeaderUI.java new file mode 100644 index 0000000..a835efc --- /dev/null +++ b/src/eu/engys/util/ui/groupcolumnheader/GroupableTableHeaderUI.java @@ -0,0 +1,157 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.groupcolumnheader; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Vector; + +import javax.swing.JComponent; +import javax.swing.plaf.basic.BasicTableHeaderUI; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; + +public class GroupableTableHeaderUI extends BasicTableHeaderUI { + + protected Vector paintedGroups = new Vector(); + + @Override + public void paint(Graphics g, JComponent c) { + Rectangle clipBounds = g.getClipBounds(); + GroupableTableColumnModel cm = (GroupableTableColumnModel) header.getColumnModel(); + if (cm == null) + return; + ((GroupableTableHeader) header).setColumnMargin(); + int column = 0; + Dimension size = header.getSize(); + Rectangle cellRect = new Rectangle(0, 0, size.width, size.height); + Hashtable h = new Hashtable(); + + Enumeration columns = cm.getColumns(); + while (columns.hasMoreElements()) { + cellRect.height = size.height; + cellRect.y = 0; + TableColumn aColumn = (TableColumn) columns.nextElement(); + Iterator colGrpIter = cm.getColumnGroups(aColumn); + if (colGrpIter != null) { + int groupHeight = 0; + while (colGrpIter.hasNext()) { + ColumnGroup cGroup = (ColumnGroup) colGrpIter.next(); + Rectangle groupRect = (Rectangle) h.get(cGroup); + if (groupRect == null) { + groupRect = new Rectangle(cellRect); + Dimension d = cGroup.getSize(header.getTable()); + groupRect.width = d.width; + groupRect.height = d.height; + h.put(cGroup, groupRect); + } + if (!paintedGroups.contains(cGroup)) { + paintCell(g, groupRect, cGroup); + paintedGroups.add(cGroup); + } + groupHeight += groupRect.height; + cellRect.height = size.height - groupHeight; + cellRect.y = groupHeight; + } + } + cellRect.width = aColumn.getWidth(); + if (cellRect.intersects(clipBounds)) { + paintCell(g, cellRect, column); + } + cellRect.x += cellRect.width; + column++; + } + paintedGroups.clear(); + } + + private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) { + TableColumn aColumn = header.getColumnModel().getColumn(columnIndex); + TableCellRenderer renderer = aColumn.getHeaderRenderer(); + if (renderer == null) { + renderer = header.getDefaultRenderer(); + } + Component component = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false, false, -1, columnIndex); + rendererPane.add(component); + rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); + } + + private void paintCell(Graphics g, Rectangle cellRect, ColumnGroup cGroup) { + TableCellRenderer renderer = cGroup.getHeaderRenderer(); + Component component = renderer.getTableCellRendererComponent(header.getTable(), cGroup.getHeaderValue(), false, false, -1, -1); + rendererPane.add(component); + rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); + } + + private int getHeaderHeight() { + int height = 0; + GroupableTableColumnModel columnModel = (GroupableTableColumnModel) header.getColumnModel(); + for (int column = 0; column < columnModel.getColumnCount(); column++) { + TableColumn aColumn = columnModel.getColumn(column); + TableCellRenderer renderer = aColumn.getHeaderRenderer(); + if (renderer == null) { + renderer = header.getDefaultRenderer(); + } + Component comp = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false, false, -1, column); + int cHeight = comp.getPreferredSize().height; + Iterator iter = columnModel.getColumnGroups(aColumn); + if (iter != null) { + while (iter.hasNext()) { + ColumnGroup cGroup = (ColumnGroup) iter.next(); + cHeight += cGroup.getSize(header.getTable()).height; + } + } + height = Math.max(height, cHeight); + } + return height; + } + + private Dimension createHeaderSize(long width) { + TableColumnModel columnModel = header.getColumnModel(); + width += columnModel.getColumnMargin() * columnModel.getColumnCount(); + if (width > Integer.MAX_VALUE) { + width = Integer.MAX_VALUE; + } + return new Dimension((int) width, getHeaderHeight()); + } + + @Override + public Dimension getPreferredSize(JComponent c) { + long width = 0; + Enumeration columns = header.getColumnModel().getColumns(); + while (columns.hasMoreElements()) { + TableColumn aColumn = (TableColumn) columns.nextElement(); + width = width + aColumn.getPreferredWidth(); + } + return createHeaderSize(width); + } +} diff --git a/src/eu/engys/util/ui/stepcomponent/FlatButtonUI.java b/src/eu/engys/util/ui/stepcomponent/FlatButtonUI.java new file mode 100644 index 0000000..3b8a311 --- /dev/null +++ b/src/eu/engys/util/ui/stepcomponent/FlatButtonUI.java @@ -0,0 +1,173 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.stepcomponent; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicToggleButtonUI; + +import sun.swing.SwingUtilities2; + +public class FlatButtonUI extends BasicToggleButtonUI { + + Color bgColor = new Color(200, 220, 240);// = Color.LIGHT_GRAY;//new Color(200, 220, 240); + Color selColor = new Color(66, 100, 150);// = Color.GRAY;//new Color(66, 100, 150); + + Color fgColor = Color.BLACK; + Color selFgColor = Color.WHITE; + Color borderColor = Color.WHITE; + + protected void installDefaults(AbstractButton b) { + String str = getPropertyPrefix(); + LookAndFeel.installColorsAndFont(b, str + "background", str + "foreground", str + "font"); +// bgColor = b.getBackground(); +// selColor = bgColor.darker(); + } + + public void paint(Graphics g, JComponent c) { + AbstractButton b = (AbstractButton) c; + + ButtonModel model = b.getModel(); + + Dimension size = b.getSize(); + FontMetrics fm = g.getFontMetrics(); + + //Insets i = c.getInsets(); + + Rectangle viewRect = new Rectangle(size); + +// viewRect.x += i.left; +// viewRect.y += i.top; +// viewRect.width -= (i.right + viewRect.x); +// viewRect.height -= (i.bottom + viewRect.y); + + Rectangle iconRect = new Rectangle(); + Rectangle textRect = new Rectangle(); + + Font f = c.getFont(); + g.setFont(f); + + // layout the text and icon + String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(), b.getIcon(), b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, b.getText() == null ? 0 : b.getIconTextGap()); + + if (model.isArmed() && model.isPressed() || model.isSelected()) { + paintButton(g,b,viewRect, selColor); + } else if (model.isRollover()) { + paintButton(g,b,viewRect, Color.ORANGE); + } else if (!b.isEnabled()) { + paintButton(g,b,viewRect, Color.LIGHT_GRAY); + } else { + paintButton(g,b,viewRect, bgColor); + } + + // Paint the Icon +// if(b.getIcon() != null) { +// paintIcon(g, b, iconRect); +// } + + // Draw the Text + if(text != null && !text.equals("")) { + paintText(g, b, textRect, text); + } + +// // draw the dashed focus line. +// if (b.isFocusPainted() && b.hasFocus()) { +// paintFocus(g, b, viewRect, textRect, iconRect); +// } + } + + protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) { + ButtonModel model = b.getModel(); + FontMetrics fm = SwingUtilities2.getFontMetrics(b, g); + int mnemonicIndex = b.getDisplayedMnemonicIndex(); + + /* Draw the Text */ + if(model.isEnabled()) { + /*** paint the text normally */ + g.setColor(model.isSelected()? selFgColor : fgColor); + SwingUtilities2.drawStringUnderlineCharAt(b, g,text, mnemonicIndex, textRect.x + getTextShiftOffset(), textRect.y + fm.getAscent() + getTextShiftOffset()); + } + else { + /*** paint the text disabled ***/ + g.setColor(b.getBackground().brighter()); + SwingUtilities2.drawStringUnderlineCharAt(b, g,text, mnemonicIndex, textRect.x, textRect.y + fm.getAscent()); + g.setColor(b.getBackground().darker()); + SwingUtilities2.drawStringUnderlineCharAt(b, g,text, mnemonicIndex, textRect.x - 1, textRect.y + fm.getAscent() - 1); + } + } + + private void paintButton(Graphics g, AbstractButton b, Rectangle viewRect, Color color) { + Polygon poly = new Polygon(); + + int BoRDo = 2; + int BRD = BoRDo/2; + int DRIFT = 10; + + poly.addPoint(viewRect.x + BRD, viewRect.y + BRD); + + if (b.isSelected()) { + poly.addPoint(viewRect.x + viewRect.width - DRIFT - 2*BRD, viewRect.y + BRD); + poly.addPoint(viewRect.x + viewRect.width - 2*BRD, viewRect.y + viewRect.height/2); + poly.addPoint(viewRect.x + viewRect.width - DRIFT - 2*BRD, viewRect.y + viewRect.height - 2*BRD); + } else { + poly.addPoint(viewRect.x + viewRect.width - DRIFT - 2*BRD, viewRect.y + BRD); + poly.addPoint(viewRect.x + viewRect.width - DRIFT - 2*BRD, viewRect.y + viewRect.height - 2*BRD); + } + + poly.addPoint(viewRect.x + BRD, viewRect.y + viewRect.height - 2*BRD); + + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + if (b.isSelected()) { + g2.setColor(color); + g2.fillPolygon(poly); + } + + g.setColor(borderColor); + g2.setStroke(new BasicStroke(BoRDo)); + g.drawPolygon(poly); + + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + } + + protected void paintIcon(Graphics g, AbstractButton b, Rectangle iconRect) {} + } diff --git a/src/eu/engys/util/ui/stepcomponent/MultiLineLabel.java b/src/eu/engys/util/ui/stepcomponent/MultiLineLabel.java new file mode 100644 index 0000000..de74b08 --- /dev/null +++ b/src/eu/engys/util/ui/stepcomponent/MultiLineLabel.java @@ -0,0 +1,698 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.stepcomponent; + +/* + * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved. + * + * http://izpack.org/ + * http://izpack.codehaus.org/ + * + * Copyright 1997,2002 Elmar Grom + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Toolkit; +import java.util.Map; +import java.util.Vector; + +import javax.swing.JComponent; + +/*---------------------------------------------------------------------------*/ +/** + *
+ * MultiLineLabel may be used in place of javax.swing.JLabel.
+ *
+ * This class implements a component that is capable of displaying multiple + * lines of text. Line breaks are inserted automatically whenever a line of text + * extends beyond the predefined maximum line length. Line breaks will only be + * inserted between words, except where a single word is longer than the maximum + * line length. Line breaks may be forced at any location in the text by + * inserting a newline (\n). White space that is not valuable (i.e. is placed at + * the beginning of a new line or at the very beginning or end of the text) is + * removed.
+ *
+ * Note: you can set the maximum width of the label either through one of + * the constructors or you can call setMaxWidth() explicitly. If + * this is not set, MultiLineLabel will derive its width from the + * parent component. + * + * @author Elmar Grom + * @version 1.0 / 04-13-02 + */ +/*---------------------------------------------------------------------------* + * Reviving some old code here that was written before there was swing. + * The original was written to work with awt. I had to do some masaging to + * make it a JComponent and I hope it behaves like a reasonably good mannered + * swing component. + *---------------------------------------------------------------------------*/ +public class MultiLineLabel extends JComponent { + + /** + * + */ + private static final long serialVersionUID = 4051045255031894837L; + + public static final int LEFT = 0; // alignment constants + + public static final int CENTER = 1; + + public static final int RIGHT = 2; + + public static final int DEFAULT_MARGIN = 10; + + public static final int DEFAULT_ALIGN = LEFT; + + public static final int LEAST_ALLOWED = 200; // default setting for + + // maxAllowed + + private static final int FOUND = 0; // constants for string search. + + private static final int NOT_FOUND = 1; + + private static final int NOT_DONE = 0; + + private static final int DONE = 1; + + private static final char[] WHITE_SPACE = { ' ', '\n', '\t' }; + + private static final char[] SPACES = { ' ', '\t' }; + + private static final char NEW_LINE = '\n'; + + protected Vector line = new Vector();// text lines to + // display + + protected String labelText; // text lines to display + + protected int numLines; // the number of lines + + protected int marginHeight; // top and bottom margins + + protected int marginWidth; // left and right margins + + protected int lineHeight; // total height of the font + + protected int lineAscent; // font height above the baseline + + protected int lineDescent; // font hight below the baseline + + protected int[] lineWidth; // width of each line + + protected int maxWidth; // width of the widest line + + private int maxAllowed = LEAST_ALLOWED; // max width allowed to use + + private boolean maxAllowedSet = false; // signals if the max allowed width + + // has been explicitly set + + protected int alignment = LEFT; // default text alignment + + /*-------------------------------------------------------------------*/ + /** + * Constructor + * + * @param text + * the text to be displayed + * @param horMargin + * the horizontal margin for the label + * @param vertMargin + * the vertical margin for the label + * @param maxWidth + * the maximum allowed width of the text + * @param justify + * the text alignment for the label + */ + /*-------------------------------------------------------------------* + * + *-------------------------------------------------------------------*/ + public MultiLineLabel(String text, int horMargin, int vertMargin, int maxWidth, int justify) { + this.labelText = text; + this.marginWidth = horMargin; + this.marginHeight = vertMargin; + this.maxAllowed = maxWidth; + this.maxAllowedSet = true; + this.alignment = justify; + } + + /*-------------------------------------------------------------------*/ + /** + * Constructor using default max-width and alignment. + * + * @param label + * the text to be displayed + * @param marginWidth + * the horizontal margin for the label + * @param marginHeight + * the vertical margin for the label + */ + /*-------------------------------------------------------------------* + * + *-------------------------------------------------------------------*/ + public MultiLineLabel(String label, int marginWidth, int marginHeight) { + this.labelText = label; + this.marginWidth = marginWidth; + this.marginHeight = marginHeight; + } + + /*-------------------------------------------------------------------*/ + /** + * Constructor using default max-width, and margin. + * + * @param label + * the text to be displayed + * @param alignment + * the text alignment for the label + */ + /*-------------------------------------------------------------------* + * + *-------------------------------------------------------------------*/ + public MultiLineLabel(String label, int alignment) { + this.labelText = label; + this.alignment = alignment; + } + + /*-------------------------------------------------------------------*/ + /** + * Constructor using default max-width, alignment, and margin. + * + * @param label + * the text to be displayed + */ + /*-------------------------------------------------------------------* + * + *-------------------------------------------------------------------*/ + public MultiLineLabel(String label) { + this.labelText = label; + } + + /*-------------------------------------------------------------------*/ + /** + * This method searches the target string for occurences of any of the + * characters in the source string. The return value is the position of the + * first hit. Based on the mode parameter the hit position is either the + * position where any of the source characters first was found or the first + * position where none of the source characters where found. + * + * @param target + * the text to be searched + * @param start + * the start position for the search + * @param source + * the list of characters to be searched for + * @param mode + * the search mode FOUND = reports first found NOT_FOUND = + * reports first not found + * @return position of the first occurence + */ + /*-------------------------------------------------------------------* + * + *-------------------------------------------------------------------*/ + int getPosition(String target, int start, char[] source, int mode) { + int status; + int position; + int scan; + int targetEnd; + int sourceLength; + char temp; + + targetEnd = (target.length() - 1); + sourceLength = source.length; + position = start; + + if (mode == FOUND) { + status = NOT_DONE; + while (status != DONE) { + position++; + if (!(position < targetEnd)) // end of string reached, the + // next + { // statement would cause a runtime error + return (targetEnd); + } + temp = target.charAt(position); + for (scan = 0; scan < sourceLength; scan++) // walk through the + // source + { // string and compare each char + if (source[scan] == temp) { + status = DONE; + } + } + } + return (position); + } else if (mode == NOT_FOUND) { + status = NOT_DONE; + while (status != DONE) { + position++; + if (!(position < targetEnd)) // end of string reached, the + // next + { // statement would cause a runtime error + return (targetEnd); + } + temp = target.charAt(position); + status = DONE; + for (scan = 0; scan < sourceLength; scan++) // walk through the + // source + { // string and compare each char + if (source[scan] == temp) { + status = NOT_DONE; + } + } + } + return (position); + } + return (0); + } + + /*-------------------------------------------------------------------*/ + /** + * This method scans the input string until the max allowed width is + * reached. The return value indicates the position just before this + * happens. + * + * @param word + * word to break + * @return position character position just before the string is too long + */ + /*-------------------------------------------------------------------* + * + *-------------------------------------------------------------------*/ + int breakWord(String word, FontMetrics fm) { + int width; + int currentPos; + int endPos; + + width = 0; + currentPos = 0; + endPos = word.length() - 1; + + // make sure we don't end up with a negative position + if (endPos <= 0) { + return (currentPos); + } + // seek the position where the word first is longer than allowed + while ((width < maxAllowed) && (currentPos < endPos)) { + currentPos++; + width = fm.stringWidth(labelText.substring(0, currentPos)); + } + // adjust to get the chatacter just before (this should make it a bit + // shorter than allowed!) + if (currentPos != endPos) { + currentPos--; + } + return (currentPos); + } + + /*-------------------------------------------------------------------*/ + /** + * This method breaks the label text up into multiple lines of text. Line + * breaks are established based on the maximum available space. A new line + * is started whenever a line break is encountered, even if the permissible + * length is not yet reached. Words are broken only if a single word happens + * to be longer than one line. + */ + /*-------------------------------------------------------------------*/ + private void divideLabel() { + int width; + int startPos; + int currentPos; + int lastPos; + int endPos; + + line.clear(); + FontMetrics fm = this.getFontMetrics(this.getFont()); + + startPos = 0; + currentPos = startPos; + lastPos = currentPos; + endPos = (labelText.length() - 1); + + while (currentPos < endPos) { + width = 0; + // ---------------------------------------------------------------- + // find the first substring that occupies more than the granted + // space. + // Break at the end of the string or a line break + // ---------------------------------------------------------------- + while ((width < maxAllowed) && (currentPos < endPos) && (labelText.charAt(currentPos) != NEW_LINE)) { + lastPos = currentPos; + currentPos = getPosition(labelText, currentPos, WHITE_SPACE, FOUND); + width = fm.stringWidth(labelText.substring(startPos, currentPos)); + } + // ---------------------------------------------------------------- + // if we have a line break we want to copy everything up to + // currentPos + // ---------------------------------------------------------------- + if (labelText.charAt(currentPos) == NEW_LINE) { + lastPos = currentPos; + } + // ---------------------------------------------------------------- + // if we are at the end of the string we want to copy everything up + // to + // the last character. Since there seems to be a problem to get the + // last + // character if the substring definition ends at the very last + // character + // we have to call a different substring function than normal. + // ---------------------------------------------------------------- + if (currentPos == endPos && width <= maxAllowed) { + lastPos = currentPos; + String s = labelText.substring(startPos); + line.addElement(s); + } + // ---------------------------------------------------------------- + // in all other cases copy the substring that we have found to fit + // and + // add it as a new line of text to the line vector. + // ---------------------------------------------------------------- + else { + // ------------------------------------------------------------ + // make sure it's not a single word. If so we must break it at + // the + // proper location. + // ------------------------------------------------------------ + if (lastPos == startPos) { + lastPos = startPos + breakWord(labelText.substring(startPos, currentPos), fm); + } + String s = labelText.substring(startPos, lastPos); + line.addElement(s); + } + + // ---------------------------------------------------------------- + // seek for the end of the white space to cut out any unnecessary + // spaces + // and tabs and set the new start condition. + // ---------------------------------------------------------------- + startPos = getPosition(labelText, lastPos, SPACES, NOT_FOUND); + currentPos = startPos; + } + + numLines = line.size(); + lineWidth = new int[numLines]; + } + + /*-------------------------------------------------------------------*/ + /** + * This method finds the font size, each line width and the widest line. + */ + /*-------------------------------------------------------------------*/ + protected void measure() { + if (!maxAllowedSet) { + maxAllowed = getParent().getSize().width; + } + + // return if width is too small + if (maxAllowed < (20)) { + return; + } + + FontMetrics fm = this.getFontMetrics(this.getFont()); + + // return if no font metrics available + if (fm == null) { + return; + } + + divideLabel(); + + this.lineHeight = fm.getHeight(); + this.lineDescent = fm.getDescent(); + this.maxWidth = 0; + + for (int i = 0; i < numLines; i++) { + this.lineWidth[i] = fm.stringWidth(this.line.elementAt(i)); + if (this.lineWidth[i] > this.maxWidth) { + this.maxWidth = this.lineWidth[i]; + } + } + } + + /*-------------------------------------------------------------------*/ + /** + * This method draws the label. + * + * @param graphics + * the device context + */ + /*-------------------------------------------------------------------*/ + public void paintComponent(Graphics graphics) { + int x; + int y; + + measure(); + Dimension d = this.getSize(); + + y = lineAscent + (d.height - (numLines * lineHeight)) / 2; + + Toolkit tk = Toolkit.getDefaultToolkit(); + Map desktopHints = (Map)(tk.getDesktopProperty("awt.font.desktophints")); + Graphics2D g2d = (Graphics2D)graphics; + + if(desktopHints != null) { + g2d.addRenderingHints(desktopHints); + } + for (int i = 0; i < numLines; i++) { + y += lineHeight; + switch (alignment) { + case LEFT: + x = marginWidth; + break; + case CENTER: + x = (d.width - lineWidth[i]) / 2; + break; + case RIGHT: + x = d.width - marginWidth - lineWidth[i]; + break; + default: + x = (d.width - lineWidth[i]) / 2; + } + graphics.drawString(line.elementAt(i), x, y-lineDescent); + //graphics.drawRect(x, y-lineHeight, d.width, lineHeight); + } + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to set the label text + * + * @param labelText + * the text to be displayed + */ + /*-------------------------------------------------------------------*/ + public void setText(String labelText) { + this.labelText = labelText; + repaint(); + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to set the font that should be used to draw the + * label + * + * @param font + * font to be used within the label + */ + /*-------------------------------------------------------------------*/ + public void setFont(Font font) { + super.setFont(font); + repaint(); + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to set the color in which the text should be + * drawn + * + * @param color + * the text color + */ + /*-------------------------------------------------------------------*/ + public void setColor(Color color) { + super.setForeground(color); + repaint(); + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to set the text alignment for the label + * + * @param alignment + * the alignment, possible values are LEFT, CENTER, RIGHT + */ + /*-------------------------------------------------------------------*/ + public void setJustify(int alignment) { + this.alignment = alignment; + repaint(); + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to set the max allowed line width + * + * @param width + * the max allowed line width in pixels + */ + /*-------------------------------------------------------------------*/ + public void setMaxWidth(int width) { + this.maxAllowed = width; + this.maxAllowedSet = true; + repaint(); + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to set the horizontal margin + * + * @param margin + * the margin to the left and to the right of the label + */ + /*-------------------------------------------------------------------*/ + public void setMarginWidth(int margin) { + this.marginWidth = margin; + repaint(); + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to set the vertical margin for the label + * + * @param margin + * the margin on the top and bottom of the label + */ + /*-------------------------------------------------------------------*/ + public void setMarginHeight(int margin) { + this.marginHeight = margin; + repaint(); + } + + /*-------------------------------------------------------------------*/ + /** + * Moves and resizes this component. The new location of the top-left corner + * is specified by x and y, and the new size is + * specified by width and height. + * + * @param x + * The new x-coordinate of this component. + * @param y + * The new y-coordinate of this component. + * @param width + * The new width of this component. + * @param height + * The new height of this component. + */ + /*-------------------------------------------------------------------*/ + public void setBounds(int x, int y, int width, int height) { + super.setBounds(x, y, width, height); + this.maxAllowed = width; + this.maxAllowedSet = true; + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to retrieve the text alignment for the label + * + * @return alignment the text alignment currently in use for the label + */ + /*-------------------------------------------------------------------*/ + public int getAlignment() { + return (this.alignment); + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to retrieve the horizontal margin for the label + * + * @return marginWidth the margin currently in use to the left and right of + * the label + */ + /*-------------------------------------------------------------------*/ + public int getMarginWidth() { + return (this.marginWidth); + } + + /*-------------------------------------------------------------------*/ + /** + * This method may be used to retrieve the vertical margin for the label + * + * @return marginHeight the margin currently in use on the top and bottom of + * the label + */ + /*-------------------------------------------------------------------*/ + public int getMarginHeight() { + return (this.marginHeight); + } + + /*-------------------------------------------------------------------*/ + /** + * This method is typically used by the layout manager, it reports the + * necessary space to display the label comfortably. + */ + /*-------------------------------------------------------------------*/ + public Dimension getPreferredSize() { + measure(); + return (new Dimension(maxAllowed, (numLines * (lineHeight + lineAscent + lineDescent)) + (2 * marginHeight))); + } + + /*-------------------------------------------------------------------*/ + /** + * This method is typically used by the layout manager, it reports the + * absolute minimum space required to display the entire label. + */ + /*-------------------------------------------------------------------*/ + public Dimension getMinimumSize() { + measure(); + return (new Dimension(maxAllowed, (numLines * (lineHeight + lineAscent + lineDescent)) + (2 * marginHeight))); + } + + /*-------------------------------------------------------------------*/ + /** + * This method is called by the system after this object is first created. + */ + /*-------------------------------------------------------------------*/ + public void addNotify() { + super.addNotify(); // invoke the superclass + } +} +/*---------------------------------------------------------------------------*/ diff --git a/src/eu/engys/util/ui/stepcomponent/RichJLabel.java b/src/eu/engys/util/ui/stepcomponent/RichJLabel.java new file mode 100644 index 0000000..c357d1d --- /dev/null +++ b/src/eu/engys/util/ui/stepcomponent/RichJLabel.java @@ -0,0 +1,142 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.stepcomponent; + +/* +Swing Hacks Tips and Tools for Killer GUIs +By Joshua Marinacci, Chris Adamson +First Edition June 2005 +Series: Hacks +ISBN: 0-596-00907-0 +Pages: 542 +website: http://www.oreilly.com/catalog/swinghks/ + */ +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.font.LineMetrics; + +import javax.swing.JFrame; +import javax.swing.JLabel; + +public class RichJLabel extends JLabel { + + private int tracking; + + public RichJLabel(String text, int tracking) { + super(text); + this.tracking = tracking; + } + + private int left_x, left_y, right_x, right_y; + + private Color left_color, right_color; + + public void setLeftShadow(int x, int y, Color color) { + left_x = x; + left_y = y; + left_color = color; + } + + public void setRightShadow(int x, int y, Color color) { + right_x = x; + right_y = y; + right_color = color; + } + + public Dimension getPreferredSize() { + String text = getText(); + FontMetrics fm = this.getFontMetrics(getFont()); + + int w = fm.stringWidth(text); + w += (text.length() - 1) * tracking; + w += left_x + right_x; + + int h = fm.getHeight(); + h += left_y + right_y; + + return new Dimension(w, h); + } + + public void paintComponent(Graphics g) { + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + char[] chars = getText().toCharArray(); + + FontMetrics fm = this.getFontMetrics(getFont()); + int h = fm.getAscent(); + LineMetrics lm = fm.getLineMetrics(getText(), g); + g.setFont(getFont()); + + int x = 0; + + for (int i = 0; i < chars.length; i++) { + char ch = chars[i]; + int w = fm.charWidth(ch) + tracking; + + g.setColor(getLeft_color()); + g.drawString("" + chars[i], x - left_x, h - left_y); + + g.setColor(getRight_color()); + g.drawString("" + chars[i], x + right_x, h + right_y); + + g.setColor(getForeground()); + g.drawString("" + chars[i], x, h); + + x += w; + } + + } + + public Color getLeft_color() { + return left_color; + } + + public Color getRight_color() { + return right_color; + } + + public static void main(String[] args) { + RichJLabel label = new RichJLabel("www.java2s.com", 0); + label.setLeftShadow(1, 1, Color.white); + label.setRightShadow(1, 1, Color.white); + label.setForeground(Color.blue); + label.setFont(label.getFont().deriveFont(140f)); + + JFrame frame = new JFrame("RichJLabel hack"); + frame.getContentPane().add(label); + frame.pack(); + frame.setVisible(true); + } + + public static void p(String str) { + System.out.println(str); + } +} diff --git a/src/eu/engys/util/ui/stepcomponent/StepButton.java b/src/eu/engys/util/ui/stepcomponent/StepButton.java new file mode 100644 index 0000000..216e742 --- /dev/null +++ b/src/eu/engys/util/ui/stepcomponent/StepButton.java @@ -0,0 +1,160 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.stepcomponent; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.JComponent; +import javax.swing.JToggleButton; +import javax.swing.border.Border; + +class StepButton extends JToggleButton { + + private final int drift; + private final int borderWidth; + private final int buttonHeight; + private final boolean first; + private final boolean last; + + private JComponent title; + private JComponent description; + + private boolean changeForeground() { + return model.isArmed() && model.isPressed() || model.isSelected(); + } + + public StepButton(String title, String text, int drift, int borderWidth, int buttonHeight) { + this(title, text, drift, borderWidth, buttonHeight, false, false); + } + + public StepButton(String title, String text, int drift, int borderWidth, int buttonHeight, boolean first, boolean last) { + super(); + this.drift = drift; + this.borderWidth = borderWidth; + this.buttonHeight = buttonHeight; + this.first = first; + this.last = last; + setName(title); + + configureTitle(title); + if (text != null) + configureDescription(text); + setActionCommand(title); + configureButton(); + } + + public void configureButton() { + setLayout(new GridBagLayout()); + setRolloverEnabled(true); + Insets in = new Insets(0, first? getDrift() : 2*getDrift() , 0, first? getDrift() : getDrift()); + + if (description != null) { + add(title, new GridBagConstraints(0,0, 1,1, 1.0, 1.0, GridBagConstraints.SOUTHWEST, GridBagConstraints.HORIZONTAL, in, 0,0)); + add(description, new GridBagConstraints(0,1, 1,1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, in, 0,0)); + } else { + add(title, new GridBagConstraints(0,0, 1,1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, in, 0,0)); + } + } + + private void configureDescription(String text) { + description = new MultiLineLabel(text) { + public Color getForeground() { + return changeForeground()? Color.WHITE : Color.BLACK; + } + }; + } + + private void configureTitle(String text) { +// title = new RichJLabel(text, 0) { +// public Color getForeground() { +// return changeForeground()? Color.WHITE : Color.BLACK; +// }; +// +// @Override +// public Color getLeft_color() { +// return changeForeground()? Color.DARK_GRAY : super.getLeft_color(); +// } +// +// @Override +// public Color getRight_color() { +// return changeForeground()? Color.BLACK : super.getRight_color(); +// } +// }; +// title.setLeftShadow(1, 1, Color.white); +// title.setRightShadow(1, 1, Color.lightGray); +// +// title.setForeground(Color.blue); +// title.setFont(title.getFont().deriveFont(20f)); + title = new MultiLineLabel(text, MultiLineLabel.CENTER) { + public Color getForeground() { + return changeForeground()? Color.WHITE : Color.BLACK; + } + }; + //title.setFont(getFont().deriveFont(getFont().getSize2D()+4)); + //title.setBorder(BorderFactory.createLineBorder(Color.RED)); + } + + public void updateUI() { + setUI(new StepButtonUI()); + } + + @Override + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + return new Dimension(d.width, buttonHeight); + } + + public boolean isFirst() { + return first; + } + + public boolean isLast() { + return last; + } + + public int getDrift() { + return drift; + } + + public int getBorderWidth() { + return borderWidth; + } + + @Override + public void setBorder(Border border) { + throw new IllegalStateException("Don't use this method"); + } + + @Override + public Border getBorder() { + return null; + } +} diff --git a/src/eu/engys/util/ui/stepcomponent/StepButtonUI.java b/src/eu/engys/util/ui/stepcomponent/StepButtonUI.java new file mode 100644 index 0000000..a0d8764 --- /dev/null +++ b/src/eu/engys/util/ui/stepcomponent/StepButtonUI.java @@ -0,0 +1,156 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.stepcomponent; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicToggleButtonUI; + +public class StepButtonUI extends BasicToggleButtonUI { + + Color bgColor = new Color(200, 220, 240); + Color selColor = new Color(66, 100, 150); + + Color fgColor = Color.BLACK; + Color selFgColor = Color.WHITE; + + protected void installDefaults(AbstractButton b) { + String str = getPropertyPrefix(); + LookAndFeel.installColorsAndFont(b, str + "background", str + "foreground", str + "font"); + } + + public void paint(Graphics g, JComponent c) { + StepButton b = (StepButton) c; + boolean isFirst = b.isFirst(); + boolean isLast = b.isLast(); + + ButtonModel model = b.getModel(); + + Dimension size = b.getSize(); + FontMetrics fm = g.getFontMetrics(); + + //Insets i = c.getInsets(); + + Rectangle viewRect = new Rectangle(size); + +// viewRect.x += i.left; +// viewRect.y += i.top; +// viewRect.width -= (i.right + viewRect.x); +// viewRect.height -= (i.bottom + viewRect.y); + + Rectangle iconRect = new Rectangle(); + Rectangle textRect = new Rectangle(); + + Font f = c.getFont(); + g.setFont(f); + + // layout the text and icon + String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(), b.getIcon(), b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, b.getText() == null ? 0 : b.getIconTextGap()); + + if (model.isArmed() && model.isPressed() || model.isSelected()) { + paintButton(g,b,viewRect, selColor, isFirst, isLast); + } else if (model.isRollover()) { + paintButton(g,b,viewRect, Color.ORANGE, isFirst, isLast); + } else if (!b.isEnabled()) { + paintButton(g,b,viewRect, Color.LIGHT_GRAY, isFirst, isLast); + } else { + paintButton(g,b,viewRect, bgColor, isFirst, isLast); + } + + // Paint the Icon +// if(b.getIcon() != null) { +// paintIcon(g, b, iconRect); +// } + + // Draw the Text + if(text != null && !text.equals("")) { + paintText(g, b, textRect, text); + } + +// // draw the dashed focus line. +// if (b.isFocusPainted() && b.hasFocus()) { +// paintFocus(g, b, viewRect, textRect, iconRect); +// } + } + + protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) {} + + private void paintButton(Graphics g, StepButton b, Rectangle viewRect, Color color, boolean isFirst, boolean isLast) { + Polygon poly = new Polygon(); + + int BoRDo = b.getBorderWidth(); + int BRD = BoRDo/2; + int DRIFT = b.getDrift(); + +// if (isFirst) +// poly.addPoint(viewRect.x + BRD + DRIFT, viewRect.y + BRD); +// else + poly.addPoint(viewRect.x + BRD, viewRect.y + BRD); + + if (isLast) { + poly.addPoint(viewRect.x + viewRect.width - 2*BRD, viewRect.y + BRD); + poly.addPoint(viewRect.x + viewRect.width - 2*BRD, viewRect.y + viewRect.height - 2*BRD); + } else { + poly.addPoint(viewRect.x + viewRect.width - DRIFT - 2*BRD, viewRect.y + BRD); + poly.addPoint(viewRect.x + viewRect.width - 2*BRD, viewRect.y + viewRect.height/2); + poly.addPoint(viewRect.x + viewRect.width - DRIFT - 2*BRD, viewRect.y + viewRect.height - 2*BRD); + } + +// if (isFirst) +// poly.addPoint(viewRect.x + BRD + DRIFT, viewRect.y + viewRect.height - BRD); +// else + poly.addPoint(viewRect.x + BRD, viewRect.y + viewRect.height - 2*BRD); + + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + g2.setColor(color); + g2.fillPolygon(poly); + + g.setColor(Color.WHITE); + g2.setStroke(new BasicStroke(BoRDo)); + g.drawPolygon(poly); + + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + } + + protected void paintIcon(Graphics g, AbstractButton b, Rectangle iconRect) {} + } diff --git a/src/eu/engys/util/ui/stepcomponent/StepComponent.java b/src/eu/engys/util/ui/stepcomponent/StepComponent.java new file mode 100644 index 0000000..5784243 --- /dev/null +++ b/src/eu/engys/util/ui/stepcomponent/StepComponent.java @@ -0,0 +1,141 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.stepcomponent; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.ButtonGroup; +import javax.swing.DefaultSingleSelectionModel; +import javax.swing.JPanel; + +public class StepComponent extends JPanel { + + private static final int HEIGHT = 30; + private static final int DRIFT = 30; + private static final int BRD = 4; + + private final ButtonGroup bg = new ButtonGroup(); + private final ArrayList buttons = new ArrayList(); + + private int drift = DRIFT; + private int borderWidth = BRD; + private int buttonHeight = HEIGHT; + + private DefaultSingleSelectionModel selectionModel; + private SelectionActionListener selectionListener = new SelectionActionListener(); + + public StepComponent() { + this(DRIFT, BRD, HEIGHT); + } + + public StepComponent(int drift, int borderWidth, int height) { +// super(new FlowLayout(FlowLayout.CENTER, -2*drift, 0)); + super(new StepComponentLayout(drift)); + this.drift = drift; + this.borderWidth = borderWidth; + this.buttonHeight = height; + setOpaque(false); + this.selectionModel = new DefaultSingleSelectionModel(); + } + + public void addStep(String title, String text) { + addButton(new StepButton(title, text, drift, borderWidth, buttonHeight)); + } + + public void addFirst(String title, String text) { + addButton(new StepButton(title, text, drift, borderWidth, buttonHeight, true, false)); + } + + public void addLast(String title, String text) { + addButton(new StepButton(title, text, drift, borderWidth, buttonHeight, false, true)); + } + + private void addButton(StepButton button) { + bg.add(button); + buttons.add(button); + add(button); + button.addActionListener(selectionListener); + } + + public String getSelectedStep() { + int index = selectionModel.getSelectedIndex(); + if (index < 0) return null; + return buttons.get(index).getActionCommand(); + } + + public void setSelectedStep(String actionCommand) { + for(int i=0; i 0) { + ncols = (ncomponents + nrows - 1) / nrows; + } else { + nrows = (ncomponents + ncols - 1) / ncols; + } + int w = 0; + int h = 0; + for (int i = 0 ; i < ncomponents ; i++) { + Component comp = parent.getComponent(i); + Dimension d = comp.getPreferredSize(); + if (w < d.width) { + w = d.width; + } + if (h < d.height) { + h = d.height; + } + } + return new Dimension(insets.left + insets.right + ncols*w + (ncols)*hgap, + insets.top + insets.bottom + nrows*h + (nrows-1)*vgap); + } + } + + public Dimension minimumLayoutSize(Container parent) { +// synchronized (parent.getTreeLock()) { +// Insets insets = parent.getInsets(); +// int ncomponents = parent.getComponentCount(); +// int nrows = rows; +// int ncols = cols; +// +// if (nrows > 0) { +// ncols = (ncomponents + nrows - 1) / nrows; +// } else { +// nrows = (ncomponents + ncols - 1) / ncols; +// } +// int w = 0; +// int h = 0; +// for (int i = 0 ; i < ncomponents ; i++) { +// Component comp = parent.getComponent(i); +// Dimension d = comp.getMinimumSize(); +// if (w < d.width) { +// w = d.width; +// } +// if (h < d.height) { +// h = d.height; +// } +// } +// return new Dimension(insets.left + insets.right + ncols*w + (ncols)*hgap, +// insets.top + insets.bottom + nrows*h + (nrows-1)*vgap); +// } + return new Dimension(); + } + + public void layoutContainer(Container parent) { + synchronized (parent.getTreeLock()) { + Insets insets = parent.getInsets(); + int ncomponents = parent.getComponentCount(); + int nrows = rows; + int ncols = cols; + boolean ltr = parent.getComponentOrientation().isLeftToRight(); + + if (ncomponents == 0) { + return; + } + if (nrows > 0) { + ncols = (ncomponents + nrows - 1) / nrows; + } else { + nrows = (ncomponents + ncols - 1) / ncols; + } + + int w = parent.getWidth() - (insets.left + insets.right); + int h = parent.getHeight() - (insets.top + insets.bottom); + w = (w - (ncols) * hgap) / ncols; + h = (h - (nrows) * vgap) / nrows; + + if (ltr) { + for (int c = 0, x = insets.left ; c < ncols ; c++, x += w + hgap) { + for (int r = 0, y = insets.top ; r < nrows ; r++, y += h + vgap) { + int i = r * ncols + c; + if (i < ncomponents) { + if (i == 0) {//first + parent.getComponent(i).setBounds(x, y, w+hgap, h); + x += hgap; +// } else if (i == ncomponents-1) {//last +// parent.getComponent(i).setBounds(x, y, w+hgap, h); + } else { + parent.getComponent(i).setBounds(x, y, w, h); + } + } + } + } + } else { + for (int c = 0, x = parent.getWidth() - insets.right - w; c < ncols ; c++, x -= w + hgap) { + for (int r = 0, y = insets.top ; r < nrows ; r++, y += h + vgap) { + int i = r * ncols + c; + if (i < ncomponents) { + parent.getComponent(i).setBounds(x, y, w, h); + } + } + } + } + } + } + + /** + * Returns the string representation of this grid layout's values. + * @return a string representation of this grid layout + */ + public String toString() { + return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + + ",rows=" + rows + ",cols=" + cols + "]"; + } +} diff --git a/src/eu/engys/util/ui/textfields/AdaptativeFormat.java b/src/eu/engys/util/ui/textfields/AdaptativeFormat.java new file mode 100644 index 0000000..85fdc27 --- /dev/null +++ b/src/eu/engys/util/ui/textfields/AdaptativeFormat.java @@ -0,0 +1,67 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields; + +import java.text.FieldPosition; +import java.text.NumberFormat; +import java.text.ParsePosition; + +public class AdaptativeFormat extends NumberFormat { + + private NumberFormat f1; + private NumberFormat f2; + + private double lowThreshold; + private double highThreshold; + + public AdaptativeFormat(NumberFormat f1, NumberFormat f2, int decimalPlaces) { + this.f1 = f1; + this.f2 = f2; + + this.lowThreshold = Math.pow(10, -decimalPlaces); + this.highThreshold = Math.pow(10, decimalPlaces); + } + + @Override + public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) { + return useFirstFormat(number) ? f1.format(number, toAppendTo, pos) : f2.format(number, toAppendTo, pos); + } + + @Override + public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) { + return useFirstFormat(number) ? f1.format(number, toAppendTo, pos) : f2.format(number, toAppendTo, pos); + } + + @Override + public Number parse(String source, ParsePosition parsePosition) { + return f1.parse(source.replace('e', 'E'), parsePosition); + } + + private boolean useFirstFormat(double number) { + return number == 0 || (Math.abs(number) > lowThreshold && Math.abs(number) < highThreshold); + } +} diff --git a/src/eu/engys/util/ui/textfields/DoubleField.java b/src/eu/engys/util/ui/textfields/DoubleField.java new file mode 100644 index 0000000..2f44638 --- /dev/null +++ b/src/eu/engys/util/ui/textfields/DoubleField.java @@ -0,0 +1,245 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields; + +import java.awt.Font; +import java.awt.Insets; +import java.beans.Transient; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +import javax.swing.text.DefaultFormatterFactory; +import javax.swing.text.NumberFormatter; + +import eu.engys.util.ui.textfields.verifiers.DoubleVerifier; + +/** + * Provides a JFormattedTextField that accepts only doubles. Allows for the setting of the number + * of decimal places displayed, and min/max values allowed. + * + * See also + * https://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html + * http://stackoverflow.com/a/12978182 + * http://www.javalobby.org/java/forums/t20551.html + * + */ +public class DoubleField extends PromptTextField { + + private static final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(Locale.US); + + public static final int DEFAULT_PLACES = 10; + + private double minValue = -Double.MAX_VALUE; + private double maxValue = Double.MAX_VALUE; + + private DefaultFormatterFactory factory; + private DoubleVerifier verifier; + + private Font normalFont; + private Font nonuniformFont; + + private Double defaultValue; + + public DoubleField(Insets insets) { + super(insets); + } + + public DoubleField() { + this(-Double.MAX_VALUE, Double.MAX_VALUE, Double.valueOf(0), DEFAULT_PLACES); + } + + public DoubleField(int places) { + this(-Double.MAX_VALUE, Double.MAX_VALUE, Double.valueOf(0), places); + } + + public DoubleField(double min, double max) throws IllegalArgumentException { + this(min, max, Double.valueOf(0), DEFAULT_PLACES); + } + + public DoubleField(double min, double max, Double value) throws IllegalArgumentException { + this(min, max, value, DEFAULT_PLACES); + } + + public DoubleField(double min, double max, Double value, int places) throws IllegalArgumentException { + this.defaultValue = value; + this.minValue = min; + this.maxValue = max; + this.verifier = new DoubleVerifier(this, min, max); + + setValue(value); + setInputVerifier(verifier); + + NumberFormatter def = new NullableNumberFormatter(); + def.setValueClass(Double.class); + def.setMinimum(minValue); + def.setMaximum(maxValue); + + NumberFormatter displayFormatter = new NullableNumberFormatter(getFormatForDISPLAY(places)); + displayFormatter.setValueClass(Double.class); + displayFormatter.setMinimum(minValue); + displayFormatter.setMaximum(maxValue); + + NumberFormatter editFormatter = new NullableNumberFormatter(getFormatForEDIT(places)); + editFormatter.setValueClass(Double.class); + editFormatter.setMinimum(minValue); + editFormatter.setMaximum(maxValue); + + this.factory = new DefaultFormatterFactory(def, displayFormatter, editFormatter); + setFormatterFactory(factory); + + this.normalFont = super.getFont(); + this.nonuniformFont = super.getFont().deriveFont(Font.ITALIC); + + setColumns(NUMBER_FIELD_COLUMNS); + } + + public static AdaptativeFormat getFormatForDISPLAY(int places) { + return new AdaptativeFormat(new DoubleDisplayFormat(places), new DoubleScientificFormat(places), places); + } + + private static AdaptativeFormat getFormatForEDIT(int places) { + return new AdaptativeFormat(new DoubleEditFormat(places), new DoubleScientificFormat(places), places); + } + + @Override + @Transient + public Font getFont() { + if (nonuniformFont != null && getText().equals(DoubleVerifier.NONUNIFORM)) + return nonuniformFont; + else if (normalFont != null) + return normalFont; + + return super.getFont(); + } + + @Override + protected void invalidEdit() { + } + + /* + * If you write by hand something like 1.2E+06 the formatter does not like it. It requires no + sign + */ + @Override + public String getText() { + return super.getText().replace('e', 'E').replace("E+", "E"); + } + + /* + * If you prompt something like 1.2E+06 the formatter does not like it. It requires no + sign + */ + @Override + protected String getFixedinputString(String content) { + return content.replace('e', 'E').replace("E+", "E"); + } + + public void setDoubleValue(double value) { + super.setValue(Double.valueOf(value)); + } + + public double getDoubleValue() { + Object value = super.getValue(); + if (value != null && value instanceof Double) { + return ((Double) value).doubleValue(); + } + return Double.NaN; + } + + public Double getDefaultValue() { + return defaultValue; + } + + public double getMinValue() { + return minValue; + } + + public double getMaxValue() { + return maxValue; + } + + public void setMinValue(double minValue) { + this.minValue = minValue; + verifier.setMinValue(minValue); + } + + public void setMaxValue(double maxValue) { + this.maxValue = maxValue; + verifier.setMaxValue(maxValue); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" +(getName() != null ? getName() : "noname" ) + "] value: " + String.valueOf(getDoubleValue()); + } + + public static double[] toArray(DoubleField[] field) { + double[] value = new double[field.length]; + for (int i = 0; i < value.length; i++) { + value[i] = field[i].getDoubleValue(); + } + return value; + } + + public static class DoubleDisplayFormat extends DecimalFormat { + public DoubleDisplayFormat(int places) { + super(); + setDecimalFormatSymbols(decimalFormatSymbols); + setMinimumIntegerDigits(1); + setMaximumIntegerDigits(Integer.MAX_VALUE); + setMinimumFractionDigits(1); + setMaximumFractionDigits(places); + setParseIntegerOnly(false); + setGroupingUsed(true); + } + } + + public static class DoubleEditFormat extends DecimalFormat { + public DoubleEditFormat(int places) { + super(); + setDecimalFormatSymbols(decimalFormatSymbols); + setMinimumIntegerDigits(1); + setMaximumIntegerDigits(Integer.MAX_VALUE); + setMinimumFractionDigits(0); + setMaximumFractionDigits(places); + setParseIntegerOnly(false); + setGroupingUsed(false); + } + } + + public static class DoubleScientificFormat extends DecimalFormat { + public DoubleScientificFormat(int places) { + super("#.#E0##"); + setDecimalFormatSymbols(decimalFormatSymbols); + setMinimumIntegerDigits(1); + setMaximumIntegerDigits(1); + setMinimumFractionDigits(0); + setMaximumFractionDigits(places); + setParseIntegerOnly(false); + setGroupingUsed(false); + } + } +} diff --git a/src/eu/engys/util/ui/textfields/FileTextField.java b/src/eu/engys/util/ui/textfields/FileTextField.java new file mode 100644 index 0000000..4ddba9f --- /dev/null +++ b/src/eu/engys/util/ui/textfields/FileTextField.java @@ -0,0 +1,80 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields; + +import java.io.File; +import java.text.ParseException; + +import javax.swing.text.DefaultFormatter; +import javax.swing.text.DefaultFormatterFactory; + +import eu.engys.util.ui.textfields.verifiers.FileVerifier; + +public class FileTextField extends PromptTextField { + + public FileTextField() { + super(); + setFormatterFactory(new DefaultFormatterFactory(new FileFormatter())); + setInputVerifier(new FileVerifier(this)); + setColumns(STRING_FIELD_COLUMNS); + } + + @Override + public File getValue() { + return (File) super.getValue(); + } + + public void setValue(File file) { + super.setValue(file); + ((FileVerifier) getInputVerifier()).verify(this); + } + + public boolean hasValidFile() { + return ((FileVerifier) getInputVerifier()).verify(this); + } + + private static class FileFormatter extends DefaultFormatter { + public FileFormatter() { + super(); + setValueClass(File.class); + } + + @Override + public Object stringToValue(String string) throws ParseException { + return string.isEmpty() ? null : new File(string); + } + + @Override + public String valueToString(Object value) throws ParseException { + if (value == null) { + return ""; + } + return File.class.cast(value).getPath(); + } + } + +} diff --git a/src/eu/engys/util/ui/textfields/IntegerField.java b/src/eu/engys/util/ui/textfields/IntegerField.java new file mode 100644 index 0000000..21e0e2c --- /dev/null +++ b/src/eu/engys/util/ui/textfields/IntegerField.java @@ -0,0 +1,153 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields; + +import java.awt.Insets; +import java.io.Serializable; +import java.text.DecimalFormat; + +import javax.swing.text.DefaultFormatterFactory; +import javax.swing.text.NumberFormatter; + +import eu.engys.util.ui.textfields.verifiers.IntegerVerifier; +/** + * Provides a JFormattedTextField that accepts only integers. + * Allows for the setting of the min/max values allowed. + * + * See also + * https://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html + * http://stackoverflow.com/a/12978182 + * + */ +public class IntegerField extends PromptTextField implements Serializable { + + private int minValue = -Integer.MAX_VALUE; + private int maxValue = Integer.MAX_VALUE; + + private DefaultFormatterFactory dff; + private IntegerVerifier verifier; + + public IntegerField(Insets insets) { + super(insets); + } + + public IntegerField() { + this(-Integer.MAX_VALUE, Integer.MAX_VALUE, 0, false); + } + + public IntegerField(int min, int max) throws IllegalArgumentException { + this(min, max, 0 < min ? min : 0, false); + } + + public IntegerField(int min, int max, int value) throws IllegalArgumentException { + this(min, max, value, false); + } + + public IntegerField(int min, int max, int value, boolean checkEmptyValue) throws IllegalArgumentException { + this.minValue = min; + this.maxValue = max; + this.verifier = new IntegerVerifier(this, min, max, checkEmptyValue); + + setValue(new Integer(value)); + setInputVerifier(verifier); + setColumns(NUMBER_FIELD_COLUMNS); + + NumberFormatter def = new NullableNumberFormatter(); + def.setValueClass(Integer.class); + def.setMinimum(minValue); + def.setMaximum(maxValue); + + NumberFormatter disp = new NullableNumberFormatter(new IntegerDisplayFormat()); + disp.setValueClass(Integer.class); + disp.setMinimum(minValue); + disp.setMaximum(maxValue); + + NumberFormatter ed = new NullableNumberFormatter(new IntegerEditFormat()); + ed.setValueClass(Integer.class); + ed.setMinimum(minValue); + ed.setMaximum(maxValue); + + dff = new DefaultFormatterFactory(def, disp, ed); + setFormatterFactory(dff); + } + + public void setIntValue(int value) { + super.setValue(Integer.valueOf(value)); + } + + public int getIntValue() { + Object value = super.getValue(); + if (value != null && value instanceof Integer) { + return ((Integer) super.getValue()).intValue(); + } + return 0; + } + + public double getMinValue() { + return minValue; + } + + public double getMaxValue() { + return maxValue; + } + + public void setMinValue(int minValue) { + this.minValue = minValue; + verifier.setMinValue(minValue); + } + + public void setMaxValue(int maxValue) { + this.maxValue = maxValue; + verifier.setMaxValue(maxValue); + } + + public static class IntegerDisplayFormat extends DecimalFormat { + public IntegerDisplayFormat() { + super(); + setMinimumIntegerDigits(1); + setMaximumIntegerDigits(Integer.MAX_VALUE); + setMinimumFractionDigits(0); + setMaximumFractionDigits(0); + setParseIntegerOnly(true); + setGroupingUsed(true); + + } + } + + public static class IntegerEditFormat extends DecimalFormat { + public IntegerEditFormat() { + super(); + setMinimumIntegerDigits(0); + setMaximumIntegerDigits(Integer.MAX_VALUE); + setMinimumFractionDigits(0); + setMaximumFractionDigits(0); + setParseIntegerOnly(true); + setGroupingUsed(false); + + } + } +} diff --git a/src/eu/engys/util/ui/textfields/NullableNumberFormatter.java b/src/eu/engys/util/ui/textfields/NullableNumberFormatter.java new file mode 100644 index 0000000..8533f5f --- /dev/null +++ b/src/eu/engys/util/ui/textfields/NullableNumberFormatter.java @@ -0,0 +1,61 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields; + +import java.text.NumberFormat; +import java.text.ParseException; + +import javax.swing.text.NumberFormatter; + +import eu.engys.util.ui.textfields.verifiers.DoubleVerifier; + +public class NullableNumberFormatter extends NumberFormatter { + + public NullableNumberFormatter() { + super(); + } + + public NullableNumberFormatter(NumberFormat format) { + super(format); + } + + public Object stringToValue(String string) throws ParseException { + if (string == null || string.length() == 0) { + return null; + } + if (string.equals(DoubleVerifier.NONUNIFORM)) { + return Double.POSITIVE_INFINITY;//super.stringToValue("Infinity"); + } + return super.stringToValue(string); + } + + public String valueToString(Object value) throws ParseException { + if ( value == null ) return ""; + if ( value instanceof Double && Double.isInfinite((Double) value)) return DoubleVerifier.NONUNIFORM; + return super.valueToString(value); + } +} diff --git a/src/eu/engys/util/ui/textfields/PromptTextField.java b/src/eu/engys/util/ui/textfields/PromptTextField.java new file mode 100644 index 0000000..6cbeca1 --- /dev/null +++ b/src/eu/engys/util/ui/textfields/PromptTextField.java @@ -0,0 +1,156 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ +package eu.engys.util.ui.textfields; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.RenderingHints; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.text.ParseException; + +import javax.swing.JFormattedTextField; +import javax.swing.KeyStroke; +import javax.swing.UIManager; +import javax.swing.text.DefaultFormatterFactory; + +import eu.engys.util.ui.ExecUtil; + +/** + * PropmptTextField add the ability to display a message on the + * text field when not focused and a value is not set. + * + * Auto-select the text when focused + * See + * + */ +public class PromptTextField extends JFormattedTextField { + + public static final Color HIGHLIGHT_FG = new Color(65, 90, 110); + public static final Color HIGHLIGHT_BG = new Color(130, 180, 220, 128); + private static final Color DEFAULT_FG = UIManager.getColor("TextField.foreground"); + private static final Color DEFAULT_BG = UIManager.getColor("TextField.background"); + private static final Color INVALID_COLOR = Color.PINK; + + public static final int NUMBER_FIELD_COLUMNS = 4; + public static final int STRING_FIELD_COLUMNS = 10; + + private String prompt = ""; + + public PromptTextField() { + super(); + } + + public PromptTextField(Insets insets) { + this(); + setMargin(insets); + } + + public void setPrompt(String prompt) { + this.prompt = prompt; + } + + public void setValidColors() { + setBackground(DEFAULT_BG); + setForeground(DEFAULT_FG); + } + + public void setInvalidColors() { + setBackground(INVALID_COLOR); + setForeground(DEFAULT_FG); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + + if (!hasFocus() && getText().isEmpty() && !prompt.isEmpty()) { + Graphics2D g2 = (Graphics2D) g; + + Object aa = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); + + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setColor(Color.GRAY.brighter()); + g2.drawString(prompt, 4, getFontMetrics(getFont()).getHeight()); + + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aa); + } + } + + @Override + protected void processFocusEvent(final FocusEvent e) { + super.processFocusEvent(e); + + if (e.isTemporary()) { + return; + } + + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + if (e.getID() == FocusEvent.FOCUS_GAINED) { + selectAll(); + } else { + getCaret().setDot(getCaretPosition()); + } + } + }); + } + + @Override + public boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { + return super.processKeyBinding(ks, e, condition, pressed); + } + + @Override + public void replaceSelection(String content) { + String s = content; + AbstractFormatterFactory formatterFactory = getFormatterFactory(); + if (formatterFactory != null && formatterFactory instanceof DefaultFormatterFactory) { + DefaultFormatterFactory factory = (DefaultFormatterFactory) formatterFactory; + AbstractFormatter displayFormat = factory.getDisplayFormatter(); + AbstractFormatter editFormat = factory.getEditFormatter(); + if (displayFormat != null && editFormat != null) { + try { + Object value = displayFormat.stringToValue(getFixedinputString(content)); + s = editFormat.valueToString(value); + } catch (ParseException e) { + } + } + } else { + } + super.replaceSelection(s); + } + + /* + * The string may need a fix. See DoubleField + */ + protected String getFixedinputString(String content) { + String s = content; + return s; + } +} diff --git a/src/eu/engys/util/ui/textfields/SpinnerField.java b/src/eu/engys/util/ui/textfields/SpinnerField.java new file mode 100644 index 0000000..33c21ff --- /dev/null +++ b/src/eu/engys/util/ui/textfields/SpinnerField.java @@ -0,0 +1,86 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields; + +import java.io.Serializable; + +import javax.swing.JFormattedTextField; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.text.DefaultFormatterFactory; +import javax.swing.text.NumberFormatter; + +public class SpinnerField extends JSpinner implements Serializable { + + + public SpinnerField() { + this(-Integer.MAX_VALUE, Integer.MAX_VALUE, 0); + } + + public SpinnerField(int min, int max) throws IllegalArgumentException { + this(min, max, 0 < min ? min : 0); + } + + public SpinnerField(int min, int max, int value) throws IllegalArgumentException { + super(new SpinnerNumberModel(value, min, max, 1)); + + JFormattedTextField textField = ((JSpinner.DefaultEditor)getEditor()).getTextField(); + + NumberFormatter def = new NullableNumberFormatter(); + def.setValueClass(Integer.class); + def.setMinimum(min); + def.setMaximum(max); + + NumberFormatter disp = new NullableNumberFormatter(new IntegerField.IntegerDisplayFormat()); + disp.setValueClass(Integer.class); + disp.setMinimum(min); + disp.setMaximum(max); + + NumberFormatter ed = new NullableNumberFormatter(new IntegerField.IntegerEditFormat()); + ed.setValueClass(Integer.class); + ed.setMinimum(min); + ed.setMaximum(max); + + DefaultFormatterFactory dff = new DefaultFormatterFactory(def, disp, ed); + textField.setFormatterFactory(dff); + + textField.setColumns(4); + } + + public void setIntValue(int value) { + super.setValue(Integer.valueOf(value)); + } + + public int getIntValue() { + Object value = super.getValue(); + if (value != null && value instanceof Integer) { + return ((Integer) super.getValue()).intValue(); + } + return 0; + } + +} diff --git a/src/eu/engys/util/ui/textfields/StringField.java b/src/eu/engys/util/ui/textfields/StringField.java new file mode 100644 index 0000000..25b3ce9 --- /dev/null +++ b/src/eu/engys/util/ui/textfields/StringField.java @@ -0,0 +1,94 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields; + +import java.text.ParseException; + +import javax.swing.text.DefaultFormatterFactory; + +import eu.engys.util.ui.textfields.verifiers.StringVerifier; +/** + * Provides a JFormattedTextField that accepts only Strings. + */ +public class StringField extends PromptTextField { + + public StringField() { + this(""); + } + + public StringField(boolean checkEmptyStrings, boolean checkForbidden) { + this("", checkEmptyStrings, checkForbidden); + } + + public StringField(String text, boolean checkEmptyStrings, boolean checkForbidden) { + this(text, -1, checkEmptyStrings, checkForbidden); + } + + public StringField(String text) { + this(text, -1, true, true); + } + + public StringField(int columns) { + this("", columns, true, true); + } + + public StringField(String text, int columns, boolean checkEmptyStrings, boolean checkForbidden) { + super(); + setFormatterFactory(new DefaultFormatterFactory(new StringFormatter())); + setText(text); + setInputVerifier(new StringVerifier(this)); + setColumns(columns != -1 ? columns : STRING_FIELD_COLUMNS); + setToVerifier(checkEmptyStrings, checkForbidden); + } + + public void setStringValue(String value) { + super.setValue(value); + } + + public String getStringValue() { + return (String) super.getValue(); + } + + public void setToVerifier(boolean checkEmptyStrings, boolean checkForbidden) { + ((StringVerifier) getInputVerifier()).setCheckEmptyStrings(checkEmptyStrings); + ((StringVerifier) getInputVerifier()).setCheckForbidden(checkForbidden); + } + + class StringFormatter extends AbstractFormatter { + @Override + public Object stringToValue(String text) throws ParseException { + return text; + } + + @Override + public String valueToString(Object value) throws ParseException { + return value != null ? value.toString() : ""; + } + } + +} + diff --git a/src/eu/engys/util/ui/textfields/verifiers/AbstractVerifier.java b/src/eu/engys/util/ui/textfields/verifiers/AbstractVerifier.java new file mode 100644 index 0000000..9a2909b --- /dev/null +++ b/src/eu/engys/util/ui/textfields/verifiers/AbstractVerifier.java @@ -0,0 +1,158 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields.verifiers; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.text.ParseException; + +import javax.swing.BorderFactory; +import javax.swing.InputVerifier; +import javax.swing.JComponent; +import javax.swing.JFormattedTextField; +import javax.swing.JLabel; +import javax.swing.JPopupMenu; +import javax.swing.JTextField; + +import eu.engys.util.ui.textfields.PromptTextField; + +/** + * See Building a Swing Validation Package with InputVerifier + * http://www.javalobby.org/java/forums/t20551.html + * + */ +public abstract class AbstractVerifier extends InputVerifier implements KeyListener { + + protected static final Color BG_COLOR = new Color(243, 255, 159); + + private final JPopupMenu popup = new JPopupMenu(); + + private JLabel messageLabel = new JLabel(); + private ValidationStatusListener listener; + private PromptTextField jcomponent; + + public AbstractVerifier(PromptTextField c) { + this.jcomponent = c; + initComponents(); + c.addKeyListener(this); + } + + private void initComponents() { + popup.setLayout(new FlowLayout()); + popup.setBorder(BorderFactory.createEmptyBorder()); + popup.setBackground(BG_COLOR); + popup.add(messageLabel); + } + + protected abstract boolean validationCriteria(JComponent jc); + + public boolean verify(JComponent jc) { + if (!validationCriteria(jc)) { + + if (listener != null) + listener.validateFailed(); + + invalid(); + return false; + } + + valid(); + + if (jcomponent instanceof JFormattedTextField) { + try { + ((JFormattedTextField) jcomponent).commitEdit(); + } catch (ParseException e) { + } + } + + if (listener != null) + listener.validatePassed(); + + return true; + } + + private void invalid() { + if (jcomponent.isShowing()) { + jcomponent.setInvalidColors(); + + popup.setSize(0, 0); + Point point = jcomponent.getLocation(); + Dimension cDim = jcomponent.getSize(); + popup.pack(); + popup.show(jcomponent, point.x - (int) cDim.getWidth() / 2, point.y + (int) cDim.getHeight() / 2); + jcomponent.requestFocus(); + } else { + // Moved to another tab (or similar) + // valid(); + jcomponent.setInvalidColors(); + } + } + + private void valid() { + jcomponent.setValidColors(); + popup.setVisible(false); + } + + public void setMessage(String text) { + messageLabel.setText(text); + } + + @Override + public void keyReleased(KeyEvent e) { + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + popup.setVisible(false); + JTextField source = (JTextField) e.getSource(); + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + verify(source); // ignore return value + source.selectAll(); + } else if (e.getKeyChar() == KeyEvent.VK_ESCAPE) { + verify(source); // ignore return value + source.selectAll(); + } + } + + public void setValidationStatusListener(ValidationStatusListener listener) { + this.listener = listener; + } + + public interface ValidationStatusListener { + void validateFailed(); // Called when a component has failed validation. + + void validatePassed(); // Called when a component has passed validation. + } +} diff --git a/src/eu/engys/util/ui/textfields/verifiers/DoubleVerifier.java b/src/eu/engys/util/ui/textfields/verifiers/DoubleVerifier.java new file mode 100644 index 0000000..a38cf7c --- /dev/null +++ b/src/eu/engys/util/ui/textfields/verifiers/DoubleVerifier.java @@ -0,0 +1,74 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields.verifiers; + +import javax.swing.JComponent; +import javax.swing.text.JTextComponent; + +import eu.engys.util.ui.textfields.DoubleField; + +public class DoubleVerifier extends AbstractVerifier { + public static final String NONUNIFORM = "Nonuniform"; + + protected double minValue = -Double.MAX_VALUE; + protected double maxValue = Double.MAX_VALUE; + + public DoubleVerifier(DoubleField c, double min, double max) { + super(c); + this.minValue = min; + this.maxValue = max; + } + + @Override + protected boolean validationCriteria(JComponent jc) { + try { + String text = ((JTextComponent) jc).getText(); + if (text == null || text.isEmpty()) return true; + + if (text.equals(NONUNIFORM)) return true; + + double val = Double.parseDouble(text); + if (val < minValue || val > maxValue) { + setMessage("Value outside range ["+minValue+", "+maxValue+"]"); + return false; + } + } catch (Exception e) { + setMessage("Invalid number format"); + return false; + } + return true; + } + + public void setMinValue(double value) { + this.minValue = value; + } + + public void setMaxValue(double value) { + this.maxValue = value; + } + +} diff --git a/src/eu/engys/util/ui/textfields/verifiers/FileVerifier.java b/src/eu/engys/util/ui/textfields/verifiers/FileVerifier.java new file mode 100644 index 0000000..8994f85 --- /dev/null +++ b/src/eu/engys/util/ui/textfields/verifiers/FileVerifier.java @@ -0,0 +1,57 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields.verifiers; + +import java.io.File; + +import javax.swing.JComponent; +import javax.swing.JTextField; + +import eu.engys.util.ui.textfields.PromptTextField; + +public class FileVerifier extends AbstractVerifier { + + public FileVerifier(PromptTextField c) { + super(c); + } + + @Override + protected boolean validationCriteria(JComponent jc) { + try { + String text = ((JTextField) jc).getText(); + if (!text.isEmpty() && !new File(text).exists()) { + setMessage("File does not exist"); + return false; + } + + } catch (Exception e) { + setMessage("Error parsing string"); + return false; + } + return true; + } +} diff --git a/src/eu/engys/util/ui/textfields/verifiers/IntegerVerifier.java b/src/eu/engys/util/ui/textfields/verifiers/IntegerVerifier.java new file mode 100644 index 0000000..37a24a6 --- /dev/null +++ b/src/eu/engys/util/ui/textfields/verifiers/IntegerVerifier.java @@ -0,0 +1,82 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields.verifiers; + +import javax.swing.JComponent; +import javax.swing.JTextField; + +import eu.engys.util.ui.textfields.IntegerField; + +public class IntegerVerifier extends AbstractVerifier { + + private boolean checkEmptyStrings = true; + + protected int minValue = -Integer.MAX_VALUE; + protected int maxValue = Integer.MAX_VALUE; + + public IntegerVerifier(IntegerField c, int min, int max, boolean checkEmptyStrings) { + super(c); + this.checkEmptyStrings = checkEmptyStrings; + this.minValue = min; + this.maxValue = max; + } + + @Override + protected boolean validationCriteria(JComponent jc) { + try { + String text = ((JTextField) jc).getText(); + if (text == null || text.isEmpty()) { + if (checkEmptyStrings) { + setMessage("Empty value"); + return false; + } + return true; + } + + double d = Double.parseDouble(text); + if (d < minValue || d > maxValue) { + setMessage("Value outside range [" + minValue + ", " + maxValue + "]"); + return false; + } + + Integer.parseInt(text); + } catch (Exception e) { + setMessage("Invalid number format"); + return false; + } + return true; + } + + public void setMinValue(int minValue) { + this.minValue = minValue; + } + + public void setMaxValue(int maxValue) { + this.maxValue = maxValue; + } + +} diff --git a/src/eu/engys/util/ui/textfields/verifiers/StringVerifier.java b/src/eu/engys/util/ui/textfields/verifiers/StringVerifier.java new file mode 100644 index 0000000..8a7f849 --- /dev/null +++ b/src/eu/engys/util/ui/textfields/verifiers/StringVerifier.java @@ -0,0 +1,76 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.textfields.verifiers; + +import javax.swing.JComponent; +import javax.swing.JTextField; + +import eu.engys.util.Util; +import eu.engys.util.ui.textfields.PromptTextField; + +public class StringVerifier extends AbstractVerifier { + + private boolean checkEmptyStrings = true; + private boolean checkForbidden = true; + + public StringVerifier(PromptTextField c) { + super(c); + } + + @Override + protected boolean validationCriteria(JComponent jc) { + try { + String text = ((JTextField) jc).getText(); + + if ( checkEmptyStrings && (text == null || text.isEmpty())){ + setMessage("Empty name"); + return false; + } + + if (checkForbidden) { + for (char ch : text.toCharArray()) { + if (Util.isForbidden(ch)) { + setMessage("Illegal charachter: " + ch); + return false; + } + } + } + } catch (Exception e) { + setMessage("Error parsing string"); + return false; + } + return true; + } + + public void setCheckEmptyStrings(boolean b) { + this.checkEmptyStrings = b; + } + + public void setCheckForbidden(boolean checkForbidden) { + this.checkForbidden = checkForbidden; + } +} diff --git a/src/eu/engys/util/ui/treetable/AbstractTreeTableModel.java b/src/eu/engys/util/ui/treetable/AbstractTreeTableModel.java new file mode 100644 index 0000000..1ae1680 --- /dev/null +++ b/src/eu/engys/util/ui/treetable/AbstractTreeTableModel.java @@ -0,0 +1,129 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.treetable; + +import javax.swing.event.EventListenerList; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.tree.TreePath; + +public abstract class AbstractTreeTableModel implements TreeTableModel { + protected Object root; + protected EventListenerList listenerList = new EventListenerList(); + + public AbstractTreeTableModel(Object root) { + this.root = root; + } + + public Object getRoot() { + return root; + } + + public boolean isLeaf(Object node) { + return getChildCount(node) == 0; + } + + public void valueForPathChanged(TreePath path, Object newValue) { + } + + public int getIndexOfChild(Object parent, Object child) { + for (int i = 0; i < getChildCount(parent); i++) { + if (getChild(parent, i).equals(child)) { + return i; + } + } + return -1; + } + + public void addTreeModelListener(TreeModelListener l) { + listenerList.add(TreeModelListener.class, l); + } + + public void removeTreeModelListener(TreeModelListener l) { + listenerList.remove(TreeModelListener.class, l); + } + + protected void fireTreeNodesChanged(Object source, Object[] path, int[] childIndices, Object[] children) { + Object[] listeners = listenerList.getListenerList(); + TreeModelEvent e = null; + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == TreeModelListener.class) { + if (e == null) + e = new TreeModelEvent(source, path, childIndices, children); + ((TreeModelListener) listeners[i + 1]).treeNodesChanged(e); + } + } + } + + protected void fireTreeNodesInserted(Object source, Object[] path, int[] childIndices, Object[] children) { + Object[] listeners = listenerList.getListenerList(); + TreeModelEvent e = null; + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == TreeModelListener.class) { + if (e == null) + e = new TreeModelEvent(source, path, childIndices, children); + ((TreeModelListener) listeners[i + 1]).treeNodesInserted(e); + } + } + } + + protected void fireTreeNodesRemoved(Object source, Object[] path, int[] childIndices, Object[] children) { + Object[] listeners = listenerList.getListenerList(); + TreeModelEvent e = null; + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == TreeModelListener.class) { + if (e == null) + e = new TreeModelEvent(source, path, childIndices, children); + ((TreeModelListener) listeners[i + 1]).treeNodesRemoved(e); + } + } + } + + protected void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children) { + Object[] listeners = listenerList.getListenerList(); + TreeModelEvent e = null; + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == TreeModelListener.class) { + if (e == null) + e = new TreeModelEvent(source, path, childIndices, children); + ((TreeModelListener) listeners[i + 1]).treeStructureChanged(e); + } + } + } + + public Class getColumnClass(int column) { + return Object.class; + } + + public boolean isCellEditable(Object node, int column) { + return getColumnClass(column) == TreeTableModel.class; + } + + public void setValueAt(Object aValue, Object node, int column) { + } + +} diff --git a/src/eu/engys/util/ui/treetable/JTreeTable.java b/src/eu/engys/util/ui/treetable/JTreeTable.java new file mode 100644 index 0000000..3f52545 --- /dev/null +++ b/src/eu/engys/util/ui/treetable/JTreeTable.java @@ -0,0 +1,196 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.treetable; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.util.EventObject; + +import javax.swing.JTable; +import javax.swing.JTree; +import javax.swing.table.TableRowSorter; + +import eu.engys.util.ui.TableUtil; +import eu.engys.util.ui.treetable.tree.JTreeTableCellRenderer; +import eu.engys.util.ui.treetable.tree.ListToTreeSelectionModelWrapper; +import eu.engys.util.ui.treetable.tree.TreeTableCellRenderer; + +public class JTreeTable extends JTable { + + private TreeTableCellRenderer tree; + + private boolean treeEditable = true; + private boolean showsIcons = false; + + private TableRowSorter sorter; + private TableFilter filter; + + public JTreeTable(TreeTableModel treeTableModel) { + super(); + + this.tree = new TreeTableCellRenderer(this, treeTableModel); + + TreeTableModelAdapter dataModel = new TreeTableModelAdapter(treeTableModel, tree); + super.setModel(dataModel); + + this.sorter = new TableRowSorter(dataModel); + setRowSorter(sorter); + + TableUtil.disableSorting(this); + + this.filter = new TableFilter(""); + sorter.setRowFilter(filter); + + ListToTreeSelectionModelWrapper selectionWrapper = new ListToTreeSelectionModelWrapper(tree); + tree.setSelectionModel(selectionWrapper); + setSelectionModel(selectionWrapper.getListSelectionModel()); + + setDefaultRenderer(TreeTableModel.class, tree); + setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor(this)); + + setShowGrid(false); + + setIntercellSpacing(new Dimension(0, 0)); + + if (tree.getRowHeight() < 1) { + setRowHeight(20); + } + + } + + public void setSearchableColumns(int... searchableColumns) { + filter.setColumnsWhereToSearch(searchableColumns); + } + + public void filter(final String filterText) { + filter.setFilterText(filterText); + sorter.sort(); + } + + public void removeRow(int row) { + ((TreeTableModelAdapter) getModel()).removeRow(row); + } + + public Object[] getNodes(int[] index) { + Object[] nodes = new Object[index.length]; + for (int i = 0; i < index.length; i++) { + nodes[i] = ((TreeTableModelAdapter) getModel()).nodeForRow(index[i]); + } + return nodes; + } + + public Object getNode(int index) { + return ((TreeTableModelAdapter) getModel()).nodeForRow(index); + } + + public void updateUI() { + super.updateUI(); + if (tree != null) { + tree.updateUI(); + } + } + + public int getEditingRow() { + return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 : editingRow; + } + + private int realEditingRow() { + return editingRow; + } + + public void sizeColumnsToFit(int resizingColumn) { + super.sizeColumnsToFit(resizingColumn); + if (getEditingColumn() != -1 && getColumnClass(editingColumn) == TreeTableModel.class) { + Rectangle cellRect = getCellRect(realEditingRow(), getEditingColumn(), false); + Component component = getEditorComponent(); + component.setBounds(cellRect); + component.validate(); + } + } + + public void setRowHeight(int rowHeight) { + super.setRowHeight(rowHeight); + if (tree != null && tree.getRowHeight() != rowHeight) { + tree.setRowHeight(getRowHeight()); + } + } + + public JTree getTree() { + return tree; + } + + public void setTreeRenderer(JTreeTableCellRenderer renderer) { + tree.setCellRenderer(renderer); + } + + public boolean editCellAt(int row, int column, EventObject e) { + boolean retValue = super.editCellAt(row, column, e); + if (retValue && getColumnClass(column) == TreeTableModel.class) { + repaint(getCellRect(row, column, false)); + } + return retValue; + } + + public void expandAll() { + for (int i = 0; i < tree.getRowCount(); i++) { + tree.expandRow(i); + } + } + + public void collapseAll() { + tree.collapsePath(tree.getPathForRow(0)); + } + + public boolean getTreeEditable() { + return treeEditable; + } + + public void setTreeEditable(boolean editable) { + this.treeEditable = editable; + } + + public boolean getShowsIcons() { + return showsIcons; + } + + public void setShowsIcons(boolean showsIcons) { + this.showsIcons = showsIcons; + } + + public void setRootVisible(boolean visible) { + tree.setRootVisible(visible); + } + + public boolean getShowsRootHandles() { + return tree.getShowsRootHandles(); + } + + public void setShowsRootHandles(boolean newValue) { + tree.setShowsRootHandles(newValue); + } +} diff --git a/src/eu/engys/util/ui/treetable/TableFilter.java b/src/eu/engys/util/ui/treetable/TableFilter.java new file mode 100644 index 0000000..e106f6d --- /dev/null +++ b/src/eu/engys/util/ui/treetable/TableFilter.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui.treetable; + +import javax.swing.RowFilter; +import javax.swing.table.TableModel; + +import org.apache.commons.lang.ArrayUtils; + +public class TableFilter extends RowFilter { + + private String filterText; + private int[] columnsWhereToSearch; + + public TableFilter(String initialFilter) { + this.filterText = initialFilter; + } + + public void setFilterText(String filterText) { + this.filterText = filterText; + } + + public void setColumnsWhereToSearch(int... columnsWhereToSearch) { + this.columnsWhereToSearch = columnsWhereToSearch; + } + + @Override + public boolean include(RowFilter.Entry entry) { + if (columnsWhereToSearch == null || columnsWhereToSearch.length == 0) { + return true; + } + + String regexpFilter = filterText.replace(".", "\\.").replace("*", ".*").replace("?", ".?").replace("+", ".+").concat(".*"); + + int numberOfTableColumns = entry.getValueCount(); + for (int i = 0; i < numberOfTableColumns; i++) { + if (ArrayUtils.contains(columnsWhereToSearch, i)) { + if (entry.getStringValue(i).matches(regexpFilter)) { + return true; + } + } + } + return false; + + } + +} diff --git a/src/eu/engys/util/ui/treetable/TreeTableCellEditor.java b/src/eu/engys/util/ui/treetable/TreeTableCellEditor.java new file mode 100644 index 0000000..078485c --- /dev/null +++ b/src/eu/engys/util/ui/treetable/TreeTableCellEditor.java @@ -0,0 +1,107 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui.treetable; + +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.util.EventObject; + +import javax.swing.DefaultCellEditor; +import javax.swing.Icon; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeCellRenderer; + +public class TreeTableCellEditor extends DefaultCellEditor { + + private final JTreeTable jTreeTable; + + public TreeTableCellEditor(JTreeTable jTreeTable) { + super(new TreeTableTextField()); + this.jTreeTable = jTreeTable; + } + + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int r, int c) { + Component component = super.getTableCellEditorComponent(table, value, isSelected, r, c); + JTree t = this.jTreeTable.getTree(); + boolean rv = t.isRootVisible(); + int offsetRow = rv ? r : r - 1; + Rectangle bounds = t.getRowBounds(offsetRow); + int offset = bounds.x; + TreeCellRenderer tcr = t.getCellRenderer(); + if (tcr instanceof DefaultTreeCellRenderer) { + Object node = t.getPathForRow(offsetRow).getLastPathComponent(); + Icon icon; + if (t.getModel().isLeaf(node)) + icon = ((DefaultTreeCellRenderer) tcr).getLeafIcon(); + else if (this.jTreeTable.getTree().isExpanded(offsetRow)) + icon = ((DefaultTreeCellRenderer) tcr).getOpenIcon(); + else + icon = ((DefaultTreeCellRenderer) tcr).getClosedIcon(); + if (icon != null) { + offset += ((DefaultTreeCellRenderer) tcr).getIconTextGap() + icon.getIconWidth(); + } + } + ((TreeTableTextField) getComponent()).offset = offset; + return component; + } + + public boolean isCellEditable(EventObject e) { + if (e instanceof MouseEvent) { + MouseEvent me = (MouseEvent) e; + if (me.getModifiers() == 0 || me.getModifiers() == InputEvent.BUTTON1_MASK) { + for (int counter = jTreeTable.getColumnCount() - 1; counter >= 0; counter--) { + if (jTreeTable.getColumnClass(counter) == TreeTableModel.class) { + MouseEvent newME = new MouseEvent(jTreeTable.getTree(), me.getID(), me.getWhen(), me.getModifiers(), me.getX() - jTreeTable.getCellRect(0, counter, true).x, me.getY(), me.getClickCount(), me.isPopupTrigger()); + this.jTreeTable.getTree().dispatchEvent(newME); + break; + } + } + } + if (me.getClickCount() >= 3) { + return this.jTreeTable.getTreeEditable(); + } + return false; + } + if (e == null) { + return this.jTreeTable.getTreeEditable(); + } + return false; + } + + public static class TreeTableTextField extends JTextField { + public int offset; + + public void setBounds(int x, int y, int w, int h) { + int newX = Math.max(x, offset); + super.setBounds(newX, y, w - (newX - x), h); + } + } +} diff --git a/src/eu/engys/util/ui/treetable/TreeTableModel.java b/src/eu/engys/util/ui/treetable/TreeTableModel.java new file mode 100644 index 0000000..483f9a6 --- /dev/null +++ b/src/eu/engys/util/ui/treetable/TreeTableModel.java @@ -0,0 +1,46 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.treetable; + +import javax.swing.tree.TreeModel; + +public interface TreeTableModel extends TreeModel { + + public int getColumnCount(); + + public String getColumnName(int column); + + public Class getColumnClass(int column); + + public Object getValueAt(Object node, int column); + + public boolean isCellEditable(Object node, int column); + + public void setValueAt(Object aValue, Object node, int column); + + public void remove(Object node); +} diff --git a/src/eu/engys/util/ui/treetable/TreeTableModelAdapter.java b/src/eu/engys/util/ui/treetable/TreeTableModelAdapter.java new file mode 100644 index 0000000..e227730 --- /dev/null +++ b/src/eu/engys/util/ui/treetable/TreeTableModelAdapter.java @@ -0,0 +1,120 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.treetable; + +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.tree.TreePath; + +public class TreeTableModelAdapter extends AbstractTableModel { + JTree tree; + TreeTableModel treeTableModel; + + public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree tree) { + this.tree = tree; + this.treeTableModel = treeTableModel; + + tree.addTreeExpansionListener(new TreeExpansionListener() { + public void treeExpanded(TreeExpansionEvent event) { + fireTableDataChanged(); + } + + public void treeCollapsed(TreeExpansionEvent event) { + fireTableDataChanged(); + } + }); + + treeTableModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + delayedFireTableDataChanged(); + } + + public void treeNodesInserted(TreeModelEvent e) { + delayedFireTableDataChanged(); + } + + public void treeNodesRemoved(TreeModelEvent e) { + delayedFireTableDataChanged(); + } + + public void treeStructureChanged(TreeModelEvent e) { + delayedFireTableDataChanged(); + } + }); + } + + public int getColumnCount() { + return treeTableModel.getColumnCount(); + } + + public String getColumnName(int column) { + return treeTableModel.getColumnName(column); + } + + public Class getColumnClass(int column) { + return treeTableModel.getColumnClass(column); + } + + public int getRowCount() { + return tree.getRowCount(); + } + + public Object nodeForRow(int row) { + TreePath treePath = tree.getPathForRow(row); + return treePath == null ? null : treePath.getLastPathComponent(); + } + + public Object getValueAt(int row, int column) { + return treeTableModel.getValueAt(nodeForRow(row), column); + } + + public boolean isCellEditable(int row, int column) { + return treeTableModel.isCellEditable(nodeForRow(row), column); + } + + public void setValueAt(Object value, int row, int column) { + treeTableModel.setValueAt(value, nodeForRow(row), column); + fireTableCellUpdated(row, column); + } + + public void removeRow(int row) { + treeTableModel.remove(nodeForRow(row)); + } + + protected void delayedFireTableDataChanged() { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + fireTableDataChanged(); + } + }); + } +} diff --git a/src/eu/engys/util/ui/treetable/tree/JTreeTableCellRenderer.java b/src/eu/engys/util/ui/treetable/tree/JTreeTableCellRenderer.java new file mode 100644 index 0000000..7f6024e --- /dev/null +++ b/src/eu/engys/util/ui/treetable/tree/JTreeTableCellRenderer.java @@ -0,0 +1,82 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui.treetable.tree; + +import java.awt.Component; + +import javax.swing.Icon; +import javax.swing.JTree; +import javax.swing.tree.DefaultTreeCellRenderer; + +import eu.engys.util.ui.treetable.JTreeTable; + +public class JTreeTableCellRenderer extends DefaultTreeCellRenderer { + + private final boolean showsIcons; + + public JTreeTableCellRenderer(JTreeTable jTreeTable) { + super(); + this.showsIcons = jTreeTable.getShowsIcons(); + + setTextSelectionColor(jTreeTable.getSelectionForeground()); + setTextNonSelectionColor(jTreeTable.getForeground()); + setBackgroundSelectionColor(jTreeTable.getSelectionBackground()); + setBackgroundNonSelectionColor(jTreeTable.getBackground()); + } + + public Icon getClosedIcon() { + return (showsIcons ? super.getClosedIcon() : null); + } + + public Icon getDefaultClosedIcon() { + return (showsIcons ? super.getDefaultClosedIcon() : null); + } + + public Icon getDefaultLeafIcon() { + return (showsIcons ? super.getDefaultLeafIcon() : null); + } + + public Icon getDefaultOpenIcon() { + return (showsIcons ? super.getDefaultOpenIcon() : null); + } + + public Icon getLeafIcon() { + return (showsIcons ? super.getLeafIcon() : null); + } + + public Icon getOpenIcon() { + return (showsIcons ? super.getOpenIcon() : null); + } + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, false, expanded, leaf, row, hasFocus); + if (row == 0) { + setIcon(super.getDefaultOpenIcon()); + } + return this; + } +} diff --git a/src/eu/engys/util/ui/treetable/tree/ListToTreeSelectionModelWrapper.java b/src/eu/engys/util/ui/treetable/tree/ListToTreeSelectionModelWrapper.java new file mode 100644 index 0000000..6ba9c8b --- /dev/null +++ b/src/eu/engys/util/ui/treetable/tree/ListToTreeSelectionModelWrapper.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui.treetable.tree; + +import javax.swing.JTree; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.TreePath; + +public class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel { + + private boolean updatingListSelectionModel; + private JTree tree; + + public ListToTreeSelectionModelWrapper(JTree tree) { + super(); + this.tree = tree; + getListSelectionModel().addListSelectionListener(createListSelectionListener()); + } + + public ListSelectionModel getListSelectionModel() { + return listSelectionModel; + } + + public void resetRowSelection() { + if (!updatingListSelectionModel) { + updatingListSelectionModel = true; + try { + super.resetRowSelection(); + } finally { + updatingListSelectionModel = false; + } + } + } + + protected ListSelectionListener createListSelectionListener() { + return new ListSelectionHandler(); + } + + protected void updateSelectedPathsFromSelectedRows() { + if (!updatingListSelectionModel) { + updatingListSelectionModel = true; + try { + int min = listSelectionModel.getMinSelectionIndex(); + int max = listSelectionModel.getMaxSelectionIndex(); + + clearSelection(); + if (min != -1 && max != -1) { + for (int counter = min; counter <= max; counter++) { + if (listSelectionModel.isSelectedIndex(counter)) { + TreePath selPath = tree.getPathForRow(counter); + + if (selPath != null) { + addSelectionPath(selPath); + } + } + } + } + } finally { + updatingListSelectionModel = false; + } + } + } + + class ListSelectionHandler implements ListSelectionListener { + public void valueChanged(ListSelectionEvent e) { + updateSelectedPathsFromSelectedRows(); + } + } +} diff --git a/src/eu/engys/util/ui/treetable/tree/TreeTableCellRenderer.java b/src/eu/engys/util/ui/treetable/tree/TreeTableCellRenderer.java new file mode 100644 index 0000000..ee5b26f --- /dev/null +++ b/src/eu/engys/util/ui/treetable/tree/TreeTableCellRenderer.java @@ -0,0 +1,95 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.util.ui.treetable.tree; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.JTree; +import javax.swing.border.Border; +import javax.swing.table.TableCellRenderer; +import javax.swing.tree.TreeModel; + +import eu.engys.util.ui.checkboxtree.AddCheckBoxToTree.CheckTreeCellRenderer; +import eu.engys.util.ui.treetable.JTreeTable; + +public class TreeTableCellRenderer extends JTree implements TableCellRenderer { + + private final JTreeTable jTreeTable; + private int visibleRow; + private TableCellRenderer tableDefaultRenderer; + + public TreeTableCellRenderer(JTreeTable jTreeTable, TreeModel model) { + super(model); + this.jTreeTable = jTreeTable; + this.tableDefaultRenderer = jTreeTable.getDefaultRenderer(Object.class); + setCellRenderer(new JTreeTableCellRenderer(jTreeTable)); + } + + public void setBounds(int x, int y, int w, int h) { + if (x < 0) return; + super.setBounds(x + 10, 0, w, this.jTreeTable.getHeight()); + } + + public void paint(Graphics g) { + g.translate(0, -visibleRow * getRowHeight() - 3); + super.paint(g); + } + + @Override + public Container getParent() { + return jTreeTable; + } + + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + visibleRow = table.convertRowIndexToModel(row); + + JComponent c = (JComponent) tableDefaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + Color background = c.getBackground(); + Color foreground = c.getForeground(); + Border border = c.getBorder(); + + setBackground(background); + setForeground(foreground); + setBorder(border); + + if (getCellRenderer() instanceof CheckTreeCellRenderer) { + ((CheckTreeCellRenderer) getCellRenderer()).setBackgroundSelectionColor(background); + ((CheckTreeCellRenderer) getCellRenderer()).setBackgroundNonSelectionColor(background); + } else { + ((JLabel) getCellRenderer()).setBackground(background); + ((JLabel) getCellRenderer()).setForeground(foreground); + } + + return this; + } +} diff --git a/src/eu/engys/util/ui/treetable/tree/TreeTableTreeModel.java b/src/eu/engys/util/ui/treetable/tree/TreeTableTreeModel.java new file mode 100644 index 0000000..d6bd14f --- /dev/null +++ b/src/eu/engys/util/ui/treetable/tree/TreeTableTreeModel.java @@ -0,0 +1,121 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.treetable.tree; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +public class TreeTableTreeModel implements TreeModel { + + private TreeTableTreeNode root; + + private List listeners = new ArrayList(); + + public TreeTableTreeModel(TreeTableTreeNode root) { + this.root = root; + } + + @Override + public Object getRoot() { + return root; + } + + @Override + public Object getChild(Object parent, int index) { + return ((TreeTableTreeNode) parent).getChild(index); + } + + @Override + public int getChildCount(Object parent) { + return ((TreeTableTreeNode) parent).getChildCount(); + } + + @Override + public boolean isLeaf(Object node) { + if (node == null) { + return true; + } + return ((TreeTableTreeNode) node).isLeaf(); + } + + @Override + public void valueForPathChanged(TreePath path, Object newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public int getIndexOfChild(Object parent, Object child) { + return ((TreeTableTreeNode) parent).getIndexOfChild((TreeTableTreeNode) child); + } + + @Override + public void addTreeModelListener(TreeModelListener l) { + listeners.add(l); + } + + @Override + public void removeTreeModelListener(TreeModelListener l) { + listeners.remove(l); + } + + public void fireTreeStructureChanged() { + TreeModelEvent e = new TreeModelEvent(getRoot(), new Object[] { getRoot() }, null, null); + for (Iterator iter = listeners.iterator(); iter.hasNext();) { + TreeModelListener l = iter.next(); + l.treeStructureChanged(e); + } + } + + public TreeNode[] getPathToRoot(TreeNode aNode) { + return getPathToRoot(aNode, 0); + } + + private TreeNode[] getPathToRoot(TreeNode aNode, int depth) { + TreeNode[] retNodes; + if (aNode == null) { + if (depth == 0) + return null; + else + retNodes = new TreeNode[depth]; + } else { + depth++; + if (aNode == root) + retNodes = new TreeNode[depth]; + else + retNodes = getPathToRoot(aNode.getParent(), depth); + retNodes[retNodes.length - depth] = aNode; + } + return retNodes; + } +} diff --git a/src/eu/engys/util/ui/treetable/tree/TreeTableTreeNode.java b/src/eu/engys/util/ui/treetable/tree/TreeTableTreeNode.java new file mode 100644 index 0000000..c0dad7c --- /dev/null +++ b/src/eu/engys/util/ui/treetable/tree/TreeTableTreeNode.java @@ -0,0 +1,39 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.util.ui.treetable.tree; + +public interface TreeTableTreeNode { + + public int getChildCount(); + + public TreeTableTreeNode getChild(int index); + + public boolean isLeaf(); + + public int getIndexOfChild(TreeTableTreeNode child); + +} diff --git a/src/eu/engys/vtk/ActorsMap.java b/src/eu/engys/vtk/ActorsMap.java new file mode 100644 index 0000000..ee0138a --- /dev/null +++ b/src/eu/engys/vtk/ActorsMap.java @@ -0,0 +1,87 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.view3D.Actor; + +public class ActorsMap { + + private final Map delegate = new LinkedHashMap<>(); + + public ActorsMap() { + } + + public ActorsMap(Map map) { + this.delegate.putAll(map); + } + + public void put(Surface key, Actor value) { + delegate.put(key, value); + } + + public Actor get(Surface key) { + return delegate.get(key); + } + + public Actor remove(Surface key) { + return delegate.remove(key); + } + + public boolean contains(Surface surface) { + return delegate.containsKey(surface); + } + + public Collection values() { + return delegate.values(); + } + + public Set keys() { + return delegate.keySet(); + } + + public void clear() { + delegate.clear(); + } + + public boolean isEmpty() { + return delegate.isEmpty(); + } + + public boolean containsActor(Actor actor) { + return delegate.containsValue(actor); + } + + public Map getDelegate() { + return delegate; + } + +} diff --git a/src/eu/engys/vtk/CellZoneActor.java b/src/eu/engys/vtk/CellZoneActor.java new file mode 100644 index 0000000..198b057 --- /dev/null +++ b/src/eu/engys/vtk/CellZoneActor.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import vtk.vtkPolyData; +import vtk.vtkUnstructuredGrid; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.facezones.FaceZone; +import eu.engys.util.ui.checkboxtree.VisibleItem; +import eu.engys.vtk.actors.DefaultActor; + +public class CellZoneActor extends DefaultActor { + + private VisibleItem zone; + + public CellZoneActor(CellZone zone, vtkUnstructuredGrid dataset) { + super(zone.getName()); + this.zone = zone; + newActor(dataset, true); + } + + public CellZoneActor(FaceZone zone, vtkPolyData dataset) { + super(zone.getName()); + this.zone = zone; + newActor(dataset, true); + } + + @Override + public VisibleItem getVisibleItem() { + return zone; + } +} diff --git a/src/eu/engys/vtk/GeometryContext.java b/src/eu/engys/vtk/GeometryContext.java new file mode 100644 index 0000000..997a3ed --- /dev/null +++ b/src/eu/engys/vtk/GeometryContext.java @@ -0,0 +1,81 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.util.LinkedHashMap; +import java.util.Map; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Context; +import eu.engys.gui.view3D.Representation; + +public class GeometryContext extends Context { + + private ActorsMap actorsMap; + private Map actorsVisibility; + + // private Map actorsProperty; + + public GeometryContext(Representation representation, Map actorsMap) { + super(representation); + this.actorsMap = new ActorsMap(actorsMap); + this.actorsVisibility = initActorsVisibility(actorsMap); + // this.actorsProperty = initActorsProperty(actorsMap); + } + + @Override + public boolean isEmpty() { + return actorsMap.isEmpty(); + } + + public void clear() { + actorsMap.clear(); + actorsVisibility.clear(); + } + + private Map initActorsVisibility(Map actorsMap) { + Map map = new LinkedHashMap<>(); + for (Surface surface : actorsMap.keySet()) { + Actor actor = actorsMap.get(surface); + map.put(surface, actor.getVisibility()); + } + return map; + } + + public ActorsMap getActorsMap() { + return actorsMap; + } + + public Map getActorsVisibility() { + return actorsVisibility; + } + + @Override + public String toString() { + return "GeometryContext [ repres = " + getRepresentation() + ", actors are " + actorsMap.getDelegate().size() + "]"; + } +} diff --git a/src/eu/engys/vtk/HelyxView3DEventListener.java b/src/eu/engys/vtk/HelyxView3DEventListener.java new file mode 100644 index 0000000..471ece6 --- /dev/null +++ b/src/eu/engys/vtk/HelyxView3DEventListener.java @@ -0,0 +1,121 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import java.awt.Color; + +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.vecmath.Point3d; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.events.EventManager.Event; +import eu.engys.gui.events.view3D.AxisEvent; +import eu.engys.gui.events.view3D.BoxEvent; +import eu.engys.gui.events.view3D.LayersCoverageEvent; +import eu.engys.gui.events.view3D.MeshQualityEvent; +import eu.engys.gui.events.view3D.PlaneEvent; +import eu.engys.gui.events.view3D.PointEvent; +import eu.engys.gui.events.view3D.SelectionEvent; +import eu.engys.gui.events.view3D.VolumeReportEvent; +import eu.engys.gui.events.view3D.VolumeReportVisibilityEvent; +import eu.engys.gui.events.view3D.VolumeReportVisibilityEvent.Kind; +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.gui.view3D.LayerInfo; +import eu.engys.gui.view3D.QualityInfo; +import eu.engys.gui.view3D.Selection; +import eu.engys.gui.view3D.View3DEventListener; +import eu.engys.util.ui.textfields.DoubleField; + +public class HelyxView3DEventListener implements View3DEventListener { + + private CanvasPanel view3D; + + public HelyxView3DEventListener(CanvasPanel view3DPanel) { + this.view3D = view3DPanel; + } + + @Override + public void eventTriggered(Object obj, final Event event) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (event instanceof PointEvent) { + DoubleField[] point = ((PointEvent) event).getPoint(); + String key = ((PointEvent) event).getKey(); + EventActionType action = ((PointEvent) event).getAction(); + Color color = ((PointEvent) event).getColor(); + view3D.showPoint(point, key, action, color); + } else if (event instanceof AxisEvent) { + AxisEvent e = (AxisEvent) event; + DoubleField[] origin = e.getAxisInfo().getCenter(); + DoubleField[] normal = e.getAxisInfo().getAxis(); + EventActionType action = e.getAxisInfo().getAction(); + view3D.showAxis(origin, normal, action); + } else if (event instanceof PlaneEvent) { + DoubleField[] origin = ((PlaneEvent) event).getOrigin(); + DoubleField[] normal = ((PlaneEvent) event).getNormal(); + EventActionType action = ((PlaneEvent) event).getAction(); + boolean interactive = ((PlaneEvent) event).isInteractive(); + if (interactive) { + view3D.showPlane(origin, normal, action); + } else { + view3D.showPlaneDisplay(origin, normal, action); + } + } else if (event instanceof BoxEvent) { + DoubleField[] min = ((BoxEvent) event).getMin(); + DoubleField[] max = ((BoxEvent) event).getMax(); + EventActionType action = ((BoxEvent) event).getAction(); + view3D.showBox(min, max, action); + } else if (event instanceof SelectionEvent) { + Selection selection = ((SelectionEvent) event).getSelection(); + EventActionType action = ((SelectionEvent) event).getAction(); + view3D.activateSelection(selection, action); + } else if (event instanceof MeshQualityEvent) { + QualityInfo qualityInfo = ((MeshQualityEvent) event).getQualityInfo(); + EventActionType action = ((MeshQualityEvent) event).getAction(); + view3D.showQualityFields(qualityInfo, action); + } else if (event instanceof LayersCoverageEvent) { + EventActionType action = ((LayersCoverageEvent) event).getAction(); + JPanel colorBar = ((LayersCoverageEvent) event).getColorBar(); + LayerInfo layerInfo = ((LayersCoverageEvent) event).getLayerInfo(); + view3D.showLayersCoverage(layerInfo, colorBar, action); + } else if (event instanceof VolumeReportEvent) { + String varName = VolumeReportEvent.class.cast(event).getVarName(); + Point3d min = VolumeReportEvent.class.cast(event).getMinAtLocation(); + Point3d max = VolumeReportEvent.class.cast(event).getMaxAtLocation(); + view3D.updateMinAndMaxForFields(varName, min, max); + } else if (event instanceof VolumeReportVisibilityEvent) { + String key = VolumeReportVisibilityEvent.class.cast(event).getKey(); + boolean visible = VolumeReportVisibilityEvent.class.cast(event).isVisible(); + Kind kind = VolumeReportVisibilityEvent.class.cast(event).getKind(); + view3D.showMinMaxFieldPoints(key, kind, visible); + } + } + }); + } +} diff --git a/src/eu/engys/vtk/InteractorStyle.java b/src/eu/engys/vtk/InteractorStyle.java new file mode 100644 index 0000000..f5dbea6 --- /dev/null +++ b/src/eu/engys/vtk/InteractorStyle.java @@ -0,0 +1,105 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import vtk.vtkInteractorStyleTrackballCamera; + +public class InteractorStyle extends vtkInteractorStyleTrackballCamera { + + public InteractorStyle() { + super(); + AddObserver("MouseMoveEvent", this, "OnMouseMove"); + AddObserver("LeftButtonPressEvent", this, "leftButtonPressed"); + AddObserver("MiddleButtonPressEvent", this, "middleButtonPressed"); + AddObserver("RightButtonPressEvent", this, "rightButtonPressed"); + AddObserver("LeftButtonReleaseEvent", this, "leftButtonReleased"); + AddObserver("MiddleButtonReleaseEvent", this, "middleButtonReleased"); + AddObserver("RightButtonReleaseEvent", this, "rightButtonReleased"); + } + + public void leftButtonPressed() { + System.out.println("InteractorStyle.leftButtonPressed()"); +// buttonDown(getLastPos(), 0); + } + + public void middleButtonPressed() { + System.out.println("InteractorStyle.middleButtonPressed()"); +// buttonDown(getLastPos(), 1); + } + + public void rightButtonPressed() { + System.out.println("InteractorStyle.rightButtonPressed()"); +// buttonDown(getLastPos(), 2); + } + + public void leftButtonReleased() { + System.out.println("InteractorStyle.leftButtonReleased()"); +// buttonUp(getLastPos(), 0); + } + + public void middleButtonReleased() { + System.out.println("InteractorStyle.middleButtonReleased()"); +// buttonUp(getLastPos(), 1); + } + + public void rightButtonReleased() { + System.out.println("InteractorStyle.rightButtonReleased()"); +// buttonUp(getLastPos(), 2); + } + + public void OnMouseMove() { + System.out.println("InteractorStyle.OnMouseMove() " + GetState()); +// int x = GetInteractor().GetEventPosition()[0]; +// int y = GetInteractor().GetEventPosition()[1]; +// switch(GetState()) +// { +// case 1: // '\001' +// postText(INTERACTOR_ACTION_ROTATE); +// Rotate(); +// InvokeEvent("InteractionEvent"); +// break; +// +// case 2: // '\002' +// postText(INTERACTOR_ACTION_PAN); +// Pan(); +// InvokeEvent("InteractionEvent"); +// break; +// +// case 4: // '\004' +// postText(INTERACTOR_ACTION_ZOOM); +// Dolly(); +// InvokeEvent("InteractionEvent"); +// break; +// +// case 3: // '\003' +// postText(INTERACTOR_ACTION_ROLL); +// Spin(); +// InvokeEvent("InteractionEvent"); +// break; +// } + } + +} diff --git a/src/eu/engys/vtk/MeshContext.java b/src/eu/engys/vtk/MeshContext.java new file mode 100644 index 0000000..6188b68 --- /dev/null +++ b/src/eu/engys/vtk/MeshContext.java @@ -0,0 +1,111 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.util.LinkedHashMap; +import java.util.Map; + +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Context; +import eu.engys.gui.view3D.Representation; + +public class MeshContext extends Context { + + private boolean allowSelection; + + private Map patches; + private Map patchesVisibility; + + private Map cellzones; + private Map zonesVisibility; + + public MeshContext(Representation representation, boolean allowSelection, Map cellzones, Map patches) { + super(representation); + this.allowSelection = allowSelection; + + this.patches = new LinkedHashMap<>(patches); + this.patchesVisibility = initPatchesVisibility(patches); + + this.cellzones = new LinkedHashMap<>(cellzones); + this.zonesVisibility = initZonesVisibility(cellzones); + } + + public void clear() { + patches.clear(); + patchesVisibility.clear(); + zonesVisibility.clear(); + cellzones.clear(); + } + + private Map initPatchesVisibility(Map patches) { + Map map = new LinkedHashMap<>(); + for (String name : patches.keySet()) { + Actor actor = patches.get(name); + map.put(name, actor.getVisibility()); + } + return map; + } + + private Map initZonesVisibility(Map cellzones) { + Map map = new LinkedHashMap<>(); + for (String name : cellzones.keySet()) { + Actor actor = cellzones.get(name); + map.put(name, actor.getVisibility()); + } + return map; + } + + @Override + public boolean isEmpty() { + return patches.isEmpty(); + } + + public boolean isAllowSelection(){ + return allowSelection; + } + + public Map getPatches() { + return patches; + } + + public Map getPatchesVisibility() { + return patchesVisibility; + } + + public Map getCellzones() { + return cellzones; + } + + public Map getZonesVisibility() { + return zonesVisibility; + } + + @Override + public String toString() { + return "MeshContext [ repres = " + representation + ", zones are " + cellzones.keySet().size() + ", patches are " + patches.keySet().size() + "]"; + } + +} diff --git a/src/eu/engys/vtk/PatchActor.java b/src/eu/engys/vtk/PatchActor.java new file mode 100644 index 0000000..39fc430 --- /dev/null +++ b/src/eu/engys/vtk/PatchActor.java @@ -0,0 +1,45 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.util.ui.checkboxtree.VisibleItem; +import eu.engys.vtk.actors.DefaultActor; + +public class PatchActor extends DefaultActor { + private Patch patch; + + public PatchActor(Patch patch) { + super(patch.getName()); + this.patch = patch; + newActor(patch.getDataSet(), true); + } + + @Override + public VisibleItem getVisibleItem() { + return patch; + } +} diff --git a/src/eu/engys/vtk/ReaderProgress.java b/src/eu/engys/vtk/ReaderProgress.java new file mode 100644 index 0000000..39961d5 --- /dev/null +++ b/src/eu/engys/vtk/ReaderProgress.java @@ -0,0 +1,44 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import vtk.vtkAlgorithm; +import eu.engys.util.progress.ProgressMonitor; + +public class ReaderProgress { + private vtkAlgorithm reader; + private ProgressMonitor monitor; + + public ReaderProgress(vtkAlgorithm reader, ProgressMonitor monitor) { + this.reader = reader; + this.monitor = monitor; + } + + public void progress() { + monitor.setCurrent(null, (int) (100*reader.GetProgress())); + } +} diff --git a/src/eu/engys/vtk/RenderPanelAdapter.java b/src/eu/engys/vtk/RenderPanelAdapter.java new file mode 100644 index 0000000..8ad8fce --- /dev/null +++ b/src/eu/engys/vtk/RenderPanelAdapter.java @@ -0,0 +1,179 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.awt.Color; +import java.awt.event.KeyListener; + +import vtk.vtkAssembly; +import vtk.vtkImageData; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.CameraManager.Position; +import eu.engys.gui.view3D.Interactor; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.gui.view3D.Representation; + +public class RenderPanelAdapter implements RenderPanel { + + @Override + public void lock() { + } + + @Override + public void Render() { + } + + @Override + public void unlock() { + } + + @Override + public void clear() { + } + + @Override + public void setCameraPosition(Position xPos) { + } + + @Override + public void resetCamera() { + } + + @Override + public void wheelForward() { + } + + @Override + public void wheelBackward() { + } + + @Override + public void zoomReset() { + } + + @Override + public void resetZoomLater() { + } + + @Override + public void resetZoomAndWait() { + } + + @Override + public void clearSelection() { + } + + @Override + public void setRepresentation(Representation r) { + } + + @Override + public Representation getRepresentation() { + return null; + } + + @Override + public void changeRepresentation(Representation r) { + } + + @Override + public void renderLater() { + } + + @Override + public void renderAndWait() { + } + + @Override + public void addActor(vtkAssembly cor) { + } + + @Override + public void addActor(Actor actor) { + } + + @Override + public void removeActor(Actor actor) { + } + + @Override + public void selectActors(boolean keep, Actor... pickedActor) { + } + + @Override + public void setLowRendering() { + + } + + @Override + public void setHighRendering() { + } + + @Override + public void setActorColor(Color c, Actor... actor) { + } + + @Override + public void addKeyListener(KeyListener listener) { + } + + @Override + public void removeKeyListener(KeyListener listener) { + } + + @Override + public void dispose() { + } + + @Override + public void ParallelProjectionOn() { + } + + @Override + public void ParallelProjectionOff() { + } + + @Override + public VTKPickManager getPickManager() { + return null; + } + + @Override + public Interactor getInteractor() { + return null; + } + + @Override + public vtkImageData toImageData() { + return null; + } + @Override + public void lowRenderingOff() { + } + @Override + public void lowRenderingOn() { + } +} diff --git a/src/eu/engys/vtk/VTK3DActionsToolBar.java b/src/eu/engys/vtk/VTK3DActionsToolBar.java new file mode 100644 index 0000000..28e5e80 --- /dev/null +++ b/src/eu/engys/vtk/VTK3DActionsToolBar.java @@ -0,0 +1,182 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import static eu.engys.util.ui.UiUtil.createButtonBarToggleButton; +import static eu.engys.util.ui.UiUtil.createToolBarButton; +import static eu.engys.util.ui.UiUtil.createToolBarToggleButton; + +import java.util.List; + +import javax.swing.ButtonGroup; +import javax.swing.JToolBar; + +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.project.Model; +import eu.engys.gui.view3D.Context; +import eu.engys.gui.view3D.Controller3D; +import eu.engys.util.plaf.ILookAndFeel; + +public class VTK3DActionsToolBar extends JToolBar { + + static final String _3D_LOAD_MESH = "3d.load.mesh"; + + static final String _3D_AXIS_XPOS = "3d.axis.xpos"; + static final String _3D_AXIS_XNEG = "3d.axis.xneg"; + static final String _3D_AXIS_YPOS = "3d.axis.ypos"; + static final String _3D_AXIS_YNEG = "3d.axis.yneg"; + static final String _3D_AXIS_ZPOS = "3d.axis.zpos"; + static final String _3D_AXIS_ZNEG = "3d.axis.zneg"; + + static final String _3D_ZOOM_RESET = "3d.zoom.reset"; + static final String _3D_ZOOM_TOBOX = "3d.zoom.tobox"; + static final String _3D_ZOOM_OUT = "3d.zoom.out"; + static final String _3D_ZOOM_IN = "3d.zoom.in"; + + static final String _3D_VIEW_PROJECTIONS = "3d.view.projections"; + static final String _3D_VIEW_OUTLINE = "3d.view.outline"; + static final String _3D_VIEW_PROFILE = "3d.view.profile"; + static final String _3D_VIEW_EDGES = "3d.view.edges"; + static final String _3D_VIEW_SURFACE = "3d.view.surface"; + static final String _3D_VIEW_WIREFRAME = "3d.view.wireframe"; + private Model model; + + public VTK3DActionsToolBar(Model model, ILookAndFeel laf) { + super(JToolBar.VERTICAL); + this.model = model; + putClientProperty("Synthetica.toolBar.buttons.paintBorder", Boolean.TRUE); + putClientProperty("Synthetica.opaque", Boolean.FALSE); + setFloatable(false); + setRollover(true); + setOpaque(false); + layoutComponents(); + } + + private void layoutComponents() { + add(createToolBarButton(ActionManager.getInstance().get(_3D_ZOOM_IN))); + add(createToolBarButton(ActionManager.getInstance().get(_3D_ZOOM_OUT))); + add(createToolBarButton(ActionManager.getInstance().get(_3D_ZOOM_TOBOX))); + add(createToolBarButton(ActionManager.getInstance().get(_3D_ZOOM_RESET))); + addSeparator(); + add(createToolBarButton(ActionManager.getInstance().get(_3D_AXIS_XPOS))); + add(createToolBarButton(ActionManager.getInstance().get(_3D_AXIS_XNEG))); + add(createToolBarButton(ActionManager.getInstance().get(_3D_AXIS_YPOS))); + add(createToolBarButton(ActionManager.getInstance().get(_3D_AXIS_YNEG))); + add(createToolBarButton(ActionManager.getInstance().get(_3D_AXIS_ZPOS))); + add(createToolBarButton(ActionManager.getInstance().get(_3D_AXIS_ZNEG))); + addSeparator(); + ButtonGroup viewGroup = new ButtonGroup(); + add(createButtonBarToggleButton(ActionManager.getInstance().get(_3D_VIEW_WIREFRAME), viewGroup)); + add(createButtonBarToggleButton(ActionManager.getInstance().get(_3D_VIEW_SURFACE), viewGroup)); + add(createButtonBarToggleButton(ActionManager.getInstance().get(_3D_VIEW_EDGES), viewGroup)); + add(createButtonBarToggleButton(ActionManager.getInstance().get(_3D_VIEW_PROFILE), viewGroup)); + add(createButtonBarToggleButton(ActionManager.getInstance().get(_3D_VIEW_OUTLINE), viewGroup)); + add(createToolBarToggleButton(ActionManager.getInstance().get(_3D_VIEW_PROJECTIONS))); + } + + public void update(List controllers) { + Context context = getaContext(controllers); + if (context != null) { + ActionManager.getInstance().get(_3D_VIEW_PROJECTIONS).setEnabled(true); + ActionManager.getInstance().get(_3D_VIEW_WIREFRAME).setEnabled(true); + ActionManager.getInstance().get(_3D_VIEW_SURFACE).setEnabled(true); + ActionManager.getInstance().get(_3D_VIEW_EDGES).setEnabled(true); + ActionManager.getInstance().get(_3D_VIEW_PROFILE).setEnabled(true); + ActionManager.getInstance().get(_3D_VIEW_OUTLINE).setEnabled(true); + + switch (context.getRepresentation()) { + case WIREFRAME: + ActionManager.getInstance().get(_3D_VIEW_WIREFRAME).setSelected(true); + break; + case SURFACE: + ActionManager.getInstance().get(_3D_VIEW_SURFACE).setSelected(true); + break; + case SURFACE_WITH_EDGES: + ActionManager.getInstance().get(_3D_VIEW_EDGES).setSelected(true); + break; + case OUTLINE: + ActionManager.getInstance().get(_3D_VIEW_OUTLINE).setSelected(true); + break; + case PROFILE: + ActionManager.getInstance().get(_3D_VIEW_PROFILE).setSelected(true); + break; + } +// if (context instanceof MeshContext) { +// MeshContext mc = (MeshContext) context; +// ActionManager.getInstance().get(_3D_LOAD_MESH).setEnabled(!model.getPatches().isEmpty() && mc.isEmpty()); +// } + } else { + ActionManager.getInstance().get(_3D_VIEW_WIREFRAME).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_SURFACE).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_EDGES).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_PROFILE).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_OUTLINE).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_PROJECTIONS).setEnabled(false); + } + + MeshContext mContext = (MeshContext) getMeshContext(controllers); + if(mContext != null){ + ActionManager.getInstance().get(_3D_LOAD_MESH).setEnabled(!model.getPatches().isEmpty() && mContext.isEmpty()); + } + } + + private Context getaContext(List controllers) { + for (Controller3D c : controllers) { + Context context = c.getCurrentContext(); + if (context != null) { + return context; + } + } + return null; + } + + private Context getMeshContext(List controllers) { + for (Controller3D c : controllers) { + Context context = c.getCurrentContext(); + if (context != null && context instanceof MeshContext) { + return context; + } + } + return null; + } + + public void clear() { + ActionManager.getInstance().get(_3D_VIEW_WIREFRAME).setSelected(false); + ActionManager.getInstance().get(_3D_VIEW_SURFACE).setSelected(false); + ActionManager.getInstance().get(_3D_VIEW_EDGES).setSelected(false); + ActionManager.getInstance().get(_3D_VIEW_PROFILE).setSelected(false); + ActionManager.getInstance().get(_3D_VIEW_OUTLINE).setSelected(false); + ActionManager.getInstance().get(_3D_VIEW_PROJECTIONS).setSelected(false); + + ActionManager.getInstance().get(_3D_VIEW_WIREFRAME).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_SURFACE).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_EDGES).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_PROFILE).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_OUTLINE).setEnabled(false); + ActionManager.getInstance().get(_3D_VIEW_PROJECTIONS).setEnabled(false); + } +} diff --git a/src/eu/engys/vtk/VTKActors.java b/src/eu/engys/vtk/VTKActors.java new file mode 100644 index 0000000..981d1fa --- /dev/null +++ b/src/eu/engys/vtk/VTKActors.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.util.Collection; +import java.util.Map; + +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.RenderPanel; + +public interface VTKActors { + + public Collection getActors(); + + public abstract boolean containsActor(Actor pickedActor); + + public abstract Map getActorsMap(); + + void setRenderPanel(RenderPanel renderPanel); +} diff --git a/src/eu/engys/vtk/VTKCameraManager.java b/src/eu/engys/vtk/VTKCameraManager.java new file mode 100644 index 0000000..d13bd21 --- /dev/null +++ b/src/eu/engys/vtk/VTKCameraManager.java @@ -0,0 +1,78 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import vtk.vtkRenderer; +import eu.engys.gui.view3D.CameraManager; + +public class VTKCameraManager implements CameraManager { + + private VTKRenderPanel vtkRenderPanel; + + public VTKCameraManager(VTKRenderPanel vtkRenderPanel) { + this.vtkRenderPanel = vtkRenderPanel; + } + + + public void setCameraPosition(Position pos) { + vtkRenderer renderer = vtkRenderPanel.GetRenderer(); + double[] fp = renderer.GetActiveCamera().GetFocalPoint(); + double[] p = renderer.GetActiveCamera().GetPosition(); + double dist = Math.sqrt(Math.pow(p[0] - fp[0], 2) + Math.pow(p[1] - fp[1], 2) + Math.pow(p[2] - fp[2], 2)); + + vtkRenderPanel.lock(); + switch (pos) { + case X_POS: + renderer.GetActiveCamera().SetPosition(fp[0] - dist, fp[1], fp[2]); + renderer.GetActiveCamera().SetViewUp(0, 0, 1); + break; + case X_NEG: + renderer.GetActiveCamera().SetPosition(fp[0] + dist, fp[1], fp[2]); + renderer.GetActiveCamera().SetViewUp(0, 0, 1); + break; + case Y_POS: + renderer.GetActiveCamera().SetPosition(fp[0], fp[1] - dist, fp[2]); + renderer.GetActiveCamera().SetViewUp(0, 0, 1); + break; + case Y_NEG: + renderer.GetActiveCamera().SetPosition(fp[0], fp[1] + dist, fp[2]); + renderer.GetActiveCamera().SetViewUp(0, 0, 1); + break; + case Z_POS: + renderer.GetActiveCamera().SetPosition(fp[0], fp[1], fp[2] - dist); + renderer.GetActiveCamera().SetViewUp(0, 1, 0); + break; + case Z_NEG: + renderer.GetActiveCamera().SetPosition(fp[0], fp[1], fp[2] + dist); + renderer.GetActiveCamera().SetViewUp(0, 1, 0); + break; + } + vtkRenderPanel.unlock(); + vtkRenderPanel.renderLater(); + } + + +} diff --git a/src/eu/engys/vtk/VTKCellZones.java b/src/eu/engys/vtk/VTKCellZones.java new file mode 100644 index 0000000..9c83de5 --- /dev/null +++ b/src/eu/engys/vtk/VTKCellZones.java @@ -0,0 +1,200 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkDataObject; +import vtk.vtkPolyData; +import vtk.vtkUnstructuredGrid; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.facezones.FaceZone; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.progress.ProgressMonitor; + +public class VTKCellZones implements VTKActors, Picker { + + private static final Logger logger = LoggerFactory.getLogger(VTKCellZones.class); + + private Map actors = new LinkedHashMap<>(); + private Map names = new LinkedHashMap<>(); + private RenderPanel renderPanel; + private Model model; + private ProgressMonitor monitor; + + public VTKCellZones(Model model, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + } + + @Override + public void setRenderPanel(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + } + + public void load(List cellZonesDataset) { + for (int i = 0; i < cellZonesDataset.size(); i++) { + vtkDataObject dataset = cellZonesDataset.get(i); + + if (dataset instanceof vtkPolyData) { + FaceZone zone = model.getFaceZones().get(i); + zone.setLoaded(true); + addActorToZones(new CellZoneActor(zone, (vtkPolyData) dataset)); + } else if (dataset instanceof vtkUnstructuredGrid) { + CellZone zone = model.getCellZones().get(i); + zone.setLoaded(true); + addActorToZones(new CellZoneActor(zone, (vtkUnstructuredGrid) dataset)); + } + } + } + + void addActorToZones(Actor actor) { + logger.debug("[ADD ACTOR] {} ({})", actor.getName(), actor.getVisibility() ? "visible" : "hidden"); + actors.put(actor.getName(), actor); + names.put(actor, actor.getName()); + } + + void addActorsToRenderer() { + for (String name : actors.keySet()) { + Actor actor = actors.get(name); + renderPanel.addActor(actor); + } + } + + public void addCellZonesMap(Map map, Map visibility) { + for (String name : map.keySet()) { + Actor actor = map.get(name); + actor.setVisibility(visibility.get(name)); + addActorToZones(actor); + renderPanel.addActor(actor); + } + } + + public void deleteActors() { + for (Actor actor : actors.values()) { + renderPanel.removeActor(actor); + actor.deleteActor(); + } + actors.clear(); + names.clear(); + } + + public void removeActorsFromRenderer() { + for (Actor actor : actors.values()) { + renderPanel.removeActor(actor); + } + actors.clear(); + names.clear(); + } + + public void VisibilityOff() { + for (Actor actor : actors.values()) { + actor.setVisibility(false); + } + } + + public Collection getActors() { + return actors.values(); + } + + public boolean containsActor(Actor pickedActor) { + return names.containsKey(pickedActor); + } + +// @Override +// public String getActorName(Actor pickedActor) { +// return names.get(pickedActor); +// } + + @Override + public boolean canPickCells(Actor pickedActor) { + return false; + } + + @Override + public boolean canPickMesh() { + return true; + } + + public void selectActors(CellZone[] zones) { + logger.debug("updateSurfaceVisibility: {} zones selected {}", zones.length, zones.length == 1 ? ", selection is: " + zones[0] : ""); + + List selection = new ArrayList(); + for (CellZone zone : zones) { + String name = zone.getName(); + if (zone.isVisible() && actors.containsKey(name)) { + selection.add(actors.get(name)); + } + } + renderPanel.setLowRendering(); + renderPanel.selectActors(false, selection.toArray(new Actor[0])); + renderPanel.setHighRendering(); + } + + public void updateVisibility(CellZone[] selection) { + for (CellZone cellZone : selection) { + Actor actor = actors.get(cellZone.getName()); + actor.setVisibility(cellZone.isVisible()); + } + renderPanel.renderLater(); + } + + public void update(List cellZonesDataset) { + List actorsList = new ArrayList<>(getActors()); + for (int i = 0; i < cellZonesDataset.size(); i++) { + vtkDataObject obj = cellZonesDataset.get(i); + Actor actor = actorsList.get(i); + if (obj instanceof vtkPolyData) { + logger.debug("Update polydata {}", names.get(actor)); + VTKUtil.changeDataset(actor, (vtkPolyData) obj); + } else if (obj instanceof vtkUnstructuredGrid) { + logger.debug("Update unstructured_grid {}", names.get(actor)); + VTKUtil.changeDataset(actor, (vtkUnstructuredGrid) obj); + } + } + } + + @Override + public Map getActorsMap() { + return Collections.unmodifiableMap(actors); + } + + public boolean isLoaded() { + return !actors.isEmpty(); + } + +} diff --git a/src/eu/engys/vtk/VTKColors.java b/src/eu/engys/vtk/VTKColors.java new file mode 100644 index 0000000..b205a93 --- /dev/null +++ b/src/eu/engys/vtk/VTKColors.java @@ -0,0 +1,192 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; + +import vtk.vtkLookupTable; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.core.project.mesh.ScalarBarType; +import eu.engys.gui.view3D.Actor; + +public class VTKColors { + + public static final double[] WHITE = toVTK(Color.WHITE); + public static final double[] BLACK = toVTK(Color.BLACK); + public static final double[] RED = toVTK(Color.RED); + public static final double[] GREEN = toVTK(Color.GREEN); + public static final double[] BLUE = toVTK(Color.BLUE); + public static final double[] ORANGE = toVTK(Color.ORANGE); + public static final double[] PINK = toVTK(Color.PINK); + public static final double[] CYAN = toVTK(Color.CYAN); + public static final double[] MAGENTA = toVTK(Color.MAGENTA); + public static final double[] YELLOW = toVTK(Color.YELLOW); + + public static final double AMBIENT = 0.0; + public static final double DIFFUSE = 0.9; + public static final double SPECULAR = 0.1; + public static final double SPECULAR_POWER = 0.8; + + public static final double SELECTION_AMBIENT = 0.0; + public static final double SELECTION_DIFFUSE = 1.0; + public static final double SELECTION_SPECULAR = 0.0; + public static final double SELECTION_SPECULAR_POWER = 0; + + // public static final double[] SELECTION_COLOR = new double[] {1, 0.5, 0}; + public static final double[] SELECTION_COLOR = new double[] { 0.8, 0.1, 0.1 }; + public static final double[] DESELECTION_COLOR = WHITE; + + static class ScalarsColor { + private List actors = new ArrayList<>(); + private FieldItem field; + + ScalarsColor(FieldItem field) { + this.field = field; + } + + public ScalarsColor to(VTKActors actors) { + this.actors.addAll(actors.getActors()); + + if (field.isAutomaticRange()) { + new VTKRangeCalculator(field).calculateRange_Automatically_For(actors); + } else { + // use existing range + } + + return this; + } + + public void apply() { + vtkLookupTable lut = new vtkLookupTable(); + applyTypeToLookupTable(field, lut); + + for (Actor actor : actors) { + actor.setScalarColors(lut, field); + } + } + } + + public static void applyTypeToLookupTable(FieldItem fieldItem, vtkLookupTable table) { + // Vector Mode + if (fieldItem.getComponent() <= 0) { + table.SetVectorModeToMagnitude(); + } else { + table.SetVectorModeToComponent(); + table.SetVectorComponent(fieldItem.getComponent() - 1); + } + + // Range + table.SetRange(fieldItem.getRange()); + + // Colors + ScalarBarType scalarBarType = fieldItem.getScalarBarType(); + List colors = scalarBarType.getColors(fieldItem.getResolution()); + if (scalarBarType.equals(ScalarBarType.RED_TO_BLUE_RAINBOW) || scalarBarType.equals(ScalarBarType.BLUE_TO_RED_RAINBOW)) { + table.SetNumberOfTableValues(fieldItem.getResolution()); + table.SetHueRange(scalarBarType.getColors(-1).get(0)); + table.ForceBuild(); + } else { + table.SetNumberOfTableValues(colors.size()); + for (int i = 0; i < colors.size(); i++) { + double[] values = colors.get(i); + double red = values[0]; + double green = values[1]; + double blue = values[2]; + table.SetTableValue(i, red, green, blue, 1); + } + table.Build(); + } + } + + static class IndexedColor { + private List actors = new ArrayList<>(); + + public IndexedColor to(VTKActors actors) { + this.actors.addAll(actors.getActors()); + return this; + } + + public void apply() { + vtkLookupTable lut = new vtkLookupTable(); + lut.SetTableRange(0, actors.size() - 1); + lut.ForceBuild(); + + int colorIndex = 0; + for (Actor actor : actors) { + double[] color = lut.GetColor(colorIndex++); + actor.setSolidColor(color, 1); + } + lut.Delete(); + } + } + + static class SolidColor { + private double[] color; + private List actors = new ArrayList<>(); + + public SolidColor(double[] color) { + this.color = color; + } + + public SolidColor to(VTKActors actors) { + this.actors.addAll(actors.getActors()); + return this; + } + + public void apply() { + for (Actor actor : actors) { + actor.setSolidColor(color, 1); + } + } + } + + public static SolidColor solidColor(double[] color) { + return new SolidColor(color); + } + + public static IndexedColor indexedColor() { + return new IndexedColor(); + } + + public static ScalarsColor scalarsColor(FieldItem fieldItem) { + return new ScalarsColor(fieldItem); + } + + public static double[] toVTK(Color color) { + return new double[] { color.getRed() / 255.0, color.getGreen() / 255.0, color.getBlue() / 255.0 }; + } + + public static Color toSwing(double[] color) { + return new Color((float) color[0], (float) color[1], (float) color[2]); + } + + public static Color inverse(double[] color) { + return new Color(1 - (float) color[0], 1 - (float) color[1], 1 - (float) color[2]); + } + +} diff --git a/src/eu/engys/vtk/VTKEmptyView3D.java b/src/eu/engys/vtk/VTKEmptyView3D.java new file mode 100644 index 0000000..194c594 --- /dev/null +++ b/src/eu/engys/vtk/VTKEmptyView3D.java @@ -0,0 +1,290 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JPanel; +import javax.vecmath.Point3d; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Inject; + +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.gui.events.view3D.VolumeReportVisibilityEvent.Kind; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElement; +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.gui.view3D.Controller3D; +import eu.engys.gui.view3D.Geometry3DController; +import eu.engys.gui.view3D.LayerInfo; +import eu.engys.gui.view3D.Mesh3DController; +import eu.engys.gui.view3D.QualityInfo; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.gui.view3D.Selection; +import eu.engys.gui.view3D.widget.Widget; +import eu.engys.util.ApplicationInfo; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.textfields.DoubleField; + +public class VTKEmptyView3D extends JPanel implements CanvasPanel { + + private static final Logger logger = LoggerFactory.getLogger(VTKEmptyView3D.class); + private Icon engysLogo = ResourcesUtil.getIcon(ApplicationInfo.getVendor().toLowerCase() + ".logo.full"); + + private Model model; + private ProgressMonitor monitor; + + private Mesh3DController meshController; + private Geometry3DController geometryController; + private List controllers; + + private RenderPanel renderPanel; + + @Inject + public VTKEmptyView3D(Model model, Set controllers, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + this.controllers = new ArrayList<>(); + this.renderPanel = new RenderPanelAdapter(); + + // this.meshController = new VTKMesh3DController(model, monitor); + // this.geometryController = new VTKGeometry3DController(model, monitor); + + // registerController(meshController); + // registerController(geometryController); + + for (Controller3D c : controllers) { + registerController(c); + } + } + + @Override + public void registerController(Controller3D controller) { + controller.setRenderPanel(renderPanel); + controllers.add(controller); + if (controller instanceof Geometry3DController) { + this.geometryController = (Geometry3DController) controller; + } else if (controller instanceof Mesh3DController) { + this.meshController = (Mesh3DController) controller; + } + } + + public RenderPanel getRenderPanel() { + return renderPanel; + } + + @Override + public void paintComponent(final Graphics g) { + super.paintComponent(g); + final ImageIcon image = (ImageIcon) engysLogo; + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + if (image != null) { + int xCoord = (getWidth() / 2) - (image.getIconWidth() / 2); + int yCoord = (getHeight() / 2) - (image.getIconHeight() / 2); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f)); + g.drawImage(image.getImage(), xCoord, yCoord, null); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); + } + } + + // @Override + // public void handleInitializeFieldsStarted() { + // } + // + // @Override + // public void handleInitializeFieldsFinished() { + // } + // + // @Override + // public void start() { + // } + // + // @Override + // public void stop() { + // } + + @Override + public void stop(Class klass) { + + } + + @Override + public void start(Class klass) { + + } + + @Override + public void save() { + } + + @Override + public void load() { + for (Controller3D context : controllers) { + logger.info("[LOAD] {}", context.getClass().getSimpleName()); + context.loadActors(); + } + } + + // @Override + // public void load(Class klass) { + // } + + @Override + public void geometryToMesh(GeometryToMesh g2m) { + geometryController.clear(); + meshController.clear(); + } + + @Override + public void clear() { + } + + @Override + public JPanel getPanel() { + return this; + } + + @Override + public void showBox(DoubleField[] min, DoubleField[] max, EventActionType actions) { + } + + @Override + public void showPoint(DoubleField[] point, String key, EventActionType action, Color color) { + } + + @Override + public void showPlane(DoubleField[] origin, DoubleField[] normal, EventActionType actions) { + } + + @Override + public void showPlaneDisplay(DoubleField[] origin, DoubleField[] normal, EventActionType actions) { + } + + @Override + public void showAxis(DoubleField[] origin, DoubleField[] normal, EventActionType actions) { + } + + @Override + public void activateSelection(Selection selection, EventActionType action) { + } + + @Override + public void showQualityFields(QualityInfo qualityInfo, EventActionType action) { + } + + @Override + public void showLayersCoverage(LayerInfo layerInfo, JPanel colorBar, EventActionType action) { + } + + @Override + public void layoutComponents() { + } + + @Override + public void updateMinAndMaxForFields(String varName, Point3d min, Point3d max) { + } + + @Override + public void showMinMaxFieldPoints(String key, Kind kind, boolean visible) { + } + + @Override + public Geometry3DController getGeometryController() { + return geometryController; + } + + @Override + public Mesh3DController getMeshController() { + return meshController; + } + + @SuppressWarnings("unchecked") + @Override + public T getController(Class klass) { + for (Controller3D c : controllers) { + if (klass.isInstance(c)) { + return (T) c; + } + } + return null; + } + + @Override + public BoundingBox computeBoundingBox(boolean visibleOnly) { + return VTKUtil.computeBoundingBox(controllers, true); + } + + @Override + public boolean showWidget(Widget widget) { + return false; + } + + @Override + public void showWidgetPanel(Widget widget) { + } + + @Override + public void hideWidgetPanel(Widget widget) { + } + + @Override + public void hideWidget(Widget widget) { + } + + @Override + public void resetZoom() { + } + + @Override + public void loadWidgets() { + } + + @Override + public void applyContext(Class klass) { + } + + @Override + public void dumpContext(Class klass) { + } + +} diff --git a/src/eu/engys/vtk/VTKGeometry3DController.java b/src/eu/engys/vtk/VTKGeometry3DController.java new file mode 100644 index 0000000..b9b1a36 --- /dev/null +++ b/src/eu/engys/vtk/VTKGeometry3DController.java @@ -0,0 +1,535 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.Arguments; +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.geometry.Geometry; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.Type; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.geometry.surface.Plane; +import eu.engys.core.project.geometry.surface.Region; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.View3DEvent; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Context; +import eu.engys.gui.view3D.Geometry3DController; +import eu.engys.gui.view3D.Geometry3DEventListener; +import eu.engys.gui.view3D.Picker; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.gui.view3D.Representation; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.checkboxtree.VisibleItem; +import eu.engys.vtk.actors.SurfaceToActor; +import eu.engys.vtk.actors.SurfaceToActor.ActorMode; + +public class VTKGeometry3DController implements Geometry3DController, Picker { + + private static final Logger logger = LoggerFactory.getLogger(VTKGeometry3DController.class); + + protected RenderPanel renderPanel; + private final Model model; + private final ProgressMonitor monitor; + private final ActorsMap actorsMap = new ActorsMap(); + + private boolean isLoading; + + @Inject + public VTKGeometry3DController(Model model, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + + EventManager.registerEventListener(new Geometry3DEventListener(this), View3DEvent.class); + } + + @Override + public void setRenderPanel(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + if (renderPanel.getPickManager() != null) { + renderPanel.getPickManager().registerPickerForActors(this); + } + } + + @Override + public void loadActors() { + if (Arguments.load3Dgeometry) { + isLoading = true; + + Geometry geometry = model.getGeometry(); + + monitor.info("-> Actors"); + _addSurfaces(geometry.getSurfaces()); + _addSurfaces(geometry.getLines().toArray()); + + if (geometry.hasBlock()) { + _addSurfaces(geometry.getBlock()); + } + + isLoading = false; + } + } + + @Override + public void addSurfaces(Surface... surfaces) { + _addSurfaces(surfaces); + updatePlaneActors(); + } + + protected void _addSurfaces(Surface... surfaces) { + BoundingBox bb = computeBoundingBox(new Surface[0]); + SurfaceToActor surfaceToActor = new SurfaceToActor(ActorMode.DEFAULT, bb, monitor); + for (Surface surface : surfaces) { + Actor[] actors = surfaceToActor.toActor(surface); + for (Actor a : actors) { + addActor(a); + } + } + } + + private void addActor(Actor actor) { + Surface surface = (Surface) actor.getVisibleItem(); + logger.debug("[ADD ACTOR] {} ({}) hash: {}", actor.getName(), actor.getVisibility() ? "visible" : "hidden", surface.hashCode()); + actorsMap.put(surface, actor); + if (!isLoading) { + renderPanel.addActor(actor); + } + } + + @Override + public void removeSurfaces(Surface... surfaces) { + _removeSurface(surfaces); + renderPanel.renderLater(); + } + + protected void _removeSurface(Surface... surfaces) { + for (Surface surface : surfaces) { + if (surface.hasRegions()) { + _removeSurface(surface.getRegions()); + continue; + } + logger.info("[REM SURFACE] name: {}, type: {}", surface.getName(), surface.getType()); + removeFromMap(surface); + removeFromContext(surface); + } + // updatePlaneActors(); + } + + private void removeFromMap(Surface surface) { + if (actorsMap.contains(surface)) { + Actor oldActor = actorsMap.remove(surface); + renderPanel.removeActor(oldActor); + } else { + // System.err.println("removeFromMap: " + surface.getName() + " NOT FOUND"); + } + } + + private void removeFromContext(Surface surface) { + for (GeometryContext context : contextMap.values()) { + if (context.getActorsMap() != null) { + if (context.getActorsMap().contains(surface)) { + logger.info("[REM SURFACE FROM CONTEXT] name: {}, context: {}", surface.getName(), context); + context.getActorsMap().remove(surface); + } else { + // System.err.println("removeFromContext: " + surface.getName() + " NOT FOUND"); + } + } + } + } + + boolean containsSurface(Surface... surfaces) { + for (Surface surface : surfaces) { + if (!_containsSurface(surface)) + return false; + } + return true; + } + + private boolean _containsSurface(Surface surface) { + if (surface.getType() == Type.STL) { + Stl stl = (Stl) surface; + for (Region region : stl.getSolids()) { + if (!actorsMap.contains(region)) { + return false; + } + } + return true; + } else { + return actorsMap.contains(surface); + } + } + + @Override + public void changeSurface(Surface... surfaces) { + _removeSurface(surfaces); + _addSurfaces(surfaces); + } + + @Override + public void render() { + renderPanel.renderLater(); + } + + @Override + public void zoomReset() { + renderPanel.resetZoomLater(); + } + + @Override + public void transformSurfaces(AffineTransform t, boolean save, Surface... surfaces) { + _transform(t, save, surfaces); + } + + private void _transform(AffineTransform t, boolean save, Surface[] surfaces) { + for (Surface surface : surfaces) { + if (surface.hasRegions()) { + _transform(t, save, surface.getRegions()); + if (save) { + Region region = surface.getRegions()[0]; + surface.setTransformation(new AffineTransform(region.getTransformation())); + } + continue; + } + if (actorsMap.contains(surface)) { + Actor actor = actorsMap.get(surface); + actor.transformActor(save, t); + if (save) { + surface.setTransformation(AffineTransform.fromVTK(actor.getUserTransform())); + } + } + } + } + + public void updateSurfacesSelection(Surface... surfaces) { + logger.debug("[SELECTION] {} surfaces selected {}", surfaces.length, surfaces.length == 1 ? ", selection is: " + surfaces[0].getName() : ""); + + List selection = new ArrayList(); + + _updateSurfaceSelection(surfaces, selection); + + // if (selection.isEmpty()) { + // logger.debug("updateSurfacesSelection: NONE selected!"); + // } else { + if (!actorsMap.isEmpty()) { + renderPanel.selectActors(false, selection.toArray(new Actor[0])); + } + // } + } + + private void _updateSurfaceSelection(Surface[] surfaces, List selection) { + for (Surface surface : surfaces) { + if (surface.hasRegions()) { + _updateSurfaceSelection(surface.getRegions(), selection); + continue; + } + if (surface.isVisible() && actorsMap.contains(surface)) { + selection.add(actorsMap.get(surface)); + } + } + } + + @Override + public void updateSurfaceVisibility(Surface... surfaces) { + logger.debug("[VISIBILITY] {} selected", surfaces.length == 1 ? surfaces[0] : surfaces.length); + for (Surface surface : surfaces) { + if (surface.hasRegions()) { + _updateSurfaceVisibility(surface.getRegions()); + continue; + } + _updateSurfaceVisibility(surface); + } + render(); + } + + private void _updateSurfaceVisibility(Surface... selection) { + for (Surface surface : selection) { + if (actorsMap.contains(surface)) { + Actor actor = actorsMap.get(surface); + actor.setVisibility(surface.isVisible()); + } + } + } + + @Override + public void updateSurfaceColor(Color color, Surface... selection) { + for (Surface surface : selection) { + if (surface.hasRegions()) { + updateSurfaceColor(color, surface.getRegions()); + continue; + } + _updateSurfaceColor(color, surface); + } + } + + private void _updateSurfaceColor(Color color, Surface surface) { + if (getActorsMap().containsKey(surface)) { + Actor actor = getActorsMap().get(surface); + renderPanel.setActorColor(color, actor); + } + } + + @Override + public void geometryToMesh(GeometryToMesh g2m) { + clear(); + clearContext(); + removeActorsFromRenderer(); + + loadActors(); + + for (Actor actor : getActorsList()) { + actor.setVisibility(false); + } + } + + @Override + public void clear() { + deleteActors(); + } + + private void deleteActors() { + for (Actor actor : actorsMap.values()) { + renderPanel.removeActor(actor); + actor.deleteActor(); + } + actorsMap.clear(); + } + + private void removeActorsFromRenderer() { + for (Actor actor : actorsMap.values()) { + renderPanel.removeActor(actor); + } + actorsMap.clear(); + } + + private void updatePlaneActors() { + Surface[] surfaces = model.getGeometry().getSurfaces(); + if (hasPlanes()) { + BoundingBox bb = VTKUtil.computeBoundingBox(getNonPlaneActorsList()); + for (Surface surface : surfaces) { + if (surface.getType().isPlane()) { + double diagonal = bb.getDiagonal(); + double value = Double.isInfinite(diagonal) ? 1 : diagonal > 0 ? diagonal : 1; + + Plane plane = (Plane) surface; + plane.setDiagonal(2 * value); + changeSurface(plane); + render(); + } + } + } + } + + private List getNonPlaneActorsList() { + List list = new ArrayList<>(); + for (Surface surface : actorsMap.keys()) { + if (!surface.getType().isPlane()) { + list.add(actorsMap.get(surface)); + } + } + return list; + } + + private boolean hasPlanes() { + for (Surface surface : model.getGeometry().getSurfaces()) { + if (surface.getType().isPlane()) + return true; + } + return false; + } + + @Override + public BoundingBox computeBoundingBox(Surface... surfaces) { + Collection actors; + if (surfaces.length == 0) { + actors = getListOfSurfaceActors(model.getGeometry().getSurfaces()); + } else { + actors = getListOfSurfaceActors(surfaces); + } + return VTKUtil.computeBoundingBox(actors); + } + + private Collection getListOfSurfaceActors(Surface[] surfaces) { + Collection list = new ArrayList<>(); + for (Surface surface : surfaces) { + if (surface.getType().isStl()) { + Collection l = getListOfSurfaceActors(((Stl) surface).getSolids()); + list.addAll(l); + continue; + } else if (surface.getType().isPlane()) { + continue; + } + list.add(actorsMap.get(surface)); + } + return list; + } + + @Override + public void showInternalMesh() { + hideAllActorsShowInternalMesh(); + } + + @Override + public void hideInternalMesh() { + showAllActorsHideInternalMesh(); + } + + private void hideAllActorsShowInternalMesh() { + for (Actor actor : getActorsList()) { + actor.setVisibility(false); + } + } + + private void showAllActorsHideInternalMesh() { + for (Actor actor : getActorsList()) { + actor.setVisibility(false); + } + } + + @Override + public void showField(FieldItem fieldItem) { + } + + private Map, GeometryContext> contextMap = new HashMap<>(); + private GeometryContext context; + + @Override + public Context getCurrentContext() { + return context; + } + + @Override + public void applyContext(Class klass) { + removeActorsFromRenderer(); + context = contextMap.get(klass); + if (context != null) { + logger.info("[APPLY CONTEXT] for {} is {}", klass.getSimpleName(), context); + setRepresentationFromContext(context); + addActorsFromContext(context); + } else { + logger.info("[APPLY CONTEXT] for {} is NOT FOUND", klass.getSimpleName()); + } + } + + private void setRepresentationFromContext(GeometryContext context) { + renderPanel.setRepresentation(context.getRepresentation()); + } + + private void addActorsFromContext(GeometryContext context) { + ActorsMap map = context.getActorsMap(); + Map visibility = context.getActorsVisibility(); + + if (map != null) { + for (Surface name : map.keys()) { + Actor actor = map.get(name); + if (visibility.get(name).booleanValue()) { + actor.setVisibility(true); + } else { + actor.setVisibility(false); + } + addActor(actor); + } + } + } + + @Override + public void newContext(Class klass) { + GeometryContext context = new GeometryContext(Representation.SURFACE, getActorsMap()); + contextMap.put(klass, context); + logger.info("[NEW CONTEXT] for {} is {}", klass.getSimpleName(), context); + } + + @Override + public void newEmptyContext(Class klass) { + GeometryContext context = new GeometryContext(Representation.SURFACE, Collections. emptyMap()); + contextMap.put(klass, context); + logger.info("[EMPTY CONTEXT] for {} is {}", klass.getSimpleName(), context); + } + + @Override + public void dumpContext(Class klass) { + if (contextMap.containsKey(klass)) { + contextMap.remove(klass).clear(); + } + GeometryContext context = new GeometryContext(renderPanel.getRepresentation(), actorsMap.getDelegate()); + logger.info("[DUMP CONTEXT] for {} is {}", klass.getSimpleName(), context); + contextMap.put(klass, context); + } + + @Override + public void clearContext() { + logger.info("[CLEAR CONTEXT]"); + for (GeometryContext context : contextMap.values()) { + context.clear(); + } + contextMap.clear(); + } + + @Override + public boolean containsActor(Actor pickedActor) { + return actorsMap.containsActor(pickedActor); + } + + @Override + public Collection getActorsList() { + return actorsMap.values(); + } + + @Override + public Map getActorsMap() { + return actorsMap.getDelegate(); + } + + @Override + public boolean canPickCells(Actor pickedActor) { + VisibleItem surface = pickedActor.getVisibleItem(); + return (surface instanceof Stl || surface instanceof Solid); + } + + @Override + public boolean canPickMesh() { + return false; + } + +} diff --git a/src/eu/engys/vtk/VTKInteractor.java b/src/eu/engys/vtk/VTKInteractor.java new file mode 100644 index 0000000..bac3035 --- /dev/null +++ b/src/eu/engys/vtk/VTKInteractor.java @@ -0,0 +1,101 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import vtk.vtkGenericRenderWindowInteractor; +import vtk.vtkInteractorObserver; +import vtk.vtkInteractorStyle; +import vtk.vtkInteractorStyleRubberBand3D; +import vtk.vtkInteractorStyleRubberBandZoom; +import vtk.vtkInteractorStyleTrackballCamera; +import vtk.vtkRenderWindow; +import eu.engys.gui.view3D.Interactor; + +public class VTKInteractor extends vtkGenericRenderWindowInteractor implements Interactor { + + public VTKInteractor(vtkRenderWindow rw) { + vtkInteractorStyle style = new vtkInteractorStyleTrackballCamera(); + SetRenderWindow(rw); + SetInteractorStyle(style); + +// iren.AddObserver("TimerEvent", this, "TimerEvent"); +// iren.AddObserver("CreateTimerEvent", this, "StartTimer"); +// iren.AddObserver("DestroyTimerEvent", this, "DestroyTimer"); +// +// iren.SetDesiredUpdateRate(HIGHEST_RATE); +// iren.SetStillUpdateRate(LOW_RATE); + + } + + @Override + public void setStyleToDefault() { + System.out.println("VTKInteractor.setStyleToDefault()<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); + SetInteractorStyle(new vtkInteractorStyleTrackballCamera()); + } + + @Override + public void setStyleToArea() { + System.out.println("VTKInteractor.setStyleToArea() >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + SetInteractorStyle(new vtkInteractorStyleRubberBand3D()); + } + + @Override + public void setStyleToZoom() { + SetInteractorStyle(new vtkInteractorStyleRubberBandZoom()); + } + + @Override + public void start() { + Start(); + } + + @Override + public void dispose() { + SetRenderWindow(null); + } + + @Override + public void updateSize(int w, int h) { + SetSize(w, h); + // rw.SetSize(w, h); + ConfigureEvent(); + } + + @Override + public void wheelForwardEvent() { + MouseWheelForwardEvent(); + } + + @Override + public void wheelBackwardEvent() { + MouseWheelBackwardEvent(); + } + + @Override + public void addObserver(vtkInteractorObserver widget) { + widget.SetInteractor(this); + } +} diff --git a/src/eu/engys/vtk/VTKInternalMesh.java b/src/eu/engys/vtk/VTKInternalMesh.java new file mode 100644 index 0000000..cc452f8 --- /dev/null +++ b/src/eu/engys/vtk/VTKInternalMesh.java @@ -0,0 +1,268 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import vtk.vtkCutter; +import vtk.vtkDataObject; +import vtk.vtkExtractGeometry; +import vtk.vtkPlane; +import vtk.vtkTableBasedClipDataSet; +import vtk.vtkUnstructuredGrid; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.vtk.actors.InternalMeshActor; + +public class VTKInternalMesh implements VTKActors { + + private Actor actor; + private RenderPanel renderPanel; + + private vtkCutter slicer; + private vtkExtractGeometry crinkle; + private vtkTableBasedClipDataSet clipper; + + private vtkUnstructuredGrid internalMeshDataset; + + public VTKInternalMesh(ProgressMonitor monitor) { + } + + @Override + public void setRenderPanel(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + } + + public void update(vtkDataObject dataset) { + if (actor != null) { + renderPanel.removeActor(actor); + + load(dataset); + + VisibilityOn(); + + if (slicer != null) { + slicer.SetInputData(internalMeshDataset); + slicer.Update(); + connectActorToSlicer(); + } else if (clipper != null) { + clipper.SetInputData(internalMeshDataset); + clipper.Update(); + connectActorToClipper(); + } else if (crinkle != null) { + crinkle.SetInputData(internalMeshDataset); + crinkle.Update(); + connectActorToCrinkler(); + } + + renderPanel.addActor(actor); + } + } + + public void load(vtkDataObject internalMeshDataset) { + + if (this.internalMeshDataset != null) { + VTKUtil.deleteDataset(this.internalMeshDataset); + } + + if (this.actor != null) { + this.actor.deleteActor(); + } + + this.internalMeshDataset = new vtkUnstructuredGrid(); + this.internalMeshDataset.ShallowCopy((vtkUnstructuredGrid) internalMeshDataset); + this.actor = new InternalMeshActor(this.internalMeshDataset); + } + + public void deleteActors() { + if (actor != null) { + renderPanel.removeActor(actor); + actor.deleteActor(); + actor = null; + + deleteClipper(); + deleteSlicer(); + } + } + + public void removeActorsFromRenderer() { + if (actor != null) { + renderPanel.removeActor(actor); + } + actor = null; + } + + private void deleteSlicer() { + if (slicer != null) { + slicer.RemoveAllInputs(); + slicer.Delete(); + slicer = null; + } + } + + private void deleteClipper() { + if (clipper != null) { + clipper.RemoveAllInputs(); + clipper.Delete(); + clipper = null; + } + } + + private void deleteCrinkle() { + if (crinkle != null) { + crinkle.RemoveAllInputs(); + crinkle.Delete(); + crinkle = null; + } + } + + public void VisibilityOff() { + if (actor != null) { + actor.setVisibility(false); + } + } + + public void VisibilityOn() { + if (actor != null) { + actor.setVisibility(true); + } + } + + public void disconnectFilters() { + actor.setInput(internalMeshDataset); + + deleteClipper(); + deleteSlicer(); + deleteCrinkle(); + } + + public boolean isLoaded() { + return actor != null; + } + + public void show() { + renderPanel.addActor(actor); + } + + @Override + public Collection getActors() { + return actor != null ? Arrays.asList(actor) : Collections. emptyList(); + } + + @Override + public boolean containsActor(Actor pickedActor) { + return false; + } + + public void clip(vtkPlane plane) { + deleteClipper(); + deleteSlicer(); + deleteCrinkle(); + + clipper = new vtkTableBasedClipDataSet(); + clipper.SetInputData(internalMeshDataset); + clipper.SetClipFunction(plane); + clipper.InsideOutOff(); + clipper.Update(); + + connectActorToClipper(); + + renderPanel.renderLater(); + + VTKUtil.gc(false); + } + + private void connectActorToClipper() { + actor.interactiveOff(); + actor.setInput(clipper.GetOutput()); + } + + void crinkle(vtkPlane plane) { + deleteClipper(); + deleteSlicer(); + deleteCrinkle(); + + crinkle = new vtkExtractGeometry(); + crinkle.SetInputData(internalMeshDataset); + crinkle.ExtractInsideOn(); + crinkle.ExtractOnlyBoundaryCellsOn(); + crinkle.ExtractBoundaryCellsOn(); + crinkle.SetImplicitFunction(plane); + crinkle.Update(); + + connectActorToCrinkler(); + + renderPanel.renderLater(); + } + + private void connectActorToCrinkler() { + actor.interactiveOff(); + actor.setInput(crinkle.GetOutput()); + } + + void slice(vtkPlane plane) { + deleteClipper(); + deleteSlicer(); + deleteCrinkle(); + + slicer = new vtkCutter(); + slicer.SetInputData(internalMeshDataset); + slicer.GenerateTrianglesOff(); + slicer.SetCutFunction(plane); + slicer.Update(); + // slicerSetNumberOfContours(nbContours); + + connectActorToSlicer(); + + renderPanel.renderLater(); + } + + private void connectActorToSlicer() { + actor.interactiveOff(); + actor.setInput(slicer.GetOutput()); + } + + void insideOut(boolean selected) { + if (selected) { + clipper.InsideOutOn(); + } else { + clipper.InsideOutOff(); + } + clipper.Update(); + + connectActorToClipper(); + + renderPanel.renderLater(); + } + + public Map getActorsMap() { + return null; + } +} diff --git a/src/eu/engys/vtk/VTKMesh3DController.java b/src/eu/engys/vtk/VTKMesh3DController.java new file mode 100644 index 0000000..a1efa7f --- /dev/null +++ b/src/eu/engys/vtk/VTKMesh3DController.java @@ -0,0 +1,518 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import static eu.engys.core.project.mesh.ScalarBarType.BLUE_TO_RED_RAINBOW; +import static eu.engys.vtk.VTKColors.WHITE; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; + +import javax.inject.Inject; +import javax.swing.JOptionPane; + +import org.apache.commons.collections.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkPlane; +import eu.engys.core.Arguments; +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.core.project.mesh.ScalarBarType; +import eu.engys.core.project.zero.cellzones.CellZone; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.ActorVisibilityEvent; +import eu.engys.gui.events.view3D.View3DEvent; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Context; +import eu.engys.gui.view3D.Mesh3DController; +import eu.engys.gui.view3D.Mesh3DEventListener; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.gui.view3D.Representation; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.vtk.actors.SurfaceToActor; +import eu.engys.vtk.actors.SurfaceToActor.ActorMode; + +public class VTKMesh3DController implements Mesh3DController { + + private static final Logger logger = LoggerFactory.getLogger(Mesh3DController.class); + + private final Model model; + private final ProgressMonitor monitor; + private final VTKPatches patchActors; + private final VTKCellZones cellZonesActors; + private final VTKInternalMesh internalMeshActor; + + private FieldItem currentField = null; + private double currentTimeStep = 0; + private RenderPanel renderPanel; + + @Inject + public VTKMesh3DController(Model model, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + + this.patchActors = new VTKPatches(model); + this.cellZonesActors = new VTKCellZones(model, monitor); + this.internalMeshActor = new VTKInternalMesh(monitor); + + EventManager.registerEventListener(new Mesh3DEventListener(this), View3DEvent.class); + } + + @Override + public void setRenderPanel(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + + patchActors.setRenderPanel(renderPanel); + cellZonesActors.setRenderPanel(renderPanel); + internalMeshActor.setRenderPanel(renderPanel); + + if (renderPanel.getPickManager() != null) { + renderPanel.getPickManager().registerPickerForActors(patchActors); + renderPanel.getPickManager().registerPickerForActors(cellZonesActors); + } + } + + @Override + public void geometryToMesh(GeometryToMesh g2m) { + clear(); + clearContext(); + removeActorsFromRenderer(); + + SurfaceToActor surfaceToActor = new SurfaceToActor(ActorMode.VIRTUALISED, computeBoundingBox(), monitor); + + for (Surface surface : g2m.getWillBePatches()) { + Actor[] actors = surfaceToActor.toActor(surface); + for (Actor a : actors) { + String actorName = g2m.getPatchName(surface); + a.rename(actorName); + patchActors.addActorToPatches(a); + } + } + for (Surface surface : g2m.getWillBeCellZones()) { + Actor[] actors = surfaceToActor.toActor(surface); + if (actors.length == 1) { + String zoneName = g2m.getCellZoneName(surface); + actors[0].rename(zoneName); + cellZonesActors.addActorToZones(actors[0]); + } else { + for (Actor a : actors) { + cellZonesActors.addActorToZones(a); + } + } + } + + VTKColors.indexedColor().to(patchActors).to(cellZonesActors).apply(); + } + + @Override + public void loadActors() { + if (Arguments.load3Dmesh) { + _loadExternalMesh(); + } + } + + @Override + public BoundingBox computeBoundingBox() { + return VTKUtil.computeBoundingBox(patchActors.getActors()); + } + + @Override + public boolean isInternalMeshLoaded() { + return internalMeshActor.isLoaded(); + } + + @Override + public void clear() { + deleteActors(); + this.currentField = null; + this.currentTimeStep = 0; + } + + private void deleteActors() { + patchActors.deleteActors(); + cellZonesActors.deleteActors(); + internalMeshActor.deleteActors(); + } + + private void removeActorsFromRenderer() { + patchActors.removeActorsFromRenderer(); + cellZonesActors.removeActorsFromRenderer(); + internalMeshActor.removeActorsFromRenderer(); + } + + @Override + public void updatePatchesSelection(Patch[] selection) { + patchActors.updateSelection(selection); + } + + @Override + public void updatePatchesVisibility(Patch... selection) { + patchActors.updateVisibility(selection); + } + + @Override + public void updateCellZonesSelection(CellZone[] selection) { + cellZonesActors.selectActors(selection); + } + + @Override + public void updateCellZonesVisibility(CellZone... selection) { + cellZonesActors.updateVisibility(selection); + } + + @Override + @SuppressWarnings("unchecked") + public Collection getActorsList() { + return CollectionUtils.union(patchActors.getActors(), CollectionUtils.union(cellZonesActors.getActors(), internalMeshActor.getActors())); + } + + @Override + public void readTimeSteps() { + VTKOpenFOAMDataset dataset = new VTKOpenFOAMDataset(model, null); + dataset.loadInformations(currentTimeStep); + dataset.clear(); + } + + @Override + public void showField(FieldItem fieldItem) { + this.currentField = fieldItem; + if (FieldItem.SOLID.equals(fieldItem.getName())) { + setColorsToSolid(); + } else if (FieldItem.INDEXED.equals(fieldItem.getName())) { + setColorsToIndexed(); + } else { + setColorsToScalar(); + } + } + + private void setColorsToSolid() { + VTKColors.solidColor(WHITE).to(patchActors).to(cellZonesActors).to(internalMeshActor).apply(); + renderPanel.renderLater(); + } + + private void setColorsToIndexed() { + VTKColors.indexedColor().to(patchActors).to(cellZonesActors).apply(); + VTKColors.solidColor(WHITE).to(internalMeshActor).apply(); + renderPanel.renderLater(); + } + + private void setColorsToScalar() { + VTKColors.scalarsColor(currentField).to(patchActors).to(cellZonesActors).to(internalMeshActor).apply(); + renderPanel.renderLater(); + } + + @Override + public void showTimeStep(final double currentTimeStep) { + this.currentTimeStep = currentTimeStep; + monitor.start("Loading values for timestep " + currentTimeStep, false, new Runnable() { + @Override + public void run() { + final VTKOpenFOAMDataset dataset = new VTKOpenFOAMDataset(model, monitor); + dataset.loadTimeStep(currentTimeStep); + + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + patchActors.update(dataset.getPatchesDataset()); + cellZonesActors.update(dataset.getCellZonesDataset()); + internalMeshActor.update(dataset.getInternalMeshDataset()); + dataset.clear(); + } + }); + monitor.end(); + } + }); + + if (currentField != null && currentField.isScalar()) { + setColorsToScalar(); + } + } + + @Override + public FieldItem getCurrentFieldItem() { + return currentField; + } + + @Override + public double getCurrentTimeStep() { + return currentTimeStep; + } + + // RESOLUTION + @Override + public void setScalarsActorsResolution(int resolution) { + currentField.setResolution(resolution); + setColorsToScalar(); + } + + // SCALARBAR TYPE + @Override + public void setScalarsBarType(ScalarBarType scalarBarType) { + currentField.setScalarBarType(scalarBarType); + setColorsToScalar(); + } + + // RANGE + @Override + public void setAutomaticRangeCalculation(boolean autoRange) { + currentField.setAutomaticRange(autoRange); + setColorsToScalar(); + } + + @Override + public void setManualRangeCalculation(double[] range) { + currentField.setRange(range); + setColorsToScalar(); + } + + // RESET + @Override + public void resetScalarsActorsRangeAndResolutionAndHue() { + currentField.setAutomaticRange(true); + currentField.setResolution(FieldItem.DEFAULT_RESOLUTION); + currentField.setScalarBarType(BLUE_TO_RED_RAINBOW); + + setColorsToScalar(); + } + + @Override + public void showExternalMesh() { + loadExternalMesh(); + if (patchActors.isLoaded()) { + showAllActors(); + } + } + + private void loadExternalMesh() { + monitor.start("Loading mesh", false, new Runnable() { + @Override + public void run() { + _loadExternalMesh(); + monitor.end(); + } + }); + } + + private void _loadExternalMesh() { + if (!patchActors.isLoaded()) { + VTKOpenFOAMDataset dataset = new VTKOpenFOAMDataset(model, monitor); + dataset.loadExternalMesh(0); + + monitor.info("-> Patches"); + patchActors.load(dataset.getPatchesDataset()); + + monitor.info("-> Cell Zones"); + cellZonesActors.load(dataset.getCellZonesDataset()); + + VTKColors.indexedColor().to(patchActors).to(cellZonesActors).apply(); + + dataset.clear(); + } + } + + @Override + public void showInternalMesh() { + if (model.getPatches().isEmpty()) { + JOptionPane.showMessageDialog(UiUtil.getActiveWindow(), "No mesh", "Warning", JOptionPane.WARNING_MESSAGE); + return; + } + loadInternalMesh(); + if (internalMeshActor.isLoaded()) { + hideAllActorsShowInternalMesh(); + internalMeshActor.show(); + if (currentField != null) { + showField(currentField); + } else { + VTKColors.solidColor(WHITE).to(internalMeshActor).apply(); + } + } + } + + private void loadInternalMesh() { + if (!internalMeshActor.isLoaded()) { + monitor.start("Loading internal mesh", false, new Runnable() { + @Override + public void run() { + VTKOpenFOAMDataset dataset = new VTKOpenFOAMDataset(model, monitor); + dataset.loadInternalMesh(currentTimeStep); + + monitor.info("-> Internal Mesh Actor"); + internalMeshActor.load(dataset.getInternalMeshDataset()); + + dataset.clear(); + monitor.end(); + } + }); + } + } + + private void hideAllActorsShowInternalMesh() { + cellZonesActors.VisibilityOff(); + patchActors.VisibilityOff(); + internalMeshActor.VisibilityOn(); + + EventManager.triggerEvent(this, new ActorVisibilityEvent(false)); + } + + @Override + public void hideInternalMesh() { + if (internalMeshActor.isLoaded()) { + internalMeshActor.disconnectFilters(); + showAllActorsHideInternalMesh(); + } + } + + private void showAllActorsHideInternalMesh() { + cellZonesActors.VisibilityOff(); + patchActors.VisibilityOn(); + internalMeshActor.VisibilityOff(); + + EventManager.triggerEvent(this, new ActorVisibilityEvent(true)); + } + + @Override + public void clip(vtkPlane plane) { + if (internalMeshActor.isLoaded()) { + internalMeshActor.clip(plane); + } + } + + @Override + public void crinkle(vtkPlane plane) { + if (internalMeshActor.isLoaded()) { + internalMeshActor.crinkle(plane); + } + } + + @Override + public void slice(vtkPlane plane) { + if (internalMeshActor.isLoaded()) { + internalMeshActor.slice(plane); + } + } + + @Override + public void insideOut(boolean selected) { + if (internalMeshActor.isLoaded()) { + internalMeshActor.insideOut(selected); + } + } + + @Override + public void disconnectFiltersFromInternalMesh() { + if (internalMeshActor.isLoaded()) { + internalMeshActor.disconnectFilters(); + render(); + } + } + + @Override + public void render() { + renderPanel.renderLater(); + } + + @Override + public void zoomReset() { + renderPanel.resetZoomLater(); + } + + /* + * CONTEXT + */ + private HashMap, MeshContext> contextMap = new HashMap<>(); + private MeshContext context; + + private boolean allowSelection; + + @Override + public Context getCurrentContext() { + return context; + } + + @Override + public void applyContext(Class klass) { + context = contextMap.get(klass); + removeActorsFromRenderer(); + if (context != null) { + logger.info("[APPLY CONTEXT] for {} is {}", klass.getSimpleName(), context); + renderPanel.setRepresentation(context.getRepresentation()); + this.allowSelection = context.isAllowSelection(); + cellZonesActors.addCellZonesMap(context.getCellzones(), context.getZonesVisibility()); + patchActors.addPatchMap(context.getPatches(), context.getPatchesVisibility()); + } else { + logger.info("[APPLY CONTEXT] for {} is NOT FOUND", klass.getSimpleName()); + } + } + + @Override + public void newContext(Class klass) { + MeshContext context = new MeshContext(Representation.SURFACE, true, cellZonesActors.getActorsMap(), patchActors.getActorsMap()); + contextMap.put(klass, context); + logger.info("[NEW CONTEXT] for {} is {}", klass.getSimpleName(), context); + } + + @Override + public void newEmptyContext(Class klass) { + MeshContext context = new MeshContext(Representation.SURFACE, true, Collections. emptyMap(), Collections. emptyMap()); + contextMap.put(klass, context); + logger.info("[EMPTY CONTEXT] for {} is {}", klass.getSimpleName(), context); + } + + @Override + public void dumpContext(Class klass) { + if (contextMap.containsKey(klass)) { + contextMap.remove(klass).clear(); + } + MeshContext context = new MeshContext(renderPanel.getRepresentation(), allowSelection, cellZonesActors.getActorsMap(), patchActors.getActorsMap()); + contextMap.put(klass, context); + logger.info("[DUMP CONTEXT] for {} is {}", klass.getSimpleName(), context); + } + + @Override + public void clearContext() { + logger.info("[CLEAR CONTEXT]"); + for (MeshContext context : contextMap.values()) { + context.clear(); + } + contextMap.clear(); + } + + public void showAllActors() { + patchActors.addActorsToRenderer(); + cellZonesActors.addActorsToRenderer(); + } + +} diff --git a/src/eu/engys/vtk/VTKMouseHandler.java b/src/eu/engys/vtk/VTKMouseHandler.java new file mode 100644 index 0000000..20ea04e --- /dev/null +++ b/src/eu/engys/vtk/VTKMouseHandler.java @@ -0,0 +1,245 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +import javax.swing.SwingUtilities; + +import vtk.vtkGenericRenderWindowInteractor; +import vtk.vtkInteractorObserver; +import vtk.vtkInteractorStyleRubberBand3D; +import vtk.vtkInteractorStyleRubberBandZoom; +import vtk.vtkInteractorStyleTrackballCamera; + +public class VTKMouseHandler implements MouseListener, MouseMotionListener, MouseWheelListener, KeyListener { + + private boolean isDragging = false; + private VTKRenderPanel vtkRenderPanel; + + public VTKMouseHandler(VTKRenderPanel vtkRenderPanel) { + this.vtkRenderPanel = vtkRenderPanel; + } + + private int ctrlPressed(InputEvent e) { + return (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0; + } + + private int shiftPressed(InputEvent e) { + return (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0; + } + + @Override + public void mouseClicked(MouseEvent e) { +// System.out.println("MOUSE CLICKED"); + VTKPickManager pickManager = vtkRenderPanel.getPickManager(); + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) vtkRenderPanel.getInteractor(); + + if (SwingUtilities.isLeftMouseButton(e)) { + if (!isDragging) { + int[] pos = iren.GetEventPosition(); + + if (iren.GetInteractorStyle() instanceof vtkInteractorStyleTrackballCamera) { + pickManager.pick(pos[0], pos[1], e.isControlDown(), e.isShiftDown()); + } + } else if(iren.GetInteractorStyle() instanceof vtkInteractorStyleRubberBand3D) { + vtkInteractorStyleRubberBand3D style = (vtkInteractorStyleRubberBand3D) iren.GetInteractorStyle(); + int[] startPosition = style.GetStartPosition(); + int[] endPosition = style.GetEndPosition(); + pickManager.pickArea(startPosition, endPosition, e.isControlDown(), e.isShiftDown()); + } else if(iren.GetInteractorStyle() instanceof vtkInteractorStyleRubberBandZoom) { + iren.SetInteractorStyle(new vtkInteractorStyleTrackballCamera()); + } + } else if (SwingUtilities.isRightMouseButton(e)) { + if (!isDragging) { + int[] pos = iren.GetEventPosition(); + + if (iren.GetInteractorStyle() instanceof vtkInteractorStyleTrackballCamera) { + pickManager.popup(pos[0], pos[1], e); + } + } + } + } + + @Override + public void mousePressed(MouseEvent e) { +// System.out.println("MOUSE_PRESSED"); + vtkRenderPanel.lock(); + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) vtkRenderPanel.getInteractor(); + vtkInteractorObserver style = iren.GetInteractorStyle(); + + if (SwingUtilities.isLeftMouseButton(e)) { + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + iren.LeftButtonPressEvent(); + } else if (SwingUtilities.isMiddleMouseButton(e)) { + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + iren.MiddleButtonPressEvent(); + } else if (SwingUtilities.isRightMouseButton(e)) { + if (style instanceof vtkInteractorStyleRubberBand3D) { + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + } else if (style instanceof vtkInteractorStyleTrackballCamera) { + iren.SetEventInformation(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + } + iren.RightButtonPressEvent(); + } + + vtkRenderPanel.unlock(); + + isDragging = false; + } + + @Override + public void mouseReleased(MouseEvent e) { +// System.out.println("MOUSE RELEASED"); + VTKPickManager pickManager = vtkRenderPanel.getPickManager(); + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) vtkRenderPanel.getInteractor(); + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + + vtkRenderPanel.lock(); + + if (SwingUtilities.isLeftMouseButton(e)) { + iren.LeftButtonReleaseEvent(); + if(iren.GetInteractorStyle() instanceof vtkInteractorStyleRubberBandZoom) { + iren.SetInteractorStyle(new vtkInteractorStyleTrackballCamera()); + } else if(iren.GetInteractorStyle() instanceof vtkInteractorStyleRubberBand3D) { + vtkInteractorStyleRubberBand3D style = (vtkInteractorStyleRubberBand3D) iren.GetInteractorStyle(); + int[] startPosition = style.GetStartPosition(); + int[] endPosition = style.GetEndPosition(); + pickManager.pickArea(startPosition, endPosition, e.isControlDown(), e.isShiftDown()); + } + } else if (SwingUtilities.isMiddleMouseButton(e)) { + iren.MiddleButtonReleaseEvent(); + } else if (SwingUtilities.isRightMouseButton(e)) { + iren.RightButtonReleaseEvent(); + } + + vtkRenderPanel.unlock(); + + if (isDragging) { + vtkRenderPanel.setHighRendering(); + } + + isDragging = false; + } + + @Override + public void mouseEntered(MouseEvent e) { +// System.out.println("MOUSE_ENTERED"); + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) vtkRenderPanel.getInteractor(); + iren.SetEventInformationFlipY(e.getX(), e.getY(), 0, 0, '0', 0, "0"); + + vtkRenderPanel.lock(); + iren.EnterEvent(); + vtkRenderPanel.unlock(); + } + + @Override + public void mouseExited(MouseEvent e) { +// System.out.println("MOUSE_EXITED"); + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) vtkRenderPanel.getInteractor(); + iren.SetEventInformationFlipY(e.getX(), e.getY(), 0, 0, '0', 0, "0"); + + vtkRenderPanel.lock(); + iren.LeaveEvent(); + vtkRenderPanel.unlock(); + } + + @Override + public void mouseMoved(MouseEvent e) { + //System.out.println("MOUSE_MOVED"); + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) vtkRenderPanel.getInteractor(); + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + + vtkRenderPanel.lock(); + iren.MouseMoveEvent(); + vtkRenderPanel.unlock(); + isDragging = false; + } + + @Override + public void mouseDragged(MouseEvent e) { + //System.out.println("MOUSE_DRAGGED"); + vtkRenderPanel.setLowRendering(); + + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) vtkRenderPanel.getInteractor(); + vtkInteractorObserver style = iren.GetInteractorStyle(); + + if (style instanceof vtkInteractorStyleRubberBand3D) { + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + } else if (style instanceof vtkInteractorStyleRubberBandZoom) { + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + } else if (style instanceof vtkInteractorStyleTrackballCamera) { + if (SwingUtilities.isRightMouseButton(e)) { + iren.SetEventInformation(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + } else { + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + } + } + + vtkRenderPanel.lock(); + iren.MouseMoveEvent(); + vtkRenderPanel.unlock(); + + isDragging = true; + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + // System.out.println("MOUSE_WHEEL_MOVED"); + vtkRenderPanel.setLowRendering(); + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) vtkRenderPanel.getInteractor(); + iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed(e), shiftPressed(e), '0', 0, "0"); + + vtkRenderPanel.lock(); + if (e.getWheelRotation() < 0) + iren.MouseWheelForwardEvent(); + else + iren.MouseWheelBackwardEvent(); + vtkRenderPanel.unlock(); + vtkRenderPanel.setHighRendering(); + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { + } + +} diff --git a/src/eu/engys/vtk/VTKOpenFOAMDataset.java b/src/eu/engys/vtk/VTKOpenFOAMDataset.java new file mode 100644 index 0000000..6e8f6c9 --- /dev/null +++ b/src/eu/engys/vtk/VTKOpenFOAMDataset.java @@ -0,0 +1,436 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import static eu.engys.core.project.zero.fields.Fields.U; +import static eu.engys.vtk.VTKUtil.logBlockNames; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkCompositeDataPipeline; +import vtk.vtkCompositeDataSet; +import vtk.vtkDataObject; +import vtk.vtkExecutive; +import vtk.vtkInformation; +import vtk.vtkInformationDoubleVectorKey; +import vtk.vtkMultiBlockDataSet; +import vtk.vtkPolyData; +import vtk.vtkUnstructuredGrid; +import eu.engys.core.project.Model; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.core.project.mesh.FieldItem.DataType; +import eu.engys.core.project.mesh.Mesh; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.vtk.info.VTKDataInformation; + +public class VTKOpenFOAMDataset { + + private static final Logger logger = LoggerFactory.getLogger(VTKOpenFOAMDataset.class); + + private static final String DEFAULT_REGION = "defaultRegion"; + private static final String INTERNAL_MESH = "internalMesh"; + private static final String ZONES = "Zones"; + private static final String FACE_ZONES = "faceZones"; + private static final String CELL_ZONES = "cellZones"; + private static final String PATCHES = "Patches"; + + private Model model; + private ProgressMonitor monitor; + + private vtkUnstructuredGrid internalMeshDataset = null; + private List patchesDataset = new ArrayList<>(); + private List cellZonesDataset = new ArrayList<>(); + + public VTKOpenFOAMDataset(Model model, ProgressMonitor monitor) { + this.model = model; + this.monitor = monitor; + } + + public void loadInformations(double timeStep) { + logger.info("Load mesh informations for timestep {}", timeStep); + VTKOpenFOAMReader reader = new VTKOpenFOAMReader(model, monitor, "Informations of"); + reader.UpdateInformation(); + reader.ReadInternalMeshOff(); + reader.ReadPatchesOff(); + reader.ReadZonesOff(); + reader.setTimeStep(timeStep); + reader.Update(); + + extractInformations(reader, timeStep); + + reader.Delete(); + } + + public List getCellZonesDataset() { + return cellZonesDataset; + } + + public List getPatchesDataset() { + return patchesDataset; + } + + public vtkUnstructuredGrid getInternalMeshDataset() { + return internalMeshDataset; + } + + public void loadInternalMesh(double timeStep) { + VTKOpenFOAMReader reader = new VTKOpenFOAMReader(model, monitor, "Internal"); + reader.UpdateInformation(); + reader.ReadInternalMeshOn(); + reader.ReadPatchesOff(); + reader.ReadZonesOff(); + reader.setTimeStep(timeStep); + reader.Update(); + + vtkMultiBlockDataSet dataset = reader.GetOutput(); + try { + + if (isSingleRegion(dataset)) { + readSingleRegionInternalMesh(dataset); + } else { + readMultiRegionInternalMesh(dataset); + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } finally { + dataset.Delete(); + reader.Delete(); + } + } + + private void readSingleRegionInternalMesh(vtkMultiBlockDataSet dataset) { + int numberOfBlocks = dataset.GetNumberOfBlocks(); + if (numberOfBlocks > 0) { + logger.debug("READ [SINGLE] [INTERNAL] blocks are: {}", VTKUtil.logBlockNames(dataset)); + + vtkDataObject internalMesh = getBlock(INTERNAL_MESH, dataset); + if (internalMesh != null) { + extractInternalDataset(internalMesh); + } else { + logger.warn("READ [SINGLE] [INTERNAL]: {} NOT FOUND", INTERNAL_MESH); + } + } else { + logger.warn("READ [SINGLE] [INTERNAL]: EMPTY!"); + } + } + + private void readMultiRegionInternalMesh(vtkMultiBlockDataSet dataset) { + int numberOfBlocks = dataset.GetNumberOfBlocks(); + if (numberOfBlocks > 0) { + logger.debug("READ [MULTI] [INTERNAL] blocks are: {}", VTKUtil.logBlockNames(dataset)); + + vtkDataObject defaultRegion = getBlock(DEFAULT_REGION, dataset); + if (defaultRegion != null) { + readSingleRegionInternalMesh((vtkMultiBlockDataSet) defaultRegion); + } else { + logger.warn("READ [MULTI] [INTERNAL]: {} NOT FOUND", DEFAULT_REGION); + } + } else { + logger.warn("READ [MULTI] [INTERNAL]: EMPTY"); + } + } + + public void loadExternalMesh(double timeStep) { + VTKOpenFOAMReader reader = new VTKOpenFOAMReader(model, monitor, "External"); + reader.ReadInternalMeshOff(); + reader.ReadPatchesOn(); + reader.ReadZonesOn(); + reader.setTimeStep(timeStep); + reader.Update(); + + vtkMultiBlockDataSet dataset = reader.GetOutput(); + + try { + if (isSingleRegion(dataset)) { + readSingleRegion(dataset); + } else { + readMultiRegion(dataset); + } + + extractInformations(reader, timeStep); + + } catch (Exception e) { + logger.error(e.getMessage(), e); + } finally { + dataset.Delete(); + reader.Delete(); + } + } + + private boolean isSingleRegion(vtkMultiBlockDataSet dataset) { + int numberOfBlocks = dataset.GetNumberOfBlocks(); + if (numberOfBlocks > 0) { + String blockName = dataset.GetMetaData(0).Get(new vtkCompositeDataSet().NAME()); + return blockName.equals(PATCHES) || blockName.equals(ZONES) || blockName.equals(INTERNAL_MESH) ; + } + return false; + } + + private void readSingleRegion(vtkMultiBlockDataSet dataset) { + int numberOfBlocks = dataset.GetNumberOfBlocks(); + if (numberOfBlocks > 0) { + logger.debug("READ [SINGLE] [EXTERNAL] blocks are: {}", logBlockNames(dataset)); + + vtkDataObject patches = getBlock(PATCHES, dataset); + if (patches != null) { + extractPatchesDataset(patches); + } else { + logger.warn("READ [SINGLE] [PATCHES]: {} NOT FOUND", PATCHES); + } + + vtkDataObject zones = getBlock(ZONES, dataset); + if (zones != null) { + extractZonesDataset(zones); + } else { + logger.warn("READ [SINGLE] [ZONES]: {} NOT FOUND", ZONES); + } + } + } + + private void readMultiRegion(vtkMultiBlockDataSet dataset) { + int numberOfBlocks = dataset.GetNumberOfBlocks(); + if (numberOfBlocks > 0) { + logger.debug("READ [MULTI] [EXTERNAL] blocks are: {}", logBlockNames(dataset)); + + vtkDataObject defaultRegion = getBlock(DEFAULT_REGION, dataset); + if (defaultRegion != null) { + readSingleRegion((vtkMultiBlockDataSet) defaultRegion); + } else { + logger.warn("READ [MULTI] [EXTERNAL]: {} NOT LOADED", DEFAULT_REGION); + } + } else { + logger.warn("READ [MULTI] [EXTERNAL]: EMPTY!"); + } + } + + private vtkDataObject getBlock(String blockName, vtkMultiBlockDataSet dataset) { + int numberOfBlocks = dataset.GetNumberOfBlocks(); + for (int i = 0; i < numberOfBlocks; i++) { + String name = dataset.GetMetaData(i).Get(new vtkCompositeDataSet().NAME()); + if (blockName.equals(name)) { + return dataset.GetBlock(i); + } + } + return null; + } + + private void extractPatchesDataset(vtkDataObject block) { + if (block != null && block instanceof vtkMultiBlockDataSet) { + vtkMultiBlockDataSet dataset = (vtkMultiBlockDataSet) block; + int subblockNumbers = dataset.GetNumberOfBlocks(); + for (int i = 0; i < subblockNumbers; i++) { + vtkDataObject subBlock = dataset.GetBlock(i); + if (subBlock instanceof vtkPolyData) { + this.patchesDataset.add(shallowCopy((vtkPolyData) subBlock)); + } + } + } + } + + public static vtkDataObject shallowCopy(vtkPolyData data) { + vtkPolyData copy = new vtkPolyData(); + copy.ShallowCopy(data); + return copy; + } + + public static vtkUnstructuredGrid shallowCopy(vtkUnstructuredGrid data) { + vtkUnstructuredGrid copy = new vtkUnstructuredGrid(); + copy.ShallowCopy(data); + return copy; + } + + private void extractZonesDataset(vtkDataObject block) { + if (block != null && block instanceof vtkMultiBlockDataSet) { + + vtkMultiBlockDataSet zones = (vtkMultiBlockDataSet) block; + + + vtkDataObject faceZones = getBlock(FACE_ZONES, zones); + if (faceZones != null) { +// extractFaceZonesDataset(zones); + } else { + logger.warn("READ [SINGLE] [FACE ZONES]: {} NOT FOUND", FACE_ZONES); + } + + vtkDataObject cellZones = getBlock(CELL_ZONES, zones); + if (cellZones != null) { + extractCellZonesDataset(cellZones); + } else { + logger.warn("READ [SINGLE] [ZONES]: {} NOT FOUND", ZONES); + } + + + + zones.Delete(); + } + } + + private void extractCellZonesDataset(vtkDataObject block) { + if (block != null && block instanceof vtkMultiBlockDataSet) { + vtkMultiBlockDataSet cellZones = (vtkMultiBlockDataSet) block; + int cellZonesNumber = cellZones.GetNumberOfBlocks(); + for (int i = 0; i < cellZonesNumber; i++) { + vtkDataObject cellZone = cellZones.GetBlock(i); + if (cellZone instanceof vtkUnstructuredGrid) { + logger.warn("Load as a Cell Zone"); + cellZonesDataset.add(shallowCopy((vtkUnstructuredGrid) cellZone)); + } + } + } + } + + private void extractInternalDataset(vtkDataObject block) { + this.internalMeshDataset = shallowCopy((vtkUnstructuredGrid) block); + } + + public void loadTimeStep(double timeStep) { + VTKOpenFOAMReader reader = new VTKOpenFOAMReader(model, monitor, "Time steps of"); + reader.UpdateInformation(); + reader.ReadInternalMeshOn(); + reader.ReadPatchesOn(); + reader.ReadZonesOn(); + reader.setTimeStep(timeStep); + reader.Update(); + + vtkMultiBlockDataSet dataset = reader.GetOutput(); + try { + if (isSingleRegion(dataset)) { + readSingleRegionInternalMesh(dataset); + readSingleRegion(dataset); + } else { + readMultiRegionInternalMesh(dataset); + readMultiRegion(dataset); + } + + extractInformations(reader, timeStep); + + } catch (Exception e) { + logger.error(e.getMessage(), e); + } finally { + dataset.Delete(); + reader.Delete(); + } + } + + private void extractInformations(VTKOpenFOAMReader reader, double timeStep) { + VTKDataInformation info = new VTKDataInformation(); + info.AddFromMultiBlockDataSet(reader.GetOutput()); + + Mesh mesh = model.getMesh(); + mesh.readStatistics(model); + mesh.setBounds(info.getBounds()); + mesh.setMemorySize(info.getMemorySize()); + + mesh.setTimeSteps(getTimeSteps(reader)); + + readFieldItems(reader, mesh); + + mesh.getTimeStepPointFieldsMap().put(Double.valueOf(timeStep), reader.getPointArrayNames()); + mesh.getTimeStepCellFieldsMap().put(Double.valueOf(timeStep), reader.getCellArrayNames()); + + logger.info("Timesteps = {}", mesh.getTimeSteps()); + logger.info("CellFieldsItems = {}", mesh.getCellFieldMap().keySet()); + logger.info("PointFieldsItems = {}", mesh.getPointFieldMap().keySet()); + + mesh.setRegions(getRegions(reader)); + } + + private List getRegions(VTKOpenFOAMReader reader) { + return null; + } + + private void readFieldItems(VTKOpenFOAMReader reader, Mesh mesh) { + for (String newField : reader.getCellArrayNames()) { + Map cellFieldMap = mesh.getCellFieldMap(); + if (newField.startsWith(U)) { + for (int i = 0; i < FieldItem.COMPONENTS.length; i++) { + FieldItem fieldItem = new FieldItem(newField, DataType.CELL, i); + if (!cellFieldMap.containsKey(newField + "_" + i)) { + cellFieldMap.put(newField + "_" + i, fieldItem); + } + } + } else { + FieldItem fieldItem = new FieldItem(newField, DataType.CELL, -1); + if (!cellFieldMap.containsKey(newField)) { + cellFieldMap.put(newField, fieldItem); + } + } + } + for (String newField : reader.getPointArrayNames()) { + Map pointFieldMap = mesh.getPointFieldMap(); + if (newField.startsWith(U)) { + for (int i = 0; i < FieldItem.COMPONENTS.length; i++) { + FieldItem fieldItem = new FieldItem(newField, DataType.POINT, i); + if (!pointFieldMap.containsKey(newField + "_" + i)) { + pointFieldMap.put(newField + "_" + i, fieldItem); + } + } + } else { + FieldItem fieldItem = new FieldItem(newField, DataType.POINT, -1); + if (!pointFieldMap.containsKey(newField)) { + pointFieldMap.put(newField, fieldItem); + } + } + } + } + + private List getTimeSteps(VTKOpenFOAMReader reader) { + vtkExecutive exe = reader.GetExecutive(); + vtkCompositeDataPipeline pipeline = (vtkCompositeDataPipeline) exe; + vtkInformation outInfo = exe.GetOutputInformation(0); + + vtkInformationDoubleVectorKey timeStepsKey = pipeline.TIME_STEPS(); + int nTimeSteps = outInfo.Length(timeStepsKey); // Get the number of time + // steps + List timesteps = new ArrayList<>(); + for (int i = 0; i < nTimeSteps; i++) { + double timeValue = outInfo.Get(timeStepsKey, i); + timesteps.add(Double.valueOf(timeValue)); + } + return timesteps; + } + + public void clear() { + for (vtkDataObject obj : patchesDataset) { + obj.Delete(); + } + for (vtkDataObject obj : cellZonesDataset) { + obj.Delete(); + } + if (internalMeshDataset != null) { + internalMeshDataset.Delete(); + internalMeshDataset = null; + } + patchesDataset.clear(); + cellZonesDataset.clear(); + } +} diff --git a/src/eu/engys/vtk/VTKOpenFOAMReader.java b/src/eu/engys/vtk/VTKOpenFOAMReader.java new file mode 100644 index 0000000..3f76902 --- /dev/null +++ b/src/eu/engys/vtk/VTKOpenFOAMReader.java @@ -0,0 +1,256 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.apache.log4j.Level; + +import vtk.vtkCompositeDataPipeline; +import vtk.vtkDataObject; +import vtk.vtkDataSet; +import vtk.vtkExecutive; +import vtk.vtkMultiBlockDataSet; +import vtk.vtkPOpenFOAMReader; +import eu.engys.core.LoggerUtil; +import eu.engys.core.project.Model; +import eu.engys.core.project.openFOAMProject; +import eu.engys.core.project.zero.fields.Fields; +import eu.engys.core.project.zero.patches.Patches; +import eu.engys.util.VTKSettings; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.progress.SilentMonitor; +import eu.engys.util.progress.VTKProgressMonitorWrapper; + +public class VTKOpenFOAMReader { + + public static void main(String[] args) { + LoggerUtil.initTestLogger(Level.DEBUG); + VTKSettings.LoadAllNativeLibraries(); + Model model = new Model(); + model.init(); +// model.setProject(openFOAMProject.newParallelProject(new File("/home/stefano/ENGYS/examples/HELYX3/singleChannelPump_static_run"))); + model.setProject(openFOAMProject.newParallelProject(new File("/home/stefano/ENGYS/examples/HELYX3/ECOMARINE/testKCS_01_parallel_01"))); + + VTKOpenFOAMReader reader = new VTKOpenFOAMReader(model, new SilentMonitor(), ""); + reader.ReadInternalMeshOff(); + reader.ReadPatchesOff(); + reader.ReadZonesOff(); + reader.setTimeStep(0.0); +// reader.UpdateInformation(); + reader.Update(); +// reader.UpdateExtent(); + + } + + public static boolean decomposePolyhedra; + + private vtkPOpenFOAMReader reader; + private Model model; + + public VTKOpenFOAMReader(Model model, ProgressMonitor monitor, String meshType) { + this.model = model; + + File baseDir = model.getProject().getBaseDir(); + File foamFile = new File(baseDir, " "); + + boolean parallel = model.getProject().isParallel(); + + reader = new vtkPOpenFOAMReader(); + if (parallel) { + reader.SetCaseType(0); + } else { + reader.SetCaseType(1); + } + reader.SetFileName(foamFile.getAbsolutePath()); + reader.CreateCellToPointOn(); + + reader.DisableAllCellArrays(); + reader.DisableAllLagrangianArrays(); + reader.DisableAllPointArrays(); + reader.DisableAllPatchArrays(); + + reader.CacheMeshOff(); + + reader.DecomposePolyhedraOn(); // se qui si mette OFF viene giu' tutto + + reader.ReleaseDataFlagOn(); + + if (monitor != null) { + VTKProgressMonitorWrapper progressWrapper = new VTKProgressMonitorWrapper("", reader, monitor); + reader.AddObserver("StartEvent", progressWrapper, "onStart"); + reader.AddObserver("EndEvent", progressWrapper, "onEnd"); + reader.AddObserver("ProgressEvent", progressWrapper, "onProgress"); + + monitor.setIndeterminate(false); + monitor.setTotal(100); + monitor.info("-> " + meshType + " Mesh"); + } + } + + public void ReadInternalMeshOff() { + reader.SetPatchArrayStatus("internalMesh", 0); + if (decomposePolyhedra) { + reader.DecomposePolyhedraOn(); + } else { + reader.DecomposePolyhedraOff(); + } + } + + public void ReadInternalMeshOn() { + reader.SetPatchArrayStatus("internalMesh", 1); + if (decomposePolyhedra) { + reader.DecomposePolyhedraOn(); + } else { + reader.DecomposePolyhedraOff(); + } + } + + public void ReadPatchesOff() { + Patches patches = model.getPatches().patchesToDisplay(); + for (String patch : patches.toMap().keySet()) { + reader.SetPatchArrayStatus(patch, 0); + } + } + + public void ReadPatchesOn() { + Patches patches = model.getPatches().patchesToDisplay(); + for (String patch : patches.toMap().keySet()) { + reader.SetPatchArrayStatus(patch, 1); + } + } + + public void ReadZonesOn() { + reader.ReadZonesOn(); + } + + public void ReadZonesOff() { + reader.ReadZonesOff(); + } + + public void setTimeStep(double timeValue) { + vtkExecutive exe = reader.GetExecutive(); + vtkCompositeDataPipeline pipeline = (vtkCompositeDataPipeline) exe; + pipeline.SetUpdateTimeStep(0, timeValue); + } + + public void Delete() { + reader.Delete(); + reader = null; + } + + public void Update() { + reader.Update(); + VTKUtil.printDatasetData(reader); + } + + public void UpdateExtent() { + reader.UpdateWholeExtent(); + } + + public void UpdateInformation() { + reader.UpdateInformation(); + } + + public vtkExecutive GetExecutive() { + return reader.GetExecutive(); + } + + public vtkMultiBlockDataSet GetOutput() { + return reader.GetOutput(); + } + + public List getCellArrayNames() { + vtkDataSet dataSet = getAValidDataSet(reader.GetOutput()); + if (dataSet != null) { + return reorderNames(VTKUtil.getCellFields(dataSet)); + } else if (reader.GetNumberOfCellArrays() > 0) { + List list = new ArrayList<>(); + int cellArraysNumber = reader.GetNumberOfCellArrays(); + for (int i = 0; i < cellArraysNumber; i++) { + list.add(reader.GetCellArrayName(i)); + } + return list; + } else { + return Collections.emptyList(); + } + } + + public List getPointArrayNames() { + vtkDataSet dataSet = getAValidDataSet(reader.GetOutput()); + if (dataSet != null) { + return reorderNames(VTKUtil.getPointFields(dataSet)); + } else if (reader.GetNumberOfPointArrays() > 0) { + List list = new ArrayList<>(); + int pointArraysNumber = reader.GetNumberOfPointArrays(); + for (int i = 0; i < pointArraysNumber; i++) { + list.add(reader.GetPointArrayName(i)); + } + return list; + } else { + return Collections.emptyList(); + } + } + + public static List reorderNames(String[] names) { + List list = new ArrayList<>(); + for (String string : names) { + list.add(string); + } + List fields = Arrays.asList(Fields.EDITABLE_FIELDS); + List ordered = new LinkedList(); + for (String field : fields) { + int index = list.indexOf(field); + if (index >= 0) { + ordered.add(list.remove(index)); + } + } + ordered.addAll(list); + + return ordered; + } + + private vtkDataSet getAValidDataSet(vtkMultiBlockDataSet dataSet) { + if (dataSet != null) { + if (dataSet.GetNumberOfBlocks() > 0) { + vtkDataObject block = dataSet.GetBlock(0); + if (block instanceof vtkMultiBlockDataSet) { + return getAValidDataSet((vtkMultiBlockDataSet) block); + } else if (block instanceof vtkDataSet) { + return (vtkDataSet) block; + } + } + } + return null; + } + + +} diff --git a/src/eu/engys/vtk/VTKPatches.java b/src/eu/engys/vtk/VTKPatches.java new file mode 100644 index 0000000..685f133 --- /dev/null +++ b/src/eu/engys/vtk/VTKPatches.java @@ -0,0 +1,202 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkDataObject; +import vtk.vtkPolyData; +import eu.engys.core.project.Model; +import eu.engys.core.project.zero.patches.Patch; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Picker; +import eu.engys.gui.view3D.RenderPanel; + +public class VTKPatches implements VTKActors, Picker { + + private static final Logger logger = LoggerFactory.getLogger(VTKPatches.class); + + private Map actors = new LinkedHashMap<>(); + private Map names = new LinkedHashMap<>(); + + private RenderPanel renderPanel; + private Model model; + + public VTKPatches(Model model) { + this.model = model; + } + + @Override + public void setRenderPanel(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + } + + public void load(List patchesDataset) { + for (int i = 0; i < patchesDataset.size(); i++) { + vtkDataObject obj = patchesDataset.get(i); + if (obj instanceof vtkPolyData) { + Patch patch = model.getPatches().patchesToDisplay().get(i); + patch.setLoaded(true); + patch.setDataSet((vtkPolyData) obj); + addActorToPatches(new PatchActor(patch)); + } + } + } + + void addActorToPatches(Actor actor) { + logger.debug("[ADD ACTOR] {} ({})", actor.getName(), actor.getVisibility() ? "visible" : "hidden"); + actors.put(actor.getName(), actor); + names.put(actor, actor.getName()); + } + + void addActorsToRenderer() { + for (String name : actors.keySet()) { + Actor actor = actors.get(name); + renderPanel.addActor(actor); + } + } + + public void addPatchMap(Map map, Map visibility) { + for (String name : map.keySet()) { + Actor actor = map.get(name); + actor.setVisibility(visibility.get(name)); + addActorToPatches(actor); + renderPanel.addActor(actor); + + } + } + + public void deleteActors() { + for (Actor actor : actors.values()) { + renderPanel.removeActor(actor); + actor.deleteActor(); + } + actors.clear(); + names.clear(); + } + + public void removeActorsFromRenderer() { + for (Actor actor : actors.values()) { + renderPanel.removeActor(actor); + } + actors.clear(); + names.clear(); + } + + public void VisibilityOn() { + for (Actor actor : actors.values()) { + actor.setVisibility(true); + } + } + + public void VisibilityOff() { + for (Actor actor : actors.values()) { + actor.setVisibility(false); + } + } + + @Override + public Collection getActors() { + return actors.values(); + } + + @Override + public boolean containsActor(Actor actor) { + return names.containsKey(actor); + } + +// @Override +// public String getActorName(Actor pickedActor) { +// return names.get(pickedActor); +// } + + @Override + public boolean canPickCells(Actor pickedActor) { + return false; + } + + @Override + public boolean canPickMesh() { + return true; + } + + public void updateSelection(Patch[] patches) { + logger.debug("updateSurfaceVisibility: {} patches selected {}", patches.length, patches.length == 1 ? ", selection is: " + patches[0] : ""); + + List selection = new ArrayList(); + + for (Patch patch : patches) { + String name = patch.getName(); + if (patch.isVisible() && actors.containsKey(name)) { + selection.add(actors.get(name)); + } + } + renderPanel.setLowRendering(); + renderPanel.selectActors(false, selection.toArray(new Actor[0])); + renderPanel.setHighRendering(); + } + + public void updateVisibility(Patch[] selection) { + for (Patch patch : selection) { + String name = patch.getName(); + if (actors.containsKey(name)) { + Actor actor = actors.get(name); + actor.setVisibility(patch.isVisible()); + } + } + renderPanel.renderLater(); + } + + public void update(List patchesDataset) { + List actorsList = new ArrayList<>(getActors()); + for (int i = 0; i < patchesDataset.size(); i++) { + vtkDataObject subset = patchesDataset.get(i); + Actor actor = actorsList.get(i); + if (subset instanceof vtkPolyData) { + logger.debug("Update polydata {}", names.get(actor)); + VTKUtil.changeDataset(actor, (vtkPolyData) subset); + } + } + } + + @Override + public Map getActorsMap() { + return Collections.unmodifiableMap(actors); + } + + public boolean isLoaded() { + return !actors.isEmpty(); + } + +} diff --git a/src/eu/engys/vtk/VTKPickManager.java b/src/eu/engys/vtk/VTKPickManager.java new file mode 100644 index 0000000..b0a0522 --- /dev/null +++ b/src/eu/engys/vtk/VTKPickManager.java @@ -0,0 +1,222 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; + +import vtk.vtkAreaPicker; +import vtk.vtkCellPicker; +import vtk.vtkGenericRenderWindowInteractor; +import vtk.vtkWorldPointPicker; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.EventManager.Event; +import eu.engys.gui.events.view3D.ActorPopUpEvent; +import eu.engys.gui.events.view3D.ActorSelectionEvent; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.CellPicker; +import eu.engys.gui.view3D.PickInfo; +import eu.engys.gui.view3D.PickManager; +import eu.engys.gui.view3D.Picker; +import eu.engys.gui.view3D.RenderPanel; + +public class VTKPickManager implements PickManager { + + enum PickFor {ACTOR, CELL}; + + private final RenderPanel renderPanel; + private PickFor pickFor; + + public VTKPickManager(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + } + + public void pick(int x, int y, boolean control, boolean shift) { + PickInfo pi = pickCell(x, y); + pi.shift = shift; + pi.control = control; + + if (pickFor == PickFor.ACTOR) { + pickActor(pi); + } else { + pickCell(pi); + } + } + + public void pickArea(int[] startPosition, int[] endPosition, boolean control, boolean shift) { + PickInfo pi = pickArea(startPosition, endPosition); + pi.shift = shift; + pi.control = control; + + if (pickFor == PickFor.ACTOR) { + pickActor(pi); + } else { + pickCell(pi); + } + } + + void pickActor(PickInfo pi) { + if (pi != null && pi.actor != null) { + renderPanel.selectActors(pi.control, pi.actor); + EventManager.triggerEvent(this, getSelectionEvent(pi.control, pi.actor)); + } else { + renderPanel.selectActors(false); + EventManager.triggerEvent(this, getSelectionEvent(false, null)); + } + } + + private Event getSelectionEvent(boolean keep, Actor pickedActor) { + for (Picker picker : pickersForActors) { + if (picker.containsActor(pickedActor)) { + return new ActorSelectionEvent(picker, pickedActor, keep) ; + } + } + return new ActorSelectionEvent(null, null, false); + } + + private void pickCell(final PickInfo pi) { + for (final CellPicker picker : pickersForCells) { + picker.pick(pi); +// ExecUtil.invokeLater(new Runnable() { +// @Override +// public void run() { +// } +// }); + } + } + + private List pickersForActors = new ArrayList<>(); + private List pickersForCells = new ArrayList<>(); + + public void registerPickerForActors(Picker picker) { + pickersForActors.add(picker); + } + + public void registerPickerForCells(CellPicker picker) { + pickersForCells.add(picker); + } + + public void unregisterPickerForCells(CellPicker picker) { + pickersForCells.remove(picker); + } + + public void pickForActors() { + pickFor = PickFor.ACTOR; + } + + public void pickForCells() { + pickActor(null); + pickFor = PickFor.CELL; + } + + public double[] pickPoint() { + int[] position = ((vtkGenericRenderWindowInteractor)((VTKRenderPanel)renderPanel).getInteractor()).GetLastEventPosition(); + return pickPoint(position); + } + + public double[] pickPoint(int[] eventPosition) { + renderPanel.lock(); + vtkWorldPointPicker pick = new vtkWorldPointPicker(); + if (renderPanel instanceof VTKRenderPanel) { + pick.Pick(eventPosition[0], eventPosition[1], 0, ((VTKRenderPanel)renderPanel).GetRenderer()); + } + renderPanel.unlock(); + return pick.GetPickPosition(); + } + + private PickInfo pickCell(int x, int y) { + vtkCellPicker picker = new vtkCellPicker(); + picker.SetTolerance(0.0005); + renderPanel.lock(); + if (renderPanel instanceof VTKRenderPanel) { + picker.Pick(x, y, 0, ((VTKRenderPanel)renderPanel).GetRenderer()); + } + renderPanel.unlock(); + + PickInfo pi = new PickInfo(); + pi.actor = (Actor) picker.GetActor(); + pi.dataSet = picker.GetDataSet(); + pi.cellId = picker.GetCellId(); + pi.cellIJK = picker.GetCellIJK(); + pi.normal = picker.GetPickNormal(); + pi.position = picker.GetPickPosition(); + + return pi; + } + + public PickInfo pickArea(int[] start, int[] end) { + vtkCellPicker centerPicker = new vtkCellPicker(); + centerPicker.SetTolerance(0.0005); + if (renderPanel instanceof VTKRenderPanel) { + centerPicker.Pick((start[0]+end[0])/2, (start[1]+end[1])/2, 0, ((VTKRenderPanel)renderPanel).GetRenderer()); + } + + vtkAreaPicker picker = new vtkAreaPicker(); + if (renderPanel instanceof VTKRenderPanel) { + picker.AreaPick(start[0], start[1], end[0], end[1], ((VTKRenderPanel)renderPanel).GetRenderer()); + } + + PickInfo pi = new PickInfo(); + pi.actor = (Actor) picker.GetActor();//centerPicker.GetActor(); + pi.dataSet = picker.GetDataSet();//centerPicker.GetDataSet(); + pi.cellId = centerPicker.GetCellId(); + pi.cellIJK = null; + pi.normal = null; + pi.position = picker.GetPickPosition(); + pi.frustum = picker.GetFrustum(); + + return pi; + } + + public void popup(int x, int y, MouseEvent event) { + PickInfo pi = pickCell(x, y); + pi.shift = false; + pi.control = false; + + if (pickFor == PickFor.ACTOR) { + popUp(event, pi); + } + } + + void popUp(MouseEvent event, PickInfo pi) { + if (pi != null && pi.actor != null) { + EventManager.triggerEvent(this, getPopUpEvent(event, pi.actor)); + } else { + EventManager.triggerEvent(this, getPopUpEvent(event, null)); + } + } + + private Event getPopUpEvent(MouseEvent event, Actor pickedActor) { + for (Picker picker : pickersForActors) { + if (picker.containsActor(pickedActor)) { + return new ActorPopUpEvent(event, picker, pickedActor) ; + } + } + return new ActorPopUpEvent(event, null, null); + } +} diff --git a/src/eu/engys/vtk/VTKRangeCalculator.java b/src/eu/engys/vtk/VTKRangeCalculator.java new file mode 100644 index 0000000..b83ea52 --- /dev/null +++ b/src/eu/engys/vtk/VTKRangeCalculator.java @@ -0,0 +1,96 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import vtk.vtkDataArray; +import vtk.vtkMapper; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.core.project.mesh.FieldItem.DataType; +import eu.engys.gui.view3D.Actor; + +public class VTKRangeCalculator { + + private FieldItem fieldItem; + + public VTKRangeCalculator(FieldItem fieldItem) { + this.fieldItem = fieldItem; + } + + public void calculateRange_Automatically_For(VTKActors actors) { + if (!actors.getActors().isEmpty()) { + double[] range = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE }; + for (Actor actor : actors.getActors()) { + if (actor.getVisibility()) { + double[] drange = calculateRangeFor(actor); + if (drange != null) { +// System.out.println("VTKRangeCalculator.calculateRange_Automatically_For() " + Arrays.toString(drange)); + range[0] = Math.min(range[0], drange[0]); + range[1] = Math.max(range[1], drange[1]); + } + } + } + if (range[0] <= range[1] ) { +// System.out.println("VTKRangeCalculator.calculateRange_Automatically_For() " + actors.getClass() + " => " + Arrays.toString(range)); + fieldItem.setRange(range); + } + } + } + + public void calculateRange_Automatically_For(Actor actor) { + double[] range = fieldItem.getRange(); + if (actor.getVisibility()) { + double[] drange = calculateRangeFor(actor); + if (drange != null) { + range[0] = drange[0]; + range[1] = drange[1]; + } + + } + fieldItem.setRange(range); + } + + private double[] calculateRangeFor(Actor actor) { + vtkMapper mapper = actor.getMapper(); + mapper.Update(); + + vtkDataArray pScalars = null; + DataType dataType = fieldItem.getDataType(); + String fieldName = fieldItem.getName(); + + if (dataType.isCell()) { + pScalars = mapper.GetInputAsDataSet().GetCellData().GetScalars(fieldName); + } else if (dataType.isPoint()) { + pScalars = mapper.GetInputAsDataSet().GetPointData().GetScalars(fieldName); + } + + if (pScalars != null) { + return fieldItem.getComponent() >= 0 ? pScalars.GetRange(fieldItem.getComponent() - 1) : pScalars.GetRange(); + } + + return null; + } + +} diff --git a/src/eu/engys/vtk/VTKRenderPanel.java b/src/eu/engys/vtk/VTKRenderPanel.java new file mode 100644 index 0000000..4d68bed --- /dev/null +++ b/src/eu/engys/vtk/VTKRenderPanel.java @@ -0,0 +1,595 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.Timer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkActorCollection; +import vtk.vtkAssembly; +import vtk.vtkImageData; +import vtk.vtkLight; +import vtk.vtkObject; +import vtk.vtkPanel; +import vtk.vtkWindowToImageFilter; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.CameraManager; +import eu.engys.gui.view3D.CameraManager.Position; +import eu.engys.gui.view3D.Interactor; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.gui.view3D.Representation; +import eu.engys.util.PrefUtil; +import eu.engys.util.plaf.ILookAndFeel; +import eu.engys.util.ui.ExecUtil; + +public class VTKRenderPanel extends vtkPanel implements RenderPanel { + + private enum LowRendering {ON, OFF} + + private static final Logger logger = LoggerFactory.getLogger(VTKRenderPanel.class); + + public class DelayTimer extends Timer implements ActionListener { + public DelayTimer() { + super(PrefUtil.getInt(PrefUtil._3D_LOCK_INTRACTIVE_TIME, 2000), null); + addActionListener(this); + } + + public void actionPerformed(ActionEvent evt) { + InteractiveOff(); + } + } + + public class CountdownTimer extends Timer implements ActionListener { + + private int delay = PrefUtil.getInt(PrefUtil._3D_LOCK_INTRACTIVE_TIME, 2000); + private int counter = delay; + + public CountdownTimer() { + super(UPDATE_RATE, null); + addActionListener(this); + } + + @Override + public void stop() { + super.stop(); + counter = delay; + } + + public void actionPerformed(ActionEvent evt) { + // System.err.println("Full rendering in "+(counter/1000.0)+"s"); + if (counter <= 0) { + stop(); + return; + } + counter -= UPDATE_RATE; + } + } + + private static final int UPDATE_RATE = 500; + + private static final double LOWEST_RATE = 0.001; + private static final double LOW_RATE = 0.01; + private static final double HIGH_RATE = 5.0; + private static final double HIGHEST_RATE = 15000; + + protected Timer timer = new DelayTimer(); + protected Timer countdown = new CountdownTimer(); + + private Interactor iren; + private Set selection = new HashSet<>(); + + private ILookAndFeel laf; + private VTKMouseHandler handler; + private VTKPickManager pickManager; + + private CameraManager cameraManager; + private LowRendering lowRendering = LowRendering.ON; + + public VTKRenderPanel(ILookAndFeel laf) { + this.laf = laf; + Initialize(); + } + + private void Initialize() { + iren = new VTKInteractor(rw); + + double[] color1 = laf.get3DColor1(); + double[] color2 = laf.get3DColor2(); + double[] colorSelection = laf.get3DSelectionColor(); + + handler = new VTKMouseHandler(this); + addMouseListener(handler); + addMouseMotionListener(handler); + addMouseWheelListener(handler); + addKeyListener(handler); + + pickManager = new VTKPickManager(this); + pickManager .pickForActors(); + + cameraManager = new VTKCameraManager(this); + + ren.GradientBackgroundOn(); + ren.SetBackground(color1); + ren.SetBackground2(color2); + ren.SetGradientBackground(true); + + // ren.RemoveAllLights(); + ren.AutomaticLightCreationOff(); + ren.LightFollowCameraOn(); + + ren.AddLight(createLight( 45, 45)); + ren.AddLight(createLight(-45, 45)); + ren.AddLight(createLight( 45,-45)); + ren.AddLight(createLight(-45,-45)); + + sren.AutomaticLightCreationOn(); + sren.GradientBackgroundOff(); + //iren.start(); + + addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent event) { + updateSize(getWidth(), getHeight()); + } + }); + +// VTKUtil.observe(rw, ""); + +// rw.AddObserver("AbortCheckEvent", this, "AbortCheckEvent"); + } + +// public void AbortCheckEvent() { +// if (rw.GetEventPending() != 0) { +// System.out.println("VTKRenderPanel.AbortCheckEvent() >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "); +// rw.SetAbortRender(1); +// } +// } + + private vtkLight createLight(double elevation, double azimuth) { + vtkLight light = new vtkLight(); + light.SetIntensity(0.5); + light.SetColor(1,1,1); + light.SetLightTypeToCameraLight(); + light.SetDirectionAngle(elevation, azimuth); + light.SwitchOn(); + + return light; + } + + public void Delete() { + iren = null; + super.Delete(); + } + + public void lock() { + logger.trace("-------------------------- LOCK ---------------------------------"); + Lock(); + } + + public void unlock() { + logger.trace("------------------------- UNLOCK --------------------------------"); + UnLock(); + } + + @Override + public void dispose() { + DestroyTimer(); + + iren.dispose(); + iren = null; + + super.dispose(); + + Initialize(); + } + + private void updateSize(int w, int h) { + if (windowset == 1) { + lock(); + iren.updateSize(w,h); + unlock(); + } + } + + public void renderLater() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + Render(); + } + }); + } + + public void renderAndWait() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + Render(); + } + }); + } + + public void resetZoomLater() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + zoomReset(); + } + }); + } + + public void resetZoomAndWait() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + zoomReset(); + } + }); + } + + @Override + public void setHighRendering() { +// System.out.println("VTKRenderPanel.setHighRendering()"); + if (iren == null) { + return; + } + + if (lowRendering == LowRendering.OFF) { + return; + } + + StartTimer(); + } + + @Override + public void setLowRendering() { +// System.out.println("VTKRenderPanel.setLowRendering()"); + if (iren == null) { + return; + } + + if (lowRendering == LowRendering.OFF) { + return; + } + + DestroyTimer(); + + InteractiveOn(); + } + + private void InteractiveOn() { +// System.err.println("VTKRenderPanel.InteractiveOn()"); + lock(); + + for (Actor actor : getAllActors()) { + actor.interactiveOn(); + } + + unlock(); + } + + private void InteractiveOff() { +// System.err.println("VTKRenderPanel.InteractiveOff()"); + lock(); + + for (Actor actor : getAllActors()) { + actor.interactiveOff(); + } + + unlock(); + renderLater(); + } + + private void StartTimer() { + if (timer.isRunning()) { + timer.stop(); + countdown.stop(); + } + + countdown.start(); + + int delay = PrefUtil.getInt(PrefUtil._3D_LOCK_INTRACTIVE_TIME, 2000); + timer.setDelay(delay); + timer.setRepeats(false); + timer.start(); + } + + public void DestroyTimer() { + if (timer.isRunning()) { + timer.stop(); + countdown.stop(); + } + } + + @Override + public void wheelForward() { + if (iren == null) + return; + lock(); + iren.wheelForwardEvent(); + unlock(); + } + + @Override + public void wheelBackward() { + if (iren == null) + return; + lock(); + iren.wheelBackwardEvent(); + unlock(); + } + + @Override + public void zoomReset() { + if (iren == null) + return; + lock(); + GetRenderer().ResetCamera(); + unlock(); + renderLater(); + } + + @Override + public void setCameraPosition(Position pos) { + cameraManager.setCameraPosition(pos); + } + + @Override + public void addActor(vtkAssembly actor) { + lock(); + GetRenderer().AddActor(actor); + unlock(); + } + + @Override + public void addActor(Actor actor) { + lock(); + actor.setRepresentation(representation); + GetRenderer().AddActor(actor.getActor()); + correctSelectionVisualization(); + unlock(); + } + + private void correctSelectionVisualization() { + int memory_limit = PrefUtil.getInt(PrefUtil._3D_TRANSPARENCY_MEMORY, 10 * 1024); + int size = 0; + for (Actor actor : getAllActors()) { + size += actor.getMemorySize(); + } + + logger.debug("Total Memory Size: {}", size); + + for (Actor actor : getAllActors()) { + if (size > memory_limit) { + actor.deselectedStateOff(); + } else { + actor.deselectedStateOn(); + } + } + } + + @Override + public void removeActor(Actor actor) { + lock(); + GetRenderer().RemoveActor(actor.getActor()); + GetSelectionRenderer().RemoveActor(actor.getSelectionActor()); + correctSelectionVisualization(); + unlock(); + } + + @Override + public void clearSelection() { + lock(); + for (Actor actor : getAllActors()) { + actor.restoreFromSelection(); + } + unlock(); + } + + public void selectActors(boolean keepSelected, Actor... actors) { + setLowRendering(); + lock(); + + if (!keepSelected) { + selection.clear(); + } + + List toSelect = new ArrayList<>(); + if (keepSelected) { + for (Actor actor : actors) { + if (selection.contains(actor)) { + selection.remove(actor); + } else { + toSelect.add(actor); + } + } + } else { + toSelect.addAll(Arrays.asList(actors)); + } + + selection.addAll(toSelect); + + for (Actor actor : getAllActors()) { +// actor.interactiveOn(); + if (selection.size() > 0) { + if (selection.contains(actor)) { + actor.selectActor(); + GetSelectionRenderer().AddActor(actor.getSelectionActor()); + } else { + actor.deselectActor(); + GetSelectionRenderer().RemoveActor(actor.getSelectionActor()); + } + } else { + GetSelectionRenderer().RemoveActor(actor.getSelectionActor()); + actor.restoreFromSelection(); + } + } + unlock(); +// renderLater(); + Render(); +// renderAndWait(); + setHighRendering(); + } + + private List getAllActors() { + List list = new ArrayList<>(); + vtkActorCollection actors = ren.GetActors(); + for (int a = 0; a < actors.GetNumberOfItems(); a++) { + vtkObject item = actors.GetItemAsObject(a); + if (item instanceof Actor) { + list.add((Actor) item); + } + } + + return list; + } + + private List getSelectionActors() { + List list = new ArrayList<>(); + vtkActorCollection actors = sren.GetActors(); + for (int a = 0; a < actors.GetNumberOfItems(); a++) { + vtkObject item = actors.GetItemAsObject(a); + System.out.println("VTKRenderPanel.getSelectionActors() " +item); + } + + return list; + } + + + @Override + public void setActorColor(Color c, Actor... actors) { + if (c == null) + return; + + lock(); + double[] color = new double[] { c.getRed() / 255.0, c.getGreen() / 255.0, c.getBlue() / 255.0 }; + double opacity = c.getAlpha() / 255.0; + + for (Actor actor : actors) { + if (actor == null) + continue; + actor.setSolidColor(color, opacity); + + } + unlock(); + } + + @Override + public void clear() { + selection.clear(); + } + + Representation representation = Representation.WIREFRAME; + + public void setRepresentation(Representation representation) { + this.representation = representation; + } + + public Representation getRepresentation() { + return representation; + } + + @Override + public void changeRepresentation(Representation r) { + lock(); + setRepresentation(r); + for (Actor actor : getAllActors()) { + actor.setRepresentation(representation); + } + unlock(); + Render(); + } + + @Override + public void ParallelProjectionOn() { + lock(); + GetRenderer().GetActiveCamera().ParallelProjectionOn(); + unlock(); + Render(); + } + + @Override + public void ParallelProjectionOff() { + lock(); + GetRenderer().GetActiveCamera().ParallelProjectionOff(); + unlock(); + Render(); + } + +// @Override +// public vtkRenderer GetRenderer() { +// return super.GetRenderer(); +// } +// +// @Override +// public vtkRenderWindow GetRenderWindow() { +// return super.GetRenderWindow(); +// } + + @Override + public Interactor getInteractor() { + return this.iren; + } + + @Override + public VTKPickManager getPickManager() { + return pickManager; + } + + @Override + public vtkImageData toImageData() { + vtkWindowToImageFilter w2i = new vtkWindowToImageFilter(); + w2i.SetInput(rw); + w2i.Modified(); + rw.Render(); + w2i.Update(); + + return w2i.GetOutput(); + } + + @Override + public void lowRenderingOn() { + this.lowRendering = LowRendering.ON; + } + + @Override + public void lowRenderingOff() { + this.lowRendering = LowRendering.OFF; + } +} diff --git a/src/eu/engys/vtk/VTKUtil.java b/src/eu/engys/vtk/VTKUtil.java new file mode 100644 index 0000000..de34be4 --- /dev/null +++ b/src/eu/engys/vtk/VTKUtil.java @@ -0,0 +1,395 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkAlgorithm; +import vtk.vtkAlgorithmOutput; +import vtk.vtkCellData; +import vtk.vtkCleanPolyData; +import vtk.vtkCompositeDataPipeline; +import vtk.vtkCompositeDataSet; +import vtk.vtkDataArray; +import vtk.vtkDataObject; +import vtk.vtkDataSet; +import vtk.vtkDataSetSurfaceFilter; +import vtk.vtkDoubleArray; +import vtk.vtkExecutive; +import vtk.vtkInformation; +import vtk.vtkInformationDoubleKey; +import vtk.vtkInformationDoubleVectorKey; +import vtk.vtkMapper; +import vtk.vtkMultiBlockDataSet; +import vtk.vtkObject; +import vtk.vtkOpenFOAMReader; +import vtk.vtkPointData; +import vtk.vtkPolyData; +import vtk.vtkPolyDataAlgorithm; +import vtk.vtkPolyDataMapper; +import vtk.vtkReferenceInformation; +import vtk.vtkStreamingDemandDrivenPipeline; +import vtk.vtkTrivialProducer; +import vtk.vtkUnstructuredGrid; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Controller3D; +import eu.engys.util.Util; +import eu.engys.util.VTKSettings; + +public class VTKUtil { + + private static final Logger logger = LoggerFactory.getLogger(VTKUtil.class); + + public static BoundingBox computeBoundingBox(List controllers, boolean visibleOnly) { + + List allVisibleActors = new ArrayList<>(); + + for (Controller3D controller : controllers) { + Collection actors = controller.getActorsList(); + for (Actor vtkActor : actors) { + if (!visibleOnly || (visibleOnly && vtkActor.getVisibility())) { + allVisibleActors.add(vtkActor); + } + } + } + + return computeBoundingBox(allVisibleActors); + } + + public static BoundingBox computeBoundingBox(Collection actors) { + if(Util.isVarArgsNotNull(actors.toArray(new Actor[0]))){ + double xmin = Double.MAX_VALUE; + double xmax = -Double.MAX_VALUE; + double ymin = Double.MAX_VALUE; + double ymax = -Double.MAX_VALUE; + double zmin = Double.MAX_VALUE; + double zmax = -Double.MAX_VALUE; + + for (Actor actor : actors) { + if (actor != null) { + double[] bounds = actor.getBounds(); + xmin = Math.min(xmin, bounds[0]); + xmax = Math.max(xmax, bounds[1]); + ymin = Math.min(ymin, bounds[2]); + ymax = Math.max(ymax, bounds[3]); + zmin = Math.min(zmin, bounds[4]); + zmax = Math.max(zmax, bounds[5]); + } + } + + return new BoundingBox(xmin, xmax, ymin, ymax, zmin, zmax); + } else { + return new BoundingBox(0, 0, 0, 0, 0, 0); + } + + } + + public static void printDatasetData(vtkOpenFOAMReader reader) { + logger.debug("[reader] ---------------" + reader.GetFileName() + "----------------"); + int patchesNumber = reader.GetNumberOfPatchArrays(); + logger.debug("[reader] Patches Number: " + patchesNumber); + logger.debug("[reader] Patches List: "); + for (int i = 0; i < patchesNumber; i++) { + String patchName = reader.GetPatchArrayName(i); + int status = reader.GetPatchArrayStatus(patchName); + logger.debug("[reader] (" + i + ") " + patchName + ", status: " + (status == 0 ? "disabled" : "enabled")); + } + + int cellArraysNumber = reader.GetNumberOfCellArrays(); + logger.debug("[reader] Cell Arrays Number: " + cellArraysNumber); + logger.debug("[reader] Cell Arrays List: "); + for (int i = 0; i < cellArraysNumber; i++) { + String cellArrayName = reader.GetCellArrayName(i); + int status = reader.GetCellArrayStatus(cellArrayName); + logger.debug("[reader] (" + i + ") " + cellArrayName + ", status: " + (status == 0 ? "disabled" : "enabled")); + } + + int pointArraysNumber = reader.GetNumberOfPointArrays(); + logger.debug("[reader] Point Arrays Number: " + pointArraysNumber); + logger.debug("[reader] Point Arrays List: "); + for (int i = 0; i < pointArraysNumber; i++) { + String pointArrayName = reader.GetPointArrayName(i); + int status = reader.GetPointArrayStatus(pointArrayName); + logger.debug("[reader] (" + i + ") " + pointArrayName + ", status: " + (status == 0 ? "disabled" : "enabled")); + } + + logger.debug("[reader] Decompose Polyhedra: " + reader.GetDecomposePolyhedra()); + + int lagrangianArraysNumber = reader.GetNumberOfLagrangianArrays(); + logger.debug("[reader] Lagrangian Arrays Number: " + lagrangianArraysNumber); + logger.debug("[reader] Lagrangian Arrays List: "); + for (int i = 0; i < lagrangianArraysNumber; i++) { + String lagrangianArrayName = reader.GetLagrangianArrayName(i); + int status = reader.GetLagrangianArrayStatus(lagrangianArrayName); + logger.debug("[reader] (" + i + ") " + lagrangianArrayName + ", status: " + (status == 0 ? "disabled" : "enabled")); + } + + logger.debug("[reader] Read Zones: " + reader.GetReadZones()); + + vtkDoubleArray times = reader.GetTimeValues(); + if (times != null) { + logger.debug("[reader] Time Values: ["); + for (int i = 0; i < times.GetSize(); i++) { + logger.debug("[Time]" + times.GetValue(i) + ", "); + } + logger.debug("]"); + } else { + // reader.UpdateInformation(); // Scan time steps and create + // metadata + vtkExecutive exe = reader.GetExecutive(); + vtkInformation outInfo = exe.GetOutputInformation(0); + vtkInformationDoubleVectorKey timeStepsKey = new vtkStreamingDemandDrivenPipeline().TIME_STEPS(); + int nTimeSteps = outInfo.Length(timeStepsKey); // Get the number of + // time steps + logger.debug("[reader] Time Values: " + nTimeSteps); + for (int i = 0; i < nTimeSteps; i++) { + double timeValue = outInfo.Get(timeStepsKey, i); // Get the i-th + // time value + logger.debug("[reader] Step: " + i + ", Value: " + timeValue); + } + } + + vtkExecutive exe = reader.GetExecutive(); + vtkCompositeDataPipeline pipeline = (vtkCompositeDataPipeline) exe; + vtkInformation outInfo = exe.GetOutputInformation(0); + vtkInformationDoubleVectorKey TIME_STEPS = pipeline.TIME_STEPS(); + vtkInformationDoubleKey UPDATE_TIME_STEP = pipeline.UPDATE_TIME_STEP(); + + int nTimeSteps = outInfo.Length(TIME_STEPS); // Get the number of time steps + logger.debug("[pipeline] Time Values: " + nTimeSteps); + logger.debug("[pipeline] Time Values: current is " + outInfo.Get(UPDATE_TIME_STEP)); + for (int i = 0; i < nTimeSteps; i++) { + double timeValue = outInfo.Get(TIME_STEPS, i); // Get the i-th time value + logger.debug("[pipeline] Step: " + i + ", Value: " + timeValue); + + } + + vtkMultiBlockDataSet dataset = reader.GetOutput(); + int blocksNumber = dataset.GetNumberOfBlocks(); + logger.debug("[dataset]\tBlocks Number: " + blocksNumber); + for (int i = 0; i < blocksNumber; i++) { + vtkDataObject block = dataset.GetBlock(i); + String name = dataset.GetMetaData(i).Get(new vtkCompositeDataSet().NAME()); + readBlock(block, name, i, "\t"); + } + logger.debug("[reader] ---------------" + reader.GetFileName() + "----------------"); + } + + private static void readBlock(vtkDataObject block, String name, int i, String indent) { + if (block instanceof vtkMultiBlockDataSet) { + vtkMultiBlockDataSet multiBlockDataSet = (vtkMultiBlockDataSet) block; + int nBlocks = multiBlockDataSet.GetNumberOfBlocks(); + logger.debug("[dataset]" + indent + "Block {} '{}': MultiBlockDataset, {} Sub Blocks", i, name, nBlocks); + for (int j = 0; j < nBlocks; j++) { + vtkDataObject subBlock = multiBlockDataSet.GetBlock(j); + String subName = multiBlockDataSet.GetMetaData(j).Get(new vtkCompositeDataSet().NAME()); + readBlock(subBlock, subName, j, indent + indent); + } + } else if (block instanceof vtkUnstructuredGrid) { + logger.debug("[dataset]" + indent + "Block {} '{}': UnstructuredGrid", i, name); + readFields((vtkDataSet) block, indent); + } else if (block instanceof vtkPolyData) { + logger.debug("[dataset]" + indent + "Block {} '{}': PolyData", i, name); + readFields((vtkDataSet) block, indent); + } else { + logger.debug("[dataset]" + indent + "Block {} '{}': OTHER {}", i, name, block); + } + } + + private static void readFields(vtkDataSet dataSet, String indent) { + String[] pointFields = getPointFields(dataSet); + logger.debug("[dataset]" + indent + "\tPointData Arrays Number: " + pointFields.length); + for (int i = 0; i < pointFields.length; i++) { + logger.debug("[dataset]" + indent + "\t\t array " + i + ": " + pointFields[i]); + } + String[] cellFields = getCellFields(dataSet); + logger.debug("[dataset]" + indent + "\tCellData Arrays Number: " + cellFields.length); + for (int i = 0; i < cellFields.length; i++) { + logger.debug("[dataset]" + indent + "\t\t array " + i + ": " + cellFields[i]); + } + } + + public static String[] getPointFields(vtkDataSet dataSet) { + vtkPointData pointData = dataSet.GetPointData(); + String[] fields = new String[pointData.GetNumberOfArrays()]; + for (int i = 0; i < fields.length; i++) { + fields[i] = pointData.GetArrayName(i); + } + return fields; + } + + public static String[] getCellFields(vtkDataSet dataSet) { + vtkCellData cellData = dataSet.GetCellData(); + String[] fields = new String[cellData.GetNumberOfArrays()]; + for (int i = 0; i < fields.length; i++) { + fields[i] = cellData.GetArrayName(i); + } + return fields; + } + + public static void gc(boolean debug) { + if (VTKSettings.librariesAreLoaded()) { + vtkReferenceInformation info = vtkObject.JAVA_OBJECT_MANAGER.gc(debug); + if (debug) { + logger.debug("K: " + info.listKeptReferenceToString()); + logger.debug("R: " + info.listRemovedReferenceToString()); + } + } + } + + public static vtkPolyData geometryFilter(vtkUnstructuredGrid dataset) { + vtkUnstructuredGrid input = new vtkUnstructuredGrid(); + input.ShallowCopy(dataset); + + vtkDataSetSurfaceFilter filter = new vtkDataSetSurfaceFilter(); + filter.SetInputData(input); + filter.PassThroughCellIdsOn(); + filter.PassThroughPointIdsOn(); + filter.Update(); + input.Delete(); + + vtkPolyData output = filter.GetOutput(); + filter.Delete(); + + return output; + } + + public static vtkPolyData repairDataSet(vtkPolyData dataset) { + vtkCleanPolyData clean = new vtkCleanPolyData(); + // clean.ConvertLinesToPointsOff(); //def: on + // clean.ConvertPolysToLinesOff(); //def: on + // clean.ConvertStripsToPolysOff(); //def: on + // clean.PieceInvariantOff(); //def: on + // clean.PointMergingOff(); //def: on + // clean.SetAbsoluteTolerance(0); //def: 1.0 + // clean.SetTolerance(0);//def: 0.0 + // clean.ToleranceIsAbsoluteOn(); //def: off + clean.SetInputData(dataset); + clean.Update(); + + return clean.GetOutput(); + } + + public static void exit() { + vtkObject.JAVA_OBJECT_MANAGER.deleteAll(); + } + + public static void changeDataset(Actor actor, vtkPolyData subset) { + vtkMapper mapper = actor.getMapper(); + ((vtkPolyDataMapper) mapper).SetInputData((vtkPolyData) subset); + } + + public static void changeDataset(Actor actor, vtkUnstructuredGrid subset) { + vtkMapper mapper = actor.getMapper(); + vtkAlgorithmOutput filterOutput = mapper.GetInputConnection(0, 0); + + if (filterOutput.GetProducer() instanceof vtkPolyDataAlgorithm ) { + vtkPolyDataAlgorithm filter = (vtkPolyDataAlgorithm) filterOutput.GetProducer(); + + VTKUtil.deleteDataset(filter.GetInput()); + filter.SetInputData(subset); + mapper.Update(); + } else if (filterOutput.GetProducer() instanceof vtkTrivialProducer ) { + vtkAlgorithm filter = (vtkAlgorithm) filterOutput.GetProducer(); + filter.SetInputDataObject(subset); + mapper.Update(); + } else { + logger.warn("CANNOT CHANGE DATASET FOR: {}", "unstructured grid"); + } + } + + public static void deleteDataset(vtkDataObject dataObject) { + if (dataObject instanceof vtkDataSet) { + vtkDataSet dataSet = (vtkDataSet) dataObject; + vtkPointData pointData = dataSet.GetPointData(); + vtkDataArray pScalars = pointData.GetScalars(); + if (pScalars != null) + pScalars.Delete(); + pointData.Delete(); + + vtkCellData cellData = dataSet.GetCellData(); + vtkDataArray cScalars = cellData.GetScalars(); + if (cScalars != null) + cScalars.Delete(); + cellData.Delete(); + + dataSet.Delete(); + } else { + System.err.println("NOT A DATASET"); + } + } + + public static void observe(vtkObject obj, String label) { + ConsoleObserver o = new ConsoleObserver(obj, label); + + obj.AddObserver("AbortCheckEvent", o, "AbortCheckEvent"); + obj.AddObserver("StartEvent", o, "StartEvent"); + obj.AddObserver("EndEvent", o, "EndEvent"); + obj.AddObserver("ProgressEvent", o, "ProgressEvent"); + obj.AddObserver("TimerEvent", o, "TimerEvent"); + obj.AddObserver("ConfigureEvent", o, "ConfigureEvent"); + obj.AddObserver("ErrorEvent", o, "ErrorEvent"); + obj.AddObserver("WarningEvent", o, "WarningEvent"); + } + + static class ConsoleObserver { + private vtkObject obj; + private String label; + private long time = 0L; + public ConsoleObserver(vtkObject obj, String label) { + this.obj = obj; + this.label = label; + } + public void AbortCheckEvent() { System.err.println("+++ AbortCheckEvent +++" + obj.GetClassName() + " - " + label); } + public void StartEvent() { System.err.println("StartEvent " + obj.GetClassName() + " - " + label); this.time = System.currentTimeMillis();} + public void EndEvent() { System.err.println("EndEvent " + obj.GetClassName() + " - " + label + " - ET: " + (System.currentTimeMillis() - time)/1000D + " sec");} + public void ProgressEvent() { System.err.println("ProgressEvent " + obj.GetClassName() + " - " + label);} + public void ConfigureEvent() { System.err.println("ConfigureEvent " + obj.GetClassName() + " - " + label);} + public void TimerEvent() { System.err.println("TimerEvent " + obj.GetClassName() + " - " + label);} + public void ErrorEvent() { System.err.println("ErrorEvent " + obj.GetClassName() + " - " + label);} + public void WarningEvent() { System.err.println("WarningEvent " + obj.GetClassName() + " - " + label);} + } + + public static String logBlockNames(vtkMultiBlockDataSet dataset) { + StringBuilder sb = new StringBuilder(); + int numberOfBlocks = dataset.GetNumberOfBlocks(); + for (int i = 0; i < numberOfBlocks; i++) { + String name = dataset.GetMetaData(i).Get(new vtkCompositeDataSet().NAME()); + sb.append("(" + i + ") "); + sb.append(name); + sb.append(" "); + } + + return sb.toString(); + } +} diff --git a/src/eu/engys/vtk/VTKView3D.java b/src/eu/engys/vtk/VTKView3D.java new file mode 100644 index 0000000..444ce12 --- /dev/null +++ b/src/eu/engys/vtk/VTKView3D.java @@ -0,0 +1,584 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.vecmath.Point3d; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.controller.GeometryToMesh; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.core.project.Model; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.gui.events.EventManager; +import eu.engys.gui.events.view3D.View3DEvent; +import eu.engys.gui.events.view3D.VolumeReportVisibilityEvent.Kind; +import eu.engys.gui.view.View3DElement; +import eu.engys.gui.view.ViewElement; +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.gui.view3D.Controller3D; +import eu.engys.gui.view3D.Geometry3DController; +import eu.engys.gui.view3D.LayerInfo; +import eu.engys.gui.view3D.Mesh3DController; +import eu.engys.gui.view3D.QualityInfo; +import eu.engys.gui.view3D.Selection; +import eu.engys.gui.view3D.widget.Widget; +import eu.engys.util.plaf.ILookAndFeel; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.ExecUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.vtk.widgets.AxesWidget; +import eu.engys.vtk.widgets.AxisWidgetManager; +import eu.engys.vtk.widgets.ExtractSelectionWidget; +import eu.engys.vtk.widgets.LayersCoverageWidget; +import eu.engys.vtk.widgets.LogoWidget; +import eu.engys.vtk.widgets.MinMaxPointWidgetManager; +import eu.engys.vtk.widgets.PlaneDisplayWidget; +import eu.engys.vtk.widgets.PlaneWidget; +import eu.engys.vtk.widgets.PointWidgetManager; +import eu.engys.vtk.widgets.QualityWidget; +import eu.engys.vtk.widgets.panels.BoundingBoxBar; +import eu.engys.vtk.widgets.shapes.BoxWidget; + +public class VTKView3D extends JPanel implements CanvasPanel { + + private static Logger logger = LoggerFactory.getLogger(CanvasPanel.class); + + private Set viewElements; + private Set view3DElements; + private Map, View3DElement> elementsByClass = new HashMap<>(); + private Map elementsByTitle = new HashMap<>(); + + private final Model model; + private final Set widgets; + private final VTKRenderPanel renderPanel; + private final VTKView3DController view3DController; + + private final List controllers; + + private VTK3DActionsToolBar genericToolBar; + + private PointWidgetManager pointWidgetManager; + private AxisWidgetManager axisWidgetManager; + private MinMaxPointWidgetManager minMaxPointWidgetManager; + private AxesWidget axesWidget; +// private CORWidget corWidget; + private BoxWidget boxWidget; + private PlaneWidget planeWidget; + private PlaneDisplayWidget planeDisplayWidget; + private ExtractSelectionWidget selectionWidget; + private QualityWidget qualityWidget; + private LayersCoverageWidget layersWidget; + private LogoWidget logoWidget; + + private WidgetToolBar widgetToolBar; + private BoundingBoxBar boundingBoxBar; + private JPanel southPanel; + private WidgetPanel widgetPanel; + + private Mesh3DController meshController; + private Geometry3DController geometryController; + + private ILookAndFeel laf; + private ProgressMonitor monitor; + + @Inject + public VTKView3D(Model model, ILookAndFeel laf, Set viewElements, Set controllers, Set widgets, ProgressMonitor monitor) { + super(); + this.model = model; + this.laf = laf; + this.viewElements = viewElements; + this.view3DElements = new LinkedHashSet<>(); + this.widgets = widgets; + this.monitor = monitor; + this.renderPanel = new VTKRenderPanel(laf); + this.view3DController = new VTKView3DController(this); + this.controllers = new ArrayList<>(); + +// this.meshController = new VTKMesh3DController(model, monitor); +// this.geometryController = new VTKGeometry3DController(model, monitor); +// +// registerController(meshController); +// registerController(geometryController); + + for (Controller3D c : controllers) { + registerController(c); + } + + EventManager.registerEventListener(new HelyxView3DEventListener(this), View3DEvent.class); + } + + @Override + public void registerController(Controller3D controller) { + controller.setRenderPanel(renderPanel); + controllers.add(controller); + if (this.geometryController == null && controller instanceof Geometry3DController) { + this.geometryController = (Geometry3DController) controller; + } else if (this.meshController == null && controller instanceof Mesh3DController) { + this.meshController = (Mesh3DController) controller; + } + } + + @Override + public void layoutComponents() { + setLayout(new BorderLayout()); + + for (ViewElement element : viewElements) { + layoutElements(element); + } + + this.genericToolBar = new VTK3DActionsToolBar(model, laf); + this.widgetToolBar = new WidgetToolBar(widgets); + this.boundingBoxBar = new BoundingBoxBar(this, laf); + + this.southPanel = new JPanel(new BorderLayout()); + this.southPanel.add(boundingBoxBar, BorderLayout.SOUTH); + + add(genericToolBar, BorderLayout.EAST); + if (widgetToolBar.hasWidgets()) { + add(widgetToolBar, BorderLayout.NORTH); + } + + add(renderPanel, BorderLayout.CENTER); + add(southPanel, BorderLayout.SOUTH); + + initWidgets(); + + renderPanel.GetRenderer().AddObserver("EndEvent", this, "handleEndRendering"); + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + logoWidget.update(renderPanel.getSize()); + } + }); + } + + private void layoutElements(ViewElement element) { + View3DElement view3d = element.getView3D(); + view3d.install(this); + view3DElements.add(view3d); + elementsByClass.put(element.getClass(), view3d); + elementsByTitle.put(element.getTitle(), view3d); + } + + void handleEndRendering() { + ExecUtil.invokeLater(new Runnable() { + @Override + public void run() { + // double timeInSeconds = vtkRendererPanel.GetRenderer().GetLastRenderTimeInSeconds(); + // double fps = 1.0 / timeInSeconds; + // System.out.println("FPS " + fps); + BoundingBox bb = boundingBoxBar.update(); +// corWidget.update(bb); + } + }); + } + + private void initWidgets() { + for (Widget widget : widgets) { + widget.populate(this); + } + this.widgetPanel = new WidgetPanel(widgets); + this.axesWidget = new AxesWidget(renderPanel); + this.logoWidget = new LogoWidget(renderPanel); +// this.corWidget = new CORWidget(renderPanel); + this.planeWidget = new PlaneWidget(renderPanel); + this.planeDisplayWidget = new PlaneDisplayWidget(renderPanel); + this.selectionWidget = new ExtractSelectionWidget(renderPanel, monitor); + this.qualityWidget = new QualityWidget(model, renderPanel, monitor); + this.layersWidget = new LayersCoverageWidget(model, renderPanel, monitor); + this.boxWidget = new BoxWidget(renderPanel); + this.pointWidgetManager = new PointWidgetManager(renderPanel); + this.axisWidgetManager = new AxisWidgetManager(renderPanel); + this.minMaxPointWidgetManager = new MinMaxPointWidgetManager(renderPanel); + } + +// @Override +// public void start() { +// widgetPanel.clear(); +// vtkRendererPanel.resetZoomLater(); +// } + + @Override + public void load() { + for (Controller3D context : controllers) { + logger.info("[LOAD 3D] {}", context.getClass().getSimpleName()); + context.loadActors(); + } + + for (View3DElement element : view3DElements) { + logger.info("[LOAD 3D] {}", element.getClass().getSimpleName()); + _load3D(element); + } + + logger.info("[LOAD] 3D Widgets"); + loadWidgets(); + } + + private void _load3D(final View3DElement view3DElement) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + view3DElement.load(VTKView3D.this); + } + }); + } + + @Override + public void save() { +// if (view3DElement == currentElement) { +// view3DElement.save(this); +// } + } + + @Override + public void stop(Class klass) { + stopWidgets(); + if (elementsByClass.containsKey(klass)) { + final View3DElement view3DElement = elementsByClass.get(klass); + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + view3DElement.stop(VTKView3D.this); + view3DElement.save(VTKView3D.this); + } + }); + } + } + + @Override + public void start(Class klass) { + if (klass == null) { + _start(view3DElements.iterator().next()); + resetZoom(); + } else if (elementsByClass.containsKey(klass)) { + _start(elementsByClass.get(klass)); + } + } + + private void _start(final View3DElement view3DElement) { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + view3DElement.start(VTKView3D.this); + } + }); + renderPanel.renderLater(); + } + + @Override + public void resetZoom() { + renderPanel.resetZoomAndWait(); + } + + @Override + public Geometry3DController getGeometryController() { + return geometryController; + } + + @Override + public Mesh3DController getMeshController() { + return meshController; + } + + @SuppressWarnings("unchecked") + @Override + public T getController(Class klass) { + for (Controller3D c : controllers) { + if (klass.isInstance(c)) { + return (T) c; + } + } + return null; + } + + public VTKRenderPanel getVTKRendererPanel() { + return renderPanel; + } + + @Override + public BoundingBox computeBoundingBox(boolean visibleOnly) { + return VTKUtil.computeBoundingBox(controllers, visibleOnly); + } + + @Override + public void geometryToMesh(GeometryToMesh g2m) { + renderPanel.clearSelection(); + + for (Controller3D controller : controllers) { + controller.geometryToMesh(g2m); + } + + for (View3DElement element : view3DElements) { + _load3D(element); + } + } + + @Override + public void clear() { + ExecUtil.invokeAndWait(new Runnable() { + @Override + public void run() { + renderPanel.lock(); + _clear(); + renderPanel.unlock(); + } + }); + } + + private void _clear() { + logger.info("[CLEAR] "); + renderPanel.clear(); + widgetPanel.clear(); + widgetToolBar.clear(); + + planeWidget.clear(); + planeDisplayWidget.clear(); + selectionWidget.clear(); + qualityWidget.clear(); + layersWidget.clear(); + pointWidgetManager.clear(); + axisWidgetManager.clear(); + minMaxPointWidgetManager.clear(); + + genericToolBar.clear(); + + for (Widget widget : widgets) { + widget.clear(); + } + axesWidget.clear(); +// corWidget.clear(); + + for (Controller3D context : controllers) { + context.clearContext(); + context.clear(); + } + + view3DController.setProjection(false); + VTKUtil.gc(true); + } + + public Dimension getMinimumSize() { + return new Dimension(50, 50); + } + + @Override + public JPanel getPanel() { + final JTabbedPane tabbedPane = new JTabbedPane(); + tabbedPane.addTab("", this); + UiUtil.setOneTabHide(tabbedPane); + final JPanel container = new JPanel(new BorderLayout()); + container.setBorder(BorderFactory.createEmptyBorder(23, 0, 0, 0)); + container.add(tabbedPane, BorderLayout.CENTER); + return container; + } + + @Override + public void showPoint(DoubleField[] point, String key, EventActionType action, Color color) { + pointWidgetManager.showPoint(point, key, action, color); + } + + @Override + public void showAxis(DoubleField[] origin, DoubleField[] normal, EventActionType action) { + axisWidgetManager.showPoint(origin, normal, action); + } + + @Override + public void showPlane(DoubleField[] origin, DoubleField[] normal, EventActionType action) { + BoundingBox bb = computeBoundingBox(true); + double diagonal = bb.getDiagonal() / 2; + double value = Double.isInfinite(diagonal) ? 1 : diagonal > 0 ? diagonal : 1; + planeWidget.showPlane(origin, normal, action, value); + } + + @Override + public void showPlaneDisplay(DoubleField[] origin, DoubleField[] normal, EventActionType action) { + BoundingBox bb = computeBoundingBox(true); + double diagonal = bb.getDiagonal() / 2; + double value = Double.isInfinite(diagonal) ? 1 : diagonal > 0 ? diagonal : 1; + planeDisplayWidget.showPlane(origin, normal, action, value); + } + + @Override + public void activateSelection(Selection selection, EventActionType action) { + selectionWidget.activateSelection(selection, action); + } + + @Override + public void showBox(DoubleField[] min, DoubleField[] max, EventActionType action) { + boxWidget.showBox(null, min, max, action); + } + + @Override + public void showMinMaxFieldPoints(String key, Kind kind, boolean visible) { + minMaxPointWidgetManager.setPointsVisible(key, kind, visible); + } + + @Override + public void updateMinAndMaxForFields(String varName, Point3d min, Point3d max) { + minMaxPointWidgetManager.updateCoordinates(min, max, varName); + } + + @Override + public void showQualityFields(QualityInfo qualityInfo, EventActionType action) { + qualityWidget.activateQualityField(qualityInfo, action); + } + + @Override + public void showLayersCoverage(LayerInfo layerInfo, JPanel colorBar, EventActionType action) { + layersWidget.activateLayersCoverage(layerInfo, colorBar, action); + } + + @Override + public boolean showWidget(Widget widget) { + if (widget.canShow()) { + widget.show(); + if (widget.getWidgetComponent() != null) { + showWidgetPanel(widget); + } + return true; + } else { + return false; + } + } + + @Override + public void showWidgetPanel(Widget widget) { + if (widgetPanel.isHidden()) { + southPanel.add(widgetPanel, BorderLayout.CENTER); + widgetPanel.setHidden(false); + } + widgetPanel.showPanel(widget.getWidgetComponent().getKey()); + southPanel.revalidate(); + } + + @Override + public void hideWidget(Widget widget) { + widget.hide(); + if (widget.getWidgetComponent() != null) { + hideWidgetPanel(widget); + } + } + + @Override + public void hideWidgetPanel(Widget widget) { + widgetPanel.hidePanel(widget.getWidgetComponent().getKey()); + if (widgetPanel.isEmpty()) { + widgetPanel.setHidden(true); + southPanel.remove(widgetPanel); + } + southPanel.revalidate(); + } + +// @Override +// public void handleInitializeFieldsStarted(){ +// for (Widget widget : widgets) { +// widget.handleInitializeFieldsStarted(); +// } +// } +// +// @Override +// public void handleInitializeFieldsFinished(){ +// for (Widget widget : widgets) { +// widget.handleInitializeFieldsFinished(); +// } +// } + + public void stopWidgets() { + for (Widget widget : widgets) { + widget.stop(); + } + } + + public void loadWidgets() { +// corWidget.on(); + for (Widget widget : widgets) { + widget.load(); + } + } + + public void updateWidgets_fieldChanged() { + for (Widget widget : widgets) { + widget.handleFieldChanged(); + } + } + + public void updateWidgets_timeStepChanged() { + for (Widget widget : widgets) { + widget.handleTimeStepChanged(); + } + } + + public void updateWidgets_newTimeStep() { + for (Widget widget : widgets) { + widget.handleNewTimeStepsRead(); + } + } + + public VTKView3DController getVTKController() { + return view3DController; + } + + public Model getModel() { + return model; + } + + public void dumpContext(Class klass) { + for (Controller3D c : controllers) { + c.dumpContext(klass); + } + } + + public void applyContext(Class klass) { + for (Controller3D c : controllers) { + c.applyContext(klass); + } + genericToolBar.update(controllers); + for (Widget widget : widgets) { + widget.applyContext(); + } + } + +} diff --git a/src/eu/engys/vtk/VTKView3DController.java b/src/eu/engys/vtk/VTKView3DController.java new file mode 100644 index 0000000..b26831b --- /dev/null +++ b/src/eu/engys/vtk/VTKView3DController.java @@ -0,0 +1,181 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import static eu.engys.vtk.VTK3DActionsToolBar._3D_AXIS_XNEG; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_AXIS_XPOS; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_AXIS_YNEG; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_AXIS_YPOS; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_AXIS_ZNEG; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_AXIS_ZPOS; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_LOAD_MESH; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_VIEW_EDGES; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_VIEW_OUTLINE; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_VIEW_PROFILE; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_VIEW_PROJECTIONS; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_VIEW_SURFACE; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_VIEW_WIREFRAME; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_ZOOM_IN; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_ZOOM_OUT; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_ZOOM_RESET; +import static eu.engys.vtk.VTK3DActionsToolBar._3D_ZOOM_TOBOX; +import eu.engys.core.presentation.Action; +import eu.engys.core.presentation.ActionContainer; +import eu.engys.core.presentation.ActionManager; +import eu.engys.core.presentation.ActionToggle; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.gui.view3D.CameraManager.Position; +import eu.engys.gui.view3D.Representation; + +public class VTKView3DController implements ActionContainer { + + private VTKRenderPanel vtkRendererPanel; + private VTKView3D view3D; + + public VTKView3DController(VTKView3D vtkView3D) { + this.view3D = vtkView3D; + this.vtkRendererPanel = vtkView3D.getVTKRendererPanel(); + ActionManager.getInstance().parseActions(this); + } + + @Override + public boolean isDemo() { + return false; + } + + @Action(key=_3D_LOAD_MESH) + public void loadMesh() { + view3D.getMeshController().showExternalMesh(); + view3D.load(); + view3D.start(null); + } + + @Action(key=_3D_AXIS_XPOS) + public void viewXPos() { + vtkRendererPanel.setCameraPosition(Position.X_POS); + } + + @Action(key=_3D_AXIS_XNEG) + public void viewXNeg() { + vtkRendererPanel.setCameraPosition(Position.X_NEG); + } + + @Action(key=_3D_AXIS_YPOS) + public void viewYPos() { + vtkRendererPanel.setCameraPosition(Position.Y_POS); + } + + @Action(key=_3D_AXIS_YNEG) + public void viewYNeg() { + vtkRendererPanel.setCameraPosition(Position.Y_NEG); + } + + @Action(key=_3D_AXIS_ZPOS) + public void viewZPos() { + vtkRendererPanel.setCameraPosition(Position.Z_POS); + } + + @Action(key=_3D_AXIS_ZNEG) + public void viewZNeg() { + vtkRendererPanel.setCameraPosition(Position.Z_NEG); + } + + @Action(key=_3D_ZOOM_IN) + public void zoomIn() { + vtkRendererPanel.wheelForward(); + } + + @Action(key=_3D_ZOOM_OUT) + public void zoomOut() { + vtkRendererPanel.wheelBackward(); + } + + @Action(key=_3D_ZOOM_TOBOX) + public void zoomToBox() { + vtkRendererPanel.getInteractor().setStyleToZoom(); + } + + @Action(key=_3D_ZOOM_RESET) + public void zoomReset() { + vtkRendererPanel.zoomReset(); + } + + @Action(key=_3D_VIEW_EDGES) + public void setRepresentationToSurfaceWithEdges() { + vtkRendererPanel.clearSelection(); + vtkRendererPanel.changeRepresentation(Representation.SURFACE_WITH_EDGES); + } + + @Action(key=_3D_VIEW_PROFILE) + public void setRepresentationToProfile() { + vtkRendererPanel.clearSelection(); + vtkRendererPanel.changeRepresentation(Representation.PROFILE); + } + + @Action(key=_3D_VIEW_SURFACE) + public void setRepresentationToSurface() { + vtkRendererPanel.clearSelection(); + vtkRendererPanel.changeRepresentation(Representation.SURFACE); + } + + @Action(key=_3D_VIEW_WIREFRAME) + public void setRepresentationToWireframe() { + vtkRendererPanel.clearSelection(); + vtkRendererPanel.changeRepresentation(Representation.WIREFRAME); + } + + @Action(key=_3D_VIEW_OUTLINE) + public void setRepresentationToOutline() { + vtkRendererPanel.clearSelection(); + vtkRendererPanel.changeRepresentation(Representation.OUTLINE); + } + + @ActionToggle(key=_3D_VIEW_PROJECTIONS, normal="perspective", selected="parallel") + public void setProjection(boolean parallel) { + if (parallel) { + vtkRendererPanel.ParallelProjectionOn(); + } else { + vtkRendererPanel.ParallelProjectionOff(); + } + } + + public void showScalarsForField(FieldItem fieldItem) { + view3D.getMeshController().showField(fieldItem); + view3D.getGeometryController().showField(fieldItem); + view3D.updateWidgets_fieldChanged(); + } + + public void showTimeStep(double time) { + view3D.getMeshController().showTimeStep(time); + view3D.updateWidgets_timeStepChanged(); + } + + public void readTimeSteps() { + view3D.getMeshController().readTimeSteps(); + view3D.updateWidgets_newTimeStep(); + } +} diff --git a/src/eu/engys/vtk/VTKView3DProvider.java b/src/eu/engys/vtk/VTKView3DProvider.java new file mode 100644 index 0000000..0baca03 --- /dev/null +++ b/src/eu/engys/vtk/VTKView3DProvider.java @@ -0,0 +1,82 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + + +//public class VTKView3DProvider implements Provider, Runnable { +// +// private CanvasPanel panel1; +// private ILookAndFeel laf; +// private Model model; +// private Set elements; +// private Set widgets; +// private ProgressMonitor monitor; +// private Set controllers; +// +// @Inject +// public VTKView3DProvider(Model model, ILookAndFeel laf, Set elements, Set controllers, Set widgets, ProgressMonitor monitor) { +// this.model = model; +// this.laf = laf; +// this.elements = elements; +// this.controllers = controllers; +// this.widgets = widgets; +// this.monitor = monitor; +// } +// +// @Override +// public void run() { +// if (!VTKSettings.librariesAreLoaded()) { +// VTKSettings.LoadAllNativeLibraries(); +// } +// if (VTKSettings.librariesAreLoaded()) { +// if (Arguments.no3D) { +// panel1 = new VTKEmptyView3D(model, controllers, monitor); +// } else { +// panel1 = new VTKView3D(model, laf, elements, controllers, widgets, monitor); +// } +// } else { +// panel1 = new FallbackView3D(); +// } +// } +// +// @Override +// public CanvasPanel get() { +// try { +// if (EventQueue.isDispatchThread()) { +// run(); +// } else { +// EventQueue.invokeAndWait(this); +// } +// } catch (InvocationTargetException e) { +// throw new RuntimeException(e); // should not happen +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// } +// +// return panel1; +// } +//} diff --git a/src/eu/engys/vtk/WidgetPanel.java b/src/eu/engys/vtk/WidgetPanel.java new file mode 100644 index 0000000..3afe9c8 --- /dev/null +++ b/src/eu/engys/vtk/WidgetPanel.java @@ -0,0 +1,106 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk; + +import java.awt.BorderLayout; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; + +import eu.engys.gui.view3D.widget.Widget; +import eu.engys.gui.view3D.widget.WidgetComponent; + +public class WidgetPanel extends JPanel { + + private JTabbedPane tabbedPane; + private Set components; + private Map componentsMap; + private boolean hidden = true; + + @Inject + public WidgetPanel(Set components) { + super(new BorderLayout()); + this.components = components; + this.componentsMap = new HashMap<>(); + layoutComponents(); + } + + private void layoutComponents() { + tabbedPane = new JTabbedPane(); + for (Widget widget : components) { + WidgetComponent widgetComponent = widget.getWidgetComponent(); + if (widgetComponent != null) { + componentsMap.put(widgetComponent.getKey(), widgetComponent); + } + } + add(tabbedPane, BorderLayout.CENTER); + } + + public void showPanel(String key) { + WidgetComponent c = componentsMap.get(key); + c.handleShow(); + if(getTabIndex(key) == -1){ + tabbedPane.addTab(key, c.getPanel()); + } + tabbedPane.setSelectedComponent(c.getPanel()); + } + + private int getTabIndex(String tab){ + for (int i = 0; i < tabbedPane.getTabCount(); i++) { + if(tabbedPane.getTitleAt(i).equals(tab)){ + return i; + } + } + return -1; + } + + public void hidePanel(String key) { + tabbedPane.removeTabAt(getTabIndex(key)); + } + + public boolean isEmpty() { + return tabbedPane.getTabCount() == 0; + } + + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + public boolean isHidden() { + return hidden; + } + + public void clear() { + for (WidgetComponent wc : componentsMap.values()) { + wc.clear(); + } + } +} diff --git a/src/eu/engys/vtk/WidgetToolBar.java b/src/eu/engys/vtk/WidgetToolBar.java new file mode 100644 index 0000000..f0883ca --- /dev/null +++ b/src/eu/engys/vtk/WidgetToolBar.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk; + +import static eu.engys.vtk.VTK3DActionsToolBar._3D_LOAD_MESH; + +import java.awt.FlowLayout; +import java.util.Set; + +import javax.swing.Box; +import javax.swing.JToolBar; + +import eu.engys.core.presentation.ActionManager; +import eu.engys.gui.view3D.widget.Widget; +import eu.engys.util.ui.WrappedFlowLayout; + +public class WidgetToolBar extends JToolBar { + + private Set widgets; + + public WidgetToolBar(Set widgets) { + super(JToolBar.HORIZONTAL); + setLayout(new WrappedFlowLayout(FlowLayout.LEFT, 0, 0)); + this.widgets = widgets; + putClientProperty("Synthetica.toolBar.buttons.paintBorder", Boolean.TRUE); + putClientProperty("Synthetica.opaque", Boolean.FALSE); + setFloatable(false); + setRollover(true); + layoutComponents(); + } + + private void layoutComponents() { + add(ActionManager.getInstance().get(_3D_LOAD_MESH)); + for (Widget widget : widgets) { + widget.populate(this); + } + add(Box.createHorizontalGlue()); + } + + public void clear() { + } + + public boolean hasWidgets() { + return widgets.size() > 0; + } + +} diff --git a/src/eu/engys/vtk/actions/ExtractLines.java b/src/eu/engys/vtk/actions/ExtractLines.java new file mode 100644 index 0000000..3373773 --- /dev/null +++ b/src/eu/engys/vtk/actions/ExtractLines.java @@ -0,0 +1,172 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actions; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkBox; +import vtk.vtkExtractGeometry; +import vtk.vtkFeatureEdges; +import vtk.vtkGeometryFilter; +import vtk.vtkPolyData; + +public class ExtractLines { + + private static final Logger logger = LoggerFactory.getLogger(ExtractLines.class); + + private vtkPolyData input; + + private double[] insideMin; + private double[] insideMax; + + private double[] outsideMin; + private double[] outsideMax; + + private double angle; + + private boolean boundary; + + private boolean manifold; + + private boolean nonmanifold; + + public ExtractLines() { + this.input = null; + this.insideMin = null; + this.insideMax = null; + this.outsideMin = null; + this.outsideMax = null; + } + + public void setInput(vtkPolyData input) { + this.input = input; + } + public void setAngle(double angle) { + this.angle = angle; + } + public void setInsideMin(double[] insideMin) { + this.insideMin = insideMin; + } + public void setInsideMax(double[] insideMax) { + this.insideMax = insideMax; + } + public void setOutsideMin(double[] outsideMin) { + this.outsideMin = outsideMin; + } + public void setOutsideMax(double[] outsideMax) { + this.outsideMax = outsideMax; + } + public void setBoundary(boolean boundary) { + this.boundary = boundary; + } + public void setManifold(boolean manifold) { + this.manifold = manifold; + } + public void setNonmanifold(boolean nonmanifold) { + this.nonmanifold = nonmanifold; + } + + public vtkPolyData execute() { + vtkFeatureEdges edges = new vtkFeatureEdges(); + if (boundary) { + edges.BoundaryEdgesOn(); + } else { + edges.BoundaryEdgesOff(); + } + if (manifold) { + edges.ManifoldEdgesOn(); + } else { + edges.ManifoldEdgesOff(); + } + if (nonmanifold) { + edges.NonManifoldEdgesOn(); + } else { + edges.NonManifoldEdgesOff(); + } + edges.FeatureEdgesOn(); + edges.SetFeatureAngle(angle); + edges.ColoringOff(); + edges.SetInputData(input); + edges.Update(); + + vtkPolyData output = edges.GetOutput(); + log("EDGES", output); + + if (insideMin != null && insideMax != null) { + vtkBox box = new vtkBox(); + box.SetXMin(insideMin); + box.SetXMax(insideMax); + + vtkExtractGeometry extract = new vtkExtractGeometry(); + extract.ExtractInsideOn(); + extract.ExtractBoundaryCellsOff(); + extract.SetImplicitFunction(box); + extract.SetInputData(output); + extract.Update(); + + vtkGeometryFilter geometry = new vtkGeometryFilter(); + geometry.SetInputData(extract.GetOutput()); + geometry.Update(); + + output = geometry.GetOutput(); + log("INSIDE", output); + } + + if (outsideMin != null && outsideMax != null) { + vtkBox box = new vtkBox(); + box.SetXMin(outsideMin); + box.SetXMax(outsideMax); + + vtkExtractGeometry extract = new vtkExtractGeometry(); + extract.ExtractInsideOff(); + extract.ExtractBoundaryCellsOff(); + extract.SetImplicitFunction(box); + extract.SetInputData(output); + extract.Update(); + + vtkGeometryFilter geometry = new vtkGeometryFilter(); + geometry.SetInputData(extract.GetOutput()); + geometry.Update(); + + output = geometry.GetOutput(); + log("OUTSIDE", output); + } + + return output; + } + + private void log(String title, vtkPolyData data) { + logger.info(title + "points: {}, cells: {}, lines: {}", data.GetNumberOfPoints(), data.GetNumberOfCells(), data.GetNumberOfLines()); +// final double[] bounds = data.GetBounds(); +// System.out.println(title + " Z : [" + bounds[4] + ", " + bounds[5] + "]"); +// System.out.println(title + " points: " + data.GetNumberOfPoints()); +// System.out.println(title + " cells : " + data.GetNumberOfCells()); +// System.out.println(title + " lines : " + data.GetNumberOfLines()); + + } + +} diff --git a/src/eu/engys/vtk/actions/ExtractSelection.java b/src/eu/engys/vtk/actions/ExtractSelection.java new file mode 100644 index 0000000..286a453 --- /dev/null +++ b/src/eu/engys/vtk/actions/ExtractSelection.java @@ -0,0 +1,377 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actions; + +import java.util.HashSet; +import java.util.Set; + +import javax.vecmath.Vector3d; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkCellData; +import vtk.vtkDataArray; +import vtk.vtkDataSet; +import vtk.vtkExtractPolyDataGeometry; +import vtk.vtkExtractSelection; +import vtk.vtkFloatArray; +import vtk.vtkGeometryFilter; +import vtk.vtkIdFilter; +import vtk.vtkIdList; +import vtk.vtkIdTypeArray; +import vtk.vtkPolyData; +import vtk.vtkPolyDataNormals; +import vtk.vtkSelection; +import vtk.vtkSelectionNode; +import eu.engys.gui.view3D.PickInfo; +import eu.engys.gui.view3D.Selection; +import eu.engys.gui.view3D.Selection.SelectionMode; + +public class ExtractSelection { + + private static final Logger logger = LoggerFactory.getLogger(ExtractSelection.class); + + private Selection selection; + + private vtkPolyData selectionData; + private vtkPolyData inverseSelectionData; + private vtkIdTypeArray list; + + public void setSelection(Selection selection) { + this.selection = selection; + } + + public void execute(PickInfo pi) { + + String name = (pi.actor != null ? pi.actor.getName() : null); + + logger.debug("------------- PICK --------------"); + logger.debug(" ACTOR : " + name); + logger.debug(" CELL : " + pi.cellId); + logger.debug(" FRUSTUM : " + (pi.frustum != null ? pi.frustum.GetClassName() : "null")); + if (selection.getDataSet() != null) { + logger.debug(" DATASET 1 "); + logger.debug(" hashcode : " + selection.getDataSet().hashCode()); + logger.debug(" cells : " + selection.getDataSet().GetNumberOfCells()); + logger.debug(" point : " + selection.getDataSet().GetNumberOfPoints()); + } else { + logger.debug(" DATASET 1 : " + "null"); + } + if (pi.dataSet != null) { + logger.debug(" DATASET 2 "); + logger.debug(" hashcode : " + pi.dataSet.hashCode()); + logger.debug(" cells : " + pi.dataSet.GetNumberOfCells()); + logger.debug(" points : " + pi.dataSet.GetNumberOfPoints()); + } else { + logger.debug(" DATASET 2 : " + "null"); + } + + boolean keepSelection = selection.isKeepSelection() || pi.control; + +// if (selection.getDataSet() != pi.dataSet) { +// return; +// } + + if (keepSelection) { + logger.debug("SELECTION: KEEP"); + this.list = selection.getIdList() != null ? selection.getIdList() : new vtkIdTypeArray(); + } else { + logger.debug("SELECTION: DISCARD"); + this.list = new vtkIdTypeArray(); + } + + switch (selection.getType()) { + case CELL: + logger.debug("PICK BY: CELL"); + pickByCell(pi); + break; + case AREA: + logger.debug("PICK BY: AREA"); + pickByArea(pi); + break; + case FEATURE: + logger.debug("PICK BY: FEATURE"); + pickByFeature(pi); + break; + + default: + break; + } + + applySelection(selection.getDataSet()); + + selection.setSelectionData(selectionData); + selection.setInverseSelectionData(inverseSelectionData); + selection.setIdList(list); + + logger.debug("SELECTION cells: "+selectionData.GetNumberOfCells()); + logger.debug("SELECTION points: "+selectionData.GetNumberOfPoints()); + logger.debug("---------------------------"); + } + + private void pickByCell(PickInfo pi) { + int cellId = pi.cellId; + if (cellId < 0) + return; + + performSelection(cellId); + } + + private void pickByArea(PickInfo pi) { + if (pi.frustum != null && pi.dataSet != null) { + + vtkDataSet input = selection.getDataSet();//pi.dataSet; + vtkIdFilter idFilter = new vtkIdFilter(); + idFilter.CellIdsOn(); +// idFilter.PointIdsOff(); +// idFilter.FieldDataOff(); + idFilter.SetIdsArrayName("originalCellIds"); + idFilter.SetInputData(input); + idFilter.Update(); + + vtkExtractPolyDataGeometry extractor = new vtkExtractPolyDataGeometry(); + extractor.SetInputData(idFilter.GetOutput()); + extractor.ExtractInsideOn(); + extractor.ExtractBoundaryCellsOff(); + extractor.SetImplicitFunction(pi.frustum); + extractor.Update(); + vtkDataSet output = extractor.GetOutput(); + + vtkIdTypeArray ids = (vtkIdTypeArray) output.GetCellData().GetArray("originalCellIds"); + if (ids != null) { + for (int i = 0; i < ids.GetNumberOfTuples(); i++) { + int id = ids.GetValue(i); + performSelection(id); + } + } + +// vtkExtractSelectedFrustum extractor = new vtkExtractSelectedFrustum(); +// extractor.SetInput(pi.dataSet); +// extractor.ShowBoundsOff(); +// extractor.PreserveTopologyOff(); +// extractor.SetFrustum(pi.frustum); +// extractor.Update(); +// vtkDataSet output = (vtkDataSet) extractor.GetOutput(); +// +// vtkIdTypeArray ids = (vtkIdTypeArray) output.GetCellData().GetArray("vtkOriginalCellIds"); +// if (ids != null) { +// for (int i = 0; i < ids.GetNumberOfTuples(); i++) { +// performSelection(ids.GetValue(i)); +// } +// } + } + } + + private void pickByFeature(PickInfo pi) { + double[] normal = pi.normal; + vtkDataSet input = pi.dataSet; + int cellId = pi.cellId; + + if (input == null) + return; + + vtkPolyData output = getNormalsDataSet(normal, input); + Set cells = new HashSet<>(); + + if (output.GetNumberOfCells() > 0 ) { + analyseNeighbours(cellId, output, cells); + + performSelection(cellId); + + for (Integer id : cells) { + performSelection(id); + } + } + + } + + private void analyseNeighbours(int cellId, vtkPolyData output, Set cells) { + vtkCellData outputData = output.GetCellData(); + vtkDataArray angles = outputData.GetVectors("Angles"); + + vtkIdList cellPointIds = new vtkIdList(); + output.GetCellPoints(cellId, cellPointIds); + + // neighbor cells may be listed multiple times + // use set instead of list to get a unique list of neighbors + Set neighbors = new HashSet<>(); + /* + * For each vertice of the cell, we calculate which cells uses that + * point. So if we make this, for each vertice, we have all the + * neighbors. In the case we use ''cellPointIds'' as a parameter of + * ''GeteCellNeighbors'', we will obtain an empty set. Because the only + * cell that is using that set of points is the current one. That is why + * we have to make each vertice at time. + */ + + for (int i = 0; i < cellPointIds.GetNumberOfIds(); i++) { + vtkIdList idList = new vtkIdList(); + idList.InsertNextId(cellPointIds.GetId(i)); + + // get the neighbors of the cell + vtkIdList neighborCellIds = new vtkIdList(); + + output.GetCellNeighbors(cellId, idList, neighborCellIds); + + for (int j = 0; j < neighborCellIds.GetNumberOfIds(); j++) { + int id = neighborCellIds.GetId(j); + double angle = angles.GetComponent(id, 0); + if (angle < selection.getFeatureAngle()) { + neighbors.add(id); + } + } + } + + Set newCells = new HashSet<>(); + for (Integer id : neighbors) { + if (!cells.contains(id)) { + newCells.add(id); + cells.add(id); + } + } + + if (!newCells.isEmpty()) { + for (Integer newCell : newCells) { + analyseNeighbours(newCell, output, cells); + } + } + } + + private vtkPolyData getNormalsDataSet(double[] normal, vtkDataSet dataSet) { + vtkPolyDataNormals normalsFilter = new vtkPolyDataNormals(); + normalsFilter.SetInputData(dataSet); + normalsFilter.SplittingOff(); + normalsFilter.SetFeatureAngle(60); + normalsFilter.ComputeCellNormalsOn(); + // normalsFilter.AutoOrientNormalsOn(); + normalsFilter.Update(); + + vtkPolyData output = normalsFilter.GetOutput(); + vtkCellData outputData = output.GetCellData(); + vtkDataArray normals = outputData.GetVectors("Normals"); + + vtkFloatArray angles = new vtkFloatArray(); + angles.SetName("Angles"); + + if (normals != null) { + for (int i = 0; i < normals.GetNumberOfTuples(); i++) { + double[] t = normals.GetTuple3(i); + double a = computeAngle(t, normal); + angles.InsertNextValue(a); + } + } + outputData.AddArray(angles); + return output; + } + + private double computeAngle(double[] t, double[] normal) { + Vector3d v = new Vector3d(t); + Vector3d n = new Vector3d(normal); + double angle = n.angle(v); + + return Math.toDegrees(angle); + } + + private void performSelection(int cellId) { + if (selection.getMode() == SelectionMode.SELECT) { + select(cellId); + } else { + deselect(cellId); + } + } + + private void select(int cellId) { + list.InsertNextValue(cellId); + } + + private void deselect(int cellId) { + int index = -1; + if ((index = alreadySelected(cellId)) >= 0) { + list.RemoveTuple(index); + } + } + + private int alreadySelected(int cellId) { + for (int i = 0; i < list.GetNumberOfTuples(); i++) { + if (list.GetValue(i) == cellId) { + return i; + } + } + return -1; + } + + private void applySelection(vtkDataSet dataSet) { + vtkSelection selection = new vtkSelection(); + vtkSelectionNode node = new vtkSelectionNode(); + node.SetContentType(4); //INDICES + node.SetFieldType(0); //CELL + node.SetSelectionList(list); + selection.AddNode(node); + + vtkExtractSelection filter = new vtkExtractSelection(); + filter.SetInputData(0, dataSet); + filter.SetInputData(1, selection); + filter.Update(); + + vtkGeometryFilter geom = new vtkGeometryFilter(); + geom.SetInputData(filter.GetOutput()); + geom.Update(); + + selectionData = geom.GetOutput(); + selection.Delete(); + node.Delete(); + filter.Delete(); + geom.Delete(); + + selection = new vtkSelection(); + node = new vtkSelectionNode(); + node.SetContentType(4); // INDICES + node.SetFieldType(0); // CELL + node.SetSelectionList(list); + node.GetProperties().Set(node.INVERSE(), 1); + selection.AddNode(node); + + filter = new vtkExtractSelection(); + filter.SetInputData(0, dataSet); + filter.SetInputData(1, selection); +// VTKProgressConsoleWrapper progressWrapper = new VTKProgressConsoleWrapper("", filter, monitor); +// filter.AddObserver("StartEvent", progressWrapper, "onStart"); +// filter.AddObserver("EndEvent", progressWrapper, "onEnd"); +// filter.AddObserver("ProgressEvent", progressWrapper, "onProgress"); + filter.Update(); + + geom = new vtkGeometryFilter(); + geom.SetInputData(filter.GetOutput()); + geom.Update(); + + inverseSelectionData = geom.GetOutput(); + selection.Delete(); + node.Delete(); + filter.Delete(); + geom.Delete(); + } +} diff --git a/src/eu/engys/vtk/actions/IntersectSurfaces.java b/src/eu/engys/vtk/actions/IntersectSurfaces.java new file mode 100644 index 0000000..1ff4c9c --- /dev/null +++ b/src/eu/engys/vtk/actions/IntersectSurfaces.java @@ -0,0 +1,111 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actions; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkIntersectionPolyDataFilter; +import vtk.vtkPolyData; +import vtk.vtkTriangleFilter; + +public class IntersectSurfaces { + + private static final Logger logger = LoggerFactory.getLogger(IntersectSurfaces.class); + + private vtkPolyData input1; + private vtkPolyData input2; + + private boolean triangulateInput1; + private boolean triangulateInput2; + + public IntersectSurfaces() { + this.input1 = null; + this.input2 = null; + } + + public void setInput1(vtkPolyData input1) { + this.input1 = input1; + } + public void setInput2(vtkPolyData input2) { + this.input2 = input2; + } + + public void setTriangulateInput1(boolean triangulateInput1) { + this.triangulateInput1 = triangulateInput1; + } + + public void setTriangulateInput2(boolean triangulateInput2) { + this.triangulateInput2 = triangulateInput2; + } + + public vtkPolyData execute() { + if (input1 != null && input2 != null) { + + vtkIntersectionPolyDataFilter intersect = new vtkIntersectionPolyDataFilter(); + + if (triangulateInput1) { + vtkTriangleFilter triangle = new vtkTriangleFilter(); + triangle.SetInputData(input1); + triangle.Update(); + + intersect.SetInputData(0, triangle.GetOutput()); + } else { + intersect.SetInputData(0, input1); + } + + if (triangulateInput2) { + vtkTriangleFilter triangle = new vtkTriangleFilter(); + triangle.SetInputData(input2); + triangle.Update(); + + intersect.SetInputData(1, triangle.GetOutput()); + } else { + intersect.SetInputData(1, input2); + } + + intersect.SplitFirstOutputOff(); + intersect.SplitSecondOutputOff(); + intersect.Update(); + + log("LINE", intersect.GetOutput()); + return intersect.GetOutput(); + } else { + return null; + } + } + + private void log(String title, vtkPolyData data) { + logger.info(title + "points: {}, cells: {}, lines: {}", data.GetNumberOfPoints(), data.GetNumberOfCells(), data.GetNumberOfLines()); + final double[] bounds = data.GetBounds(); + System.out.println(title + " Z : [" + bounds[4] + ", " + bounds[5] + "]"); + System.out.println(title + " points: " + data.GetNumberOfPoints()); + System.out.println(title + " cells : " + data.GetNumberOfCells()); + System.out.println(title + " lines : " + data.GetNumberOfLines()); + + } + +} diff --git a/src/eu/engys/vtk/actors/BoxActor.java b/src/eu/engys/vtk/actors/BoxActor.java new file mode 100644 index 0000000..1a9eba8 --- /dev/null +++ b/src/eu/engys/vtk/actors/BoxActor.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import eu.engys.core.project.geometry.surface.Box; + +public class BoxActor extends SurfaceActor { + + public BoxActor(Box box) { + super(box); + newActor(box.getDataSet(), box.isVisible()); + } +} diff --git a/src/eu/engys/vtk/actors/CylinderActor.java b/src/eu/engys/vtk/actors/CylinderActor.java new file mode 100644 index 0000000..318f178 --- /dev/null +++ b/src/eu/engys/vtk/actors/CylinderActor.java @@ -0,0 +1,38 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import eu.engys.core.project.geometry.surface.Cylinder; + +public class CylinderActor extends SurfaceActor { + + public CylinderActor(Cylinder cylinder) { + super(cylinder); + newActor(cylinder.getDataSet(), cylinder.isVisible()); + } + + +} diff --git a/src/eu/engys/vtk/actors/DefaultActor.java b/src/eu/engys/vtk/actors/DefaultActor.java new file mode 100644 index 0000000..ebbe0ef --- /dev/null +++ b/src/eu/engys/vtk/actors/DefaultActor.java @@ -0,0 +1,592 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import vtk.vtkActor; +import vtk.vtkDataSet; +import vtk.vtkDataSetSurfaceFilter; +import vtk.vtkFeatureEdges; +import vtk.vtkLookupTable; +import vtk.vtkMapper; +import vtk.vtkOutlineFilter; +import vtk.vtkPolyData; +import vtk.vtkPolyDataAlgorithm; +import vtk.vtkPolyDataMapper; +import vtk.vtkProperty; +import vtk.vtkQuadricClustering; +import vtk.vtkTransform; +import vtk.vtkUnstructuredGrid; +import eu.engys.core.project.geometry.stl.AffineTransform; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.Representation; +import eu.engys.util.PrefUtil; +import eu.engys.vtk.VTKColors; +import eu.engys.vtk.VTKUtil; + +public abstract class DefaultActor extends vtkActor implements Actor { + + private enum SelectionState {BASE, SELECTED, DESELECTED}; + + private static final double BASE_OPACITY = 1.0; + private static final double DESELECTION_OPACITY = 0.2; + private static final double SELECTION_OPACITY = 0.6; + + private vtkPolyDataMapper mapper; + private vtkPolyDataMapper LODMapper; + private String name; + private vtkQuadricClustering LODFilter; + private vtkTransform transform; + private vtkPolyDataMapper outlineMapper; + private vtkPolyDataAlgorithm outlineFilter; + private vtkFeatureEdges edges; + private vtkPolyDataMapper edgesMapper; + + private boolean outline; + private boolean profile; + private boolean scalar; + private SelectionState selectionState = SelectionState.BASE; + private boolean useDeselectedState = true; + + private vtkProperty DESELECTION_PROPERTY; + private vtkProperty SELECTION_PROPERTY; + private vtkProperty BASE_PROPERTY; + + private int memorySize; + private vtkActor selectionActor; + + public DefaultActor(String name) { + this.name = name; + this.transform = new vtkTransform(); + this.selectionActor = new vtkActor(); + + setUpBaseProperty(); + setUpSelectionProperty(); + setUpDeselectionProperty(); + } + + private void setUpBaseProperty() { + BASE_PROPERTY = new vtkProperty(); + BASE_PROPERTY.SetColor(VTKColors.WHITE); + BASE_PROPERTY.SetOpacity(BASE_OPACITY); + } + + private void applyCommonProperty(vtkActor actor) { + actor.GetProperty().SetRepresentationToSurface(); + actor.GetProperty().EdgeVisibilityOff(); + actor.GetProperty().SetEdgeColor(VTKColors.BLACK); + actor.GetProperty().SetLineWidth(1); + + actor.GetProperty().LightingOn(); + actor.GetProperty().SetAmbient(VTKColors.AMBIENT); + actor.GetProperty().SetDiffuse(VTKColors.DIFFUSE); + actor.GetProperty().SetSpecular(VTKColors.SPECULAR); + actor.GetProperty().SetSpecularPower(VTKColors.SPECULAR_POWER); + } + + private void applyBaseProperty(vtkActor actor) { + if (selectionState != SelectionState.BASE) { + actor.GetProperty().SetColor(BASE_PROPERTY.GetColor()); + actor.GetProperty().SetOpacity(BASE_PROPERTY.GetOpacity()); + } + } + + private void setUpSelectionProperty() { + SELECTION_PROPERTY = new vtkProperty(); + SELECTION_PROPERTY.SetColor(VTKColors.SELECTION_COLOR); + SELECTION_PROPERTY.SetOpacity(SELECTION_OPACITY); + } + + private void applySelectionProperty(vtkActor actor) { + if (selectionState != SelectionState.SELECTED) { + actor.GetProperty().SetColor(BASE_PROPERTY.GetColor()); + actor.GetProperty().SetOpacity(DESELECTION_PROPERTY.GetOpacity()); + } + } + + private void setUpDeselectionProperty() { + DESELECTION_PROPERTY = new vtkProperty(); + DESELECTION_PROPERTY.SetColor(VTKColors.DESELECTION_COLOR); + DESELECTION_PROPERTY.SetOpacity(DESELECTION_OPACITY); + } + + private void applyDeselectionProperty(vtkActor actor) { + actor.GetProperty().SetColor(DESELECTION_PROPERTY.GetColor()); + actor.GetProperty().SetOpacity(DESELECTION_PROPERTY.GetOpacity()); + } + + protected void newActor(vtkPolyData dataset, boolean visible) { + vtkPolyData input = new vtkPolyData(); + input.ShallowCopy(dataset); + + this.mapper = new vtkPolyDataMapper(); + this.mapper.ImmediateModeRenderingOff(); +// this.mapper.StaticOn(); +// VTKUtil.observe(mapper, getName()); + + SetMapper(mapper); + selectionActor.SetMapper(mapper); + + this.outlineMapper = new vtkPolyDataMapper(); + this.outlineFilter = new vtkOutlineFilter(); + + this.edgesMapper = new vtkPolyDataMapper(); + this.edges = new vtkFeatureEdges(); + this.edges.SetBoundaryEdges(1); + this.edges.SetFeatureEdges(1); + this.edges.SetNonManifoldEdges(0); + this.edges.SetManifoldEdges(0); + this.edges.SetFeatureAngle(30D); + this.edges.ColoringOff(); + + this.outline = false; + this.profile = false; + this.scalar = false; + + setInput(input); + + input.Delete(); + + SetVisibility(visible ? 1 : 0); + + applyCommonProperty(this); + applyCommonProperty(selectionActor); + applyBaseProperty(this); + selectionActor.GetProperty().SetColor(SELECTION_PROPERTY.GetColor()); + selectionActor.GetProperty().SetOpacity(SELECTION_PROPERTY.GetOpacity()); + } + + protected void newActor(vtkUnstructuredGrid dataset, boolean visible) { + vtkUnstructuredGrid input = new vtkUnstructuredGrid(); + input.ShallowCopy(dataset); + + vtkDataSetSurfaceFilter filter = new vtkDataSetSurfaceFilter(); + filter.SetInputData(input); + filter.PassThroughCellIdsOn(); + filter.PassThroughPointIdsOn(); + filter.Update(); + input.Delete(); + + newActor(filter.GetOutput(), visible); + filter.Delete(); + } + + void createLOD() + { + this.LODMapper.ImmediateModeRenderingOff(); + this.LODMapper.StaticOn(); +// VTKUtil.observe(LODMapper, "LOD_" + getName()); + + int dim = 30; + + this.LODFilter.UseInputPointsOn(); + this.LODFilter.CopyCellDataOn(); + this.LODFilter.UseInternalTrianglesOff(); + this.LODFilter.SetNumberOfDivisions(dim, dim, dim); + this.LODFilter.AutoAdjustNumberOfDivisionsOff(); + } + + @Override + public void setInput(vtkPolyData input) { +// System.out.println("DefaultActor.setInput() size: " + input.GetActualMemorySize() + " kB"); + mapper.RemoveAllInputs(); + mapper.SetInputData(input); + + int memory_limit = PrefUtil.getInt(PrefUtil._3D_LOCK_INTRACTIVE_MEMORY, 512); + this.memorySize = input.GetActualMemorySize(); + if (memorySize > memory_limit) { + if (LODMapper == null) { + this.LODMapper = new vtkPolyDataMapper(); + this.LODFilter = new vtkQuadricClustering(); + + createLOD(); + } + } else { + this.LODMapper = null; + this.LODFilter = null; + } + + if (LODMapper != null) { + LODFilter.RemoveAllInputs(); + LODFilter.SetInputData(input); + LODFilter.Update(); + + LODMapper.RemoveAllInputs(); + LODMapper.SetInputData(LODFilter.GetOutput()); + LODMapper.Update(); + } + + if (outlineFilter != null) { + outlineFilter.RemoveAllInputs(); + outlineFilter.SetInputData(input); + outlineFilter.Update(); + + outlineMapper.RemoveAllInputs(); + outlineMapper.SetInputData(outlineFilter.GetOutput()); + outlineMapper.Update(); + } + + if (edges != null) { + edges.RemoveAllInputs(); + edges.SetInputData(input); + edges.Update(); + + edgesMapper.RemoveAllInputs(); + edgesMapper.SetInputData(edges.GetOutput()); + edgesMapper.Update(); + } + } + + @Override + public void setInput(vtkUnstructuredGrid input) { + vtkPolyData filter = VTKUtil.geometryFilter(input); + setInput(filter); + } + + @Override + public void interactiveOn() { + if (!outline && !profile) { + if (LODMapper != null) { + SetMapper(LODMapper); + selectionActor.SetMapper(LODMapper); + } + } + } + + @Override + public void interactiveOff() { + if (!outline && !profile) { + if (LODMapper != null) { + SetMapper(mapper); + selectionActor.SetMapper(mapper); + } + } + } + + @Override + public String getName() { + return name; + } + + @Override + public void rename(String name) { + this.name = name; + } + + @Override + public vtkMapper getMapper() { + return GetMapper(); + } + + @Override + public boolean getVisibility() { + return GetVisibility() == 1; + } + + @Override + public void setVisibility(boolean onoff) { + SetVisibility(onoff ? 1 : 0); + selectionActor.SetVisibility(GetVisibility()); + } + + @Override + public double[] getBounds() { + return GetBounds(); + } + + @Override + public vtkActor getActor() { + return this; + } + + @Override + public vtkActor getSelectionActor() { + return selectionActor; + } + + @Override + public void deleteActor() { + if (LODFilter != null) { + LODMapper.RemoveAllInputs(); + LODMapper.Delete(); + LODFilter.RemoveAllInputs(); + LODFilter.Delete(); + } + vtkDataSet dataset = mapper.GetInputAsDataSet(); + + VTKUtil.deleteDataset(dataset); + + mapper.RemoveAllInputs(); + mapper.Delete(); + + selectionActor.SetMapper(null); + selectionActor.Delete(); + + SetMapper(null); + Delete(); + } + + @Override + public void transformActor(boolean save, AffineTransform t) { + vtkTransform transform = t.toVTK(this.transform); + + SetUserTransform(transform); + selectionActor.SetUserTransform(transform); + + if (save) { + this.transform = transform; + } + } + + @Override + public vtkTransform getUserTransform() { + return (vtkTransform) GetUserTransform(); + } + + @Override + public void setSolidColor(double[] color, double opacity) { + this.scalar = false; + setColor(color, opacity); + + scalarVisibilityOff(); + } + + @Override + public void setScalarColors(vtkLookupTable lut, FieldItem field) { + this.scalar = true; + setColor(VTKColors.WHITE, BASE_OPACITY); + + if (mapper != null) { + setScalarColor(mapper, lut, field); + } + + if (LODMapper != null) { + setScalarColor(LODMapper, lut, field); + } + } + + protected void setLineWidth(int width) { + GetProperty().SetLineWidth(width); + +// BASE_PROPERTY.SetLineWidth(width); +// SELECTION_PROPERTY.SetLineWidth(width); +// DESELECTION_PROPERTY.SetLineWidth(width); + } + + protected void setColor(double[] color, double opacity) { + GetProperty().SetColor(color); + GetProperty().SetOpacity(opacity); + + BASE_PROPERTY.SetColor(color); + BASE_PROPERTY.SetOpacity(opacity); + +// SELECTION_PROPERTY.SetColor(color); +// DESELECTION_PROPERTY.SetColor(color); + } + + private static void setScalarColor(vtkMapper mapper, vtkLookupTable lut, FieldItem field) { + mapper.SetLookupTable(lut); + mapper.UseLookupTableScalarRangeOn(); + mapper.ScalarVisibilityOn(); + mapper.SetColorModeToMapScalars(); + + if (field.getDataType().isCell()) { + mapper.SetScalarModeToUseCellFieldData(); + } else if (field.getDataType().isPoint()) { + mapper.SetScalarModeToUsePointFieldData(); + } + + mapper.SetScalarRange(lut.GetRange()); + mapper.SelectColorArray(field.getName()); + mapper.Update(); + } + + @Override + public void setRepresentation(Representation representation) { + switch (representation) { + case SURFACE: + GetProperty().SetRepresentationToSurface(); + GetProperty().EdgeVisibilityOff(); + +// BASE_PROPERTY.SetRepresentationToSurface(); +// BASE_PROPERTY.EdgeVisibilityOff(); + setOutLine(false); + setProfile(false); + break; + case WIREFRAME: + GetProperty().SetRepresentationToWireframe(); + GetProperty().EdgeVisibilityOff(); + +// BASE_PROPERTY.SetRepresentationToWireframe(); +// BASE_PROPERTY.EdgeVisibilityOff(); + setOutLine(false); + setProfile(false); + break; + case SURFACE_WITH_EDGES: + GetProperty().SetRepresentationToSurface(); + GetProperty().EdgeVisibilityOn(); + +// BASE_PROPERTY.SetRepresentationToSurface(); +// BASE_PROPERTY.EdgeVisibilityOn(); + setOutLine(false); + setProfile(false); + break; + case OUTLINE: +// GetProperty().SetRepresentationToSurface(); +// GetProperty().EdgeVisibilityOff(); +// +// BASE_PROPERTY.SetRepresentationToSurface(); +// BASE_PROPERTY.EdgeVisibilityOff(); + setProfile(false); + setOutLine(true); + break; + + case PROFILE: +// GetProperty().SetRepresentationToSurface(); +// GetProperty().EdgeVisibilityOff(); +// +// BASE_PROPERTY.SetRepresentationToSurface(); +// BASE_PROPERTY.EdgeVisibilityOff(); + setOutLine(false); + setProfile(true); + break; + + default: + break; + } + } + + private void setOutLine(boolean outline) { + if (outline) { + if (!this.outline) { + outlineActor(); + } + } else { + if (this.outline) { + deoutlineActor(); + } + } + this.outline = outline; + } + + private void setProfile(boolean profile) { + if (profile) { + if (!this.profile) { + profileActor(); + } + } else { + if (this.profile) { + deprofileActor(); + } + } + this.profile = profile; + } + + private void outlineActor() { + SetMapper(outlineMapper); + } + + private void deoutlineActor() { + SetMapper(mapper); + } + + private void profileActor() { + SetMapper(edgesMapper); + } + + private void deprofileActor() { + SetMapper(mapper); + } + + @Override + public void restoreFromSelection() { + if (this.selectionState != SelectionState.BASE) { + applyBaseProperty(this); + if (scalar) { + scalarVisibilityOn(); + } else { + scalarVisibilityOff(); + } + } + this.selectionState = SelectionState.BASE; + } + + @Override + public void selectActor() { + if (this.selectionState != SelectionState.SELECTED) { + applySelectionProperty(this); + scalarVisibilityOff(); + } + this.selectionState = SelectionState.SELECTED; + } + + @Override + public void deselectActor() { + if (useDeselectedState) { + if (this.selectionState != SelectionState.DESELECTED) { + applyDeselectionProperty(this); + scalarVisibilityOff(); + } + this.selectionState = SelectionState.DESELECTED; + } else { + restoreFromSelection(); + } + } + + private void scalarVisibilityOff() { + if (mapper != null) { + mapper.ScalarVisibilityOff(); + } + + if (LODMapper != null) { + LODMapper.ScalarVisibilityOff(); + } + } + + private void scalarVisibilityOn() { + if (mapper != null) { + mapper.ScalarVisibilityOn(); + } + + if (LODMapper != null) { + LODMapper.ScalarVisibilityOn(); + } + } + + @Override + public void deselectedStateOn() { + this.useDeselectedState = true; + } + @Override + public void deselectedStateOff() { + this.useDeselectedState = false; + } + + @Override + public int getMemorySize() { + return memorySize; + } +} diff --git a/src/eu/engys/vtk/actors/HelyxActor.java b/src/eu/engys/vtk/actors/HelyxActor.java new file mode 100644 index 0000000..42a8f34 --- /dev/null +++ b/src/eu/engys/vtk/actors/HelyxActor.java @@ -0,0 +1,516 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +//package eu.engys.vtk.actors; +// +//import org.apache.commons.lang.ArrayUtils; +// +//import vtk.vtkActor; +//import vtk.vtkDataSetSurfaceFilter; +//import vtk.vtkHELYXActor; +//import vtk.vtkLookupTable; +//import vtk.vtkMapper; +//import vtk.vtkPolyData; +//import vtk.vtkPolyDataMapper; +//import vtk.vtkProperty; +//import vtk.vtkTransform; +//import vtk.vtkUnstructuredGrid; +//import eu.engys.core.project.geometry.stl.AffineTransform; +//import eu.engys.core.project.mesh.FieldItem; +//import eu.engys.gui.view3D.Actor; +//import eu.engys.gui.view3D.Representation; +//import eu.engys.util.PrefUtil; +//import eu.engys.vtk.VTKColors; +//import eu.engys.vtk.VTKUtil; + +//public abstract class HelyxActor extends vtkHELYXActor implements Actor { +// +// private static final double BASE_OPACITY = 1.0; +// private static final double DESELECTION_OPACITY = BASE_OPACITY;//0.2; +// private static final double SELECTION_OPACITY = BASE_OPACITY;//0.95; +// +// private String name; +// private vtkTransform transform; +// +// private boolean outline; +// private boolean profile; +// private boolean scalar; +// +// private vtkProperty DESELECTION_PROPERTY; +// private vtkProperty SELECTION_PROPERTY; +// private vtkProperty baseProperty; +// private vtkPolyDataMapper mapper; +// +// public HelyxActor(String name) { +// this.name = name; +// this.transform = new vtkTransform(); +// +// setUpBaseProperty(); +// setUpSelectionProperty(); +// setUpDeselectionProperty(); +// } +// +// private void setUpBaseProperty() { +// baseProperty = new vtkProperty(); +// baseProperty.SetRepresentationToSurface(); +// baseProperty.EdgeVisibilityOff(); +// baseProperty.SetEdgeColor(VTKColors.BLACK); +// baseProperty.SetLineWidth(1); +// +//// baseProperty.SetColor(WHITE); +// baseProperty.LightingOn(); +// baseProperty.SetOpacity(BASE_OPACITY); +// +// baseProperty.SetAmbient(VTKColors.AMBIENT); +// baseProperty.SetDiffuse(VTKColors.DIFFUSE); +// baseProperty.SetSpecular(VTKColors.SPECULAR); +// baseProperty.SetSpecularPower(VTKColors.SPECULAR_POWER); +// } +// +// private void applyBaseProperty() { +// if (!ArrayUtils.isEquals(GetProperty().GetColor(), VTKColors.WHITE)) { +// GetProperty().SetRepresentationToSurface(); +// GetProperty().EdgeVisibilityOff(); +// GetProperty().SetEdgeColor(VTKColors.BLACK); +// GetProperty().SetLineWidth(1); +// +// GetProperty().SetColor(VTKColors.WHITE); +// GetProperty().LightingOn(); +// GetProperty().SetOpacity(BASE_OPACITY); +// +// GetProperty().SetAmbient(VTKColors.AMBIENT); +// GetProperty().SetDiffuse(VTKColors.DIFFUSE); +// GetProperty().SetSpecular(VTKColors.SPECULAR); +// GetProperty().SetSpecularPower(VTKColors.SPECULAR_POWER); +// } +// } +// +// private void setUpSelectionProperty() { +// SELECTION_PROPERTY = new vtkProperty(); +// SELECTION_PROPERTY.SetRepresentationToSurface(); +// SELECTION_PROPERTY.EdgeVisibilityOff(); +//// SELECTION_PROPERTY.EdgeVisibilityOn(); +// SELECTION_PROPERTY.SetEdgeColor(VTKColors.WHITE); +// SELECTION_PROPERTY.SetLineWidth(1); +// +// SELECTION_PROPERTY.SetColor(VTKColors.SELECTION_COLOR); +// SELECTION_PROPERTY.LightingOff(); +//// SELECTION_PROPERTY.SetOpacity(SELECTION_OPACITY); +// +// SELECTION_PROPERTY.SetAmbient(VTKColors.SELECTION_AMBIENT); +// SELECTION_PROPERTY.SetDiffuse(VTKColors.SELECTION_DIFFUSE); +// SELECTION_PROPERTY.SetSpecular(VTKColors.SELECTION_SPECULAR); +// SELECTION_PROPERTY.SetSpecularPower(VTKColors.SELECTION_SPECULAR_POWER); +// } +// +// private void applySelectionProperty() { +// if (ArrayUtils.isEquals(GetProperty().GetColor(), VTKColors.WHITE)) { +// GetProperty().SetRepresentationToSurface(); +// GetProperty().EdgeVisibilityOff(); +//// GetProperty().EdgeVisibilityOn(); +// GetProperty().SetEdgeColor(VTKColors.WHITE); +// GetProperty().SetLineWidth(1); +// +// GetProperty().SetColor(VTKColors.SELECTION_COLOR); +// GetProperty().LightingOn(); +//// SELECTION_PROPERTY.SetOpacity(SELECTION_OPACITY); +// +// GetProperty().SetAmbient(VTKColors.SELECTION_AMBIENT); +// GetProperty().SetDiffuse(VTKColors.SELECTION_DIFFUSE); +// GetProperty().SetSpecular(VTKColors.SELECTION_SPECULAR); +// GetProperty().SetSpecularPower(VTKColors.SELECTION_SPECULAR_POWER); +// } +// } +// +// private void setUpDeselectionProperty() { +// DESELECTION_PROPERTY = new vtkProperty(); +// DESELECTION_PROPERTY.SetOpacity(DESELECTION_OPACITY); +// +// DESELECTION_PROPERTY.SetColor(VTKColors.DESELECTION_COLOR); +// DESELECTION_PROPERTY.SetAmbient(VTKColors.SELECTION_AMBIENT); +// DESELECTION_PROPERTY.SetDiffuse(VTKColors.SELECTION_DIFFUSE); +// DESELECTION_PROPERTY.SetSpecular(VTKColors.SELECTION_SPECULAR); +// DESELECTION_PROPERTY.SetSpecularPower(VTKColors.SELECTION_SPECULAR_POWER); +// } +// +// private void applyDeselectionProperty() { +// GetProperty().SetOpacity(DESELECTION_OPACITY); +// +// GetProperty().SetColor(VTKColors.DESELECTION_COLOR); +// GetProperty().SetAmbient(VTKColors.SELECTION_AMBIENT); +// GetProperty().SetDiffuse(VTKColors.SELECTION_DIFFUSE); +// GetProperty().SetSpecular(VTKColors.SELECTION_SPECULAR); +// GetProperty().SetSpecularPower(VTKColors.SELECTION_SPECULAR_POWER); +// } +// +// protected void newActor(vtkPolyData dataset, boolean visible) { +// vtkPolyData input = new vtkPolyData(); +// input.ShallowCopy(dataset); +// +// this.mapper = new vtkPolyDataMapper(); +// SetMapper(mapper); +// //StaticOn(); +// +// this.outline = false; +// this.profile = false; +// this.scalar = false; +// +// setInput(input); +// +// input.Delete(); +// +// SetVisibility(visible ? 1 : 0); +// +// GetProperty().DeepCopy(baseProperty); +// } +// +// protected void newActor(vtkUnstructuredGrid dataset, boolean visible) { +// vtkUnstructuredGrid input = new vtkUnstructuredGrid(); +// input.ShallowCopy(dataset); +// +// vtkDataSetSurfaceFilter filter = new vtkDataSetSurfaceFilter(); +// filter.SetInputData(input); +// filter.PassThroughCellIdsOn(); +// filter.PassThroughPointIdsOn(); +// filter.Update(); +// input.Delete(); +// +// newActor(filter.GetOutput(), visible); +// filter.Delete(); +// } +// +// @Override +// public void setInput(vtkPolyData input) { +//// System.out.println("DefaultActor.setInput() size: " + input.GetActualMemorySize() + " kB"); +// mapper.RemoveAllInputs(); +// mapper.SetInputData(input); +// +// int memory = PrefUtil.getInt(PrefUtil._3D_LOCK_INTRACTIVE_MEMORY, 512); +// if (input.GetActualMemorySize() > memory) { +// SetEnableLOD(1); +// } else { +// SetEnableLOD(1); +// } +// +// } +// +// @Override +// public void setInput(vtkUnstructuredGrid input) { +// vtkPolyData filter = VTKUtil.geometryFilter(input); +// setInput(filter); +// } +// +// @Override +// public void interactiveOn() { +// if (!outline && !profile) { +// SetDisplayTypeToInteractive(); +// } +// } +// +// @Override +// public void interactiveOff() { +// if (!outline && !profile) { +// SetDisplayTypeToFull(); +// } +// } +// +// @Override +// public String getName() { +// return name; +// } +// +// @Override +// public void rename(String name) { +// this.name = name; +// } +// +// @Override +// public vtkMapper getMapper() { +// return GetMapper(); +// } +// +// @Override +// public boolean getVisibility() { +// return GetVisibility() == 1; +// } +// +// @Override +// public void setVisibility(boolean onoff) { +// SetVisibility(onoff ? 1 : 0); +// } +// +// @Override +// public double[] getBounds() { +// return GetBounds(); +// } +// +// @Override +// public vtkActor getActor() { +// return this; +// } +// +// @Override +// public void deleteActor() { +//// if (LODFilter != null) { +//// LODMapper.RemoveAllInputs(); +//// LODMapper.Delete(); +//// LODFilter.RemoveAllInputs(); +//// LODFilter.Delete(); +//// } +//// vtkDataSet dataset = mapper.GetInputAsDataSet(); +//// +//// VTKUtil.deleteDataset(dataset); +//// +//// mapper.RemoveAllInputs(); +//// mapper.Delete(); +// +// SetMapper(null); +// Delete(); +// } +// +// @Override +// public void transformActor(boolean save, AffineTransform t) { +// vtkTransform transform = t.toVTK(this.transform); +// +// SetUserTransform(transform); +// +// if (save) { +// this.transform = transform; +// } +// } +// +// @Override +// public vtkTransform getUserTransform() { +// return (vtkTransform) GetUserTransform(); +// } +// +// @Override +// public void setSolidColor(double[] color, double opacity) { +// this.scalar = false; +// setColor(color, opacity); +// +// scalarVisibilityOff(); +// } +// +// @Override +// public void setScalarColors(vtkLookupTable lut, FieldItem field) { +// this.scalar = true; +// setColor(VTKColors.WHITE, BASE_OPACITY); +// +//// if (mapper != null) { +//// setScalarColor(mapper, lut, field); +//// } +//// +//// if (LODMapper != null) { +//// setScalarColor(LODMapper, lut, field); +//// } +// } +// +// protected void setLineWidth(int width) { +// GetProperty().SetLineWidth(width); +// +// baseProperty.SetLineWidth(width); +// SELECTION_PROPERTY.SetLineWidth(width); +// DESELECTION_PROPERTY.SetLineWidth(width); +// } +// +// protected void setColor(double[] color, double opacity) { +// GetProperty().SetColor(color); +// GetProperty().SetOpacity(opacity); +// +// baseProperty.SetColor(color); +// baseProperty.SetOpacity(opacity); +// +//// SELECTION_PROPERTY.SetColor(color); +// +//// DESELECTION_PROPERTY.SetColor(color); +// } +// +// private static void setScalarColor(vtkMapper mapper, vtkLookupTable lut, FieldItem field) { +// mapper.SetLookupTable(lut); +// mapper.UseLookupTableScalarRangeOn(); +// mapper.ScalarVisibilityOn(); +// mapper.SetColorModeToMapScalars(); +// +// if (field.getDataType().isCell()) { +// mapper.SetScalarModeToUseCellFieldData(); +// } else if (field.getDataType().isPoint()) { +// mapper.SetScalarModeToUsePointFieldData(); +// } +// +// mapper.SetScalarRange(lut.GetRange()); +// mapper.SelectColorArray(field.getName()); +// mapper.Update(); +// } +// +// @Override +// public void setRepresentation(Representation representation) { +// switch (representation) { +// case SURFACE: +// GetProperty().SetRepresentationToSurface(); +// GetProperty().EdgeVisibilityOff(); +// +// baseProperty.SetRepresentationToSurface(); +// baseProperty.EdgeVisibilityOff(); +// setOutLine(false); +// setProfile(false); +// break; +// case WIREFRAME: +// GetProperty().SetRepresentationToWireframe(); +// GetProperty().EdgeVisibilityOff(); +// +// baseProperty.SetRepresentationToWireframe(); +// baseProperty.EdgeVisibilityOff(); +// setOutLine(false); +// setProfile(false); +// break; +// case SURFACE_WITH_EDGES: +// GetProperty().SetRepresentationToSurface(); +// GetProperty().EdgeVisibilityOn(); +// +// baseProperty.SetRepresentationToSurface(); +// baseProperty.EdgeVisibilityOn(); +// setOutLine(false); +// setProfile(false); +// break; +// case OUTLINE: +// GetProperty().SetRepresentationToSurface(); +// GetProperty().EdgeVisibilityOff(); +// +// baseProperty.SetRepresentationToSurface(); +// baseProperty.EdgeVisibilityOff(); +// setOutLine(true); +// setProfile(false); +// break; +// +// case PROFILE: +// GetProperty().SetRepresentationToSurface(); +// GetProperty().EdgeVisibilityOff(); +// +// baseProperty.SetRepresentationToSurface(); +// baseProperty.EdgeVisibilityOff(); +// setOutLine(false); +// setProfile(true); +// break; +// +// default: +// break; +// } +// } +// +// private void setOutLine(boolean outline) { +// if (outline) { +// if (!this.outline) { +// outlineActor(); +// } +// } else { +// if (this.outline) { +// deoutlineActor(); +// } +// } +// this.outline = outline; +// } +// +// private void setProfile(boolean profile) { +// if (profile) { +// if (!this.profile) { +// profileActor(); +// } +// } else { +// if (this.profile) { +// deprofileActor(); +// } +// } +// this.profile = profile; +// } +// +// private void outlineActor() { +// SetDisplayTypeToOutline(); +// } +// +// private void deoutlineActor() { +// SetDisplayTypeToFull(); +// } +// +// private void profileActor() { +// SetDisplayTypeToProfile(); +// } +// +// private void deprofileActor() { +// SetDisplayTypeToFull(); +// } +// +// @Override +// public void restoreFromSelection() { +//// GetProperty().DeepCopy(baseProperty); +// applyBaseProperty(); +// +// if (scalar) { +// scalarVisibilityOn(); +// } else { +// scalarVisibilityOff(); +// } +// } +// +// @Override +// public void selectActor() { +//// GetProperty().DeepCopy(SELECTION_PROPERTY); +// applySelectionProperty(); +// +// scalarVisibilityOff(); +// } +// +// @Override +// public void deselectActor() { +//// GetProperty().DeepCopy(DESELECTION_PROPERTY); +//// applyDeselectionProperty(); +// applyBaseProperty(); +// +// scalarVisibilityOff(); +// } +// +// private void scalarVisibilityOff() { +// GetMapper().ScalarVisibilityOff(); +//// if (mapper != null) { +//// mapper.ScalarVisibilityOff(); +//// } +//// +//// if (LODMapper != null) { +//// LODMapper.ScalarVisibilityOff(); +//// } +// } +// +// private void scalarVisibilityOn() { +// GetMapper().ScalarVisibilityOn(); +//// if (mapper != null) { +//// mapper.ScalarVisibilityOn(); +//// } +//// +//// if (LODMapper != null) { +//// LODMapper.ScalarVisibilityOn(); +//// } +// } +// +//} diff --git a/src/eu/engys/vtk/actors/InternalMeshActor.java b/src/eu/engys/vtk/actors/InternalMeshActor.java new file mode 100644 index 0000000..442c07b --- /dev/null +++ b/src/eu/engys/vtk/actors/InternalMeshActor.java @@ -0,0 +1,46 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import vtk.vtkUnstructuredGrid; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +public class InternalMeshActor extends DefaultActor { + + public InternalMeshActor(vtkUnstructuredGrid internalMeshDataset) { + super("internalMesh"); + newActor(internalMeshDataset, false); + + GetMapper().ScalarVisibilityOff(); + VisibilityOff(); + GetProperty().SetOpacity(1); + } + + @Override + public VisibleItem getVisibleItem() { + return null; + } +} diff --git a/src/eu/engys/vtk/actors/LineActor.java b/src/eu/engys/vtk/actors/LineActor.java new file mode 100644 index 0000000..9e52752 --- /dev/null +++ b/src/eu/engys/vtk/actors/LineActor.java @@ -0,0 +1,47 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.gui.view3D.Representation; +import eu.engys.vtk.VTKColors; + + +public class LineActor extends SurfaceActor { + + public LineActor(FeatureLine line) { + super(line); + setColor(VTKColors.toVTK(line.getColor()), 1.0); + setLineWidth(2); + newActor(line.getDataSet(), line.isVisible()); + } + + @Override + public void setRepresentation(Representation representation) { + // do nothing!!! + } + +} diff --git a/src/eu/engys/vtk/actors/PlaneActor.java b/src/eu/engys/vtk/actors/PlaneActor.java new file mode 100644 index 0000000..9999976 --- /dev/null +++ b/src/eu/engys/vtk/actors/PlaneActor.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import eu.engys.core.project.geometry.surface.Plane; + +public class PlaneActor extends SurfaceActor { + + public PlaneActor(Plane plane) { + super(plane); + newActor(plane.getDataSet(), plane.isVisible()); + } +} diff --git a/src/eu/engys/vtk/actors/PlaneRegionActor.java b/src/eu/engys/vtk/actors/PlaneRegionActor.java new file mode 100644 index 0000000..0d86195 --- /dev/null +++ b/src/eu/engys/vtk/actors/PlaneRegionActor.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import vtk.vtkLookupTable; +import eu.engys.core.project.geometry.surface.PlaneRegion; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.gui.view3D.Representation; +import eu.engys.vtk.VTKColors; +import eu.engys.vtk.actors.SurfaceToActor.ActorMode; + +public class PlaneRegionActor extends SurfaceActor { + + private ActorMode mode; + + public PlaneRegionActor(PlaneRegion plane, ActorMode mode) { + super(plane); + this.mode = mode; + newActor(plane.getDataSet(), plane.isVisible()); + if (mode == ActorMode.DEFAULT) { + setColor(VTKColors.CYAN, 0.5); + } + } + + @Override + public void setRepresentation(Representation representation) { + if (mode == ActorMode.DEFAULT) { + super.setRepresentation(Representation.SURFACE_WITH_EDGES); + } else { + super.setRepresentation(representation); + } + } + + @Override + public void setScalarColors(vtkLookupTable lut, FieldItem field) { + if (mode == ActorMode.VIRTUALISED) { + super.setScalarColors(lut, field); + } + } + + @Override + public void setSolidColor(double[] color, double opacity) { + if (mode == ActorMode.VIRTUALISED) { + super.setSolidColor(color, opacity); + } + } +} diff --git a/src/eu/engys/vtk/actors/RingActor.java b/src/eu/engys/vtk/actors/RingActor.java new file mode 100644 index 0000000..f7458d2 --- /dev/null +++ b/src/eu/engys/vtk/actors/RingActor.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import eu.engys.core.project.geometry.surface.Ring; + +public class RingActor extends SurfaceActor { + + public RingActor(Ring ring) { + super(ring); + newActor(ring.getDataSet(), ring.isVisible()); + } +} diff --git a/src/eu/engys/vtk/actors/SolidActor.java b/src/eu/engys/vtk/actors/SolidActor.java new file mode 100644 index 0000000..419f2d1 --- /dev/null +++ b/src/eu/engys/vtk/actors/SolidActor.java @@ -0,0 +1,38 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import eu.engys.core.project.geometry.surface.Solid; + + +public class SolidActor extends SurfaceActor { + + public SolidActor(Solid solid) { + super(solid); + newActor(solid.getDataSet(), solid.isVisible()); + transformActor(true, solid.getTransformation()); + } +} diff --git a/src/eu/engys/vtk/actors/SphereActor.java b/src/eu/engys/vtk/actors/SphereActor.java new file mode 100644 index 0000000..132bdd6 --- /dev/null +++ b/src/eu/engys/vtk/actors/SphereActor.java @@ -0,0 +1,36 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import eu.engys.core.project.geometry.surface.Sphere; + +public class SphereActor extends SurfaceActor { + + public SphereActor(Sphere sphere) { + super(sphere); + newActor(sphere.getDataSet(), sphere.isVisible()); + } +} diff --git a/src/eu/engys/vtk/actors/StlActor.java b/src/eu/engys/vtk/actors/StlActor.java new file mode 100644 index 0000000..6a71460 --- /dev/null +++ b/src/eu/engys/vtk/actors/StlActor.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import vtk.vtkAppendPolyData; +import vtk.vtkCleanPolyData; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.core.project.geometry.surface.Stl; + + +public class StlActor extends SurfaceActor { + + public StlActor(Stl stl) { + super(stl); + + vtkAppendPolyData append = new vtkAppendPolyData(); + + for (Solid solid : stl.getSolids()) { + append.SetInputData(solid.getDataSet()); + } + append.Update(); + + vtkCleanPolyData clean = new vtkCleanPolyData(); + clean.AddInputData(append.GetOutput()); + clean.Update(); + + newActor(clean.GetOutput(), stl.isVisible()); + append.Delete(); + clean.Delete(); + + transformActor(true, stl.getTransformation()); + } +} diff --git a/src/eu/engys/vtk/actors/SurfaceActor.java b/src/eu/engys/vtk/actors/SurfaceActor.java new file mode 100644 index 0000000..16900d3 --- /dev/null +++ b/src/eu/engys/vtk/actors/SurfaceActor.java @@ -0,0 +1,43 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.actors; + +import eu.engys.core.project.geometry.Surface; +import eu.engys.util.ui.checkboxtree.VisibleItem; + +abstract class SurfaceActor extends DefaultActor { + private Surface surface; + + public SurfaceActor(Surface surface) { + super(surface.getPatchName()); + this.surface = surface; + } + + @Override + public VisibleItem getVisibleItem() { + return surface; + } +} diff --git a/src/eu/engys/vtk/actors/SurfaceToActor.java b/src/eu/engys/vtk/actors/SurfaceToActor.java new file mode 100644 index 0000000..809c01a --- /dev/null +++ b/src/eu/engys/vtk/actors/SurfaceToActor.java @@ -0,0 +1,183 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.actors; + +import static eu.engys.util.FormatUtil.format; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.core.project.geometry.FeatureLine; +import eu.engys.core.project.geometry.Surface; +import eu.engys.core.project.geometry.surface.Box; +import eu.engys.core.project.geometry.surface.Cylinder; +import eu.engys.core.project.geometry.surface.MultiPlane; +import eu.engys.core.project.geometry.surface.Plane; +import eu.engys.core.project.geometry.surface.PlaneRegion; +import eu.engys.core.project.geometry.surface.Ring; +import eu.engys.core.project.geometry.surface.Solid; +import eu.engys.core.project.geometry.surface.Sphere; +import eu.engys.core.project.geometry.surface.Stl; +import eu.engys.gui.view3D.Actor; +import eu.engys.util.progress.ProgressMonitor; + +public class SurfaceToActor { + + public enum ActorMode { + DEFAULT, VIRTUALISED + }; + + private static final Logger logger = LoggerFactory.getLogger(SurfaceToActor.class); + + private final ActorMode mode; + private final ProgressMonitor monitor; + private final BoundingBox boundingBox; + + public SurfaceToActor(ActorMode mode, BoundingBox boundingBox, ProgressMonitor monitor) { + this.mode = mode; + this.boundingBox = boundingBox; + this.monitor = monitor; + } + + public Actor[] toActor(Surface surface) { + // System.out.println("SurfaceToActor.toActor() "+surface.getName() + " ["+surface.getType()+"] "+(surface.isVisible() ? "visible" : " NOT visible")); + switch (surface.getType()) { + case BOX: + Box box = (Box) surface; + return getBoxActor(box); + case CYLINDER: + Cylinder cyl = (Cylinder) surface; + return getCylinderActor(cyl); + case SPHERE: + Sphere sphere = (Sphere) surface; + return getSphereActor(sphere); + case RING: + Ring ring = (Ring) surface; + return getRingActor(ring); + case PLANE: + if (surface instanceof Plane) { + Plane plane = (Plane) surface; + return getPlaneActor(plane); + } else if (surface instanceof PlaneRegion) { + PlaneRegion plane = (PlaneRegion) surface; + return getPlaneRegionActor(plane); + } else { + return new SurfaceActor[0]; + } + case STL: + Stl stl = (Stl) surface; + return getSTLActor(stl); + case MULTI: + MultiPlane multi = (MultiPlane) surface; + return getMultiPlaneActor(multi); + case SOLID: + Solid solid = (Solid) surface; + return getSolidActor(solid); + case LINE: + FeatureLine line = (FeatureLine) surface; + return getLineActor(line); + default: + return null; + } + } + + private Actor[] getSTLActor(Stl stl) { + logger.info("[ADD STL] name: {}", stl.getPatchName()); + List actors = new ArrayList<>(); + if (mode == ActorMode.DEFAULT) { + try { + for (Solid solid : stl.getSolids()) { + actors.add(new SolidActor(solid)); + } + } catch (Throwable e) { + logger.error("Errors loading STL", e); + } + } else { + actors.add(new StlActor(stl)); + } + return actors.toArray(new Actor[0]); + } + + private Actor[] getSolidActor(Solid solid) { + logger.info("[ADD SOLID] name: {}", solid.getPatchName()); + return new Actor[] { new SolidActor(solid) }; + } + + private SurfaceActor[] getLineActor(FeatureLine line) { + logger.info("[ADD LINE] name: {}", line.getPatchName()); + return new SurfaceActor[] { new LineActor(line) }; + } + + private SurfaceActor[] getBoxActor(Box box) { + logger.info("[ADD BOX] min: {}, max: {}", format(box.getMin()).toCents(), format(box.getMax()).toCents()); + return new SurfaceActor[] { new BoxActor(box) }; + } + + private SurfaceActor[] getCylinderActor(Cylinder cylinder) { + logger.info("[ADD CYLINDER] point1: {}, point2: {}, radius: {}", format(cylinder.getPoint1()).toCents(), format(cylinder.getPoint2()).toCents(), format(cylinder.getRadius()).toCents()); + return new SurfaceActor[] { new CylinderActor(cylinder) }; + } + + private SurfaceActor[] getSphereActor(Sphere sphere) { + logger.info("[ADD SPHERE] center: {}, radius: {}", format(sphere.getCenter()).toCents(), sphere.getRadius()); + return new SurfaceActor[] { new SphereActor(sphere) }; + } + + private SurfaceActor[] getRingActor(Ring ring) { + logger.info("[ADD RING] point1: {}, point2: {}, innerRadius: {}, outerRadius: {}", format(ring.getPoint1()).toCents(), format(ring.getPoint2()).toCents(), ring.getInnerRadius(), ring.getOuterRadius()); + return new SurfaceActor[] { new RingActor(ring) }; + } + + private SurfaceActor[] getMultiPlaneActor(MultiPlane surface) { + logger.info("[ADD MULTIPLANE] name: {}", surface.getPatchName()); + List actors = new ArrayList<>(); + for (PlaneRegion plane : surface.getPlanes()) { + actors.add(new PlaneRegionActor(plane, mode)); + } + return actors.toArray(new SurfaceActor[0]); + } + + private SurfaceActor[] getPlaneRegionActor(PlaneRegion plane) { + logger.info("[ADD PLANE] name: {}", plane.getPatchName()); + return new SurfaceActor[] { new PlaneRegionActor(plane, mode) }; + } + + private SurfaceActor[] getPlaneActor(Plane plane) { + if (plane.getCenter() == null) { + plane.setCenter(boundingBox.getCenter()); + } + if (plane.getNormal() == null) { + plane.setNormal(new double[] {0, 0, 1}); + } + logger.info("[ADD PLANE] origin: {}, normal: {}", format(plane.getCenter()).toCents(), format(plane.getNormal()).toCents()); + return new SurfaceActor[] { new PlaneActor(plane) }; + } +} diff --git a/src/eu/engys/vtk/info/VTKArrayInformation.java b/src/eu/engys/vtk/info/VTKArrayInformation.java new file mode 100644 index 0000000..809a850 --- /dev/null +++ b/src/eu/engys/vtk/info/VTKArrayInformation.java @@ -0,0 +1,647 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.info; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import vtk.vtkAbstractArray; +import vtk.vtkDataArray; +import vtk.vtkObject; + +public class VTKArrayInformation { + String Name; + double[][] Ranges; + List ComponentNames; + String DefaultComponentName; + List InformationKeys; + int DataType; + int NumberOfComponents; + int NumberOfTuples; + boolean IsPartial; + private Object NumberOfInformationKeys; + +// namespace +// { +// typedef std::vector vtkInternalComponentNameBase; +// +// struct vtkPVArrayInformationInformationKey +// { +// vtkStdString Location; +// vtkStdString Name; +// }; +// +// typedef std::vector vtkInternalInformationKeysBase; +// } +// +// class vtkPVArrayInformation::vtkInternalComponentNames: +// public vtkInternalComponentNameBase +// { +// }; +// +// class vtkPVArrayInformation::vtkInternalInformationKeys: +// public vtkInternalInformationKeysBase +// { +// }; + + //---------------------------------------------------------------------------- + public VTKArrayInformation() + { + this.Initialize(); + } + + //---------------------------------------------------------------------------- + void Initialize() + { + this.Name = null; + this.DataType = VTKConstants.VTK_VOID; + this.NumberOfComponents = 0; + this.NumberOfTuples = 0; + + this.ComponentNames = new ArrayList<>(); + this.DefaultComponentName = null; + + this.Ranges = null; + this.IsPartial = false; + + this.InformationKeys = new ArrayList<>(); + } + + //---------------------------------------------------------------------------- + void PrintSelf(PrintStream os, String indent) + { + if (this.Name != null) + { + os.println(indent+"Name: " + this.Name); + } + os.println(indent+"DataType: " + this.DataType); + os.println(indent+"NumberOfComponents: " + this.NumberOfComponents); + if (this.ComponentNames != null) + { + os.println(indent+"ComponentNames:"); + for (int i = 0; i < this.ComponentNames.size(); ++i) + { + os.println(indent+indent+this.ComponentNames.get(i)); + } + } + os.println(indent+"NumberOfTuples: " + this.NumberOfTuples); + os.println(indent+"IsPartial: " + this.IsPartial); + + os.println(indent+"Ranges :"); + int num = this.NumberOfComponents; + if (num > 1) + { + ++num; + } + for (int idx = 0; idx < num; ++idx) + { + os.println(indent+indent+this.Ranges[idx][0] + ", " + this.Ranges[idx][1]); + } + + os.println(indent+"InformationKeys :"); + if(this.InformationKeys != null) + { +// num = this.NumberOfInformationKeys; +// for (idx = 0; idx < num; ++idx) +// { +// os + i2 + this.GetInformationKeyLocation(idx) + "::" +// + this.GetInformationKeyName(idx)); +// } + } else + { + os.println(indent+indent+"None"); + } + } + + //---------------------------------------------------------------------------- +// void vtkPVArrayInformation::SetNumberOfComponents(int numComps) +// { +// if (this.NumberOfComponents == numComps) +// { +// return; +// } +// if (this.Ranges) +// { +// delete[] this.Ranges; +// this.Ranges = NULL; +// } +// this.NumberOfComponents = numComps; +// if (numComps <= 0) +// { +// this.NumberOfComponents = 0; +// return; +// } +// if (numComps > 1) +// { // Extra range for vector magnitude (first in array). +// numComps = numComps + 1; +// } +// +// int idx; +// this.Ranges = new double[numComps * 2]; +// for (idx = 0; idx < numComps; ++idx) +// { +// this.Ranges[2 * idx] = VTK_DOUBLE_MAX; +// this.Ranges[2 * idx + 1] = -VTK_DOUBLE_MAX; +// } +// } + + //---------------------------------------------------------------------------- +// void vtkPVArrayInformation::SetComponentName(vtkIdType component, +// const char *name) +// { +// if (component < 0 || name == NULL) +// { +// return; +// } +// +// unsigned int index = static_cast (component); +// if (this.ComponentNames == NULL) +// { +// //delayed allocate +// this.ComponentNames +// = new vtkPVArrayInformation::vtkInternalComponentNames(); +// } +// +// if (index == this.ComponentNames.size()) +// { +// //the array isn't large enough, so we will resize +// this.ComponentNames.push_back(new vtkStdString(name)); +// return; +// } +// else if (index > this.ComponentNames.size()) +// { +// this.ComponentNames.resize(index + 1, NULL); +// } +// +// //replace an exisiting element +// vtkStdString *compName = this.ComponentNames.at(index); +// if (!compName) +// { +// compName = new vtkStdString(name); +// this.ComponentNames.at(index) = compName; +// } +// else +// { +// compName.assign(name); +// } +// } + + //---------------------------------------------------------------------------- +// const char* vtkPVArrayInformation::GetComponentName(vtkIdType component) +// { +// unsigned int index = static_cast (component); +// //check signed component for less than zero +// if (this.ComponentNames && component >= 0 && index +// < this.ComponentNames.size()) +// { +// vtkStdString *compName = this.ComponentNames.at(index); +// if (compName) +// { +// return compName.c_str(); +// } +// } +// else if (this.ComponentNames && component == -1 +// && this.ComponentNames.size() >= 1) +// { +// //we have a scalar array, and we need the component name +// vtkStdString *compName = this.ComponentNames.at(0); +// if (compName) +// { +// return compName.c_str(); +// } +// } +// //we have failed to find a user set component name, use the default component name +// this.DetermineDefaultComponentName(component, this.GetNumberOfComponents()); +// return this.DefaultComponentName.c_str(); +// } + + //---------------------------------------------------------------------------- +// void vtkPVArrayInformation::SetComponentRange(int comp, double min, double max) +// { +// if (comp >= this.NumberOfComponents || this.NumberOfComponents <= 0) +// { +// vtkErrorMacro("Bad component"); +// } +// if (this.NumberOfComponents > 1) +// { // Shift over vector mag range. +// ++comp; +// } +// if (comp < 0) +// { // anything less than 0 just defaults to the vector mag. +// comp = 0; +// } +// this.Ranges[comp * 2] = min; +// this.Ranges[comp * 2 + 1] = max; +// } + + //---------------------------------------------------------------------------- +// double* vtkPVArrayInformation::GetComponentRange(int comp) +// { +// if (comp >= this.NumberOfComponents || this.NumberOfComponents <= 0) +// { +// vtkErrorMacro("Bad component"); +// return NULL; +// } +// if (this.NumberOfComponents > 1) +// { // Shift over vector mag range. +// ++comp; +// } +// if (comp < 0) +// { // anything less than 0 just defaults to the vector mag. +// comp = 0; +// } +// return this.Ranges + comp * 2; +// } + + //---------------------------------------------------------------------------- +// void vtkPVArrayInformation::GetComponentRange(int comp, double *range) +// { +// double *ptr; +// +// ptr = this.GetComponentRange(comp); +// +// if (ptr == NULL) +// { +// range[0] = VTK_DOUBLE_MAX; +// range[1] = -VTK_DOUBLE_MAX; +// return; +// } +// +// range[0] = ptr[0]; +// range[1] = ptr[1]; +// } + + //---------------------------------------------------------------------------- +// void vtkPVArrayInformation::GetDataTypeRange(double range[2]) +// { +// int dataType = this.GetDataType(); +// switch (dataType) +// { +// case VTK_BIT: +// range[0] = VTK_BIT_MAX; +// range[1] = VTK_BIT_MAX; +// break; +// case VTK_UNSIGNED_CHAR: +// range[0] = VTK_UNSIGNED_CHAR_MIN; +// range[1] = VTK_UNSIGNED_CHAR_MAX; +// break; +// case VTK_CHAR: +// range[0] = VTK_CHAR_MIN; +// range[1] = VTK_CHAR_MAX; +// break; +// case VTK_UNSIGNED_SHORT: +// range[0] = VTK_UNSIGNED_SHORT_MIN; +// range[1] = VTK_UNSIGNED_SHORT_MAX; +// break; +// case VTK_SHORT: +// range[0] = VTK_SHORT_MIN; +// range[1] = VTK_SHORT_MAX; +// break; +// case VTK_UNSIGNED_INT: +// range[0] = VTK_UNSIGNED_INT_MIN; +// range[1] = VTK_UNSIGNED_INT_MAX; +// break; +// case VTK_INT: +// range[0] = VTK_INT_MIN; +// range[1] = VTK_INT_MAX; +// break; +// case VTK_UNSIGNED_LONG: +// range[0] = VTK_UNSIGNED_LONG_MIN; +// range[1] = VTK_UNSIGNED_LONG_MAX; +// break; +// case VTK_LONG: +// range[0] = VTK_LONG_MIN; +// range[1] = VTK_LONG_MAX; +// break; +// case VTK_FLOAT: +// range[0] = VTK_FLOAT_MIN; +// range[1] = VTK_FLOAT_MAX; +// break; +// case VTK_DOUBLE: +// range[0] = VTK_DOUBLE_MIN; +// range[1] = VTK_DOUBLE_MAX; +// break; +// default: +// // Default value: +// range[0] = 0; +// range[1] = 1; +// break; +// } +// } + //---------------------------------------------------------------------------- + void AddRanges(VTKArrayInformation info) + { + if (this.NumberOfComponents != info.NumberOfComponents) + { + System.err.println("Component mismatch."); + } + + double[] range = info.Ranges[0]; + if (this.NumberOfComponents > 1) + { + if (range[0] < this.Ranges[0][0]) + { + Ranges[0][0] = range[0]; + } + if (range[1] > Ranges[0][1]) + { + Ranges[0][1] = range[1]; + } + for (int idx = 0; idx < this.NumberOfComponents; ++idx) + { + range = info.Ranges[idx]; + if (range[0] < Ranges[idx+1][0]) + { + Ranges[idx+1][0] = range[0]; + } + if (range[1] > Ranges[idx+1][1]) + { + Ranges[idx+1][1] = range[1]; + } + } + } else { + if (range[0] < this.Ranges[0][0]) + { + Ranges[0][0] = range[0]; + } + if (range[1] > Ranges[0][1]) + { + Ranges[0][1] = range[1]; + } + } + + + this.NumberOfTuples += info.NumberOfTuples; + } + + //---------------------------------------------------------------------------- + void DeepCopy(VTKArrayInformation info) + { + this.Name = info.Name; + this.DataType = info.DataType; + this.NumberOfComponents = info.NumberOfComponents; + this.NumberOfTuples = info.NumberOfTuples; + + if (this.NumberOfComponents > 1) + { + this.Ranges = new double[this.NumberOfComponents+1][2]; + for (int idx = 0; idx < this.NumberOfComponents+1; ++idx) + { + this.Ranges[idx] = info.Ranges[idx]; + } + } else { + this.Ranges = new double[this.NumberOfComponents][2]; + this.Ranges[0] = info.Ranges[0]; + } + + + //clear the vector of old data + if (this.ComponentNames != null) + { + this.ComponentNames = null; + } + + if (info.ComponentNames != null) + { +// this.ComponentNames +// = new vtkPVArrayInformation::vtkInternalComponentNames(); +// //copy the passed in components if they exist +// this.ComponentNames.reserve(info.ComponentNames.size()); +// const char *name; +// for (unsigned i = 0; i < info.ComponentNames.size(); ++i) +// { +// name = info.GetComponentName(i); +// if (name) +// { +// this.SetComponentName(i, name); +// } +// } + } + + if (this.InformationKeys == null) + { + this.InformationKeys = new ArrayList<>(); + } + + //clear the vector of old data + this.InformationKeys.clear(); + + if (info.InformationKeys != null) + { +// //copy the passed in components if they exist +// for (unsigned i = 0; i < info.InformationKeys.size(); ++i) +// { +// this.InformationKeys.push_back(info.InformationKeys.at(i)); +// } + } + } + + //---------------------------------------------------------------------------- + boolean Compare(VTKArrayInformation info) { + if (info == null) { + return false; + } + if (info.Name.equals(this.Name) && info.NumberOfComponents == this.NumberOfComponents && this.NumberOfInformationKeys == info.NumberOfInformationKeys) { + return true; + } + return false; + } + + //---------------------------------------------------------------------------- + void CopyFromObject(vtkObject obj) + { + this.Initialize(); + + vtkAbstractArray array = (vtkAbstractArray) obj; +// if (!array) +// { +// vtkErrorMacro("Cannot downcast to abstract array."); +// this.Initialize(); +// return; +// } + + this.Name = array.GetName(); + this.DataType = array.GetDataType(); + this.NumberOfComponents = array.GetNumberOfComponents(); + this.NumberOfTuples = array.GetNumberOfTuples(); + + if (array.HasAComponentName()) + { + //copy the component names over + for (int i = 0; i < this.NumberOfComponents; ++i) + { + String name = array.GetComponentName(i); + if (name != null) + { + //each component doesn't have to be named + this.ComponentNames.add(i, name); + } + } + } + + if (obj instanceof vtkDataArray) + { + vtkDataArray data_array = (vtkDataArray) obj; + + if (this.NumberOfComponents > 1) + { + this.Ranges = new double[this.NumberOfComponents+1][2]; + // First store range of vector magnitude. + data_array.GetRange(this.Ranges[0], -1); + for (int idx = 0; idx < this.NumberOfComponents; ++idx) + { + data_array.GetRange(this.Ranges[idx+1], idx); + } + } else { + this.Ranges = new double[this.NumberOfComponents][2]; + data_array.GetRange(this.Ranges[0], 0); + } + } + +// if(this.InformationKeys) +// { +// this.InformationKeys.clear(); +// delete this.InformationKeys; +// this.InformationKeys = 0; +// } + if (array.HasInformation()) + { +// vtkInformation info = array.GetInformation(); +// vtkInformationIterator it = new vtkInformationIterator(); +// it.SetInformationWeak(info); +// it.GoToFirstItem(); +// while (!it.IsDoneWithTraversal()) +// { +// vtkInformationKey key = it.GetCurrentKey(); +// this.AddInformationKey(key.GetLocation(), key.GetName()); +// it.GoToNextItem(); +// } +// it.Delete(); + } + } + + //---------------------------------------------------------------------------- + void AddInformation(VTKArrayInformation info) + { + if (info == null) { + return; + } + + if (info.NumberOfComponents > 0) + { + if (this.NumberOfComponents == 0) + { + // If this object is uninitialized, copy. + this.DeepCopy(info); + } + else + { + // Leave everything but ranges and unique values as original, add ranges and unique values. + this.AddRanges(info); + //this.AddInformationKeys(info); + } + } + } + + //----------------------------------------------------------------------------- +// void DetermineDefaultComponentName( +// const int &component_no, const int &num_components) +// { +// if (!this.DefaultComponentName) +// { +// this.DefaultComponentName = new vtkStdString(); +// } +// +// this.DefaultComponentName.assign(vtkPVPostFilter::DefaultComponentName(component_no, num_components)); +// } + +// void AddInformationKeys(VTKArrayInformation info) +// { +// for (int k = 0; k < info.NumberOfInformationKeys; k++) +// { +// this.AddUniqueInformationKey(info.GetInformationKeyLocation(k), +// info.GetInformationKeyName(k)); +// } +// } + +// void AddInformationKey(String location, String name) +// { +// if(this.InformationKeys == null) +// { +// this.InformationKeys = new vtkInternalInformationKeys(); +// } +// vtkPVArrayInformationInformationKey info = vtkPVArrayInformationInformationKey(); +// info.Location = location; +// info.Name = name; +// this.InformationKeys.push_back(info); +// } + +// void AddUniqueInformationKey(String location, String name) +// { +// if (!this.HasInformationKey(location, name)) +// { +// this.AddInformationKey(location, name); +// } +// } + +// int GetNumberOfInformationKeys() +// { +// return static_cast(this.InformationKeys ? this.InformationKeys.size() : 0); +// } + +// String GetInformationKeyLocation(int index) +// { +// if (index < 0 || index >= this.GetNumberOfInformationKeys()) +// return NULL; +// +// return this.InformationKeys.at(index).Location; +// } + +// String GetInformationKeyName(int index) +// { +// if (index < 0 || index >= this.GetNumberOfInformationKeys()) +// return NULL; +// +// return this.InformationKeys.at(index).Name; +// } + +// int HasInformationKey(String location, String name) +// { +// for (int k = 0; k < this.GetNumberOfInformationKeys(); k++) +// { +// String key_location = this.GetInformationKeyLocation(k); +// String key_name = this.GetInformationKeyName(k); +// if (strcmp(location, key_location) == 0 && strcmp(name, key_name) == 0) +// { +// return 1; +// } +// } +// return 0; +// } + +} diff --git a/src/eu/engys/vtk/info/VTKCompositeDataInformation.java b/src/eu/engys/vtk/info/VTKCompositeDataInformation.java new file mode 100644 index 0000000..e04e62c --- /dev/null +++ b/src/eu/engys/vtk/info/VTKCompositeDataInformation.java @@ -0,0 +1,419 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.info; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import vtk.vtkCompositeDataSet; +import vtk.vtkDataObject; +import vtk.vtkInformation; +import vtk.vtkMultiBlockDataSet; +import vtk.vtkMultiPieceDataSet; +import vtk.vtkObject; + +public class VTKCompositeDataInformation { + + class DataInformation { + VTKDataInformation Info; + String Name; + } + + private boolean DataIsComposite; + private boolean DataIsMultiPiece; + private int NumberOfPieces; + private List ChildrenInformation; + + public VTKCompositeDataInformation() { + // this.Internal = new vtkPVCompositeDataInformationInternals; + this.DataIsComposite = false; + this.DataIsMultiPiece = false; + this.NumberOfPieces = 0; + // DON'T FORGET TO UPDATE Initialize(). + } + + boolean GetDataIsComposite() { + return DataIsComposite; + } + + boolean GetDataIsMultiPiece() { + return DataIsMultiPiece; + } + void PrintSelf(PrintStream os, String indent) + { + os.println(indent+"DataIsMultiPiece: " + this.DataIsMultiPiece); + os.println(indent+"DataIsComposite: " + this.DataIsComposite); + } + +// VTKDataInformation GetDataInformationForCompositeIndex(int index) +// { +// if (!this.DataIsComposite) +// { +// return null; +// } +// +// if (this.DataIsMultiPiece) +// { +// if (index < this.NumberOfPieces) { +// (*index)=-1; +// return null; +// } +// +// (*index) -= this.NumberOfPieces; +// } +// +// for ( DataInformation d : ChildrenInformation) +// { +// if (d.Info != null) +// { +// VTKDataInformation info = d.Info.GetDataInformationForCompositeIndex(index); +// if ( (*index) == -1) +// { +// return info; +// } +// } else { +// (*index)--; +// if ((*index) < 0) +// { +// return null; +// } +// } +// } +// return null; +// } + + void Initialize() { + this.DataIsMultiPiece = false; + this.NumberOfPieces = 0; + this.DataIsComposite = false; + this.ChildrenInformation = new ArrayList<>(); + } + + int GetNumberOfChildren() { + return this.DataIsMultiPiece ? this.NumberOfPieces : ChildrenInformation.size(); + } + + VTKDataInformation GetDataInformation(int idx) { + if (this.DataIsMultiPiece) { + return null; + } + + if (idx >= ChildrenInformation.size()) { + return null; + } + + return this.ChildrenInformation.get(idx).Info; + } + + String GetName(int idx) { + if (this.DataIsMultiPiece) { + return null; + } + + if (idx >= this.ChildrenInformation.size()) { + return null; + } + + return this.ChildrenInformation.get(idx).Name; + } + + void CopyFromObject(vtkObject object) { + this.Initialize(); + + if (!(object instanceof vtkCompositeDataSet)) { + return; + } + + vtkCompositeDataSet cds = (vtkCompositeDataSet) object; + this.DataIsComposite = true; + + if (object instanceof vtkMultiPieceDataSet) { + vtkMultiPieceDataSet mpDS = (vtkMultiPieceDataSet) object; + this.DataIsMultiPiece = true; + this.NumberOfPieces = mpDS.GetNumberOfPieces(); + return; + } + + if(object instanceof vtkMultiBlockDataSet){ + vtkMultiBlockDataSet mbds = (vtkMultiBlockDataSet) object; + for (int i = 0; i < mbds.GetNumberOfBlocks(); i++) { + VTKDataInformation childInfo = null; + vtkDataObject block = mbds.GetBlock(i); + if (block != null) { + if (block != null) { + childInfo = new VTKDataInformation(); + childInfo.CopyFromObject(block); + } + DataInformation d = new DataInformation(); + d.Info = childInfo; + + vtkInformation info = block.GetInformation(); + if (info.Has(cds.NAME()) != 0) { + d.Name = info.Get(cds.NAME()); + } + +// if (iter.HasCurrentMetaData() != 0) { +// vtkInformation info = iter.GetCurrentMetaData(); +// if (info.Has(cds.NAME()) != 0) { +// d.Name = info.Get(cds.NAME()); +// } +// } + + ChildrenInformation.add(d); + } + } + } + // vtkTimerLog::MarkEndEvent("Copying information from composite data"); + } + + + // void vtkPVCompositeDataInformation::CopyFromAMR(vtkUniformGridAMR* amr) + // { + // unsigned int num_levels = amr.GetNumberOfLevels(); + // if (num_levels == 0) + // { + // this.Internal.ChildrenInformation.clear(); + // } + // else + // { + // this.Internal.ChildrenInformation.resize(num_levels); + // } + // + // // we use this to "simulate" a composite tree from AMR + // vtkNew tempMultiPiece; + // vtkNew tempDSInfo; + // + // for (unsigned int level=0; level < num_levels; level++) + // { + // unsigned int num_datasets = amr.GetNumberOfDataSets(level); + // tempMultiPiece.SetNumberOfPieces(num_datasets); + // + // vtkNew levelInfo; + // levelInfo.CopyFromCompositeDataSetInitialize(tempMultiPiece.GetPointer()); + // + // // now fill up levelInfo with meta-data about arrays. + // for (unsigned int idx=0; idx < num_datasets; idx++) + // { + // vtkUniformGrid* dataset = amr.GetDataSet(level, idx); + // if (dataset) + // { + // tempDSInfo.CopyFromObject(dataset); + // levelInfo.AddInformation(tempDSInfo.GetPointer(), 1); + // } + // } + // levelInfo.CopyFromCompositeDataSetFinalize(tempMultiPiece.GetPointer()); + // this.Internal.ChildrenInformation[level].Info = levelInfo.GetPointer(); + // } + // } + + //Called to merge informations from two processess. + void AddInformation(VTKCompositeDataInformation info) + { + if (info == null) + { + System.err.println("Cound not cast object to data information."); + return; + } + + this.DataIsComposite = info.GetDataIsComposite(); + this.DataIsMultiPiece = info.GetDataIsMultiPiece(); + if (this.DataIsMultiPiece) + { + if (this.NumberOfPieces != info.NumberOfPieces) + { + // vtkWarningMacro("Mismatch in number of pieces among processes."); + } + if (info.NumberOfPieces > this.NumberOfPieces) + { + this.NumberOfPieces = info.NumberOfPieces; + } + return; + } + + int otherNumChildren = info.ChildrenInformation.size(); + int numChildren = this.ChildrenInformation.size(); + if ( otherNumChildren > numChildren) + { + numChildren = otherNumChildren; + //this.ChildrenInformation.resize(numChildren); + } + + for (int i=0; i < otherNumChildren; i++) + { + VTKDataInformation otherInfo = info.ChildrenInformation.get(i).Info; + VTKDataInformation localInfo = this.ChildrenInformation.get(i).Info; + if (otherInfo != null) + { + if (localInfo != null) + { + localInfo.AddInformation(otherInfo); + } + else + { + VTKDataInformation dinf = new VTKDataInformation(); + dinf.AddInformation(otherInfo); + this.ChildrenInformation.get(i).Info = dinf; + } + } + + String otherName = info.ChildrenInformation.get(i).Name; + String localName = this.ChildrenInformation.get(i).Name; + if (!otherName.isEmpty()) + { + if (!localName.isEmpty() && localName != otherName) + { + //vtkWarningMacro("Same block is named as \'" << localName.c_str() + // << "\' as well as \'" << otherName.c_str() << "\'"); + } + localName = otherName; + } + } + } + + // void vtkPVCompositeDataInformation::CopyToStream( + // vtkClientServerStream* css) + // { + // // vtkTimerLog::MarkStartEvent("Copying composite information to stream"); + // css.Reset(); + // *css << vtkClientServerStream::Reply + // << this.DataIsComposite + // << this.DataIsMultiPiece + // << this.NumberOfPieces; + // + // unsigned int numChildren = static_cast( + // this.Internal.ChildrenInformation.size()); + // *css << numChildren; + // + // for(unsigned i=0; i(length)); + // } + // } + // *css << numChildren; // DONE marker + // *css << vtkClientServerStream::End; + // // vtkTimerLog::MarkEndEvent("Copying composite information to stream"); + // } + // + // //---------------------------------------------------------------------------- + // void vtkPVCompositeDataInformation::CopyFromStream( + // const vtkClientServerStream* css) + // { + // this.Initialize(); + // + // if(!css.GetArgument(0, 0, &this.DataIsComposite)) + // { + // vtkErrorMacro("Error parsing data set type."); + // return; + // } + // + // if(!css.GetArgument(0, 1, &this.DataIsMultiPiece)) + // { + // vtkErrorMacro("Error parsing data set type."); + // return; + // } + // + // if(!css.GetArgument(0, 2, &this.NumberOfPieces)) + // { + // vtkErrorMacro("Error parsing number of pieces."); + // return; + // } + // + // unsigned int numChildren; + // if(!css.GetArgument(0, 3, &numChildren)) + // { + // vtkErrorMacro("Error parsing number of children."); + // return; + // } + // int msgIdx = 3; + // this.Internal.ChildrenInformation.resize(numChildren); + // + // while (1) + // { + // msgIdx++; + // unsigned int childIdx; + // if(!css.GetArgument(0, msgIdx, &childIdx)) + // { + // vtkErrorMacro("Error parsing data set type."); + // return; + // } + // if (childIdx >= numChildren) //receiver DONE marker. + // { + // break; + // } + // msgIdx++; + // + // const char* name = 0; + // if (!css.GetArgument(0, msgIdx, &name)) + // { + // vtkErrorMacro("Error parsing the name for the block."); + // return; + // } + // + // vtkTypeUInt32 length; + // std::vector data; + // vtkClientServerStream dcss; + // + // msgIdx++; + // // Data information. + // vtkPVDataInformation* dataInf = vtkPVDataInformation::New(); + // if(!css.GetArgumentLength(0, msgIdx, &length)) + // { + // vtkErrorMacro("Error parsing length of cell data information."); + // dataInf.Delete(); + // return; + // } + // data.resize(length); + // if(!css.GetArgument(0, msgIdx, &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing cell data information."); + // dataInf.Delete(); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // dataInf.CopyFromStream(&dcss); + // this.Internal.ChildrenInformation[childIdx].Info = dataInf; + // this.Internal.ChildrenInformation[childIdx].Name = name; + // dataInf.Delete(); + // } + // + // } + +} diff --git a/src/eu/engys/vtk/info/VTKConstants.java b/src/eu/engys/vtk/info/VTKConstants.java new file mode 100644 index 0000000..e87614c --- /dev/null +++ b/src/eu/engys/vtk/info/VTKConstants.java @@ -0,0 +1,68 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.info; + +public class VTKConstants { + + public static final int VTK_VOID = -1; + public static final int VTK_POLY_DATA = 0; + public static final int VTK_STRUCTURED_POINTS = 1; + public static final int VTK_STRUCTURED_GRID = 2; + public static final int VTK_RECTILINEAR_GRID = 3; + public static final int VTK_UNSTRUCTURED_GRID = 4; + public static final int VTK_PIECEWISE_FUNCTION = 5; + public static final int VTK_IMAGE_DATA = 6; + public static final int VTK_DATA_OBJECT = 7; + public static final int VTK_DATA_SET = 8; + public static final int VTK_POINT_SET = 9; + public static final int VTK_UNIFORM_GRID = 10; + public static final int VTK_COMPOSITE_DATA_SET = 11; + public static final int VTK_MULTIGROUP_DATA_SET = 12; + public static final int VTK_MULTIBLOCK_DATA_SET = 13; + public static final int VTK_HIERARCHICAL_DATA_SET = 14; + public static final int VTK_HIERARCHICAL_BOX_DATA_SET = 15; + public static final int VTK_GENERIC_DATA_SET = 16; + public static final int VTK_HYPER_OCTREE = 17; + public static final int VTK_TEMPORAL_DATA_SET = 18; + public static final int VTK_TABLE = 19; + public static final int VTK_GRAPH = 20; + public static final int VTK_TREE = 21; + public static final int VTK_SELECTION = 22; + public static final int VTK_DIRECTED_GRAPH = 23; + public static final int VTK_UNDIRECTED_GRAPH = 24; + public static final int VTK_MULTIPIECE_DATA_SET = 25; + public static final int VTK_DIRECTED_ACYCLIC_GRAPH = 26; + public static final int VTK_ARRAY_DATA = 27; + public static final int VTK_REEB_GRAPH = 28; + public static final int VTK_UNIFORM_GRID_AMR = 29; + public static final int VTK_NON_OVERLAPPING_AMR = 30; + public static final int VTK_OVERLAPPING_AMR = 31; + public static final int VTK_HYPER_TREE_GRID = 32; + public static final int VTK_MOLECULE = 33; + public static final int VTK_PISTON_DATA_OBJECT = 34; + public static final int VTK_PATH = 35; + +} diff --git a/src/eu/engys/vtk/info/VTKDataInformation.java b/src/eu/engys/vtk/info/VTKDataInformation.java new file mode 100644 index 0000000..2baac66 --- /dev/null +++ b/src/eu/engys/vtk/info/VTKDataInformation.java @@ -0,0 +1,1240 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.info; + +import java.io.PrintStream; + +import vtk.vtkAlgorithm; +import vtk.vtkAlgorithmOutput; +import vtk.vtkCompositeDataSet; +import vtk.vtkDataObject; +import vtk.vtkDataSet; +import vtk.vtkFieldData; +import vtk.vtkGenericDataSet; +import vtk.vtkImageData; +import vtk.vtkInformation; +import vtk.vtkMultiBlockDataSet; +import vtk.vtkObject; +import vtk.vtkPointSet; +import vtk.vtkRectilinearGrid; +import vtk.vtkStructuredGrid; +import vtk.vtkUniformGrid; +import eu.engys.util.Util; + +public class VTKDataInformation { + + private VTKCompositeDataInformation CompositeDataInformation = new VTKCompositeDataInformation(); + private VTKDataSetAttributesInformation PointDataInformation = new VTKDataSetAttributesInformation(); + private VTKDataSetAttributesInformation CellDataInformation = new VTKDataSetAttributesInformation(); + private VTKDataSetAttributesInformation VertexDataInformation = new VTKDataSetAttributesInformation(); + private VTKDataSetAttributesInformation EdgeDataInformation = new VTKDataSetAttributesInformation(); + private VTKDataSetAttributesInformation RowDataInformation = new VTKDataSetAttributesInformation(); + private VTKDataSetAttributesInformation FieldDataInformation = new VTKDataSetAttributesInformation(); + private VTKArrayInformation PointArrayInformation = new VTKArrayInformation(); + + private int CompositeDataSetType, DataSetType, NumberOfPoints, NumberOfCells, NumberOfRows, MemorySize, PolygonCount, NumberOfDataSets, HasTime, PortNumber; + private String DataClassName, TimeLabel, CompositeDataClassName; + private double[] Bounds; + private int[] Extent; + private double Time; + private boolean SortArrays; + + public VTKDataInformation() { + Initialize(); + } + + private void Initialize() { + this.DataSetType = -1; + this.CompositeDataSetType = -1; + this.NumberOfPoints = 0; + this.NumberOfCells = 0; + this.NumberOfRows = 0; + this.NumberOfDataSets = 0; + this.MemorySize = 0; + this.PolygonCount = 0; + this.Bounds = new double[6]; + this.Bounds[0] = this.Bounds[2] = this.Bounds[4] = Double.MAX_VALUE; + this.Bounds[1] = this.Bounds[3] = this.Bounds[5] = -Double.MAX_VALUE; + this.Extent = new int[6]; + this.Extent[0] = this.Extent[2] = this.Extent[4] = Integer.MAX_VALUE; + this.Extent[1] = this.Extent[3] = this.Extent[5] = -Integer.MAX_VALUE; + this.PointDataInformation.Initialize(); + this.CellDataInformation.Initialize(); + this.VertexDataInformation.Initialize(); + this.EdgeDataInformation.Initialize(); + this.RowDataInformation.Initialize(); + this.FieldDataInformation.Initialize(); + this.CompositeDataInformation.Initialize(); + this.PointArrayInformation.Initialize(); + this.DataClassName = ""; + this.CompositeDataClassName = ""; + // this.TimeSpan[0] = VTK_DOUBLE_MAX; + // this.TimeSpan[1] = -VTK_DOUBLE_MAX; + this.HasTime = 0; + this.Time = 0.0; + // this.SetTimeLabel(NULL); + } + + private void DeepCopy(VTKDataInformation dataInfo, boolean copyCompositeInformation) { + + this.DataSetType = dataInfo.DataSetType; + this.CompositeDataSetType = dataInfo.CompositeDataSetType; + this.DataClassName = dataInfo.DataClassName; + this.CompositeDataClassName = dataInfo.CompositeDataClassName; + + this.NumberOfDataSets = dataInfo.NumberOfDataSets; + + this.NumberOfPoints = dataInfo.NumberOfPoints; + this.NumberOfCells = dataInfo.NumberOfCells; + this.NumberOfRows = dataInfo.NumberOfRows; + this.MemorySize = dataInfo.MemorySize; + this.PolygonCount = dataInfo.PolygonCount; + + Util.deepCopy(dataInfo.Bounds, this.Bounds); + Util.deepCopy(dataInfo.Extent, this.Extent); + + // Copy attribute information. + this.PointDataInformation.DeepCopy(dataInfo.PointDataInformation); + this.CellDataInformation.DeepCopy(dataInfo.CellDataInformation); + this.VertexDataInformation.DeepCopy(dataInfo.VertexDataInformation); + this.EdgeDataInformation.DeepCopy(dataInfo.EdgeDataInformation); + this.RowDataInformation.DeepCopy(dataInfo.RowDataInformation); + this.FieldDataInformation.DeepCopy(dataInfo.FieldDataInformation); + if (copyCompositeInformation) { + this.CompositeDataInformation.AddInformation(dataInfo.CompositeDataInformation); + } + this.PointArrayInformation.AddInformation(dataInfo.PointArrayInformation); + + // double *timespan; + // timespan = dataInfo.GetTimeSpan(); + // this.TimeSpan[0] = timespan[0]; + // this.TimeSpan[1] = timespan[1]; + // this.SetTimeLabel(dataInfo.GetTimeLabel()); + } + + public void AddFromMultiBlockDataSet(vtkMultiBlockDataSet data) { + for (int i = 0; i < data.GetNumberOfBlocks(); i++) { + vtkDataObject block = data.GetBlock(i); + if (block != null) { + VTKDataInformation dinf = new VTKDataInformation(); + dinf.CopyFromObject(block); + dinf.DataClassName = block.GetClassName(); + dinf.DataSetType = block.GetDataObjectType(); + this.AddInformation(dinf, true); + block.Delete(); + } + } + + } + + public void CopyFromObject(vtkObject object) { + vtkDataObject dobj = null; + vtkInformation info = null; + // Handle the case where the a vtkAlgorithmOutput is passed instead of + // the data object. vtkSMPart uses vtkAlgorithmOutput. + if (!(object instanceof vtkDataObject)) { + if (object instanceof vtkAlgorithmOutput) { + vtkAlgorithmOutput algOutput = (vtkAlgorithmOutput) object; + vtkAlgorithm producer = algOutput.GetProducer(); + if (producer != null && producer.GetClassName().equals("vtkPVNullSource")) { + // Don't gather any data information from the hypothetical + // null source. + return; + } + + if (producer.IsA("vtkPVPostFilter") == 0) { + algOutput = producer.GetInputConnection(0, 0); + } + info = producer.GetOutputPortInformation(this.PortNumber); + dobj = producer.GetOutputDataObject(algOutput.GetIndex()); + + producer.Delete(); + algOutput.Delete(); + } else if (object instanceof vtkAlgorithm) { + vtkAlgorithm algo = (vtkAlgorithm) object; + // We don't use vtkAlgorithm::GetOutputDataObject() since that + // call a UpdateDataObject() pass, which may raise errors if the + // algo + // is not fully setup yet. + if (algo.GetClassName().equals("vtkPVNullSource")) { + // Don't gather any data information from the hypothetical + // null source. + return; + } + info = algo.GetExecutive().GetOutputInformation(this.PortNumber); + // if (!info || vtkDataObject::GetData(info) == NULL) + // { + // return; + // } + dobj = algo.GetOutputDataObject(this.PortNumber); + algo.Delete(); + } + } else { + dobj = (vtkDataObject) object; + } + + if (object instanceof vtkCompositeDataSet) { + vtkCompositeDataSet cds = (vtkCompositeDataSet) dobj; + this.CopyFromCompositeDataSet(cds); + this.CopyCommonMetaData(cds, info); + return; + } + + if (object instanceof vtkDataSet) { + vtkDataSet ds = (vtkDataSet) dobj; + this.CopyFromDataSet(ds); + this.CopyCommonMetaData(ds, info); + return; + } + + if (object instanceof vtkGenericDataSet) { + vtkGenericDataSet ads = (vtkGenericDataSet) dobj; + this.CopyFromGenericDataSet(ads); + this.CopyCommonMetaData(ads, info); + return; + } + + // vtkGraph* graph = vtkGraph::SafeDownCast(dobj); + // if( graph) + // { + // this.CopyFromGraph(graph); + // this.CopyCommonMetaData(dobj, info); + // return; + // } + // + // vtkTable* table = vtkTable::SafeDownCast(dobj); + // if (table) + // { + // this.CopyFromTable(table); + // this.CopyCommonMetaData(dobj, info); + // return; + // } + // + // vtkSelection* selection = vtkSelection::SafeDownCast(dobj); + // if (selection) + // { + // this.CopyFromSelection(selection); + // this.CopyCommonMetaData(dobj, info); + // return; + // } + // + // String cname = dobj.GetClassName(); + // vtkPVDataInformationHelper *dhelper = + // vtkPVDataInformation::FindHelper + // (cname); + // if (dhelper) + // { + // dhelper.CopyFromDataObject(this, dobj); + // this.CopyCommonMetaData(dobj, info); + // dhelper.Delete(); + // return; + // } + + // Because custom applications may implement their own data + // object types, this isn't an error condition - just + // display the name of the data object and return quietly. + this.DataClassName = dobj.GetClassName(); + this.CopyCommonMetaData(dobj, info); + } + + private void CopyFromCompositeDataSetInitialize(vtkCompositeDataSet data) { + this.Initialize(); + this.CompositeDataInformation.CopyFromObject(data); + } + + private void CopyFromCompositeDataSetFinalize(vtkCompositeDataSet data) { + this.CompositeDataClassName = data.GetClassName(); + this.CompositeDataSetType = data.GetDataObjectType(); + + if (this.DataSetType == -1) { + // This is a composite dataset with no non-empty leaf node. Set some + // data type (Look at BUG #7144). + this.DataClassName = "vtkDataSet"; + this.DataSetType = VTKConstants.VTK_DATA_SET; + } + } + + private void CopyFromCompositeDataSet(vtkCompositeDataSet data) { + this.CopyFromCompositeDataSetInitialize(data); + + int numDataSets = this.CompositeDataInformation.GetNumberOfChildren(); + if (this.CompositeDataInformation.GetDataIsMultiPiece()) { + } else { + for (int cc = 0; cc < numDataSets; cc++) { + VTKDataInformation childInfo = this.CompositeDataInformation.GetDataInformation(cc); + if (childInfo != null) { + this.AddInformation(childInfo, true); + } + } + } + + this.CopyFromCompositeDataSetFinalize(data); + + // AddInformation should have updated NumberOfDataSets correctly to + // count number of non-zero datasets. We don't need to fix it here. + // this.NumberOfDataSets = numDataSets; + } + + private void CopyCommonMetaData(vtkDataObject data, vtkInformation pinfo) { + // Gather some common stuff + // if (pinfo && + // pinfo.Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE())) + // { + // double *times = + // pinfo.Get(vtkStreamingDemandDrivenPipeline::TIME_RANGE()); + // this.TimeSpan[0] = times[0]; + // this.TimeSpan[1] = times[1]; + // } + // + // this.SetTimeLabel( + // (pinfo && + // pinfo.Has(vtkStreamingDemandDrivenPipeline::TIME_LABEL_ANNOTATION())) + // ? + // pinfo.Get(vtkStreamingDemandDrivenPipeline::TIME_LABEL_ANNOTATION()) + // : NULL); + // + // vtkInformation *dinfo = data.GetInformation(); + // if (dinfo.Has(vtkDataObject::DATA_TIME_STEP())) + // { + // double time = dinfo.Get(vtkDataObject::DATA_TIME_STEP()); + // this.Time = time; + // this.HasTime = 1; + // } + } + + private void CopyFromDataSet(vtkDataSet data) { + int idx; + double[] bds = null; + int[] ext = null; + + this.DataClassName = data.GetClassName(); + this.DataSetType = data.GetDataObjectType(); + + this.NumberOfDataSets = 1; + + switch (this.DataSetType) { + case VTKConstants.VTK_IMAGE_DATA: + ext = ((vtkImageData) data).GetExtent(); + break; + case VTKConstants.VTK_STRUCTURED_GRID: + ext = ((vtkStructuredGrid) data).GetExtent(); + break; + case VTKConstants.VTK_RECTILINEAR_GRID: + ext = ((vtkRectilinearGrid) data).GetExtent(); + break; + case VTKConstants.VTK_UNIFORM_GRID: + ext = ((vtkUniformGrid) data).GetExtent(); + break; + case VTKConstants.VTK_UNSTRUCTURED_GRID: + case VTKConstants.VTK_POLY_DATA: + this.PolygonCount = data.GetNumberOfCells(); + break; + } + if (ext != null) { + for (idx = 0; idx < 6; ++idx) { + this.Extent[idx] = ext[idx]; + } + } + + this.NumberOfPoints = data.GetNumberOfPoints(); + if (this.NumberOfPoints == 0) { + return; + } + + // We do not want to get the number of dual cells from an octree + // because this triggers generation of connectivity arrays. + if (data.GetDataObjectType() != VTKConstants.VTK_HYPER_OCTREE) { + this.NumberOfCells = data.GetNumberOfCells(); + } + + bds = data.GetBounds(); + for (idx = 0; idx < 6; ++idx) { + this.Bounds[idx] = bds[idx]; + } + this.MemorySize = data.GetActualMemorySize(); + + if (data instanceof vtkPointSet) { + vtkPointSet ps = (vtkPointSet) data; + if (ps.GetPoints() != null) { + this.PointArrayInformation.CopyFromObject(ps.GetPoints().GetData()); + } + } + + // Copy Point Data information + this.PointDataInformation.CopyFromDataSetAttributes(data.GetPointData()); + + // Copy Cell Data information + this.CellDataInformation.CopyFromDataSetAttributes(data.GetCellData()); + + // Copy Field Data information, if any + vtkFieldData fd = data.GetFieldData(); + if (fd != null && fd.GetNumberOfArrays() > 0) { + this.FieldDataInformation.CopyFromFieldData(fd); + } + } + + private void CopyFromGenericDataSet(vtkGenericDataSet data) { + this.DataClassName = data.GetClassName(); + this.DataSetType = data.GetDataObjectType(); + + this.NumberOfDataSets = 1; + this.NumberOfPoints = data.GetNumberOfPoints(); + if (this.NumberOfPoints == 0) { + return; + } + // We do not want to get the number of dual cells from an octree + // because this triggers generation of connectivity arrays. + if (data.GetDataObjectType() != VTKConstants.VTK_HYPER_OCTREE) { + this.NumberOfCells = data.GetNumberOfCells(-1); + } + + data.GetBounds(this.Bounds); + + this.MemorySize = data.GetActualMemorySize(); + + switch (this.DataSetType) { + case VTKConstants.VTK_POLY_DATA: + this.PolygonCount = data.GetNumberOfCells(2); + break; + } + + // Copy Point Data information + this.PointDataInformation.CopyFromGenericAttributesOnPoints(data.GetAttributes()); + + // Copy Cell Data information + this.CellDataInformation.CopyFromGenericAttributesOnCells(data.GetAttributes()); + } + + public void AddInformation(VTKDataInformation info) { + this.AddInformation(info, false); + } + + private void AddInformation(VTKDataInformation info, boolean addingParts) { + if (info == null) { + System.err.println("Cound not cast object to data information."); + return; + } + + // if (!addingParts) { + // this.SetCompositeDataClassName(info.CompositeDataClassName); + // this.CompositeDataSetType = info.CompositeDataSetType; + // this.CompositeDataInformation.AddInformation(info.CompositeDataInformation); + // } + + if (info.NumberOfDataSets == 0) { + return; + } + + if (this.NumberOfPoints == 0 && this.NumberOfCells == 0 && this.NumberOfDataSets == 0) { + // Just copy the other array information. + this.DeepCopy(info, !addingParts); + return; + } + + // For data set, lets pick the common super class. + // This supports Heterogeneous collections. + // We need a new classification: Structured. + // This would allow extracting grid from mixed structured collections. + if (this.DataSetType != info.DataSetType) { // IsTypeOf method will not + // work here. Must be done + // manually. + if (this.DataSetType == VTKConstants.VTK_IMAGE_DATA || this.DataSetType == VTKConstants.VTK_RECTILINEAR_GRID || this.DataSetType == VTKConstants.VTK_DATA_SET || info.DataSetType == VTKConstants.VTK_IMAGE_DATA || info.DataSetType == VTKConstants.VTK_RECTILINEAR_GRID || info.DataSetType == VTKConstants.VTK_DATA_SET) { + this.DataSetType = VTKConstants.VTK_DATA_SET; + this.DataClassName = "vtkDataSet"; + } else { + if (this.DataSetType == VTKConstants.VTK_GENERIC_DATA_SET || info.DataSetType == VTKConstants.VTK_GENERIC_DATA_SET) { + this.DataSetType = VTKConstants.VTK_GENERIC_DATA_SET; + this.DataClassName = "vtkGenericDataSet"; + } else { + this.DataSetType = VTKConstants.VTK_POINT_SET; + this.DataClassName = "vtkPointSet"; + } + } + } + + // Empty data set? Ignore bounds, extent and array info. + if (info.NumberOfCells == 0 && info.NumberOfPoints == 0) { + return; + } + + // First the easy stuff. + this.NumberOfPoints += info.NumberOfPoints; + this.NumberOfCells += info.NumberOfCells; + this.MemorySize += info.MemorySize; + this.NumberOfRows += info.NumberOfRows; + + switch (this.DataSetType) { + case VTKConstants.VTK_POLY_DATA: + this.PolygonCount += info.NumberOfCells; + break; + } + if (addingParts) { + // Adding data information of parts + this.NumberOfDataSets += info.NumberOfDataSets; + } else { + // Adding data information of 1 part across processors + if (this.CompositeDataClassName != null) { + // Composite data blocks are not distributed across processors. + // Simply add their number. + this.NumberOfDataSets += info.NumberOfDataSets; + } else { + // Simple data blocks are distributed across processors, use + // the largest number (actually, NumberOfDataSets should always + // be 1 since the data information is for a part) + if (this.NumberOfDataSets < info.NumberOfDataSets) { + this.NumberOfDataSets = info.NumberOfDataSets; + } + } + } + + // Bounds are only a little harder. + double[] bds = info.Bounds; + for (int i = 0; i < 3; ++i) { + int j = i * 2; + if (bds[j] < this.Bounds[j]) { + this.Bounds[j] = bds[j]; + } + ++j; + if (bds[j] > this.Bounds[j]) { + this.Bounds[j] = bds[j]; + } + } + + // Extents are only a little harder. + int[] ext = info.Extent; + for (int i = 0; i < 3; ++i) { + int j = i * 2; + if (ext[j] < this.Extent[j]) { + this.Extent[j] = ext[j]; + } + ++j; + if (ext[j] > this.Extent[j]) { + this.Extent[j] = ext[j]; + } + } + + // Now for the messy part, all of the arrays. + this.PointArrayInformation.AddInformation(info.PointArrayInformation); + this.PointDataInformation.AddInformation(info.PointDataInformation); + this.CellDataInformation.AddInformation(info.CellDataInformation); + this.VertexDataInformation.AddInformation(info.VertexDataInformation); + this.EdgeDataInformation.AddInformation(info.EdgeDataInformation); + this.RowDataInformation.AddInformation(info.RowDataInformation); + this.FieldDataInformation.AddInformation(info.FieldDataInformation); + // this.GenericAttributesInformation.AddInformation(info.GetGenericAttributesInformation()); + + // double times = info.GetTimeSpan(); + // if (times[0] < this.TimeSpan[0]) { + // this.TimeSpan[0] = times[0]; + // } + // if (times[1] > this.TimeSpan[1]) { + // this.TimeSpan[1] = times[1]; + // } + // + // if (!this.HasTime && info.GetHasTime()) { + // this.Time = info.GetTime(); + // this.HasTime = 1; + // } + // + // this.SetTimeLabel(info.GetTimeLabel()); + } + + String GetPrettyDataTypeString() { + int dataType = this.DataSetType; + if (this.CompositeDataSetType >= 0) { + dataType = this.CompositeDataSetType; + } + + switch (dataType) { + case VTKConstants.VTK_POLY_DATA: + return "Polygonal Mesh"; + case VTKConstants.VTK_STRUCTURED_POINTS: + return "Image (Uniform Rectilinear Grid)"; + case VTKConstants.VTK_STRUCTURED_GRID: + return "Structured (Curvilinear) Grid"; + case VTKConstants.VTK_RECTILINEAR_GRID: + return "Rectilinear Grid"; + case VTKConstants.VTK_UNSTRUCTURED_GRID: + return "Unstructured Grid"; + case VTKConstants.VTK_PIECEWISE_FUNCTION: + return "Piecewise function"; + case VTKConstants.VTK_IMAGE_DATA: + return "Image (Uniform Rectilinear Grid)"; + case VTKConstants.VTK_DATA_OBJECT: + return "Data Object"; + case VTKConstants.VTK_DATA_SET: + return "Data Set"; + case VTKConstants.VTK_POINT_SET: + return "Point Set"; + case VTKConstants.VTK_UNIFORM_GRID: + return "Image (Uniform Rectilinear Grid) with blanking"; + case VTKConstants.VTK_COMPOSITE_DATA_SET: + return "Composite Dataset"; + case VTKConstants.VTK_MULTIGROUP_DATA_SET: + return "Multi-group Dataset"; + case VTKConstants.VTK_MULTIBLOCK_DATA_SET: + return "Multi-block Dataset"; + case VTKConstants.VTK_HIERARCHICAL_DATA_SET: + return "Hierarchical DataSet (Deprecated)"; + case VTKConstants.VTK_HIERARCHICAL_BOX_DATA_SET: + return "AMR Dataset (Deprecated)"; + case VTKConstants.VTK_NON_OVERLAPPING_AMR: + return "Non-Overlapping AMR Dataset"; + case VTKConstants.VTK_OVERLAPPING_AMR: + return "Overlapping AMR Dataset"; + case VTKConstants.VTK_GENERIC_DATA_SET: + return "Generic Dataset"; + case VTKConstants.VTK_HYPER_OCTREE: + return "Hyper-octree"; + case VTKConstants.VTK_HYPER_TREE_GRID: + return "Hyper-tree Grid"; + case VTKConstants.VTK_TEMPORAL_DATA_SET: + return "Temporal Dataset"; + case VTKConstants.VTK_TABLE: + return "Table"; + case VTKConstants.VTK_GRAPH: + return "Graph"; + case VTKConstants.VTK_TREE: + return "Tree"; + case VTKConstants.VTK_SELECTION: + return "Selection"; + case VTKConstants.VTK_DIRECTED_GRAPH: + return "Directed Graph"; + case VTKConstants.VTK_UNDIRECTED_GRAPH: + return "Undirected Graph"; + case VTKConstants.VTK_MULTIPIECE_DATA_SET: + return "Multi-piece Dataset"; + case VTKConstants.VTK_DIRECTED_ACYCLIC_GRAPH: + return "Directed Acyclic Graph"; + default: + // vtkPVDataInformationHelper *dhelper = + // vtkPVDataInformation::FindHelper + // (this.DataClassName); + // if (dhelper) + // { + // const char *namestr = dhelper.GetPrettyDataTypeString(); + // dhelper.Delete(); + // return namestr; + // } + } + + return "UnknownType"; + } + + int IsDataStructured() { + switch (this.DataSetType) { + case VTKConstants.VTK_IMAGE_DATA: + case VTKConstants.VTK_STRUCTURED_GRID: + case VTKConstants.VTK_RECTILINEAR_GRID: + case VTKConstants.VTK_UNIFORM_GRID: + case VTKConstants.VTK_GENERIC_DATA_SET: + return 1; + } + return 0; + } + + public void PrintSelf(PrintStream os) { + + os.println("PortNumber: " + this.PortNumber); + os.println("DataSetType: " + this.DataSetType); + os.println("CompositeDataSetType: " + this.CompositeDataSetType); + os.println("NumberOfPoints: " + this.NumberOfPoints); + os.println("NumberOfRows: " + this.NumberOfRows); + os.println("NumberOfCells: " + this.NumberOfCells); + os.println("NumberOfDataSets: " + this.NumberOfDataSets); + os.println("MemorySize: " + this.MemorySize); + os.println("PolygonCount: " + this.PolygonCount); + os.println("Bounds: " + this.Bounds[0] + ", " + this.Bounds[1] + ", " + this.Bounds[2] + ", " + this.Bounds[3] + ", " + this.Bounds[4] + ", " + this.Bounds[5]); + os.println("Extent: " + this.Extent[0] + ", " + this.Extent[1] + ", " + this.Extent[2] + ", " + this.Extent[3] + ", " + this.Extent[4] + ", " + this.Extent[5]); + + String indent = " "; + os.println("PointDataInformation "); + this.PointDataInformation.PrintSelf(os, indent); + os.println("CellDataInformation "); + this.CellDataInformation.PrintSelf(os, indent); + os.println("VertexDataInformation"); + this.VertexDataInformation.PrintSelf(os, indent); + os.println("EdgeDataInformation"); + this.EdgeDataInformation.PrintSelf(os, indent); + os.println("RowDataInformation"); + this.RowDataInformation.PrintSelf(os, indent); + os.println("FieldDataInformation "); + this.FieldDataInformation.PrintSelf(os, indent); + os.println("CompositeDataInformation "); + this.CompositeDataInformation.PrintSelf(os, indent); + os.println("PointArrayInformation "); + this.PointArrayInformation.PrintSelf(os, indent); + + os.println("DataClassName: " + (this.DataClassName != null ? this.DataClassName : "(none)")); + os.println("CompositeDataClassName: " + (this.CompositeDataClassName != null ? this.CompositeDataClassName : "(none)")); + + // os.println("TimeSpan: " + this.TimeSpan[0] + ", " + this.TimeSpan[1] + // ); + + if (this.TimeLabel != null) { + os.println("TimeLabel: " + this.TimeLabel); + } + } + + public int getCompositeDataSetType() { + return CompositeDataSetType; + } + + public int getDataSetType() { + return DataSetType; + } + + public int getNumberOfPoints() { + return NumberOfPoints; + } + + public int getNumberOfCells() { + return NumberOfCells; + } + + public int getNumberOfRows() { + return NumberOfRows; + } + + public int getMemorySize() { + return MemorySize; + } + + public int getPolygonCount() { + return PolygonCount; + } + + public double[] getBounds() { + return Bounds; + } + + public int[] getExtent() { + return Extent; + } + + public String getDataClassName() { + return DataClassName; + } + + public String getCompositeDataClassName() { + return CompositeDataClassName; + } + + public int getNumberOfDataSets() { + return NumberOfDataSets; + } + + // String GetDataSetTypeAsString() + // { + // if(this.DataSetType == -1) + // { + // return "UnknownType"; + // } + // else + // { + // return vtkDataObjectTypes::GetClassNameFromTypeId(this.DataSetType); + // } + // } + + // Need to do this manually. + // int DataSetTypeIsA(String type) { + // if (strcmp(type, "vtkDataObject") == 0) { // Every type is of type + // vtkDataObject. + // return 1; + // } + // if (strcmp(type, "vtkDataSet") == 0) { // Every type is of type + // vtkDataObject. + // if (this.DataSetType == VTK_POLY_DATA || this.DataSetType == + // VTK_STRUCTURED_GRID || this.DataSetType == VTK_UNSTRUCTURED_GRID || + // this.DataSetType == VTK_IMAGE_DATA || this.DataSetType == + // VTK_RECTILINEAR_GRID || this.DataSetType == VTK_UNSTRUCTURED_GRID || + // this.DataSetType == VTK_HYPER_TREE_GRID || this.DataSetType == + // VTK_STRUCTURED_POINTS) { + // return 1; + // } + // } + // if (strcmp(type, this.GetDataSetTypeAsString()) == 0) { // If class names + // are the same, then they are of the same type. + // return 1; + // } + // if (strcmp(type, "vtkPointSet") == 0) { + // if (this.DataSetType == VTK_POLY_DATA || this.DataSetType == + // VTK_STRUCTURED_GRID || this.DataSetType == VTK_UNSTRUCTURED_GRID) { + // return 1; + // } + // } + // if (strcmp(type, "vtkStructuredData") == 0) { + // if (this.DataSetType == VTK_IMAGE_DATA || this.DataSetType == + // VTK_STRUCTURED_GRID || this.DataSetType == VTK_RECTILINEAR_GRID) { + // return 1; + // } + // } + // + // return 0; + // } + + // VTKDataInformation GetDataInformationForCompositeIndex(int index) + // { + // if (index == 0) + // { + // (*index)--; + // return this; + // } + // + // (*index)--; + // return + // this.CompositeDataInformation.GetDataInformationForCompositeIndex(index); + // } + + // void CopyToStream(vtkClientServerStream* css) + // { + // css.Reset(); + // *css << vtkClientServerStream::Reply; + // *css << this.DataClassName + // << this.DataSetType + // << this.NumberOfDataSets + // << this.NumberOfPoints + // << this.NumberOfCells + // << this.NumberOfRows + // << this.MemorySize + // << this.PolygonCount + // << this.Time + // << this.HasTime + // << this.TimeLabel + // << vtkClientServerStream::InsertArray(this.Bounds, 6) + // << vtkClientServerStream::InsertArray(this.Extent, 6); + // + // size_t length; + // const unsigned char* data; + // vtkClientServerStream dcss; + // + // this.PointArrayInformation.CopyToStream(&dcss); + // dcss.GetData(&data, &length); + // *css << vtkClientServerStream::InsertArray(data, + // static_cast(length)); + // + // dcss.Reset(); + // + // this.PointDataInformation.CopyToStream(&dcss); + // dcss.GetData(&data, &length); + // *css << vtkClientServerStream::InsertArray(data, + // static_cast(length)); + // + // dcss.Reset(); + // + // this.CellDataInformation.CopyToStream(&dcss); + // dcss.GetData(&data, &length); + // *css << vtkClientServerStream::InsertArray(data, + // static_cast(length)); + // + // dcss.Reset(); + // + // this.VertexDataInformation.CopyToStream(&dcss); + // dcss.GetData(&data, &length); + // *css << vtkClientServerStream::InsertArray(data, + // static_cast(length)); + // + // dcss.Reset(); + // + // this.EdgeDataInformation.CopyToStream(&dcss); + // dcss.GetData(&data, &length); + // *css << vtkClientServerStream::InsertArray(data, + // static_cast(length)); + // + // dcss.Reset(); + // + // this.RowDataInformation.CopyToStream(&dcss); + // dcss.GetData(&data, &length); + // *css << vtkClientServerStream::InsertArray(data, + // static_cast(length)); + // + // *css << this.CompositeDataClassName; + // *css << this.CompositeDataSetType; + // + // dcss.Reset(); + // + // this.CompositeDataInformation.CopyToStream(&dcss); + // dcss.GetData(&data, &length); + // *css << vtkClientServerStream::InsertArray(data, + // static_cast(length)); + // + // dcss.Reset(); + // + // this.FieldDataInformation.CopyToStream(&dcss); + // dcss.GetData(&data, &length); + // *css << vtkClientServerStream::InsertArray(data, + // static_cast(length)); + // + // *css << vtkClientServerStream::InsertArray(this.TimeSpan, 2); + // + // *css << vtkClientServerStream::End; + // } + + // void CopyFromStream(const vtkClientServerStream* css) + // { + // CSS_ARGUMENT_BEGIN(); + // + // const char* dataclassname = 0; + // if (!CSS_GET_NEXT_ARGUMENT(css, 0, &dataclassname)) + // { + // vtkErrorMacro("Error parsing class name of data."); + // return; + // } + // this.SetDataClassName(dataclassname); + // + // if (!CSS_GET_NEXT_ARGUMENT(css, 0, &this.DataSetType)) + // { + // vtkErrorMacro("Error parsing data set type."); + // return; + // } + // if (!CSS_GET_NEXT_ARGUMENT(css, 0, &this.NumberOfDataSets)) + // { + // vtkErrorMacro("Error parsing number of datasets."); + // return; + // } + // if (!CSS_GET_NEXT_ARGUMENT(css, 0, &this.NumberOfPoints)) + // { + // vtkErrorMacro("Error parsing number of points."); + // return; + // } + // if (!CSS_GET_NEXT_ARGUMENT(css, 0, &this.NumberOfCells)) + // { + // vtkErrorMacro("Error parsing number of cells."); + // return; + // } + // if (!CSS_GET_NEXT_ARGUMENT(css, 0, &this.NumberOfRows)) + // { + // vtkErrorMacro("Error parsing number of cells."); + // return; + // } + // if(!CSS_GET_NEXT_ARGUMENT(css, 0, &this.MemorySize)) + // { + // vtkErrorMacro("Error parsing memory size."); + // return; + // } + // if(!CSS_GET_NEXT_ARGUMENT(css, 0, &this.PolygonCount)) + // { + // vtkErrorMacro("Error parsing memory size."); + // return; + // } + // if(!CSS_GET_NEXT_ARGUMENT(css, 0, &this.Time)) + // { + // vtkErrorMacro("Error parsing Time."); + // return; + // } + // if(!CSS_GET_NEXT_ARGUMENT(css, 0, &this.HasTime)) + // { + // vtkErrorMacro("Error parsing has-time."); + // return; + // } + // const char* timeLabel = 0; + // if (!CSS_GET_NEXT_ARGUMENT(css, 0, &timeLabel)) + // { + // vtkErrorMacro("Error parsing time label."); + // return; + // } + // this.SetTimeLabel(timeLabel); + // if(!CSS_GET_NEXT_ARGUMENT2(css, 0, this.Bounds, 6)) + // { + // vtkErrorMacro("Error parsing bounds."); + // return; + // } + // if(!CSS_GET_NEXT_ARGUMENT2(css, 0, this.Extent, 6)) + // { + // vtkErrorMacro("Error parsing extent."); + // return; + // } + // + // vtkTypeUInt32 length; + // std::vector data; + // vtkClientServerStream dcss; + // + // // Point array information. + // if(!css.GetArgumentLength(0, CSS_GET_CUR_INDEX(), &length)) + // { + // vtkErrorMacro("Error parsing length of point data information."); + // return; + // } + // data.resize(length); + // if(!css.GetArgument(0, CSS_GET_CUR_INDEX(), &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing point data information."); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // this.PointArrayInformation.CopyFromStream(&dcss); + // CSS_GET_CUR_INDEX()++; + // + // // Point data array information. + // if(!css.GetArgumentLength(0, CSS_GET_CUR_INDEX(), &length)) + // { + // vtkErrorMacro("Error parsing length of point data information."); + // return; + // } + // data.resize(length); + // if(!css.GetArgument(0, CSS_GET_CUR_INDEX(), &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing point data information."); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // this.PointDataInformation.CopyFromStream(&dcss); + // CSS_GET_CUR_INDEX()++; + // + // // Cell data array information. + // if(!css.GetArgumentLength(0, CSS_GET_CUR_INDEX(), &length)) + // { + // vtkErrorMacro("Error parsing length of cell data information."); + // return; + // } + // data.resize(length); + // if(!css.GetArgument(0, CSS_GET_CUR_INDEX(), &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing cell data information."); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // this.CellDataInformation.CopyFromStream(&dcss); + // CSS_GET_CUR_INDEX()++; + // + // // Vertex data array information. + // if(!css.GetArgumentLength(0, CSS_GET_CUR_INDEX(), &length)) + // { + // vtkErrorMacro("Error parsing length of cell data information."); + // return; + // } + // data.resize(length); + // if(!css.GetArgument(0, CSS_GET_CUR_INDEX(), &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing cell data information."); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // this.VertexDataInformation.CopyFromStream(&dcss); + // CSS_GET_CUR_INDEX()++; + // + // // Edge data array information. + // if(!css.GetArgumentLength(0, CSS_GET_CUR_INDEX(), &length)) + // { + // vtkErrorMacro("Error parsing length of cell data information."); + // return; + // } + // data.resize(length); + // if(!css.GetArgument(0, CSS_GET_CUR_INDEX(), &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing cell data information."); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // this.EdgeDataInformation.CopyFromStream(&dcss); + // CSS_GET_CUR_INDEX()++; + // + // // Row data array information. + // if(!css.GetArgumentLength(0, CSS_GET_CUR_INDEX(), &length)) + // { + // vtkErrorMacro("Error parsing length of cell data information."); + // return; + // } + // data.resize(length); + // if(!css.GetArgument(0, CSS_GET_CUR_INDEX(), &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing cell data information."); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // this.RowDataInformation.CopyFromStream(&dcss); + // CSS_GET_CUR_INDEX()++; + // + // const char* compositedataclassname = 0; + // if(!CSS_GET_NEXT_ARGUMENT(css, 0, &compositedataclassname)) + // { + // vtkErrorMacro("Error parsing class name of data."); + // return; + // } + // this.SetCompositeDataClassName(compositedataclassname); + // + // if(!CSS_GET_NEXT_ARGUMENT(css, 0, &this.CompositeDataSetType)) + // { + // vtkErrorMacro("Error parsing data set type."); + // return; + // } + // + // // Composite data information. + // if(!css.GetArgumentLength(0, CSS_GET_CUR_INDEX(), &length)) + // { + // vtkErrorMacro("Error parsing length of cell data information."); + // return; + // } + // data.resize(length); + // if(!css.GetArgument(0, CSS_GET_CUR_INDEX(), &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing cell data information."); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // if (dcss.GetNumberOfMessages() > 0) + // { + // this.CompositeDataInformation.CopyFromStream(&dcss); + // } + // else + // { + // this.CompositeDataInformation.Initialize(); + // } + // CSS_GET_CUR_INDEX()++; + // + // // Field data array information. + // if(!css.GetArgumentLength(0, CSS_GET_CUR_INDEX(), &length)) + // { + // vtkErrorMacro("Error parsing length of field data information."); + // return; + // } + // + // data.resize(length); + // if(!css.GetArgument(0, CSS_GET_CUR_INDEX(), &*data.begin(), length)) + // { + // vtkErrorMacro("Error parsing field data information."); + // return; + // } + // dcss.SetData(&*data.begin(), length); + // this.FieldDataInformation.CopyFromStream(&dcss); + // CSS_GET_CUR_INDEX()++; + // + // if(!CSS_GET_NEXT_ARGUMENT2(css, 0, this.TimeSpan, 2)) + // { + // vtkErrorMacro("Error parsing timespan."); + // return; + // } + // + // CSS_ARGUMENT_END(); + // } + + // void SetSortArrays(boolean sort) { + // this.PointDataInformation.SetSortArrays(sort); + // this.CellDataInformation.SetSortArrays(sort); + // this.FieldDataInformation.SetSortArrays(sort); + // } + + // vtkPVDataSetAttributesInformation GetAttributeInformation(int + // fieldAssociation) + // { + // switch (fieldAssociation) + // { + // case vtkDataObject::FIELD_ASSOCIATION_POINTS: + // return this.PointDataInformation; + // + // case vtkDataObject::FIELD_ASSOCIATION_CELLS: + // return this.CellDataInformation; + // + // case vtkDataObject::FIELD_ASSOCIATION_VERTICES: + // return this.VertexDataInformation; + // + // case vtkDataObject::FIELD_ASSOCIATION_EDGES: + // return this.EdgeDataInformation; + // + // case vtkDataObject::FIELD_ASSOCIATION_ROWS: + // return this.RowDataInformation; + // + // case vtkDataObject::FIELD_ASSOCIATION_NONE: + // return this.FieldDataInformation; + // } + // + // return 0; + // } + + // DO NOT USE THIS METHOD, THE ITERATOR HAS MEMORY LEAK PROBLEMS + // public void AddFromCompositeDataSet(vtkCompositeDataSet data) { + // vtkCompositeDataIterator iter = data.NewIterator(); + // int counter = 0; + // for (iter.InitTraversal(); iter.IsDoneWithTraversal() == 0; + // iter.GoToNextItem()) { + // System.out.println("VTKDataInformation.AddFromCompositeDataSet() " + + // counter++); + // // vtkDataObject dobj = iter.GetCurrentDataObject(); + // // if (dobj != null) { + // // VTKDataInformation dinf = new VTKDataInformation(); + // // dinf.CopyFromObject(dobj); + // // dinf.DataClassName = dobj.GetClassName(); + // // dinf.DataSetType = dobj.GetDataObjectType(); + // // this.AddInformation(dinf, true); + // // } + // // dobj.Delete(); + // } + // iter.Delete(); + // } + // void CopyFromSelection(vtkSelection data) { + // this.SetDataClassName(data.GetClassName()); + // this.DataSetType = data.GetDataObjectType(); + // this.NumberOfDataSets = 1; + // + // this.Bounds[0] = this.Bounds[2] = this.Bounds[4] = VTK_DOUBLE_MAX; + // this.Bounds[1] = this.Bounds[3] = this.Bounds[5] = -VTK_DOUBLE_MAX; + // + // this.MemorySize = data.GetActualMemorySize(); + // this.NumberOfCells = 0; + // this.NumberOfPoints = 0; + // + // // Copy Point Data information + // this.PointDataInformation.CopyFromFieldData(data.GetFieldData()); + // } + + // void CopyFromGraph(vtkGraph data) { + // this.SetDataClassName(data.GetClassName()); + // this.DataSetType = data.GetDataObjectType(); + // this.NumberOfDataSets = 1; + // + // this.Bounds[0] = this.Bounds[2] = this.Bounds[4] = VTK_DOUBLE_MAX; + // this.Bounds[1] = this.Bounds[3] = this.Bounds[5] = -VTK_DOUBLE_MAX; + // + // if (data.GetPoints()) + // data.GetPoints().GetBounds(this.Bounds); + // + // this.MemorySize = data.GetActualMemorySize(); + // this.NumberOfCells = data.GetNumberOfEdges(); + // this.NumberOfPoints = data.GetNumberOfVertices(); + // this.NumberOfRows = 0; + // + // this.VertexDataInformation.CopyFromFieldData(data.GetVertexData()); + // this.EdgeDataInformation.CopyFromFieldData(data.GetEdgeData()); + // } + + // void CopyFromTable(vtkTable data) { + // this.SetDataClassName(data.GetClassName()); + // this.DataSetType = data.GetDataObjectType(); + // this.NumberOfDataSets = 1; + // + // this.Bounds[0] = this.Bounds[2] = this.Bounds[4] = VTK_DOUBLE_MAX; + // this.Bounds[1] = this.Bounds[3] = this.Bounds[5] = -VTK_DOUBLE_MAX; + // + // this.MemorySize = data.GetActualMemorySize(); + // this.NumberOfCells = data.GetNumberOfRows() * data.GetNumberOfColumns(); + // this.NumberOfPoints = 0; + // this.NumberOfRows = data.GetNumberOfRows(); + // + // this.RowDataInformation.CopyFromFieldData(data.GetRowData()); + // } + +} diff --git a/src/eu/engys/vtk/info/VTKDataSetAttributesInformation.java b/src/eu/engys/vtk/info/VTKDataSetAttributesInformation.java new file mode 100644 index 0000000..ca0d46f --- /dev/null +++ b/src/eu/engys/vtk/info/VTKDataSetAttributesInformation.java @@ -0,0 +1,371 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.info; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import vtk.vtkAbstractArray; +import vtk.vtkDataSetAttributes; +import vtk.vtkFieldData; +import vtk.vtkGenericAttribute; +import vtk.vtkGenericAttributeCollection; + +public class VTKDataSetAttributesInformation { + + private static final int NUM_ATTRIBUTES = 8; + private List ArrayInformation; + private boolean SortArrays; + private int[] AttributeIndices = new int[NUM_ATTRIBUTES]; + + // ---------------------------------------------------------------------------- + public VTKDataSetAttributesInformation() { + this.ArrayInformation = new ArrayList<>(); + for (int idx = 0; idx < NUM_ATTRIBUTES; ++idx) { + this.AttributeIndices[idx] = -1; + } + this.SortArrays = true; + } + + // ---------------------------------------------------------------------------- + void PrintSelf(PrintStream os, String indent) { + + int num = this.GetNumberOfArrays(); + os.println(indent+"ArrayInformation, number of arrays: " + num); + for (int idx = 0; idx < num; ++idx) { + this.ArrayInformation.get(idx).PrintSelf(os, indent+indent); + } + os.println(indent+"SortArrays: " + this.SortArrays); + } + + // ---------------------------------------------------------------------------- + void Initialize() { + this.ArrayInformation.clear(); + for (int idx = 0; idx < NUM_ATTRIBUTES; ++idx) { + this.AttributeIndices[idx] = -1; + } + } + + // ---------------------------------------------------------------------------- + void DeepCopy(VTKDataSetAttributesInformation dataInfo) { + + // Copy array information. + this.ArrayInformation.clear(); + int num = dataInfo.GetNumberOfArrays(); + for (int idx = 0; idx < num; ++idx) { + VTKArrayInformation arrayInfo = dataInfo.ArrayInformation.get(idx); + VTKArrayInformation newArrayInfo = new VTKArrayInformation(); + newArrayInfo.DeepCopy(arrayInfo); + this.ArrayInformation.add(newArrayInfo); + } + // Now the default attributes. + for (int idx = 0; idx < NUM_ATTRIBUTES; ++idx) { + this.AttributeIndices[idx] = dataInfo.AttributeIndices[idx]; + } + } + + // ---------------------------------------------------------------------------- + void CopyFromFieldData(vtkFieldData da) { + // Clear array information. + this.ArrayInformation.clear(); + for (int idx = 0; idx < NUM_ATTRIBUTES; ++idx) { + this.AttributeIndices[idx] = -1; + } + + // Copy Field Data + int num = da.GetNumberOfArrays(); + for (int idx = 0; idx < num; ++idx) { + vtkAbstractArray array = da.GetAbstractArray(idx); + if (array.GetName() != null) { + VTKArrayInformation info = new VTKArrayInformation(); + info.CopyFromObject(array); + this.ArrayInformation.add(info); + } + } + } + + class SortedArray implements Comparable { + + public int arrayIndx; + public String arrayName; + + @Override + public int compareTo(SortedArray o) { + return arrayName.compareTo(o.arrayName); + } + + } + + // ---------------------------------------------------------------------------- + void CopyFromDataSetAttributes(vtkDataSetAttributes da) { + // Clear array information. + this.ArrayInformation.clear(); + for (int idx = 0; idx < NUM_ATTRIBUTES; ++idx) { + this.AttributeIndices[idx] = -1; + } + + // Copy Point Data + int num = da.GetNumberOfArrays(); + + // sort the arrays alphabetically + List sortArrays = new ArrayList<>(); + sortArrays.clear(); + + if (num > 0) { + for (int i = 0; i < num; i++) { + SortedArray sa = new SortedArray(); + sa.arrayIndx = i; + sa.arrayName = da.GetArrayName(i) != null ? da.GetArrayName(i) : ""; + + sortArrays.add(i, sa); + } + + if (this.SortArrays) { + Collections.sort(sortArrays); + } + } + + int infoArrayIndex = 0; + for (SortedArray sa : sortArrays) { + int arrayIndx = sa.arrayIndx; + vtkAbstractArray array = da.GetAbstractArray(arrayIndx); + + if (array.GetName() != null && !array.GetName().equals("vtkGhostLevels") && !array.GetName().equals("vtkOriginalCellIds") && !array.GetName().equals("vtkOriginalPointIds")) { + int attribute = da.IsArrayAnAttribute(arrayIndx); + VTKArrayInformation info = new VTKArrayInformation(); + info.CopyFromObject(array); + this.ArrayInformation.add(info); + // Record default attributes. + if (attribute > -1) { + this.AttributeIndices[attribute] = infoArrayIndex; + } + ++infoArrayIndex; + } + } + + sortArrays.clear(); + } + + private static final int vtkPointCentered = 0; + private static final int vtkCellCentered = 1; + private static final int vtkBoundaryCentered = 2; + + // ---------------------------------------------------------------------------- + void CopyFromGenericAttributesOnPoints(vtkGenericAttributeCollection da) { + + // Clear array information. + this.ArrayInformation.clear(); + for (int idx = 0; idx < 5; ++idx) { + this.AttributeIndices[idx] = -1; + } + + // Copy Point Data + int num = da.GetNumberOfAttributes(); + for (int idx = 0; idx < num; ++idx) { + vtkGenericAttribute array = da.GetAttribute(idx); + if (array.GetCentering() == vtkPointCentered) { + if (array.GetName() != null && (!array.GetName().equals("vtkGhostLevels"))) { + VTKGenericAttributeInformation info = new VTKGenericAttributeInformation(); + info.CopyFromObject(array); + this.ArrayInformation.add(info); + } + } + } + } + + // ---------------------------------------------------------------------------- + void CopyFromGenericAttributesOnCells(vtkGenericAttributeCollection da) { + + // Clear array information. + this.ArrayInformation.clear(); + for (int idx = 0; idx < 5; ++idx) { + this.AttributeIndices[idx] = -1; + } + + // Copy Cell Data + int num = da.GetNumberOfAttributes(); + for (int idx = 0; idx < num; ++idx) { + vtkGenericAttribute array = da.GetAttribute(idx); + if (array.GetCentering() == vtkCellCentered) { + if (array.GetName() != null && (!array.GetName().equals("vtkGhostLevels"))) { + VTKGenericAttributeInformation info = new VTKGenericAttributeInformation(); + info.CopyFromObject(array); + this.ArrayInformation.add(info); + } + } + } + } + + // ---------------------------------------------------------------------------- + void AddInformation(VTKDataSetAttributesInformation info) { + int num1 = this.GetNumberOfArrays(); + int num2 = info.GetNumberOfArrays(); + int[] newAttributeIndices = new int[NUM_ATTRIBUTES]; + + for (int idx1 = 0; idx1 < NUM_ATTRIBUTES; idx1++) { + newAttributeIndices[idx1] = -1; + } + + // First add ranges from all common arrays + for (int idx1 = 0; idx1 < num1; idx1++) { + boolean found = false; + VTKArrayInformation ai1 = this.ArrayInformation.get(idx1); + for (int idx2 = 0; idx2 < num2; idx2++) { + VTKArrayInformation ai2 = info.ArrayInformation.get(idx2); + if (ai1.Compare(ai2)) { + // Take union of range. + ai1.AddRanges(ai2); + found = true; + // Record default attributes. + int attribute1 = this.IsArrayAnAttribute(idx1); + int attribute2 = info.IsArrayAnAttribute(idx2); + if (attribute1 > -1 && attribute1 == attribute2) { + newAttributeIndices[attribute1] = idx1; + } + break; + } + } + if (!found) { + ai1.IsPartial = true; + } + } + + for (int idx1 = 0; idx1 < NUM_ATTRIBUTES; idx1++) { + this.AttributeIndices[idx1] = newAttributeIndices[idx1]; + } + + // Now add arrays that don't exist + for (int idx2 = 0; idx2 < num2; idx2++) { + VTKArrayInformation ai2 = info.ArrayInformation.get(idx2); + boolean found = false; + for (int idx1 = 0; idx1 < this.GetNumberOfArrays(); idx1++) { + VTKArrayInformation ai1 = this.ArrayInformation.get(idx1); + if (ai1.Compare(ai2)) { + found = true; + break; + } + } + if (!found) { + ai2.IsPartial = true; + this.ArrayInformation.add(ai2); + int attribute = info.IsArrayAnAttribute(idx2); + if (attribute > -1 && this.AttributeIndices[attribute] == -1) { + this.AttributeIndices[attribute] = idx2; + } + } + } + } + + // ---------------------------------------------------------------------------- + // void AddInformation(vtkPVInformation info) + // { + // vtkPVDataSetAttributesInformation* p = + // vtkPVDataSetAttributesInformation::SafeDownCast(info); + // if(p) + // { + // this.AddInformation(p); + // } + // else + // { + // vtkErrorMacro("AddInformation called with object of type " + // << (info? info.GetClassName():"")); + // } + // } + + // ---------------------------------------------------------------------------- + void AddInformation(vtkDataSetAttributes da) { + VTKDataSetAttributesInformation info = new VTKDataSetAttributesInformation(); + info.CopyFromDataSetAttributes(da); + this.AddInformation(info); + } + + // ---------------------------------------------------------------------------- + int IsArrayAnAttribute(int arrayIndex) { + int i; + + for (i = 0; i < NUM_ATTRIBUTES; ++i) { + if (this.AttributeIndices[i] == arrayIndex) { + return i; + } + } + return -1; + } + + // ---------------------------------------------------------------------------- + VTKArrayInformation GetAttributeInformation(int attributeType) { + int arrayIdx = this.AttributeIndices[attributeType]; + + if (arrayIdx < 0) { + return null; + } + return this.ArrayInformation.get(arrayIdx); + } + + // ---------------------------------------------------------------------------- + int GetNumberOfArrays() { + return this.ArrayInformation.size(); + } + + // ---------------------------------------------------------------------------- + // int GetMaximumNumberOfTuples() + // { + // VTKArrayInformation info; + // int maxNumVals = 0; + // + // this.ArrayInformation.InitTraversal(); + // while ( (info = static_cast(this.ArrayInformation.GetNextItemAsObject())) ) + // { + // maxNumVals = info.GetNumberOfTuples() > maxNumVals ? info.GetNumberOfTuples() : maxNumVals; + // } + // + // return maxNumVals; + // } + + // ---------------------------------------------------------------------------- + // vtkPVArrayInformation GetArrayInformation(String name) + // { + // vtkPVArrayInformation info; + // + // if (name == NULL) + // { + // return NULL; + // } + // + // this.ArrayInformation.InitTraversal(); + // while ( (info = static_cast(this.ArrayInformation.GetNextItemAsObject())) ) + // { + // if (strcmp(info.GetName(), name) == 0) + // { + // return info; + // } + // } + // return NULL; + // } + +} diff --git a/src/eu/engys/vtk/info/VTKGenericAttributeInformation.java b/src/eu/engys/vtk/info/VTKGenericAttributeInformation.java new file mode 100644 index 0000000..e10c473 --- /dev/null +++ b/src/eu/engys/vtk/info/VTKGenericAttributeInformation.java @@ -0,0 +1,54 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.info; + +import vtk.vtkGenericAttribute; + +public class VTKGenericAttributeInformation extends VTKArrayInformation { + + //---------------------------------------------------------------------------- + void CopyFromObject(vtkGenericAttribute array) + { + + this.Name = array.GetName(); + this.DataType = array.GetComponentType(); + this.NumberOfComponents = array.GetNumberOfComponents(); + + if (this.NumberOfComponents > 1) { + this.Ranges = new double[this.NumberOfComponents+1][2]; + // First store range of vector magnitude. + array.GetRange(-1,this.Ranges[0]); + for (int idx = 0; idx < this.NumberOfComponents; idx++) { + array.GetRange(idx, this.Ranges[idx + 1]); + } + } else { + this.Ranges = new double[1][2]; + array.GetRange(0,this.Ranges[0]); + } + } + +} diff --git a/src/eu/engys/vtk/widgets/AxesWidget.java b/src/eu/engys/vtk/widgets/AxesWidget.java new file mode 100644 index 0000000..30ffc35 --- /dev/null +++ b/src/eu/engys/vtk/widgets/AxesWidget.java @@ -0,0 +1,67 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import vtk.vtkAxesActor; +import vtk.vtkCaptionActor2D; +import vtk.vtkOrientationMarkerWidget; +import eu.engys.gui.view3D.RenderPanel; + +public class AxesWidget { + + private vtkAxesActor axes; + private vtkOrientationMarkerWidget widget; + + public AxesWidget(RenderPanel renderPanel) { + axes = new vtkAxesActor(); + + setAxisProperty(axes.GetXAxisCaptionActor2D()); + setAxisProperty(axes.GetYAxisCaptionActor2D()); + setAxisProperty(axes.GetZAxisCaptionActor2D()); + + widget = new vtkOrientationMarkerWidget(); + renderPanel.getInteractor().addObserver(widget); + widget.SetOutlineColor(0.9300, 0.5700, 0.1300); + widget.SetOrientationMarker(axes); + widget.SetViewport(0, 0, 0.25, 0.25); + widget.EnabledOn(); + widget.InteractiveOff(); + + } + + private void setAxisProperty(vtkCaptionActor2D axis) { + axis.GetTextActor().GetTextProperty().ShadowOff(); + axis.GetTextActor().GetTextProperty().SetFontFamilyToArial(); + axis.GetTextActor().GetTextProperty().ItalicOff(); + axis.GetTextActor().GetTextProperty().BoldOff(); + axis.GetTextActor().GetTextProperty().SetColor(0, 0, 0); + } + + public void clear() { + } + +} diff --git a/src/eu/engys/vtk/widgets/AxisWidget.java b/src/eu/engys/vtk/widgets/AxisWidget.java new file mode 100644 index 0000000..bb29c71 --- /dev/null +++ b/src/eu/engys/vtk/widgets/AxisWidget.java @@ -0,0 +1,217 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.vecmath.Vector3d; + +import vtk.vtkArrowSource; +import vtk.vtkHandleWidget; +import vtk.vtkMatrix4x4; +import vtk.vtkPolygonalHandleRepresentation3D; +import vtk.vtkTransform; +import vtk.vtkTransformPolyDataFilter; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.ui.textfields.DoubleField; + +public class AxisWidget { + + private final class PointFieldListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + changePosition(); + renderPanel.renderLater(); + } + } + } + + private RenderPanel renderPanel; + private PropertyChangeListener listener; + private DoubleField[] currentCenter = null; + private DoubleField[] currentNormal = null; + private vtkHandleWidget widget; + private vtkPolygonalHandleRepresentation3D representation; + private vtkArrowSource arrowSource; + + public AxisWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + + arrowSource = new vtkArrowSource(); + arrowSource.SetShaftResolution(24); // default = 6 + arrowSource.SetTipResolution(36); // default = 6 + arrowSource.Update(); + + vtkTransform transform = new vtkTransform(); + transform.RotateZ(-90); + transform.Update(); + + vtkTransformPolyDataFilter transformPD = new vtkTransformPolyDataFilter(); + transformPD.SetTransform(transform); + transformPD.SetInputData(arrowSource.GetOutput()); + transformPD.Update(); + + representation = new vtkPolygonalHandleRepresentation3D(); + representation.SetHandle(transformPD.GetOutput()); + representation.GetProperty().SetColor(0, 1, 1); + representation.DragableOff(); + representation.PickableOff(); + representation.ActiveRepresentationOff();// MuDeMe! + + widget = new vtkHandleWidget(); + renderPanel.getInteractor().addObserver(widget); + widget.SetRepresentation(representation); + widget.ManagesCursorOff(); + widget.ProcessEventsOff();// MuDeMe! + + listener = new PointFieldListener(); + } + + public void clear() { + removeListener(); + renderPanel.lock(); + widget.EnabledOff(); + widget.Delete(); + currentCenter = null; + currentNormal = null; + renderPanel.unlock(); + renderPanel.renderLater(); + } + + public void showAxis(DoubleField[] center, DoubleField[] normal, EventActionType action) { + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + widget.EnabledOff(); + removeListener(); + currentCenter = null; + currentNormal = null; + } else if (action.equals(EventActionType.SHOW)) { + removeListener(); + currentCenter = center; + currentNormal = normal; + changePosition(); + widget.EnabledOn(); + addListener(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void changePosition() { + if (isValid()) { + double[] p1 = new double[] { currentCenter[0].getDoubleValue(), currentCenter[1].getDoubleValue(), currentCenter[2].getDoubleValue() }; + double[] p2 = new double[] { currentCenter[0].getDoubleValue() + currentNormal[0].getDoubleValue(), currentCenter[1].getDoubleValue() + currentNormal[1].getDoubleValue(), currentCenter[2].getDoubleValue() + currentNormal[2].getDoubleValue() }; + transformArrow(p1, p2); + } + } + + private boolean isValid() { + return currentCenter != null && currentCenter[0].getValue() != null && currentCenter[1].getValue() != null && currentCenter[2].getValue() != null; + } + + private void transformArrow(double[] startPoint, double[] endPoint) { + // Compute a basis + Vector3d normalizedX = new Vector3d(); + Vector3d normalizedY = new Vector3d(); + Vector3d normalizedZ = new Vector3d(); + + // The X axis is a vector from start to end + normalizedX.setX(endPoint[0] - startPoint[0]); + normalizedX.setY(endPoint[1] - startPoint[1]); + normalizedX.setZ(endPoint[2] - startPoint[2]); + + double length = normalizedX.length(); + normalizedX.normalize(); + + // The Z axis is an arbitrary vector cross X + Vector3d arbitrary = new Vector3d(1, 1, 1); + + normalizedZ.cross(normalizedX, arbitrary); + normalizedZ.normalize(); + + // The Y axis is Z cross X + normalizedY.cross(normalizedZ, normalizedX); + + vtkMatrix4x4 matrix = new vtkMatrix4x4(); + + // Create the direction cosine matrix + matrix.Identity(); + matrix.SetElement(0, 0, normalizedX.getX()); + matrix.SetElement(0, 1, normalizedY.getX()); + matrix.SetElement(0, 2, normalizedZ.getX()); + matrix.SetElement(1, 0, normalizedX.getY()); + matrix.SetElement(1, 1, normalizedY.getY()); + matrix.SetElement(1, 2, normalizedZ.getY()); + matrix.SetElement(2, 0, normalizedX.getZ()); + matrix.SetElement(2, 1, normalizedY.getZ()); + matrix.SetElement(2, 2, normalizedZ.getZ()); + + // Apply the transforms + vtkTransform transform = new vtkTransform(); + transform.Translate(startPoint); + transform.Concatenate(matrix); + transform.Scale(length, length, length); + transform.Update(); + + // Transform the polydata + vtkTransformPolyDataFilter transformPD = new vtkTransformPolyDataFilter(); + transformPD.SetTransform(transform); + transformPD.SetInputData(arrowSource.GetOutput()); + transformPD.Update(); + + representation.SetHandle(transformPD.GetOutput()); + } + + private void addListener() { + if (isValid()) { + currentCenter[0].addPropertyChangeListener(listener); + currentCenter[1].addPropertyChangeListener(listener); + currentCenter[2].addPropertyChangeListener(listener); + } + if (currentNormal != null) { + currentNormal[0].addPropertyChangeListener(listener); + currentNormal[1].addPropertyChangeListener(listener); + currentNormal[2].addPropertyChangeListener(listener); + } + } + + private void removeListener() { + if (isValid()) { + currentCenter[0].removePropertyChangeListener(listener); + currentCenter[1].removePropertyChangeListener(listener); + currentCenter[2].removePropertyChangeListener(listener); + } + if (currentNormal != null) { + currentNormal[0].removePropertyChangeListener(listener); + currentNormal[1].removePropertyChangeListener(listener); + currentNormal[2].removePropertyChangeListener(listener); + } + } +} diff --git a/src/eu/engys/vtk/widgets/AxisWidgetManager.java b/src/eu/engys/vtk/widgets/AxisWidgetManager.java new file mode 100644 index 0000000..78bf95d --- /dev/null +++ b/src/eu/engys/vtk/widgets/AxisWidgetManager.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import java.util.HashMap; +import java.util.Map; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.vtk.VTKRenderPanel; + +public class AxisWidgetManager { + + private String key = "pippo"; + + private Map widgetMap = new HashMap<>(); + private VTKRenderPanel vtkRendererPanel; + + public AxisWidgetManager(VTKRenderPanel vtkRendererPanel) { + this.vtkRendererPanel = vtkRendererPanel; + } + + public void clear() { + for (AxisWidget w : widgetMap.values()) { + w.clear(); + } + widgetMap.clear(); + } + + public void showPoint(DoubleField[] center, DoubleField[] normal, EventActionType action) { + if (action.equals(EventActionType.REMOVE)) { + if (widgetMap.containsKey(key)) { + AxisWidget w = widgetMap.remove(key); + w.clear(); + } + } else { + if (!widgetMap.containsKey(key)) { + AxisWidget widget = new AxisWidget(vtkRendererPanel); + widgetMap.put(key, widget); + } + AxisWidget axisWidget = widgetMap.get(key); + axisWidget.showAxis(center, normal, action); + } + } + +} diff --git a/src/eu/engys/vtk/widgets/CORWidget.java b/src/eu/engys/vtk/widgets/CORWidget.java new file mode 100644 index 0000000..dbf88a2 --- /dev/null +++ b/src/eu/engys/vtk/widgets/CORWidget.java @@ -0,0 +1,125 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import vtk.vtkActor; +import vtk.vtkAssembly; +import vtk.vtkLineSource; +import vtk.vtkPolyDataMapper; +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.vtk.VTKRenderPanel; + +public class CORWidget { + + private VTKRenderPanel vtkRendererPanel; + private vtkActor lineX; + private vtkActor lineY; + private vtkActor lineZ; + private vtkAssembly cor; + + public CORWidget(VTKRenderPanel vtkRendererPanel) { + this.vtkRendererPanel = vtkRendererPanel; + cor = new vtkAssembly(); + + lineX = getLine(new double[] {-1, 0, 0}, new double[] {1,0,0}, 1, 1,0,0); + lineY = getLine(new double[] { 0,-1, 0}, new double[] {0,1,0}, 1, 0,1,0); + lineZ = getLine(new double[] { 0, 0,-1}, new double[] {0,0,1}, 1, 0,0,1); + + cor.AddPart(lineX); + cor.AddPart(lineY); + cor.AddPart(lineZ); + cor.UseBoundsOff(); + } + + private vtkActor getLine(double[] p1, double[] p2, float gr, int r, int g, int b) { + + vtkLineSource line = new vtkLineSource(); + + line.SetPoint1(p1[0], p1[1], p1[2]); + line.SetPoint2(p2[0], p2[1], p2[2]); + + + vtkPolyDataMapper mapper = new vtkPolyDataMapper(); + mapper.SetInputData(line.GetOutput()); + + vtkActor axes = new vtkActor(); + + axes.SetMapper(mapper); + axes.GetProperty().SetColor(r, g, b); + axes.GetProperty().SetLineWidth(gr); + + line.Delete(); + mapper.Delete(); + + return axes; + } + + private void updateLine(vtkActor line, double[] start, double[] end) { + //System.out.println("CORWidget.updateLine() start: "+Arrays.toString(start)+", end: "+Arrays.toString(end)); + vtkLineSource source = new vtkLineSource(); + source.SetPoint1(start); + source.SetPoint2(end); + source.Update(); + + vtkPolyDataMapper mapper = (vtkPolyDataMapper) line.GetMapper(); + mapper.SetInputData(source.GetOutput()); + mapper.Update(); + } + + public void update(BoundingBox bb) { + double[] center = vtkRendererPanel.GetRenderer().GetActiveCamera().GetFocalPoint(); + +// System.out.println("CORWidget.update() W: " + bb.getWidth() + ", H: "+bb.getHeight()); +// System.out.println("CORWidget.update() CENTER: " + Arrays.toString(center)); + double deltaX = (bb.getXmax() - bb.getXmin()) / 4; + double deltaY = (bb.getYmax() - bb.getYmin()) / 4; + double deltaZ = (bb.getZmax() - bb.getZmin()) / 4; + + double[] start = new double[] { center[0]-deltaX, center[1], center[2] }; + double[] end = new double[] { center[0]+deltaX, center[1], center[2] }; + updateLine(lineX, start, end); + + start = new double[] { center[0], center[1]-deltaY, center[2] }; + end = new double[] { center[0], center[1]+deltaY, center[2] }; + updateLine(lineY, start, end); + + start = new double[] { center[0], center[1], center[2]-deltaZ }; + end = new double[] { center[0], center[1], center[2]+deltaZ }; + updateLine(lineZ, start, end); + + cor.Modified(); + } + + public void clear() { + + } + + public void on() { +// vtkRendererPanel.addActor(cor); + } + +} diff --git a/src/eu/engys/vtk/widgets/ExtractSelectionWidget.java b/src/eu/engys/vtk/widgets/ExtractSelectionWidget.java new file mode 100644 index 0000000..594595f --- /dev/null +++ b/src/eu/engys/vtk/widgets/ExtractSelectionWidget.java @@ -0,0 +1,223 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkHandleWidget; +import vtk.vtkPolyData; +import vtk.vtkPolygonalHandleRepresentation3D; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.view3D.CellPicker; +import eu.engys.gui.view3D.PickInfo; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.gui.view3D.Selection; +import eu.engys.gui.view3D.Selection.SelectionType; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.vtk.actions.ExtractSelection; + +public class ExtractSelectionWidget implements CellPicker { + + private static final Logger logger = LoggerFactory.getLogger(ExtractSelectionWidget.class); + + private static final double[] COLOR = new double[] { 0.8, 0.0, 0.0 }; + + private RenderPanel renderPanel; + private vtkHandleWidget widget; + + private vtkPolygonalHandleRepresentation3D representation; + + private Selection currentSelection; + private SelectionListener listener; + + public ExtractSelectionWidget(RenderPanel renderPanel, ProgressMonitor monitor) { + this.renderPanel = renderPanel; + this.listener = new SelectionListener(); + } + + public void activateSelection(Selection selection, EventActionType action) { + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + hide(); + } else if (action.equals(EventActionType.SHOW)) { + this.currentSelection = selection; + show(); + } else if (action.equals(EventActionType.REMOVE)) { + clearSelection(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void hide() { + if (widget != null) { + renderPanel.lowRenderingOn(); + widget.Off(); + removeListener(); + currentSelection = null; + representation.SetHandle(new vtkPolyData()); + selectionBoxOff(); + renderPanel.getPickManager().pickForActors(); + renderPanel.getPickManager().unregisterPickerForCells(this); + } + } + + private void show() { + renderPanel.lowRenderingOff(); + renderPanel.getPickManager().pickForCells(); + renderPanel.getPickManager().registerPickerForCells(this); + if (widget == null) { + createWidget(); + } + + if (currentSelection.getType() == SelectionType.AREA) { + selectionBoxOn(); + } else { + selectionBoxOff(); + } + + widget.On(); + addListener(); + } + + private void createWidget() { + representation = new vtkPolygonalHandleRepresentation3D(); + representation.GetProperty().SetColor(COLOR); + // representation.GetProperty().LightingOff(); + + representation.GetSelectedProperty().SetColor(COLOR); + representation.DragableOff(); + representation.PickableOff(); + representation.ActiveRepresentationOff();// MuDeMe! + + widget = new vtkHandleWidget(); + renderPanel.getInteractor().addObserver(widget); + widget.SetRepresentation(representation); + + // widget.AllowHandleResizeOff(); + // widget.EnableAxisConstraintOff(); + // widget.EnabledOff(); + // widget.ManagesCursorOff(); + widget.ProcessEventsOff();// MuDeMe! + // widget.RemoveAllObservers(); + + } + + private void addListener() { + if (currentSelection != null) { + currentSelection.addPropertyChangeListener(listener); + } + } + + private void removeListener() { + if (currentSelection != null) { + currentSelection.removePropertyChangeListener(listener); + } + } + + @Override + public void pick(PickInfo pi) { + removeListener(); + + ExtractSelection extract = new ExtractSelection(); + extract.setSelection(currentSelection); + extract.execute(pi); + + if (representation.GetHandle() != null && representation.GetHandle().GetNumberOfCells() == 0) { + moveSelectionOnTop(); + } + representation.SetHandle(currentSelection.getSelectionData()); + renderPanel.renderLater(); + + addListener(); + } + + public void clear() { + widget = null; + representation = null; + } + + public void selectionBoxOn() { + renderPanel.getInteractor().setStyleToArea(); + } + + public void selectionBoxOff() { + renderPanel.getInteractor().setStyleToDefault(); + } + + private void moveSelectionOnTop() { + renderPanel.lock(); + widget.Off(); + widget.On(); + renderPanel.unlock(); + } + + private void clearSelection() { + if (currentSelection != null) { + currentSelection.setIdList(null); + } + if (representation != null) { + representation.SetHandle(new vtkPolyData()); + renderPanel.renderLater(); + } + } + + public Selection getSelection() { + return currentSelection; + } + + public class SelectionListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getSource() instanceof Selection) { + Selection selection = (Selection) evt.getSource(); + if (evt.getPropertyName().equals("type")) { + switch (selection.getType()) { + case CELL: + selectionBoxOff(); + break; + case AREA: + selectionBoxOn(); + break; + case FEATURE: + selectionBoxOff(); + break; + + default: + break; + } + } else if (evt.getPropertyName().equals("dataSet")) { + currentSelection.setDataSet(selection.getDataSet()); + } + } + } + } + +} diff --git a/src/eu/engys/vtk/widgets/LayersCoverageWidget.java b/src/eu/engys/vtk/widgets/LayersCoverageWidget.java new file mode 100644 index 0000000..c7e87f2 --- /dev/null +++ b/src/eu/engys/vtk/widgets/LayersCoverageWidget.java @@ -0,0 +1,223 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets; + +import java.awt.Component; +import java.awt.GridLayout; +import java.io.File; +import java.text.DecimalFormat; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkLookupTable; +import vtk.vtkPolyData; +import vtk.vtkPolyDataReader; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.core.project.Model; +import eu.engys.core.project.mesh.FieldItem; +import eu.engys.core.project.mesh.FieldItem.DataType; +import eu.engys.gui.view3D.Actor; +import eu.engys.gui.view3D.LayerInfo; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.gui.view3D.Representation; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.util.ui.checkboxtree.VisibleItem; +import eu.engys.util.ui.textfields.AdaptativeFormat; +import eu.engys.vtk.VTKColors; +import eu.engys.vtk.VTKRangeCalculator; +import eu.engys.vtk.actors.DefaultActor; + +public class LayersCoverageWidget { + + class vtkPolyDataWidget { + + private RenderPanel renderPanel; + private Actor actor; + private vtkLookupTable lut; + + public vtkPolyDataWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + + vtkPolyDataReader reader = new vtkPolyDataReader(); + reader.ReadAllFieldsOn(); + reader.ReadAllScalarsOn(); + reader.SetFileName(new File(model.getProject().getBaseDir(), LAYER_INFO_VTK).getAbsolutePath()); + reader.Update(); + + final vtkPolyData layerInfo = reader.GetOutput(); + + this.actor = new DefaultActor("LayersInfo") { + { + newActor(layerInfo, true); + } + @Override + public VisibleItem getVisibleItem() { + return null; + } + @Override + public void setRepresentation(Representation representation) { + super.setRepresentation(Representation.SURFACE); + } + }; + } + + public void update(FieldItem field) { + new VTKRangeCalculator(field).calculateRange_Automatically_For(actor); + lut = new vtkLookupTable(); + VTKColors.applyTypeToLookupTable(field, lut); + this.actor.setScalarColors(lut, field); + } + + private void On() { + renderPanel.addActor(actor); + } + + private void Off() { + renderPanel.removeActor(actor); + } + + public vtkLookupTable getLut() { + return lut; + } + + public void Delete() { + renderPanel.removeActor(actor); + actor.deleteActor(); + lut.Delete(); + } + } + + private static final String LAYER_INFO_VTK = "layerInfo.vtk"; + private static final Logger logger = LoggerFactory.getLogger(LayersCoverageWidget.class); + + private final Model model; + private final RenderPanel renderPanel; + private final ProgressMonitor monitor; + + private vtkPolyDataWidget widget; + + private JPanel colorBar; + private LayerInfo layerInfo; + + public LayersCoverageWidget(Model model, RenderPanel renderPanel, ProgressMonitor monitor) { + this.model = model; + this.renderPanel = renderPanel; + this.monitor = monitor; + } + + public void activateLayersCoverage(LayerInfo layerInfo, JPanel colorBar, EventActionType action) { + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + if (this.colorBar != null) { + this.colorBar.removeAll(); + } + hide(); + } else if (action.equals(EventActionType.SHOW)) { + if (this.colorBar != null) { + this.colorBar.removeAll(); + } + this.colorBar = colorBar; + this.layerInfo = layerInfo; + show(); + } else if (action.equals(EventActionType.REMOVE)) { + clear(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void hide() { + if (widget != null) { + widget.Off(); + } + } + + private void show() { + if (widget == null) { + createWidget(); + } + + updateWidget(); + + widget.On(); + } + + private void updateWidget() { + FieldItem field = new FieldItem(layerInfo.getKey(), DataType.CELL, -1); + if (widget != null) { + widget.update(field); + } + if (colorBar != null) { + colorBar.removeAll(); + colorBar.setLayout(new GridLayout(1, 0)); +// colorBar.setLayout(new FlowLayout(SwingConstants.LEFT, 2, 1)); + double[] range = field.getRange(); + if (layerInfo.isDiscrete()) { + for (int i = (int) range[0]; i<= (int) range[1]; i++) { + colorBar.add(getLabelForValue(i, INT_FORMATTER.format(i))); + } + } else { + colorBar.add(getLabelForValue(range[0], DOUBLE_FORMATTER.format(range[0]))); + colorBar.add(getLabelForValue(range[1], DOUBLE_FORMATTER.format(range[1]))); + } + colorBar.revalidate(); + colorBar.repaint(); + } + } + + private static final AdaptativeFormat DOUBLE_FORMATTER = new AdaptativeFormat(new DecimalFormat("0.0##"), new DecimalFormat("0.0##E0"), 3); + private static final DecimalFormat INT_FORMATTER = new DecimalFormat("0"); + + private Component getLabelForValue(double value, String text) { + double[] color = new double[3]; + JLabel label = new JLabel(text); + label.setHorizontalAlignment(SwingConstants.CENTER); + label.setOpaque(true); + widget.getLut().GetColor(value, color); + label.setBackground(VTKColors.toSwing(color)); + label.setForeground(VTKColors.inverse(color)); + return label; + } + + private void createWidget() { + widget = new vtkPolyDataWidget(renderPanel); + } + + public void clear() { + renderPanel.lock(); + if (widget != null) { + widget.Delete(); + } + widget = null; + renderPanel.unlock(); + } + +} diff --git a/src/eu/engys/vtk/widgets/LogoWidget.java b/src/eu/engys/vtk/widgets/LogoWidget.java new file mode 100644 index 0000000..c492c34 --- /dev/null +++ b/src/eu/engys/vtk/widgets/LogoWidget.java @@ -0,0 +1,119 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import java.awt.Dimension; +import java.nio.file.Path; +import java.nio.file.Paths; + +import vtk.vtkGenericRenderWindowInteractor; +import vtk.vtkImageData; +import vtk.vtkLogoRepresentation; +import vtk.vtkLogoWidget; +import vtk.vtkPNGReader; +import eu.engys.gui.view3D.Interactor; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.ApplicationInfo; + +public class LogoWidget { + + private RenderPanel renderPanel; + private vtkLogoWidget logoWidget; + private vtkLogoRepresentation logoRepresentation; + private vtkImageData imageData; + + public LogoWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + this.imageData = createImageData(); + vtkLogoRepresentation logoRepresentation = createRepresentation(); + createWidget(logoRepresentation); + logoWidget.On(); + } + + private void createWidget(vtkLogoRepresentation logoRepresentation) { + logoWidget = new vtkLogoWidget(); + logoWidget.SetRepresentation(logoRepresentation); + logoWidget.ResizableOff(); + logoWidget.ProcessEventsOff(); + logoWidget.SelectableOff(); + + renderPanel.getInteractor().addObserver(logoWidget); + } + + private vtkLogoRepresentation createRepresentation() { + logoRepresentation = new vtkLogoRepresentation(); + logoRepresentation.SetImage(imageData); + + logoRepresentation.DragableOff(); + logoRepresentation.PickableOff(); + logoRepresentation.SetShowBorderToOff(); + logoRepresentation.ProportionalResizeOff(); + logoRepresentation.GetImageProperty().SetDisplayLocationToBackground(); + logoRepresentation.GetImageProperty().SetOpacity(0.7); + logoRepresentation.GetBorderProperty().SetOpacity(0); + logoRepresentation.VisibilityOn(); + + return logoRepresentation; + } + + private void placeRepresentation(Dimension size) { + logoRepresentation.GetPositionCoordinate().SetCoordinateSystemToDisplay(); + logoRepresentation.GetPosition2Coordinate().SetCoordinateSystemToDisplay(); + double imageWidth = imageData.GetBounds()[1]; + double imageHeight = imageData.GetBounds()[3]; + + double bottomLeftCornerX = size.width - imageWidth - 40; + double bottomLeftCornerY = 40; + double topRightCornerX = imageWidth + 1; + double topRightCornerY = imageHeight + 1; + + logoRepresentation.SetPosition(bottomLeftCornerX, bottomLeftCornerY); + logoRepresentation.SetPosition2(topRightCornerX, topRightCornerY); + + renderPanel.lock(); + final Interactor interactor = renderPanel.getInteractor(); + if (interactor instanceof vtkGenericRenderWindowInteractor) { + vtkGenericRenderWindowInteractor iren = (vtkGenericRenderWindowInteractor) interactor; + iren.LeftButtonPressEvent(); + iren.LeftButtonReleaseEvent(); + } + renderPanel.unlock(); + } + + private vtkImageData createImageData() { + vtkPNGReader reader = new vtkPNGReader(); + Path fileName = Paths.get(ApplicationInfo.getRootPath(), "img", ApplicationInfo.getVendor() + ".png"); + reader.SetFileName(fileName.toString()); + reader.Update(); + return reader.GetOutput(); + } + + public void update(Dimension size) { + placeRepresentation(size); + } + +} diff --git a/src/eu/engys/vtk/widgets/MinMaxPointWidget.java b/src/eu/engys/vtk/widgets/MinMaxPointWidget.java new file mode 100644 index 0000000..b06d6de --- /dev/null +++ b/src/eu/engys/vtk/widgets/MinMaxPointWidget.java @@ -0,0 +1,117 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import javax.vecmath.Point3d; + +import vtk.vtkHandleWidget; +import vtk.vtkSphereHandleRepresentation; +import eu.engys.gui.events.view3D.VolumeReportVisibilityEvent.Kind; +import eu.engys.gui.view3D.RenderPanel; + +public class MinMaxPointWidget { + + private RenderPanel renderPanel; + private vtkHandleWidget minWidget; + private vtkHandleWidget maxWidget; + private Point3d minPoint; + private Point3d maxPoint; + + public MinMaxPointWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + minWidget = createHandleWidget(new double[] { 0, 0, 1 }); + maxWidget = createHandleWidget(new double[] { 1, 0, 0 }); + } + + private vtkHandleWidget createHandleWidget(double[] color) { + + vtkSphereHandleRepresentation rep = new vtkSphereHandleRepresentation(); + rep.GetProperty().SetColor(color); + rep.GetProperty().SetLineWidth(1.0); + rep.GetSelectedProperty().SetColor(0.1, 0.1, 0.1); + rep.PickableOff(); + rep.DragableOff(); + // rep.ConstrainedOff(); + // rep.TranslationModeOff(); + + vtkHandleWidget widget = new vtkHandleWidget(); + widget.EnableAxisConstraintOff(); + widget.SetRepresentation(rep); + widget.EnabledOff(); + + renderPanel.getInteractor().addObserver(widget); + + return widget; + } + + public void clear() { + minWidget.EnabledOff(); + maxWidget.EnabledOff(); + minWidget.Delete(); + maxWidget.Delete(); + renderPanel.renderLater(); + } + + public void showPoint(Kind kind) { + if (kind.isMin() && minWidget.GetEnabled() == 0) { + minWidget.EnabledOn(); + renderPanel.renderLater(); + } else if (kind.isMax() && maxWidget.GetEnabled() == 0) { + maxWidget.EnabledOn(); + renderPanel.renderLater(); + } + updateCoordinates(); + } + + public void hidePoint(Kind kind) { + if (kind.isMin() && minWidget.GetEnabled() == 1) { + minWidget.EnabledOff(); + renderPanel.renderLater(); + } else if (kind.isMax() && maxWidget.GetEnabled() == 1) { + maxWidget.EnabledOff(); + renderPanel.renderLater(); + } + } + + public void setPoints(Point3d minPoint, Point3d maxPoint) { + this.minPoint = minPoint; + this.maxPoint = maxPoint; + updateCoordinates(); + } + + private void updateCoordinates() { + if (minWidget.GetEnabled() == 1 && minPoint != null) { + ((vtkSphereHandleRepresentation) minWidget.GetRepresentation()).SetWorldPosition(new double[] { minPoint.getX(), minPoint.getY(), minPoint.getZ() }); + renderPanel.renderLater(); + } + if (maxWidget.GetEnabled() == 1 && maxPoint != null) { + ((vtkSphereHandleRepresentation) maxWidget.GetRepresentation()).SetWorldPosition(new double[] { maxPoint.getX(), maxPoint.getY(), maxPoint.getZ() }); + renderPanel.renderLater(); + } + } + +} diff --git a/src/eu/engys/vtk/widgets/MinMaxPointWidgetManager.java b/src/eu/engys/vtk/widgets/MinMaxPointWidgetManager.java new file mode 100644 index 0000000..ff44365 --- /dev/null +++ b/src/eu/engys/vtk/widgets/MinMaxPointWidgetManager.java @@ -0,0 +1,74 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import java.util.HashMap; +import java.util.Map; + +import javax.vecmath.Point3d; + +import eu.engys.gui.events.view3D.VolumeReportVisibilityEvent.Kind; +import eu.engys.vtk.VTKRenderPanel; + +public class MinMaxPointWidgetManager { + + private Map widgetMap = new HashMap<>(); + private VTKRenderPanel vtkRendererPanel; + + public MinMaxPointWidgetManager(VTKRenderPanel vtkRendererPanel) { + this.vtkRendererPanel = vtkRendererPanel; + } + + public void clear() { + for (MinMaxPointWidget w : widgetMap.values()) { + w.clear(); + } + widgetMap.clear(); + } + + public void setPointsVisible(String key, Kind kind, boolean visible) { + if(visible){ + getPointWidget(key).showPoint(kind); + } else { + getPointWidget(key).hidePoint(kind); + } + } + + public void updateCoordinates(Point3d minPoint, Point3d maxPoint, String key) { + MinMaxPointWidget pointWidget = getPointWidget(key); + pointWidget.setPoints(minPoint, maxPoint); + } + + private MinMaxPointWidget getPointWidget(String key) { + if (!widgetMap.containsKey(key)) { + MinMaxPointWidget widget = new MinMaxPointWidget(vtkRendererPanel); + widgetMap.put(key, widget); + } + return widgetMap.get(key); + } + +} diff --git a/src/eu/engys/vtk/widgets/PlaneDisplayWidget.java b/src/eu/engys/vtk/widgets/PlaneDisplayWidget.java new file mode 100644 index 0000000..be8a497 --- /dev/null +++ b/src/eu/engys/vtk/widgets/PlaneDisplayWidget.java @@ -0,0 +1,113 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets; + +import vtk.vtkHandleWidget; +import vtk.vtkPlaneSource; +import vtk.vtkPolygonalHandleRepresentation3D; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.ui.textfields.DoubleField; + +public class PlaneDisplayWidget { + + private RenderPanel renderPanel; + private vtkHandleWidget widget; + private vtkPolygonalHandleRepresentation3D representation; + private DoubleField[] currentOrigin = null; + private DoubleField[] currentNormal = null; + + public PlaneDisplayWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + } + + public void showPlane(DoubleField[] origin, DoubleField[] normal, EventActionType action, double diagonal) { + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + if(widget != null){ + widget.Off(); + currentOrigin = null; + currentNormal = null; + } + } else if (action.equals(EventActionType.SHOW)) { + if(widget == null){ + createWidget(); + } + currentOrigin = origin; + currentNormal = normal; + changePosition(diagonal); + widget.On(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void createWidget() { + widget = new vtkHandleWidget(); + + representation = new vtkPolygonalHandleRepresentation3D(); + representation.GetProperty().SetColor(1, 1, 1); + representation.GetSelectedProperty().SetColor(1, 1, 1); + representation.DragableOff(); + representation.PickableOff(); + representation.ActiveRepresentationOff(); +// rep.SetWorldPosition(new double[] { 0.0, 0.0, 0.0 }); + + widget.SetRepresentation(representation); + widget.EnableAxisConstraintOff(); + widget.ProcessEventsOff(); + + renderPanel.getInteractor().addObserver(widget); + } + + + private void changePosition(double diagonal) { + double value = Double.isInfinite(diagonal) ? 1 : diagonal > 0 ? diagonal : 1; + + vtkPlaneSource planeSource = new vtkPlaneSource(); + planeSource.SetOrigin(0, 0, 0); + planeSource.SetPoint1(value, 0, 0); + planeSource.SetPoint2(0, value, 0); + planeSource.SetCenter(currentOrigin[0].getDoubleValue(), currentOrigin[1].getDoubleValue(), currentOrigin[2].getDoubleValue()); + planeSource.SetNormal(currentNormal[0].getDoubleValue(), currentNormal[1].getDoubleValue(), currentNormal[2].getDoubleValue()); + planeSource.Update(); + + representation.SetHandle(planeSource.GetOutput()); + } + + public void clear() { + renderPanel.lock(); + if(widget != null){ + widget.EnabledOff(); + widget.Delete(); + widget = null; + } + currentOrigin = null; + currentNormal = null; + renderPanel.unlock(); + renderPanel.renderLater(); + } +} diff --git a/src/eu/engys/vtk/widgets/PlaneWidget.java b/src/eu/engys/vtk/widgets/PlaneWidget.java new file mode 100644 index 0000000..cfbbbbc --- /dev/null +++ b/src/eu/engys/vtk/widgets/PlaneWidget.java @@ -0,0 +1,171 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import vtk.vtkPlaneWidget; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.ui.textfields.DoubleField; + +public class PlaneWidget { + + private RenderPanel renderPanel; + private vtkPlaneWidget widget; + private PropertyChangeListener listener; + private DoubleField[] currentOrigin = null; + private DoubleField[] currentNormal = null; + + public PlaneWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + listener = new PlaneFieldListener(); + } + + public void showPlane(DoubleField[] origin, DoubleField[] normal, EventActionType action, double diagonal) { + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + if(widget != null){ + widget.Off(); + removeListener(); + currentOrigin = null; + currentNormal = null; + } + } else if (action.equals(EventActionType.SHOW)) { + removeListener(); + if(widget == null){ + createWidget(diagonal); + } + currentOrigin = origin; + currentNormal = normal; + changePosition(); + widget.On(); + addListener(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void createWidget(double diagonal) { + widget = new vtkPlaneWidget(); + widget.SetHandleSize(1); + widget.SetRepresentationToSurface(); + widget.AddObserver("EndInteractionEvent", this, "handleEndInteraction"); + + widget.SetOrigin(0, 0, 0); + widget.SetPoint1(diagonal, 0, 0); + widget.SetPoint2(0, diagonal, 0); + +// widget.SetHandleSize(3); +// widget.SetPlaceFactor(1); +// widget.PlaceWidget(); +// widget.SetResolution(1); +// widget.GetPlaneProperty().SetColor(VTKColors.GREEN); +// widget.GetPlaneProperty().SetOpacity(0.7); +// widget.GetPlaneProperty().EdgeVisibilityOn(); + + renderPanel.getInteractor().addObserver(widget); + } + + public void clear() { + removeListener(); + renderPanel.lock(); + if(widget != null){ + widget.EnabledOff(); + widget.Delete(); + widget = null; + } + currentOrigin = null; + currentNormal = null; + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void changePosition() { + if (currentOrigin != null) { + widget.SetCenter(new double[] { currentOrigin[0].getDoubleValue(), currentOrigin[1].getDoubleValue(), currentOrigin[2].getDoubleValue() }); + } + if (currentNormal != null) { + widget.SetNormal(new double[] { currentNormal[0].getDoubleValue(), currentNormal[1].getDoubleValue(), currentNormal[2].getDoubleValue() }); + } + } + + private void addListener() { + if (currentOrigin != null) { + currentOrigin[0].addPropertyChangeListener(listener); + currentOrigin[1].addPropertyChangeListener(listener); + currentOrigin[2].addPropertyChangeListener(listener); + } + if (currentNormal != null) { + currentNormal[0].addPropertyChangeListener(listener); + currentNormal[1].addPropertyChangeListener(listener); + currentNormal[2].addPropertyChangeListener(listener); + } + } + + private void removeListener() { + if (currentOrigin != null) { + currentOrigin[0].removePropertyChangeListener(listener); + currentOrigin[1].removePropertyChangeListener(listener); + currentOrigin[2].removePropertyChangeListener(listener); + } + if (currentNormal != null) { + currentNormal[0].removePropertyChangeListener(listener); + currentNormal[1].removePropertyChangeListener(listener); + currentNormal[2].removePropertyChangeListener(listener); + } + } + + void handleEndInteraction() { + removeListener(); + if (currentOrigin != null) { + double[] position = widget.GetCenter(); + currentOrigin[0].setDoubleValue(position[0]); + currentOrigin[1].setDoubleValue(position[1]); + currentOrigin[2].setDoubleValue(position[2]); + } + if (currentNormal != null) { + double[] position = widget.GetNormal(); + currentNormal[0].setDoubleValue(position[0]); + currentNormal[1].setDoubleValue(position[1]); + currentNormal[2].setDoubleValue(position[2]); + } + addListener(); + } + + private final class PlaneFieldListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + changePosition(); + renderPanel.Render(); + } + } + } + +} diff --git a/src/eu/engys/vtk/widgets/PointWidget.java b/src/eu/engys/vtk/widgets/PointWidget.java new file mode 100644 index 0000000..d463171 --- /dev/null +++ b/src/eu/engys/vtk/widgets/PointWidget.java @@ -0,0 +1,139 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import java.awt.Color; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import vtk.vtkHandleWidget; +import vtk.vtkSphereHandleRepresentation; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.ui.textfields.DoubleField; + +public class PointWidget { + + private final class PointFieldListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + changePosition(); + renderPanel.renderLater(); + } + } + } + + private RenderPanel renderPanel; + private vtkSphereHandleRepresentation rep; + private vtkHandleWidget hwidget; + private PropertyChangeListener listener; + private DoubleField[] currentPoint = null; + + public PointWidget(RenderPanel renderPanel, Color color) { + this.renderPanel = renderPanel; + hwidget = new vtkHandleWidget(); + + renderPanel.getInteractor().addObserver(hwidget); + + rep = new vtkSphereHandleRepresentation(); + hwidget.SetRepresentation(rep); + hwidget.EnableAxisConstraintOff(); + hwidget.AddObserver("EndInteractionEvent", this, "handleEndInteraction"); + + rep.SetWorldPosition(new double[] { 0.0, 0.0, 0.0 }); + + float[] colorRGB = new float[3]; + color.getRGBColorComponents(colorRGB); + rep.GetProperty().SetColor(colorRGB[0], colorRGB[1], colorRGB[2]); + + rep.GetProperty().SetLineWidth(1.0); + rep.GetSelectedProperty().SetColor(0.1, 0.1, 0.1); + + listener = new PointFieldListener(); + } + + public void clear() { + removeListener(); + renderPanel.lock(); + hwidget.EnabledOff(); + hwidget.Delete(); + currentPoint = null; + renderPanel.unlock(); + renderPanel.renderLater(); + } + + public void showPoint(DoubleField[] point, EventActionType action) { + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + hwidget.EnabledOff(); + removeListener(); + currentPoint = null; + } else if (action.equals(EventActionType.SHOW)) { + removeListener(); + hwidget.EnabledOn(); + currentPoint = point; + changePosition(); + addListener(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void changePosition() { + if (currentPoint != null) { + rep.SetWorldPosition(new double[] { currentPoint[0].getDoubleValue(), currentPoint[1].getDoubleValue(), currentPoint[2].getDoubleValue() }); + } + } + + private void addListener() { + if (currentPoint != null) { + currentPoint[0].addPropertyChangeListener(listener); + currentPoint[1].addPropertyChangeListener(listener); + currentPoint[2].addPropertyChangeListener(listener); + } + } + + private void removeListener() { + if (currentPoint != null) { + currentPoint[0].removePropertyChangeListener(listener); + currentPoint[1].removePropertyChangeListener(listener); + currentPoint[2].removePropertyChangeListener(listener); + } + } + + void handleEndInteraction() { + removeListener(); + if (currentPoint != null) { + double[] position = rep.GetWorldPosition(); + currentPoint[0].setDoubleValue(position[0]); + currentPoint[1].setDoubleValue(position[1]); + currentPoint[2].setDoubleValue(position[2]); + } + addListener(); + } +} diff --git a/src/eu/engys/vtk/widgets/PointWidgetManager.java b/src/eu/engys/vtk/widgets/PointWidgetManager.java new file mode 100644 index 0000000..349096c --- /dev/null +++ b/src/eu/engys/vtk/widgets/PointWidgetManager.java @@ -0,0 +1,69 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets; + +import java.awt.Color; +import java.util.HashMap; +import java.util.Map; + +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.util.ui.textfields.DoubleField; +import eu.engys.vtk.VTKRenderPanel; + +public class PointWidgetManager { + + private Map widgetMap = new HashMap<>(); + private VTKRenderPanel vtkRendererPanel; + + public PointWidgetManager(VTKRenderPanel vtkRendererPanel) { + this.vtkRendererPanel = vtkRendererPanel; + } + + public void clear() { + for (PointWidget w : widgetMap.values()) { + w.clear(); + } + widgetMap.clear(); + } + + public void showPoint(DoubleField[] point, String key, EventActionType action, Color color) { + if (action.equals(EventActionType.REMOVE)) { + if (widgetMap.containsKey(key)) { + PointWidget w = widgetMap.remove(key); + w.clear(); + } + } else { + if (!widgetMap.containsKey(key)) { + PointWidget widget = new PointWidget(vtkRendererPanel, color); + widgetMap.put(key, widget); + } + PointWidget pointWidget = widgetMap.get(key); + pointWidget.showPoint(point, action); + } + } + +} diff --git a/src/eu/engys/vtk/widgets/QualityWidget.java b/src/eu/engys/vtk/widgets/QualityWidget.java new file mode 100644 index 0000000..3835127 --- /dev/null +++ b/src/eu/engys/vtk/widgets/QualityWidget.java @@ -0,0 +1,223 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets; + +import java.awt.Color; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import vtk.vtkHandleWidget; +import vtk.vtkPolyData; +import vtk.vtkPolygonalHandleRepresentation3D; +import vtk.vtkThreshold; +import vtk.vtkUnstructuredGrid; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.core.project.Model; +import eu.engys.gui.view3D.QualityInfo; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.progress.ProgressMonitor; +import eu.engys.vtk.VTKColors; +import eu.engys.vtk.VTKOpenFOAMDataset; +import eu.engys.vtk.VTKUtil; + +public class QualityWidget { + + public class QualityListener implements PropertyChangeListener{ + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("threshold")) { + if (evt.getSource() instanceof QualityInfo) { + updateWidget(); + } + } + } + } + + private static final Logger logger = LoggerFactory.getLogger(QualityWidget.class); + + private static final int FIELD_ASSOCIATION_CELLS = 1; + + private final Model model; + private final RenderPanel renderPanel; + private final ProgressMonitor monitor; + + private vtkHandleWidget widget; + private vtkPolygonalHandleRepresentation3D representation; + private QualityListener listener; + + private QualityInfo currentQualityInfo; + + public QualityWidget(Model model, RenderPanel renderPanel, ProgressMonitor monitor) { + this.model = model; + this.renderPanel = renderPanel; + this.monitor = monitor; + this.listener = new QualityListener(); + } + + public void activateQualityField(QualityInfo qualityInfo, EventActionType action) { + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + hide(); + } else if (action.equals(EventActionType.SHOW)) { + this.currentQualityInfo = qualityInfo; + show(); + } else if (action.equals(EventActionType.REMOVE)) { + clearSelection(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void hide() { + if (widget != null) { + widget.Off(); + removeListener(); + currentQualityInfo = null; + representation.SetHandle(new vtkPolyData()); + } + } + + private void show() { + if (widget == null) { + createWidget(); + } + + updateWidget(); + + widget.On(); + addListener(); + } + + private void setColor(Color color) { + double[] d = VTKColors.toVTK(color); + representation.GetProperty().SetColor(d); + representation.GetSelectedProperty().SetColor(d); + } + + private void createWidget() { + representation = new vtkPolygonalHandleRepresentation3D(); +// representation.GetProperty().LightingOff(); + + representation.DragableOff(); + representation.PickableOff(); + representation.ActiveRepresentationOff();//MuDeMe! + + widget = new vtkHandleWidget(); + renderPanel.getInteractor().addObserver(widget); + widget.SetRepresentation(representation); + +// widget.AllowHandleResizeOff(); +// widget.EnableAxisConstraintOff(); +// widget.EnabledOff(); +// widget.ManagesCursorOff(); + widget.ProcessEventsOff();//MuDeMe! +// widget.RemoveAllObservers(); + + } + + private vtkUnstructuredGrid internalMesh; + + private void updateWidget() { + if (internalMesh == null) { + loadInternalMesh(); + } + + setColor(currentQualityInfo.getColor()); + + vtkThreshold threshold = new vtkThreshold(); +// threshold.SetAttributeModeToUseCellData(); + threshold.SetInputData(internalMesh); +// threshold.AllScalarsOff(); + + switch (currentQualityInfo.getMeasure().getTest()) { + case MORE_THAN: + threshold.ThresholdByLower(currentQualityInfo.getThreshold()); + break; + case LESS_THAN: + threshold.ThresholdByUpper(currentQualityInfo.getThreshold()); + break; + default: + System.err.println("ERROR: Threshold not set!"); + break; + } + + threshold.SetInputArrayToProcess(0, 0, 0, "vtkDataObject::FIELD_ASSOCIATION_CELLS", currentQualityInfo.getMeasure().getFieldName()); + threshold.Update(); + + vtkPolyData dataSet = VTKUtil.geometryFilter(threshold.GetOutput()); + + representation.SetHandle(dataSet); + renderPanel.renderLater(); + } + + private void loadInternalMesh() { + monitor.start("Loading internal mesh", false, new Runnable() { + @Override + public void run() { + VTKOpenFOAMDataset dataset = new VTKOpenFOAMDataset(model, monitor); + dataset.loadInternalMesh(0); + + monitor.info("-> Internal Mesh Actor"); + internalMesh = VTKOpenFOAMDataset.shallowCopy(dataset.getInternalMeshDataset()); + + dataset.clear(); + monitor.end(); + } + }); + } + + private void addListener() { + if (currentQualityInfo != null && !currentQualityInfo.isListenedBy(listener)) { + currentQualityInfo.addPropertyChangeListener(listener); + } + } + + private void removeListener() { + if (currentQualityInfo != null && currentQualityInfo.isListenedBy(listener)) { + currentQualityInfo.removePropertyChangeListener(listener); + } + } + + public void clear() { + widget = null; + representation = null; + } + + private void clearSelection() { + if (representation != null) { + representation.SetHandle(new vtkPolyData()); + renderPanel.renderLater(); + } + } + + public QualityInfo getQualityInfo() { + return currentQualityInfo; + } + +} diff --git a/src/eu/engys/vtk/widgets/fake/FakeClipperWidget.java b/src/eu/engys/vtk/widgets/fake/FakeClipperWidget.java new file mode 100644 index 0000000..366778b --- /dev/null +++ b/src/eu/engys/vtk/widgets/fake/FakeClipperWidget.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets.fake; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.JToolBar; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class FakeClipperWidget extends FakeWidget { + + private static final Icon ICON = ResourcesUtil.getIcon("3d.widget.plane.icon"); + + @Override + public void populate(JToolBar toolbar) { + AbstractButton button = UiUtil.createToolBarButton(new ViewAction(ICON, TOOLTIP) { + + @Override + public void actionPerformed(ActionEvent e) { + } + }); + button.setEnabled(false); + components.add(button); + toolbar.add(button); + } + +} diff --git a/src/eu/engys/vtk/widgets/fake/FakeExportImageWidget.java b/src/eu/engys/vtk/widgets/fake/FakeExportImageWidget.java new file mode 100644 index 0000000..4d41e16 --- /dev/null +++ b/src/eu/engys/vtk/widgets/fake/FakeExportImageWidget.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets.fake; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.JToolBar; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class FakeExportImageWidget extends FakeWidget { + + private static final Icon ICON = ResourcesUtil.getIcon("3d.widget.export.icon"); + + @Override + public void populate(JToolBar toolbar) { + AbstractButton button = UiUtil.createToolBarButton(new ViewAction(ICON, TOOLTIP) { + + @Override + public void actionPerformed(ActionEvent e) { + } + }); + button.setEnabled(false); + components.add(button); + toolbar.add(button); + } + +} diff --git a/src/eu/engys/vtk/widgets/fake/FakeFieldsWidget.java b/src/eu/engys/vtk/widgets/fake/FakeFieldsWidget.java new file mode 100644 index 0000000..d972c6d --- /dev/null +++ b/src/eu/engys/vtk/widgets/fake/FakeFieldsWidget.java @@ -0,0 +1,64 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets.fake; + +import static eu.engys.util.ui.UiUtil.createToolBarComboButton; + +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JComboBox; +import javax.swing.JToolBar; + +import eu.engys.core.project.mesh.FieldItem; + +public class FakeFieldsWidget extends FakeWidget { + + private static final String PROTOTYPE = "UWater-Magnitude-Icon"; + + @Override + public void populate(JToolBar toolbar) { + toolbar.addSeparator(); + JComboBox fieldsCombo = createToolBarComboButton(getFieldsActions(new ArrayList()), TOOLTIP, PROTOTYPE, false, true); + fieldsCombo.setEnabled(false); + components.add(fieldsCombo); + toolbar.add(fieldsCombo); + } + + public List getFieldsActions(List fieldItems) { + List actions = new ArrayList<>(); + actions.add(new AbstractAction(FieldItem.SOLID) { + + @Override + public void actionPerformed(ActionEvent e) { + } + }); + return actions; + } +} diff --git a/src/eu/engys/vtk/widgets/fake/FakeRulerWidget.java b/src/eu/engys/vtk/widgets/fake/FakeRulerWidget.java new file mode 100644 index 0000000..7213305 --- /dev/null +++ b/src/eu/engys/vtk/widgets/fake/FakeRulerWidget.java @@ -0,0 +1,55 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets.fake; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.JToolBar; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class FakeRulerWidget extends FakeWidget { + + private static final Icon ICON = ResourcesUtil.getIcon("3d.widget.ruler.icon"); + + @Override + public void populate(JToolBar toolbar) { + AbstractButton button = UiUtil.createToolBarButton(new ViewAction(ICON, TOOLTIP) { + + @Override + public void actionPerformed(ActionEvent e) { + } + }); + button.setEnabled(false); + components.add(button); + toolbar.add(button); + } + +} diff --git a/src/eu/engys/vtk/widgets/fake/FakeScalarBarWidget.java b/src/eu/engys/vtk/widgets/fake/FakeScalarBarWidget.java new file mode 100644 index 0000000..41c37cb --- /dev/null +++ b/src/eu/engys/vtk/widgets/fake/FakeScalarBarWidget.java @@ -0,0 +1,70 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets.fake; + +import java.awt.event.ActionEvent; + +import javax.swing.Icon; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class FakeScalarBarWidget extends FakeWidget { + + private static final Icon SCALAR_BAR_ICON = ResourcesUtil.getIcon("3d.widget.scalarbar.icon"); + private static final Icon EDIT_SCALAR_BAR_ICON = ResourcesUtil.getIcon("3d.widget.editscalarbar.icon"); + + @Override + public void populate(JToolBar toolbar) { + JToggleButton showButton = UiUtil.createToolBarToggleButton(showAction, true); + JToggleButton editButton = UiUtil.createToolBarToggleButton(editAction, true); + + showButton.setEnabled(false); + editButton.setEnabled(false); + + components.add(showButton); + components.add(editButton); + + toolbar.add(showButton); + toolbar.add(editButton); + + } + + private ViewAction showAction = new ViewAction(null, SCALAR_BAR_ICON, TOOLTIP, false) { + @Override + public void actionPerformed(ActionEvent e) { + } + }; + + private ViewAction editAction = new ViewAction(null, EDIT_SCALAR_BAR_ICON, TOOLTIP, false) { + @Override + public void actionPerformed(ActionEvent e) { + } + }; +} diff --git a/src/eu/engys/vtk/widgets/fake/FakeSelectionWidget.java b/src/eu/engys/vtk/widgets/fake/FakeSelectionWidget.java new file mode 100644 index 0000000..6d882e8 --- /dev/null +++ b/src/eu/engys/vtk/widgets/fake/FakeSelectionWidget.java @@ -0,0 +1,56 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets.fake; + +import java.awt.event.ActionEvent; + +import javax.swing.Icon; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class FakeSelectionWidget extends FakeWidget { + + private static final Icon ICON = ResourcesUtil.getIcon("3d.widget.feature.icon"); + + @Override + public void populate(JToolBar toolbar) { + JToggleButton button = UiUtil.createToolBarToggleButton(action, true); + button.setEnabled(false); + toolbar.add(button); + components.add(button); + } + + private ViewAction action = new ViewAction(ICON, TOOLTIP) { + @Override + public void actionPerformed(ActionEvent e) { + } + }; + +} diff --git a/src/eu/engys/vtk/widgets/fake/FakeTimeStepsWidget.java b/src/eu/engys/vtk/widgets/fake/FakeTimeStepsWidget.java new file mode 100644 index 0000000..aee6d61 --- /dev/null +++ b/src/eu/engys/vtk/widgets/fake/FakeTimeStepsWidget.java @@ -0,0 +1,114 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets.fake; + +import static eu.engys.util.ui.UiUtil.createToolBarComboButton; + +import java.awt.event.ActionEvent; +import java.util.Collections; + +import javax.swing.AbstractButton; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JComboBox; +import javax.swing.JToolBar; + +import eu.engys.util.ui.ResourcesUtil; +import eu.engys.util.ui.UiUtil; +import eu.engys.util.ui.ViewAction; + +public class FakeTimeStepsWidget extends FakeWidget { + + private static final String PROTOTYPE = "12345.67"; + + public static final String[] COMPONENTS = new String[] { "Magnitude", "X", "Y", "Z" }; + + public static final Icon PREV_ICON = ResourcesUtil.getIcon("3d.widget.times.prev.icon"); + public static final Icon NEXT_ICON = ResourcesUtil.getIcon("3d.widget.times.next.icon"); + public static final Icon FIRST_ICON = ResourcesUtil.getIcon("3d.widget.times.first.icon"); + public static final Icon LAST_ICON = ResourcesUtil.getIcon("3d.widget.times.last.icon"); + public static final Icon REFRESH_ICON = ResourcesUtil.getIcon("3d.widget.times.refresh.icon"); + + private Action NEXT_STEP = new ViewAction(null, NEXT_ICON, TOOLTIP, false) { + @Override + public void actionPerformed(ActionEvent e) { + } + }; + private Action PREVIOUS_STEP = new ViewAction(null, PREV_ICON, TOOLTIP, false) { + @Override + public void actionPerformed(ActionEvent e) { + } + }; + private Action FIRST_STEP = new ViewAction(null, FIRST_ICON, TOOLTIP, false) { + @Override + public void actionPerformed(ActionEvent e) { + } + }; + private Action LAST_STEP = new ViewAction(null, LAST_ICON, TOOLTIP, false) { + @Override + public void actionPerformed(ActionEvent e) { + } + }; + private Action REFRESH = new ViewAction(null, REFRESH_ICON, TOOLTIP, false) { + @Override + public void actionPerformed(ActionEvent e) { + } + }; + + @Override + public void populate(JToolBar toolbar) { + JComboBox timesCombo = createToolBarComboButton(Collections. emptyList(), TOOLTIP, PROTOTYPE, true, true); + AbstractButton firstButton = UiUtil.createToolBarButton(FIRST_STEP); + AbstractButton previousButton = UiUtil.createToolBarButton(PREVIOUS_STEP); + AbstractButton nextButton = UiUtil.createToolBarButton(NEXT_STEP); + AbstractButton lastButton = UiUtil.createToolBarButton(LAST_STEP); + AbstractButton refreshButton = UiUtil.createToolBarButton(REFRESH); + + timesCombo.setEnabled(false); + firstButton.setEnabled(false); + previousButton.setEnabled(false); + nextButton.setEnabled(false); + lastButton.setEnabled(false); + refreshButton.setEnabled(false); + + toolbar.addSeparator(); + toolbar.add(timesCombo); + toolbar.add(firstButton); + toolbar.add(previousButton); + toolbar.add(nextButton); + toolbar.add(lastButton); + toolbar.add(refreshButton); + toolbar.addSeparator(); + + components.add(timesCombo); + components.add(firstButton); + components.add(previousButton); + components.add(nextButton); + components.add(lastButton); + components.add(refreshButton); + } + +} diff --git a/src/eu/engys/vtk/widgets/fake/FakeWidget.java b/src/eu/engys/vtk/widgets/fake/FakeWidget.java new file mode 100644 index 0000000..dd3fbd6 --- /dev/null +++ b/src/eu/engys/vtk/widgets/fake/FakeWidget.java @@ -0,0 +1,118 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + +package eu.engys.vtk.widgets.fake; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JComponent; + +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.gui.view3D.widget.Widget; +import eu.engys.gui.view3D.widget.WidgetComponent; + +public abstract class FakeWidget implements Widget { + + protected static final String TOOLTIP = "To enable this feature please contact: info@engys.com"; + + protected List components = new ArrayList(); + + @Override + public void populate(CanvasPanel view3d) { + } + + @Override + public boolean canShow() { + return false; + } + + @Override + public void show() { + disableAll(); + } + + @Override + public void hide() { + disableAll(); + } + + @Override + public void clear() { + disableAll(); + } + + @Override + public void stop() { + disableAll(); + } + + @Override + public WidgetComponent getWidgetComponent() { + return null; + } + + @Override + public void load() { + disableAll(); + } + + @Override + public void applyContext() { + disableAll(); + } + + @Override + public void handleFieldChanged() { + disableAll(); + } + + @Override + public void handleTimeStepChanged() { + disableAll(); + } + + @Override + public void handleNewTimeStepsRead() { + disableAll(); + } + +// @Override +// public void handleInitializeFieldsStarted() { +// disableAll(); +// } +// +// @Override +// public void handleInitializeFieldsFinished() { +// disableAll(); +// } + + private void disableAll() { + for (JComponent c : components) { + c.setEnabled(false); + } + } + +} diff --git a/src/eu/engys/vtk/widgets/panels/BoundingBoxBar.java b/src/eu/engys/vtk/widgets/panels/BoundingBoxBar.java new file mode 100644 index 0000000..1db2b3a --- /dev/null +++ b/src/eu/engys/vtk/widgets/panels/BoundingBoxBar.java @@ -0,0 +1,120 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets.panels; + +import java.awt.Color; +import java.awt.FlowLayout; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +import eu.engys.core.project.geometry.BoundingBox; +import eu.engys.gui.view3D.CanvasPanel; +import eu.engys.util.Symbols; +import eu.engys.util.plaf.ILookAndFeel; + +public class BoundingBoxBar extends JPanel { + + private JLabel xlabel; + private JLabel ylabel; + private JLabel zlabel; + private CanvasPanel view3D; + + public BoundingBoxBar(CanvasPanel view3D, ILookAndFeel laf) { + super(new FlowLayout(FlowLayout.LEFT)); + this.view3D = view3D; + this.xlabel = new JLabel(); + this.ylabel = new JLabel(); + this.zlabel = new JLabel(); + xlabel.setForeground(Color.RED.darker()); + ylabel.setForeground(Color.GREEN.darker()); + zlabel.setForeground(Color.BLUE.darker()); + add(xlabel); + add(ylabel); + add(zlabel); + +// setOpaque(true); +// double[] color = laf.get3DColor1(); +// setBackground(new Color((float) color[0], (float) color[1], (float) color[2])); + } + +// @Override +// protected void paintComponent(Graphics g) { +// Dimension size = getSize(); +// g.setColor(getBackground()); +// g.fillRect(0, 0, size.width, size.height); +// } + + public BoundingBox update() { + BoundingBox box = view3D.computeBoundingBox(true); + if (isEmpty(box)) { + box = new BoundingBox(0, 0, 0, 0, 0, 0); + } + + String formattedXmin = getFormattedNumber(box.getXmin()); + String formattedYmin = getFormattedNumber(box.getYmin()); + String formattedZmin = getFormattedNumber(box.getZmin()); + + String formattedXmax = getFormattedNumber(box.getXmax()); + String formattedYmax = getFormattedNumber(box.getYmax()); + String formattedZmax = getFormattedNumber(box.getZmax()); + + String formattedXDifference = getFormattedNumber((box.getXmax() - box.getXmin())); + String formattedYDifference = getFormattedNumber((box.getYmax() - box.getYmin())); + String formattedZDifference = getFormattedNumber((box.getZmax() - box.getZmin())); + + String xLabelText = String.format(Locale.US, "X [%s , %s] delta %s", formattedXmin, formattedXmax, formattedXDifference).replace("delta", Symbols.DELTA); + String yLabelText = String.format(Locale.US, "Y [%s , %s] delta %s", formattedYmin, formattedYmax, formattedYDifference).replace("delta", Symbols.DELTA); + String zLabelText = String.format(Locale.US, "Z [%s , %s] delta %s", formattedZmin, formattedZmax, formattedZDifference).replace("delta", Symbols.DELTA); + + xlabel.setText(xLabelText); + ylabel.setText(yLabelText); + zlabel.setText(zLabelText); + + return box; + } + + private boolean isEmpty(BoundingBox box) { + boolean xok = box.getXmin() == Double.MAX_VALUE && box.getXmax() == -Double.MAX_VALUE; + boolean yok = box.getYmin() == Double.MAX_VALUE && box.getYmax() == -Double.MAX_VALUE; + boolean zok = box.getZmin() == Double.MAX_VALUE && box.getZmax() == -Double.MAX_VALUE; + return xok && yok && zok; + } + + private String getFormattedNumber(double d) { + DecimalFormat formatter = null; + if (String.valueOf(d).length() > 6) { + formatter = new DecimalFormat("0.00E0", new DecimalFormatSymbols(Locale.US)); + } else { + formatter = new DecimalFormat("#,###,##0.0##############", new DecimalFormatSymbols(Locale.US)); + } + return formatter.format(d); + } +} diff --git a/src/eu/engys/vtk/widgets/shapes/BoxWidget.java b/src/eu/engys/vtk/widgets/shapes/BoxWidget.java new file mode 100644 index 0000000..5313015 --- /dev/null +++ b/src/eu/engys/vtk/widgets/shapes/BoxWidget.java @@ -0,0 +1,192 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets.shapes; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import vtk.vtkActor; +import vtk.vtkBoxRepresentation; +import vtk.vtkBoxWidget2; +import vtk.vtkTransform; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.ui.textfields.DoubleField; + +public class BoxWidget { + + private RenderPanel renderPanel; + private vtkBoxWidget2 widget; + private vtkActor actor; + private BoxFieldListener listener; + private DoubleField[] currentPoint1 = null; + private DoubleField[] currentPoint2 = null; + + public BoxWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + listener = new BoxFieldListener(); + } + + final Runnable callback = new Runnable() { + vtkTransform trasform = new vtkTransform(); + + public void run() { + if (actor != null) { + vtkBoxRepresentation rep = (vtkBoxRepresentation) widget.GetRepresentation(); + rep.GetTransform(trasform); + actor.SetUserTransform(trasform); + } + + removeListener(); + double[] position = widget.GetRepresentation().GetBounds(); + if (currentPoint1 != null) { + currentPoint1[0].setDoubleValue(position[0]); + currentPoint1[1].setDoubleValue(position[2]); + currentPoint1[2].setDoubleValue(position[4]); + } + if (currentPoint2 != null) { + currentPoint2[0].setDoubleValue(position[1]); + currentPoint2[1].setDoubleValue(position[3]); + currentPoint2[2].setDoubleValue(position[5]); + } + addListener(); + } + }; + + public void showBox(vtkActor actor, DoubleField[] point1, DoubleField[] point2, EventActionType action) { + this.actor = actor; + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + if (widget != null) { + widget.Off(); + removeListener(); + currentPoint1 = null; + currentPoint2 = null; + } + } else if (action.equals(EventActionType.SHOW)) { + removeListener(); + if (widget == null) { + createWidget(); + } + widget.On(); + currentPoint1 = point1; + currentPoint2 = point2; + changePosition(); + addListener(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void createWidget() { + final vtkBoxRepresentation representation = new vtkBoxRepresentation(); + representation.SetPlaceFactor(1); + if (actor != null) { + representation.PlaceWidget(actor.GetBounds()); + } else { + representation.PlaceWidget(new double[]{ 0.0,1.0,0.0,1.0,0.0,1.0}); + } + + widget = new vtkBoxWidget2(); + renderPanel.getInteractor().addObserver(widget); + widget.AddObserver("EndInteractionEvent", callback, "run"); + + widget.SetRepresentation(representation); + widget.RotationEnabledOff(); + } + + public void clear() { + removeListener(); + renderPanel.lock(); + if (widget != null) { +// widget.RemoveAllObservers(); + widget.EnabledOff(); + widget.Delete(); + widget = null; + } + currentPoint1 = null; + currentPoint2 = null; + renderPanel.unlock(); + renderPanel.renderLater(); + } + + public void hideWidget() { + clear(); + } + + private void changePosition() { + if (currentPoint1 != null && currentPoint2 != null) { + double minX = currentPoint1[0].getDoubleValue(); + double maxX = currentPoint2[0].getDoubleValue(); + + double minY = currentPoint1[1].getDoubleValue(); + double maxY = currentPoint2[1].getDoubleValue(); + + double minZ = currentPoint1[2].getDoubleValue(); + double maxZ = currentPoint2[2].getDoubleValue(); + + ((vtkBoxRepresentation) widget.GetRepresentation()).PlaceWidget(new double[] { minX, maxX, minY, maxY, minZ, maxZ }); + } + } + + private void addListener() { + if (currentPoint1 != null) { + currentPoint1[0].addPropertyChangeListener(listener); + currentPoint1[1].addPropertyChangeListener(listener); + currentPoint1[2].addPropertyChangeListener(listener); + } + if (currentPoint2 != null) { + currentPoint2[0].addPropertyChangeListener(listener); + currentPoint2[1].addPropertyChangeListener(listener); + currentPoint2[2].addPropertyChangeListener(listener); + } + } + + private void removeListener() { + if (currentPoint1 != null) { + currentPoint1[0].removePropertyChangeListener(listener); + currentPoint1[1].removePropertyChangeListener(listener); + currentPoint1[2].removePropertyChangeListener(listener); + } + if (currentPoint2 != null) { + currentPoint2[0].removePropertyChangeListener(listener); + currentPoint2[1].removePropertyChangeListener(listener); + currentPoint2[2].removePropertyChangeListener(listener); + } + } + + private final class BoxFieldListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + changePosition(); + renderPanel.renderLater(); + } + } + } + +} diff --git a/src/eu/engys/vtk/widgets/shapes/CylinderWidget.java b/src/eu/engys/vtk/widgets/shapes/CylinderWidget.java new file mode 100644 index 0000000..d53a666 --- /dev/null +++ b/src/eu/engys/vtk/widgets/shapes/CylinderWidget.java @@ -0,0 +1,207 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets.shapes; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import vtk.vtkActor; +import vtk.vtkBoxRepresentation; +import vtk.vtkBoxWidget2; +import vtk.vtkLineSource; +import vtk.vtkTransform; +import vtk.vtkTubeFilter; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.ui.textfields.DoubleField; + +public class CylinderWidget { + + private RenderPanel renderPanel; + + private vtkBoxWidget2 widget; + private vtkActor actor; + private BoxFieldListener listener; + private DoubleField[] currentPoint1 = null; + private DoubleField[] currentPoint2 = null; + private DoubleField currentRadius = null; + + public CylinderWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + listener = new BoxFieldListener(); + } + + final Runnable callback = new Runnable() { + vtkTransform transform = new vtkTransform(); + + public void run() { + if (actor != null) { + vtkBoxRepresentation rep = (vtkBoxRepresentation) widget.GetRepresentation(); + rep.GetTransform(transform); + actor.SetUserTransform(transform); + + vtkTubeFilter tubeFilter = (vtkTubeFilter) actor.GetMapper().GetInputConnection(0, 0).GetProducer(); + vtkLineSource cyl = (vtkLineSource) tubeFilter.GetInputConnection(0, 0).GetProducer(); + + double[] tPoint1 = transform.TransformVector(cyl.GetPoint1()); + double[] tPoint2 = transform.TransformVector(cyl.GetPoint2()); + + double[] center = transform.GetPosition(); + + double radius = 0; + // How to find it??? + + removeListener(); + if (currentPoint1 != null) { + currentPoint1[0].setDoubleValue(tPoint1[0] + center[0]); + currentPoint1[1].setDoubleValue(tPoint1[1] + center[1]); + currentPoint1[2].setDoubleValue(tPoint1[2] + center[2]); + } + if (currentPoint2 != null) { + currentPoint2[0].setDoubleValue(tPoint2[0] + center[0]); + currentPoint2[1].setDoubleValue(tPoint2[1] + center[1]); + currentPoint2[2].setDoubleValue(tPoint2[2] + center[2]); + } + if (currentRadius != null) { + currentRadius.setDoubleValue(radius); + } + + addListener(); + } + } + }; + + public void showWidget(vtkActor actor, DoubleField[] point1, DoubleField[] point2, DoubleField radius, EventActionType action) { + this.actor = actor; + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + if (widget != null) { + widget.Off(); + removeListener(); + currentPoint1 = null; + currentPoint2 = null; + currentRadius = null; + } + } else if (action.equals(EventActionType.SHOW)) { + removeListener(); + if (widget == null) { + createWidget(); + } + widget.On(); + currentPoint1 = point1; + currentPoint2 = point2; + currentRadius = radius; + changePosition(); + addListener(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void createWidget() { + final vtkBoxRepresentation representation = new vtkBoxRepresentation(); + representation.SetPlaceFactor(1); + representation.PlaceWidget(actor.GetBounds()); + + widget = new vtkBoxWidget2(); + widget.RemoveAllObservers(); + widget.AddObserver("EndInteractionEvent", callback, "run"); + + renderPanel.getInteractor().addObserver(widget); + + widget.SetRepresentation(representation); + } + + public void clear() { + removeListener(); + renderPanel.lock(); + if (widget != null) { + widget.EnabledOff(); + widget.Delete(); + widget = null; + } + currentPoint1 = null; + currentPoint2 = null; + currentRadius = null; + renderPanel.unlock(); + renderPanel.renderLater(); + } + + public void hideWidget() { + clear(); + } + + private void changePosition() { + // If you change the coordinates from the GeometriesPanelBuilder it + // doesn't work great + ((vtkBoxRepresentation) widget.GetRepresentation()).PlaceWidget(actor.GetBounds()); + renderPanel.Render(); + } + + private void addListener() { + if (currentPoint1 != null) { + currentPoint1[0].addPropertyChangeListener(listener); + currentPoint1[1].addPropertyChangeListener(listener); + currentPoint1[2].addPropertyChangeListener(listener); + } + if (currentPoint2 != null) { + currentPoint2[0].addPropertyChangeListener(listener); + currentPoint2[1].addPropertyChangeListener(listener); + currentPoint2[2].addPropertyChangeListener(listener); + } + if (currentRadius != null) { + currentRadius.addPropertyChangeListener(listener); + } + } + + private void removeListener() { + if (currentPoint1 != null) { + currentPoint1[0].removePropertyChangeListener(listener); + currentPoint1[1].removePropertyChangeListener(listener); + currentPoint1[2].removePropertyChangeListener(listener); + } + if (currentPoint2 != null) { + currentPoint2[0].removePropertyChangeListener(listener); + currentPoint2[1].removePropertyChangeListener(listener); + currentPoint2[2].removePropertyChangeListener(listener); + } + if (currentRadius != null) { + currentRadius.removePropertyChangeListener(listener); + } + } + + private final class BoxFieldListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + changePosition(); + renderPanel.Render(); + } + } + } + +} diff --git a/src/eu/engys/vtk/widgets/shapes/SphereWidget.java b/src/eu/engys/vtk/widgets/shapes/SphereWidget.java new file mode 100644 index 0000000..034da8a --- /dev/null +++ b/src/eu/engys/vtk/widgets/shapes/SphereWidget.java @@ -0,0 +1,228 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package eu.engys.vtk.widgets.shapes; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import vtk.vtkActor; +import vtk.vtkBoxRepresentation; +import vtk.vtkBoxWidget2; +import vtk.vtkTransform; +import eu.engys.core.dictionary.model.EventActionType; +import eu.engys.gui.view3D.RenderPanel; +import eu.engys.util.ui.textfields.DoubleField; + +public class SphereWidget { + + private RenderPanel renderPanel; + private vtkBoxWidget2 widget; + private vtkActor actor; + private BoxFieldListener listener; + private DoubleField[] currentCenter = null; + private DoubleField currentRadius = null; + + public SphereWidget(RenderPanel renderPanel) { + this.renderPanel = renderPanel; + listener = new BoxFieldListener(); + } + + final Runnable callback = new Runnable() { + vtkTransform transform = new vtkTransform(); + + public void run() { + if (actor != null) { + vtkBoxRepresentation rep = (vtkBoxRepresentation) widget.GetRepresentation(); + rep.GetTransform(transform); + actor.SetUserTransform(transform); + } + + removeListener(); + double[] position = widget.GetRepresentation().GetBounds(); + + double x = (position[0] + position[1]) / 2; + double y = (position[2] + position[3]) / 2; + double z = (position[4] + position[5]) / 2; + + double diffX = Math.abs(position[0] - position[1]); + double diffY = Math.abs(position[2] - position[3]); + double diffZ = Math.abs(position[4] - position[5]); + + double radius = Math.min(diffX, Math.min(diffY, diffZ)) / 2; + + if (currentCenter != null) { + currentCenter[0].setDoubleValue(x); + currentCenter[1].setDoubleValue(y); + currentCenter[2].setDoubleValue(z); + } + if (currentRadius != null) { + currentRadius.setDoubleValue(radius); + } + addListener(); + } + }; + + final Runnable callback2 = new Runnable() { + vtkTransform transform = new vtkTransform(); + + public void run() { + if (actor != null) { + vtkBoxRepresentation rep = (vtkBoxRepresentation) widget.GetRepresentation(); + rep.GetTransform(transform); + + double[] scale = transform.GetScale(); + double[] position = transform.GetPosition(); + + double scaleX = scale[0]; + double scaleY = scale[1]; + double scaleZ = scale[2]; + + double max = Math.max(scaleX, Math.max(scaleY, scaleZ)); + + vtkTransform newT = new vtkTransform(); +// newT. + newT.Scale(max, max, max); + + rep.SetTransform(newT); + } + + } + }; + + public void showWidget(vtkActor actor, DoubleField[] center, DoubleField radius, EventActionType action) { + this.actor = actor; + renderPanel.lock(); + if (action.equals(EventActionType.HIDE)) { + if (widget != null) { + widget.Off(); + removeListener(); + currentCenter = null; + currentRadius = null; + } + } else if (action.equals(EventActionType.SHOW)) { + removeListener(); + if (widget == null) { + createWidget(); + } + widget.On(); + currentCenter = center; + currentRadius = radius; + changePosition(); + addListener(); + } + renderPanel.unlock(); + renderPanel.renderLater(); + } + + private void createWidget() { + final vtkBoxRepresentation representation = new vtkBoxRepresentation(); + representation.SetPlaceFactor(1); + representation.PlaceWidget(actor.GetBounds()); + + widget = new vtkBoxWidget2(); + widget.AddObserver("EndInteractionEvent", callback, "run"); + widget.AddObserver("InteractionEvent", callback2, "run"); + + widget.SetRepresentation(representation); + widget.RotationEnabledOff(); + + renderPanel.getInteractor().addObserver(widget); + } + + public void clear() { + removeListener(); + renderPanel.lock(); + if (widget != null) { + // widget.RemoveAllObservers(); + widget.EnabledOff(); + widget.Delete(); + widget = null; + } + currentCenter = null; + currentRadius = null; + renderPanel.unlock(); + renderPanel.renderLater(); + } + + public void hideWidget() { + clear(); + } + + private void changePosition() { + if (currentCenter != null && currentRadius != null) { + double x = currentCenter[0].getDoubleValue(); + double y = currentCenter[1].getDoubleValue(); + double z = currentCenter[2].getDoubleValue(); + + double radius = currentRadius.getDoubleValue(); + + double minX = x - radius; + double maxX = x + radius; + + double minY = y - radius; + double maxY = y + radius; + + double minZ = z - radius; + double maxZ = z + radius; + + ((vtkBoxRepresentation) widget.GetRepresentation()).PlaceWidget(new double[] { minX, maxX, minY, maxY, minZ, maxZ }); + } + } + + private void addListener() { + if (currentCenter != null) { + currentCenter[0].addPropertyChangeListener(listener); + currentCenter[1].addPropertyChangeListener(listener); + currentCenter[2].addPropertyChangeListener(listener); + } + if (currentRadius != null) { + currentRadius.addPropertyChangeListener(listener); + } + } + + private void removeListener() { + if (currentCenter != null) { + currentCenter[0].removePropertyChangeListener(listener); + currentCenter[1].removePropertyChangeListener(listener); + currentCenter[2].removePropertyChangeListener(listener); + } + if (currentRadius != null) { + currentRadius.removePropertyChangeListener(listener); + } + } + + private final class BoxFieldListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("value")) { + changePosition(); + renderPanel.Render(); + } + } + } + +} diff --git a/src/vtk/vtkPanel.java b/src/vtk/vtkPanel.java new file mode 100644 index 0000000..56d319a --- /dev/null +++ b/src/vtk/vtkPanel.java @@ -0,0 +1,194 @@ +/*--------------------------------*- Java -*---------------------------------*\ + | o | + | o o | HelyxOS: The Open Source GUI for OpenFOAM | + | o O o | Copyright (C) 2012-2016 ENGYS | + | o o | http://www.engys.com | + | o | | + |---------------------------------------------------------------------------| + | License | + | This file is part of HelyxOS. | + | | + | HelyxOS is free software; you can redistribute it and/or modify it | + | under the terms of the GNU General Public License as published by the | + | Free Software Foundation; either version 2 of the License, or (at your | + | option) any later version. | + | | + | HelyxOS 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 General Public License | + | for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with HelyxOS; if not, write to the Free Software Foundation, | + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +\*---------------------------------------------------------------------------*/ + + +package vtk; + +import java.awt.Canvas; +import java.awt.Graphics; + +public class vtkPanel extends Canvas { + + private static final long serialVersionUID = 1L; + + protected vtkRenderWindow rw; + protected vtkRenderer ren; + protected vtkRenderer sren; + protected int windowset = 0; + protected boolean rendering = false; + + public void dispose() { + rendering = true; + + ren.RemoveAllLights(); + ren.RemoveAllObservers(); +// ren.RemoveAllProps(); + ren.RemoveAllViewProps(); + + rw.RemoveRenderer(ren); + + ren.Delete(); + rw.Delete(); + + ren = null; + rw = null; + + vtkObject.JAVA_OBJECT_MANAGER.deleteAll(); + + rw = new vtkRenderWindow(); + ren = new vtkRenderer(); + + rw.AddRenderer(ren); + windowset = 0; + rendering = false; + } + + public void Delete() { + if (rendering) { + return; + } + rendering = true; + // We prevent any further rendering + + if (this.getParent() != null) { + this.getParent().remove(this); + } + // Free internal VTK objects + ren = null; + // On linux we prefer to have a memory leak instead of a crash + if (!rw.GetClassName().equals("vtkXOpenGLRenderWindow")) { + rw = null; + } else { + System.out.println("The renderwindow has been kept arount to prevent a crash"); + } + } + + protected native int RenderCreate(vtkRenderWindow id0); + + protected native int Lock(); + + protected native int UnLock(); + + public vtkPanel() { + this.rw = new vtkRenderWindow(); + this.ren = new vtkRenderer(); + this.sren = new vtkRenderer(); + + + ren.SetLayer(0); + ren.InteractiveOn(); + + sren.SetLayer(1); + sren.InteractiveOff(); + + rw.SetNumberOfLayers(2); + rw.AddRenderer(ren); + rw.AddRenderer(sren); + + sren.SetActiveCamera(ren.GetActiveCamera()); + } + + public vtkRenderer GetRenderer() { + return ren; + } + + public vtkRenderer GetSelectionRenderer() { + return sren; + } + + public vtkRenderWindow GetRenderWindow() { + return rw; + } + + public void addNotify() { + super.addNotify(); + windowset = 0; + rendering = false; + rw.SetForceMakeCurrent(); + repaint(); + } + + public void removeNotify() { + if(windowset == 0) { + super.removeNotify(); + return; + } + if(rw != null) + { + Lock(); + rw.Finalize(); + UnLock(); + windowset = 0; + } + rendering = true; + super.removeNotify(); + } + + public synchronized void Render() { + if (!rendering) { + rendering = true; + if (rw != null) { + if (windowset == 0) { + createBufferStrategy(2); + // set the window id + RenderCreate(rw); + Lock(); + rw.SetSize(getWidth(), getHeight()); + UnLock(); + windowset = 1; + } + Lock(); + rw.Render(); + UnLock(); + } + rendering = false; + } + } + + public boolean isWindowSet() { + return (this.windowset == 1); + } + + public void paint(Graphics g) { + this.Render(); + } + + public void update(Graphics g) { + paint(g); + } + + public void resetCameraClippingRange() { + Lock(); + ren.ResetCameraClippingRange(); + UnLock(); + } + + public void resetCamera() { + Lock(); + ren.ResetCamera(); + UnLock(); + } + +}

5h2z2+u&aa*&=2I^4>%wcjh= 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%0Du8ayy{^ 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 literal 0 HcmV?d00001 diff --git a/src/eu/engys/resources/helyxos_products.png b/src/eu/engys/resources/helyxos_products.png new file mode 100644 index 0000000000000000000000000000000000000000..682ea2b06de7d666cdf73e7a98f08ba515c90610 GIT binary patch literal 145329 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