From 4ecd4a28a8440c65797d798ce603908289fb3933 Mon Sep 17 00:00:00 2001 From: Firas Bouzazi <firas.bouzazi@imt-atlantique.net> Date: Tue, 26 Nov 2024 11:11:39 +0100 Subject: [PATCH] pne editor adapters added --- .idea/libraries/pne_editor.xml | 11 + .idea/misc.xml | 3 + pne-editor/.idea/.gitignore | 8 + pne-editor/.idea/codeStyles/Project.xml | 7 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + pne-editor/.idea/misc.xml | 9 + pne-editor/.idea/modules.xml | 8 + pne-editor/.idea/pne-editor.iml | 9 + .../.settings/org.eclipse.jdt.core.prefs | 11 + pne-editor/README.md | 28 + pne-editor/examples/insurance-company.pflow | 400 +++++++++ pne-editor/examples/start-stop-cancel.pflowx | 81 ++ pne-editor/lib/hamcrest-core-1.3.jar | Bin 0 -> 45024 bytes pne-editor/lib/javax.xml.bind.jar | Bin 0 -> 103515 bytes .../pn-imta-initial-models-and-adapters.jar | Bin 0 -> 130430 bytes pne-editor/src/logger/PNEditorLogger.java | 98 +++ pne-editor/src/org/petriNet/Arc.java | 50 ++ pne-editor/src/org/petriNet/IncomingArc.java | 31 + .../src/org/petriNet/IncomingArc_Simple.java | 9 + .../src/org/petriNet/IncomingArc_Videur.java | 25 + .../src/org/petriNet/IncomingArc_Zero.java | 13 + pne-editor/src/org/petriNet/Main.java | 134 +++ pne-editor/src/org/petriNet/OutgoingArc.java | 15 + pne-editor/src/org/petriNet/PetriNet.java | 457 ++++++++++ .../src/org/petriNet/PetriNetService.java | 31 + pne-editor/src/org/petriNet/Place.java | 53 ++ pne-editor/src/org/petriNet/Transition.java | 105 +++ .../pneditor/PNEConstantsConfiguration.java | 84 ++ .../src/org/pneditor/editor/DrawingBoard.java | 68 ++ .../org/pneditor/editor/LocalClipboard.java | 85 ++ pne-editor/src/org/pneditor/editor/Main.java | 29 + .../src/org/pneditor/editor/MainFrame.java | 47 ++ pne-editor/src/org/pneditor/editor/Root.java | 786 ++++++++++++++++++ .../src/org/pneditor/editor/UndoManager.java | 135 +++ .../pneditor/editor/actions/AboutAction.java | 77 ++ .../editor/actions/ChangeModelAction.java | 129 +++ .../actions/algorithms/BoundednessAction.java | 63 ++ .../actions/draw/ArcSelectToolAction.java | 49 ++ .../actions/draw/PlaceSelectToolAction.java | 50 ++ .../draw/SelectionSelectToolAction.java | 50 ++ .../actions/draw/TokenSelectToolAction.java | 49 ++ .../draw/TransitionSelectToolAction.java | 49 ++ .../editor/actions/edit/CopyAction.java | 51 ++ .../editor/actions/edit/CutAction.java | 55 ++ .../editor/actions/edit/DeleteAction.java | 59 ++ .../editor/actions/edit/PasteAction.java | 61 ++ .../editor/actions/edit/RedoAction.java | 52 ++ .../editor/actions/edit/SelectAllAction.java | 42 + .../editor/actions/edit/UndoAction.java | 54 ++ .../element/SetArcInhibitoryAction.java | 46 + .../element/SetArcMultiplicityAction.java | 88 ++ .../actions/element/SetArcRegularAction.java | 46 + .../actions/element/SetArcResetAction.java | 46 + .../actions/element/SetLabelAction.java | 63 ++ .../actions/element/SetTokensAction.java | 78 ++ .../editor/actions/file/ExportAction.java | 89 ++ .../editor/actions/file/ImportAction.java | 86 ++ .../editor/actions/file/NewFileAction.java | 66 ++ .../editor/actions/file/OpenFileAction.java | 92 ++ .../editor/actions/file/QuitAction.java | 48 ++ .../editor/actions/file/SaveAction.java | 71 ++ .../editor/actions/file/SaveFileAsAction.java | 91 ++ .../pneditor/editor/canvas/ArcFeature.java | 187 +++++ .../org/pneditor/editor/canvas/Canvas.java | 259 ++++++ .../pneditor/editor/canvas/ClickFeature.java | 85 ++ .../editor/canvas/DraggingFeature.java | 151 ++++ .../editor/canvas/EdgeZigzagFeature.java | 176 ++++ .../org/pneditor/editor/canvas/Feature.java | 45 + .../editor/canvas/PanningFeature.java | 117 +++ .../editor/canvas/PetriNetFeature.java | 73 ++ .../canvas/PlaceTransitionMakerFeature.java | 90 ++ .../editor/canvas/PopupMenuFeature.java | 113 +++ .../editor/canvas/ScrollingFeature.java | 162 ++++ .../org/pneditor/editor/canvas/Selection.java | 77 ++ .../canvas/SelectionChangedListener.java | 26 + .../canvas/SelectionDrawingFeature.java | 133 +++ .../pneditor/editor/canvas/TokenFeature.java | 180 ++++ .../pneditor/editor/canvas/VisualHandle.java | 56 ++ .../editor/canvas/VisualSelection.java | 60 ++ .../editor/commands/AddArcCommand.java | 90 ++ .../editor/commands/AddPlaceCommand.java | 70 ++ .../editor/commands/AddTokenCommand.java | 58 ++ .../editor/commands/AddTransitionCommand.java | 67 ++ .../pneditor/editor/commands/CutCommand.java | 57 ++ .../editor/commands/DeleteArcCommand.java | 72 ++ .../editor/commands/DeleteElementCommand.java | 69 ++ .../commands/DeleteElementsCommand.java | 70 ++ .../editor/commands/DeletePlaceCommand.java | 94 +++ .../commands/DeleteTransitionCommand.java | 90 ++ .../commands/FireTransitionCommand.java | 84 ++ .../editor/commands/MoveElementCommand.java | 58 ++ .../editor/commands/MoveElementsCommand.java | 69 ++ .../editor/commands/PasteCommand.java | 105 +++ .../editor/commands/RemoveTokenCommand.java | 54 ++ .../editor/commands/SetArcInhibitCommand.java | 98 +++ .../commands/SetArcMultiplicityCommand.java | 70 ++ .../editor/commands/SetArcRegularCommand.java | 86 ++ .../editor/commands/SetArcResetCommand.java | 81 ++ .../commands/SetEdgeZigzagPointCommand.java | 64 ++ .../editor/commands/SetLabelCommand.java | 63 ++ .../editor/commands/SetTokensCommand.java | 59 ++ .../editor/filechooser/EpsFileType.java | 76 ++ .../editor/filechooser/FileChooserDialog.java | 63 ++ .../editor/filechooser/FileIconView.java | 41 + .../pneditor/editor/filechooser/FileType.java | 87 ++ .../editor/filechooser/FileTypeException.java | 30 + .../editor/filechooser/PflowFileType.java | 85 ++ .../editor/filechooser/PngFileType.java | 75 ++ .../pneditor/editor/filechooser/Preview.java | 123 +++ .../pneditor/editor/filechooser/Sidebar.java | 78 ++ .../filechooser/ViptoolPnmlFileType.java | 85 ++ .../pneditor/editor/gpetrinet/GraphicArc.java | 336 ++++++++ .../editor/gpetrinet/GraphicElement.java | 148 ++++ .../editor/gpetrinet/GraphicNode.java | 54 ++ .../editor/gpetrinet/GraphicPetriNet.java | 263 ++++++ .../editor/gpetrinet/GraphicPlace.java | 165 ++++ .../editor/gpetrinet/GraphicTransition.java | 89 ++ .../pneditor/editor/gpetrinet/PreviewArc.java | 166 ++++ .../org/pneditor/petrinet/AbstractArc.java | 43 + .../org/pneditor/petrinet/AbstractNode.java | 51 ++ .../org/pneditor/petrinet/AbstractPlace.java | 42 + .../pneditor/petrinet/AbstractTransition.java | 33 + .../org/pneditor/petrinet/Boundedness.java | 206 +++++ .../pneditor/petrinet/PetriNetInterface.java | 207 +++++ .../ResetArcMultiplicityException.java | 9 + .../petrinet/UnimplementedCaseException.java | 9 + .../petrinet/adapters/Bouzazi/ArcAdapter.java | 60 ++ .../adapters/Bouzazi/PetriNetAdapter.java | 113 +++ .../adapters/Bouzazi/PlaceAdapter.java | 38 + .../adapters/Bouzazi/TransitionAdapter.java | 30 + .../pneditor/petrinet/adapters/imta/.trick | 0 .../pneditor/petrinet/adapters/initial/.trick | 0 .../org/pneditor/petrinet/models/imta/.trick | 0 .../pneditor/petrinet/models/initial/.trick | 0 .../pneditor/save/xml/DocumentExporter.java | 123 +++ .../pneditor/save/xml/DocumentImporter.java | 140 ++++ .../src/org/pneditor/save/xml/XmlArc.java | 43 + .../org/pneditor/save/xml/XmlDocument.java | 40 + .../src/org/pneditor/save/xml/XmlNode.java | 38 + .../org/pneditor/save/xml/XmlPetriNet.java | 54 ++ .../src/org/pneditor/save/xml/XmlPlace.java | 30 + .../src/org/pneditor/save/xml/XmlPoint.java | 33 + .../org/pneditor/save/xml/XmlTransition.java | 26 + .../org/pneditor/util/CachedGraphics2D.java | 538 ++++++++++++ pne-editor/src/org/pneditor/util/Colors.java | 33 + pne-editor/src/org/pneditor/util/Command.java | 30 + .../src/org/pneditor/util/EPSGraphics2D.java | 635 ++++++++++++++ .../src/org/pneditor/util/GraphicsTools.java | 210 +++++ pne-editor/src/org/pneditor/util/Point.java | 92 ++ .../src/org/pneditor/util/StringTools.java | 57 ++ .../org/pneditor/workflow/WorkflowLogger.java | 56 ++ pne-editor/src/resources/icon16.png | Bin 0 -> 664 bytes pne-editor/src/resources/icon32.png | Bin 0 -> 1473 bytes pne-editor/src/resources/icon48.png | Bin 0 -> 2310 bytes pne-editor/src/resources/pneditor/About16.gif | Bin 0 -> 644 bytes pne-editor/src/resources/pneditor/Add16.gif | Bin 0 -> 238 bytes pne-editor/src/resources/pneditor/Copy16.gif | Bin 0 -> 288 bytes pne-editor/src/resources/pneditor/Cut16.gif | Bin 0 -> 652 bytes .../src/resources/pneditor/Delete16.gif | Bin 0 -> 208 bytes pne-editor/src/resources/pneditor/New16.gif | Bin 0 -> 426 bytes pne-editor/src/resources/pneditor/Open16.gif | Bin 0 -> 228 bytes pne-editor/src/resources/pneditor/Paste16.gif | Bin 0 -> 298 bytes .../src/resources/pneditor/Preferences16.gif | Bin 0 -> 207 bytes pne-editor/src/resources/pneditor/Redo16.gif | Bin 0 -> 201 bytes .../src/resources/pneditor/Remove16.gif | Bin 0 -> 213 bytes pne-editor/src/resources/pneditor/Save16.gif | Bin 0 -> 206 bytes .../src/resources/pneditor/SaveAs16.gif | Bin 0 -> 255 bytes pne-editor/src/resources/pneditor/Undo16.gif | Bin 0 -> 137 bytes pne-editor/src/resources/pneditor/addrole.gif | Bin 0 -> 138 bytes .../src/resources/pneditor/addtorole16.gif | Bin 0 -> 111 bytes pne-editor/src/resources/pneditor/arc16.gif | Bin 0 -> 295 bytes .../src/resources/pneditor/canvas/arc.gif | Bin 0 -> 129 bytes .../src/resources/pneditor/canvas/fire.gif | Bin 0 -> 217 bytes .../resources/pneditor/canvas/fullrole.gif | Bin 0 -> 139 bytes .../resources/pneditor/canvas/mixedrole.gif | Bin 0 -> 166 bytes .../resources/pneditor/canvas/partialrole.gif | Bin 0 -> 172 bytes .../pneditor/canvas/partialrole2.gif | Bin 0 -> 166 bytes .../src/resources/pneditor/canvas/place.gif | Bin 0 -> 374 bytes .../src/resources/pneditor/canvas/token.gif | Bin 0 -> 117 bytes .../pneditor/canvas/token_or_fire.gif | Bin 0 -> 211 bytes .../resources/pneditor/canvas/transition.gif | Bin 0 -> 153 bytes .../src/resources/pneditor/closesubnet.gif | Bin 0 -> 97 bytes .../pneditor/converttransitiontosubnet.gif | Bin 0 -> 100 bytes .../src/resources/pneditor/deleterole.gif | Bin 0 -> 132 bytes pne-editor/src/resources/pneditor/export.gif | Bin 0 -> 156 bytes .../resources/pneditor/filechooser/eps.gif | Bin 0 -> 599 bytes .../resources/pneditor/filechooser/file.gif | Bin 0 -> 368 bytes .../resources/pneditor/filechooser/pflow.gif | Bin 0 -> 387 bytes .../resources/pneditor/filechooser/png.gif | Bin 0 -> 599 bytes .../resources/pneditor/filechooser/pnml.gif | Bin 0 -> 579 bytes pne-editor/src/resources/pneditor/import.gif | Bin 0 -> 183 bytes pne-editor/src/resources/pneditor/label.gif | Bin 0 -> 100 bytes pne-editor/src/resources/pneditor/layout.gif | Bin 0 -> 143 bytes pne-editor/src/resources/pneditor/layout.xcf | Bin 0 -> 1317 bytes pne-editor/src/resources/pneditor/log.gif | Bin 0 -> 677 bytes .../src/resources/pneditor/multiplicity.gif | Bin 0 -> 306 bytes .../src/resources/pneditor/opensubnet.gif | Bin 0 -> 89 bytes pne-editor/src/resources/pneditor/place16.gif | Bin 0 -> 148 bytes .../resources/pneditor/removefromrole16.gif | Bin 0 -> 132 bytes .../src/resources/pneditor/replacesubnet.gif | Bin 0 -> 180 bytes .../pneditor/replacetransitionbysubnet.gif | Bin 0 -> 180 bytes .../src/resources/pneditor/savesubnetas.gif | Bin 0 -> 151 bytes pne-editor/src/resources/pneditor/select.gif | Bin 0 -> 89 bytes .../resources/pneditor/setarcresetaction.gif | Bin 0 -> 116 bytes .../src/resources/pneditor/staticplace.gif | Bin 0 -> 132 bytes .../src/resources/pneditor/synthesize.gif | Bin 0 -> 580 bytes .../src/resources/pneditor/synthesize.xcf | Bin 0 -> 1325 bytes .../resources/pneditor/token_and_fire16.gif | Bin 0 -> 166 bytes pne-editor/src/resources/pneditor/tokens.gif | Bin 0 -> 157 bytes .../src/resources/pneditor/transition16.gif | Bin 0 -> 86 bytes src/main/java/org/petriNet/Main.java | 2 +- 211 files changed, 13237 insertions(+), 1 deletion(-) create mode 100644 .idea/libraries/pne_editor.xml create mode 100644 pne-editor/.idea/.gitignore create mode 100644 pne-editor/.idea/codeStyles/Project.xml create mode 100644 pne-editor/.idea/codeStyles/codeStyleConfig.xml create mode 100644 pne-editor/.idea/misc.xml create mode 100644 pne-editor/.idea/modules.xml create mode 100644 pne-editor/.idea/pne-editor.iml create mode 100644 pne-editor/.settings/org.eclipse.jdt.core.prefs create mode 100644 pne-editor/README.md create mode 100644 pne-editor/examples/insurance-company.pflow create mode 100644 pne-editor/examples/start-stop-cancel.pflowx create mode 100644 pne-editor/lib/hamcrest-core-1.3.jar create mode 100644 pne-editor/lib/javax.xml.bind.jar create mode 100644 pne-editor/lib/pn-imta-initial-models-and-adapters.jar create mode 100644 pne-editor/src/logger/PNEditorLogger.java create mode 100644 pne-editor/src/org/petriNet/Arc.java create mode 100644 pne-editor/src/org/petriNet/IncomingArc.java create mode 100644 pne-editor/src/org/petriNet/IncomingArc_Simple.java create mode 100644 pne-editor/src/org/petriNet/IncomingArc_Videur.java create mode 100644 pne-editor/src/org/petriNet/IncomingArc_Zero.java create mode 100644 pne-editor/src/org/petriNet/Main.java create mode 100644 pne-editor/src/org/petriNet/OutgoingArc.java create mode 100644 pne-editor/src/org/petriNet/PetriNet.java create mode 100644 pne-editor/src/org/petriNet/PetriNetService.java create mode 100644 pne-editor/src/org/petriNet/Place.java create mode 100644 pne-editor/src/org/petriNet/Transition.java create mode 100644 pne-editor/src/org/pneditor/PNEConstantsConfiguration.java create mode 100644 pne-editor/src/org/pneditor/editor/DrawingBoard.java create mode 100644 pne-editor/src/org/pneditor/editor/LocalClipboard.java create mode 100644 pne-editor/src/org/pneditor/editor/Main.java create mode 100644 pne-editor/src/org/pneditor/editor/MainFrame.java create mode 100644 pne-editor/src/org/pneditor/editor/Root.java create mode 100644 pne-editor/src/org/pneditor/editor/UndoManager.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/AboutAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/ChangeModelAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/algorithms/BoundednessAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/draw/ArcSelectToolAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/draw/PlaceSelectToolAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/draw/SelectionSelectToolAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/draw/TokenSelectToolAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/draw/TransitionSelectToolAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/edit/CopyAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/edit/CutAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/edit/DeleteAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/edit/PasteAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/edit/RedoAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/edit/SelectAllAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/edit/UndoAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/element/SetArcInhibitoryAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/element/SetArcMultiplicityAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/element/SetArcRegularAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/element/SetArcResetAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/element/SetLabelAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/element/SetTokensAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/file/ExportAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/file/ImportAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/file/NewFileAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/file/OpenFileAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/file/QuitAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/file/SaveAction.java create mode 100644 pne-editor/src/org/pneditor/editor/actions/file/SaveFileAsAction.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/ArcFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/Canvas.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/ClickFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/DraggingFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/EdgeZigzagFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/Feature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/PanningFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/PetriNetFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/PlaceTransitionMakerFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/PopupMenuFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/ScrollingFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/Selection.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/SelectionChangedListener.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/SelectionDrawingFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/TokenFeature.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/VisualHandle.java create mode 100644 pne-editor/src/org/pneditor/editor/canvas/VisualSelection.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/AddArcCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/AddPlaceCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/AddTokenCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/AddTransitionCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/CutCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/DeleteArcCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/DeleteElementCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/DeleteElementsCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/DeletePlaceCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/DeleteTransitionCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/FireTransitionCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/MoveElementCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/MoveElementsCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/PasteCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/RemoveTokenCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/SetArcInhibitCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/SetArcMultiplicityCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/SetArcRegularCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/SetArcResetCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/SetEdgeZigzagPointCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/SetLabelCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/commands/SetTokensCommand.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/EpsFileType.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/FileChooserDialog.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/FileIconView.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/FileType.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/FileTypeException.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/PflowFileType.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/PngFileType.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/Preview.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/Sidebar.java create mode 100644 pne-editor/src/org/pneditor/editor/filechooser/ViptoolPnmlFileType.java create mode 100644 pne-editor/src/org/pneditor/editor/gpetrinet/GraphicArc.java create mode 100644 pne-editor/src/org/pneditor/editor/gpetrinet/GraphicElement.java create mode 100644 pne-editor/src/org/pneditor/editor/gpetrinet/GraphicNode.java create mode 100644 pne-editor/src/org/pneditor/editor/gpetrinet/GraphicPetriNet.java create mode 100644 pne-editor/src/org/pneditor/editor/gpetrinet/GraphicPlace.java create mode 100644 pne-editor/src/org/pneditor/editor/gpetrinet/GraphicTransition.java create mode 100644 pne-editor/src/org/pneditor/editor/gpetrinet/PreviewArc.java create mode 100644 pne-editor/src/org/pneditor/petrinet/AbstractArc.java create mode 100644 pne-editor/src/org/pneditor/petrinet/AbstractNode.java create mode 100644 pne-editor/src/org/pneditor/petrinet/AbstractPlace.java create mode 100644 pne-editor/src/org/pneditor/petrinet/AbstractTransition.java create mode 100644 pne-editor/src/org/pneditor/petrinet/Boundedness.java create mode 100644 pne-editor/src/org/pneditor/petrinet/PetriNetInterface.java create mode 100644 pne-editor/src/org/pneditor/petrinet/ResetArcMultiplicityException.java create mode 100644 pne-editor/src/org/pneditor/petrinet/UnimplementedCaseException.java create mode 100644 pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/ArcAdapter.java create mode 100644 pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/PetriNetAdapter.java create mode 100644 pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/PlaceAdapter.java create mode 100644 pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/TransitionAdapter.java create mode 100644 pne-editor/src/org/pneditor/petrinet/adapters/imta/.trick create mode 100644 pne-editor/src/org/pneditor/petrinet/adapters/initial/.trick create mode 100644 pne-editor/src/org/pneditor/petrinet/models/imta/.trick create mode 100644 pne-editor/src/org/pneditor/petrinet/models/initial/.trick create mode 100644 pne-editor/src/org/pneditor/save/xml/DocumentExporter.java create mode 100644 pne-editor/src/org/pneditor/save/xml/DocumentImporter.java create mode 100644 pne-editor/src/org/pneditor/save/xml/XmlArc.java create mode 100644 pne-editor/src/org/pneditor/save/xml/XmlDocument.java create mode 100644 pne-editor/src/org/pneditor/save/xml/XmlNode.java create mode 100644 pne-editor/src/org/pneditor/save/xml/XmlPetriNet.java create mode 100644 pne-editor/src/org/pneditor/save/xml/XmlPlace.java create mode 100644 pne-editor/src/org/pneditor/save/xml/XmlPoint.java create mode 100644 pne-editor/src/org/pneditor/save/xml/XmlTransition.java create mode 100644 pne-editor/src/org/pneditor/util/CachedGraphics2D.java create mode 100644 pne-editor/src/org/pneditor/util/Colors.java create mode 100644 pne-editor/src/org/pneditor/util/Command.java create mode 100644 pne-editor/src/org/pneditor/util/EPSGraphics2D.java create mode 100644 pne-editor/src/org/pneditor/util/GraphicsTools.java create mode 100644 pne-editor/src/org/pneditor/util/Point.java create mode 100644 pne-editor/src/org/pneditor/util/StringTools.java create mode 100644 pne-editor/src/org/pneditor/workflow/WorkflowLogger.java create mode 100644 pne-editor/src/resources/icon16.png create mode 100644 pne-editor/src/resources/icon32.png create mode 100644 pne-editor/src/resources/icon48.png create mode 100644 pne-editor/src/resources/pneditor/About16.gif create mode 100644 pne-editor/src/resources/pneditor/Add16.gif create mode 100644 pne-editor/src/resources/pneditor/Copy16.gif create mode 100644 pne-editor/src/resources/pneditor/Cut16.gif create mode 100644 pne-editor/src/resources/pneditor/Delete16.gif create mode 100644 pne-editor/src/resources/pneditor/New16.gif create mode 100644 pne-editor/src/resources/pneditor/Open16.gif create mode 100644 pne-editor/src/resources/pneditor/Paste16.gif create mode 100644 pne-editor/src/resources/pneditor/Preferences16.gif create mode 100644 pne-editor/src/resources/pneditor/Redo16.gif create mode 100644 pne-editor/src/resources/pneditor/Remove16.gif create mode 100644 pne-editor/src/resources/pneditor/Save16.gif create mode 100644 pne-editor/src/resources/pneditor/SaveAs16.gif create mode 100644 pne-editor/src/resources/pneditor/Undo16.gif create mode 100644 pne-editor/src/resources/pneditor/addrole.gif create mode 100644 pne-editor/src/resources/pneditor/addtorole16.gif create mode 100644 pne-editor/src/resources/pneditor/arc16.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/arc.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/fire.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/fullrole.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/mixedrole.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/partialrole.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/partialrole2.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/place.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/token.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/token_or_fire.gif create mode 100644 pne-editor/src/resources/pneditor/canvas/transition.gif create mode 100644 pne-editor/src/resources/pneditor/closesubnet.gif create mode 100644 pne-editor/src/resources/pneditor/converttransitiontosubnet.gif create mode 100644 pne-editor/src/resources/pneditor/deleterole.gif create mode 100644 pne-editor/src/resources/pneditor/export.gif create mode 100644 pne-editor/src/resources/pneditor/filechooser/eps.gif create mode 100644 pne-editor/src/resources/pneditor/filechooser/file.gif create mode 100644 pne-editor/src/resources/pneditor/filechooser/pflow.gif create mode 100644 pne-editor/src/resources/pneditor/filechooser/png.gif create mode 100644 pne-editor/src/resources/pneditor/filechooser/pnml.gif create mode 100644 pne-editor/src/resources/pneditor/import.gif create mode 100644 pne-editor/src/resources/pneditor/label.gif create mode 100644 pne-editor/src/resources/pneditor/layout.gif create mode 100644 pne-editor/src/resources/pneditor/layout.xcf create mode 100644 pne-editor/src/resources/pneditor/log.gif create mode 100644 pne-editor/src/resources/pneditor/multiplicity.gif create mode 100644 pne-editor/src/resources/pneditor/opensubnet.gif create mode 100644 pne-editor/src/resources/pneditor/place16.gif create mode 100644 pne-editor/src/resources/pneditor/removefromrole16.gif create mode 100644 pne-editor/src/resources/pneditor/replacesubnet.gif create mode 100644 pne-editor/src/resources/pneditor/replacetransitionbysubnet.gif create mode 100644 pne-editor/src/resources/pneditor/savesubnetas.gif create mode 100644 pne-editor/src/resources/pneditor/select.gif create mode 100644 pne-editor/src/resources/pneditor/setarcresetaction.gif create mode 100644 pne-editor/src/resources/pneditor/staticplace.gif create mode 100644 pne-editor/src/resources/pneditor/synthesize.gif create mode 100644 pne-editor/src/resources/pneditor/synthesize.xcf create mode 100644 pne-editor/src/resources/pneditor/token_and_fire16.gif create mode 100644 pne-editor/src/resources/pneditor/tokens.gif create mode 100644 pne-editor/src/resources/pneditor/transition16.gif diff --git a/.idea/libraries/pne_editor.xml b/.idea/libraries/pne_editor.xml new file mode 100644 index 0000000..70f5bb4 --- /dev/null +++ b/.idea/libraries/pne_editor.xml @@ -0,0 +1,11 @@ +<component name="libraryTable"> + <library name="pne-editor"> + <CLASSES> + <root url="file://$PROJECT_DIR$/../pne-editor" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="file://$PROJECT_DIR$/../pne-editor/src" /> + </SOURCES> + </library> +</component> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 699a522..665a20d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="ExternalStorageConfigurationManager" enabled="true" /> + <component name="JavadocGenerationManager"> + <option name="OUTPUT_DIRECTORY" value="$USER_HOME$/Desktop/javadoc" /> + </component> <component name="MavenProjectsManager"> <option name="originalFiles"> <list> diff --git a/pne-editor/.idea/.gitignore b/pne-editor/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/pne-editor/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/pne-editor/.idea/codeStyles/Project.xml b/pne-editor/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..919ce1f --- /dev/null +++ b/pne-editor/.idea/codeStyles/Project.xml @@ -0,0 +1,7 @@ +<component name="ProjectCodeStyleConfiguration"> + <code_scheme name="Project" version="173"> + <ScalaCodeStyleSettings> + <option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" /> + </ScalaCodeStyleSettings> + </code_scheme> +</component> \ No newline at end of file diff --git a/pne-editor/.idea/codeStyles/codeStyleConfig.xml b/pne-editor/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/pne-editor/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ +<component name="ProjectCodeStyleConfiguration"> + <state> + <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" /> + </state> +</component> \ No newline at end of file diff --git a/pne-editor/.idea/misc.xml b/pne-editor/.idea/misc.xml new file mode 100644 index 0000000..c6e01e1 --- /dev/null +++ b/pne-editor/.idea/misc.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="PDMPlugin"> + <option name="skipTestSources" value="false" /> + </component> + <component name="ProjectRootManager" version="2" project-jdk-name="21" project-jdk-type="JavaSDK"> + <output url="file://$PROJECT_DIR$/out" /> + </component> +</project> \ No newline at end of file diff --git a/pne-editor/.idea/modules.xml b/pne-editor/.idea/modules.xml new file mode 100644 index 0000000..473bd99 --- /dev/null +++ b/pne-editor/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/pne-editor.iml" filepath="$PROJECT_DIR$/.idea/pne-editor.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/pne-editor/.idea/pne-editor.iml b/pne-editor/.idea/pne-editor.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/pne-editor/.idea/pne-editor.iml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module> \ No newline at end of file diff --git a/pne-editor/.settings/org.eclipse.jdt.core.prefs b/pne-editor/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/pne-editor/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/pne-editor/README.md b/pne-editor/README.md new file mode 100644 index 0000000..27f492c --- /dev/null +++ b/pne-editor/README.md @@ -0,0 +1,28 @@ +PNEditor (Petri Net editor) +======== + +The original PNE can be downloaded from [www.pneditor.org](http://www.pneditor.org/) + +This instance is the result of a student project by Joris Thaveau for teaching purpose. + +It is a simplified Petri net editor that allows the editing of many PetriNet models. + +To use: + +1. Run org.pneditor.editor.Main as a Java application +2. Select the model used (the menu scans the org.pneditor.petrinet.adapters folder to build a list of available models and adapters). initial and imta are available. Places and transitions are displayed in different ways. +3. Edit the PetriNet and fire transitions. + +You may experiment some unexpected exceptions. Especially if you mix models. + +The pedagogical approach consists in: + +1. Develop your own PetriNet model in an independent project/environment - with no GUI, just the ''business'' view +2. Pack it as a jar, and let it be visible in the path +3. Develop an Adapter in the org.pneditor.petrinet.adapters folder of PNE to make your model editable + +The adapter may be simple or complex depending on the "distance" between your model and the one expected by PNE. + +Code license: [GNU GPL v3](http://www.gnu.org/licenses/gpl.html) + +Requirements: Java SE 8+ diff --git a/pne-editor/examples/insurance-company.pflow b/pne-editor/examples/insurance-company.pflow new file mode 100644 index 0000000..9dbdfdc --- /dev/null +++ b/pne-editor/examples/insurance-company.pflow @@ -0,0 +1,400 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document> + <id/> + <x/> + <y/> + <label/> + <subnet> + <id/> + <x>0</x> + <y>0</y> + <label/> + <place> + <id>26</id> + <x>-230</x> + <y>141</y> + <label>begin</label> + <tokens>1</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>10</id> + <x>-230</x> + <y>9</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>8</id> + <x>-15</x> + <y>4</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>2</id> + <x>-18</x> + <y>-154</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>20</id> + <x>-17</x> + <y>-94</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>17</id> + <x>117</x> + <y>4</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>5</id> + <x>240</x> + <y>4</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>4</id> + <x>69</x> + <y>193</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>7</id> + <x>187</x> + <y>138</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>19</id> + <x>329</x> + <y>138</y> + <label>end</label> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>3</id> + <x>-157</x> + <y>-65</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>14</id> + <x>300</x> + <y>-121</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <place> + <id>16</id> + <x>-62</x> + <y>139</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <transition> + <id>23</id> + <x>-230</x> + <y>71</y> + <label>Register</label> + </transition> + <transition> + <id>25</id> + <x>-230</x> + <y>-65</y> + <label>Classify</label> + </transition> + <transition> + <id>24</id> + <x>99</x> + <y>-154</y> + <label>Phone garage</label> + </transition> + <transition> + <id>18</id> + <x>101</x> + <y>-94</y> + <label>Check insurance</label> + </transition> + <transition> + <id>1</id> + <x>179</x> + <y>4</y> + <label>Check history</label> + </transition> + <transition> + <id>11</id> + <x>300</x> + <y>4</y> + <label>Phone garage</label> + </transition> + <transition> + <id>12</id> + <x>-124</x> + <y>139</y> + <label>Decide</label> + </transition> + <transition> + <id>9</id> + <x>135</x> + <y>193</y> + <label>Pay</label> + </transition> + <transition> + <id>27</id> + <x>254</x> + <y>138</y> + <label>Send letter</label> + </transition> + <transition> + <id>22</id> + <x>-84</x> + <y>-128</y> + <label>simple</label> + </transition> + <transition> + <id>15</id> + <x>-83</x> + <y>4</y> + <label>complex</label> + </transition> + <transition> + <id>6</id> + <x>50</x> + <y>4</y> + <label>Check insurance</label> + </transition> + <transition> + <id>13</id> + <x>2</x> + <y>193</y> + <label>ok</label> + </transition> + <transition> + <id>21</id> + <x>2</x> + <y>98</y> + <label>not ok</label> + </transition> + <arc> + <sourceId>21</sourceId> + <destinationId>7</destinationId> + <multiplicity>1</multiplicity> + <breakPoint> + <x>131</x> + <y>98</y> + </breakPoint> + </arc> + <arc> + <sourceId>16</sourceId> + <destinationId>21</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>16</sourceId> + <destinationId>13</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>12</sourceId> + <destinationId>16</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>13</sourceId> + <destinationId>4</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>24</sourceId> + <destinationId>14</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>14</sourceId> + <destinationId>12</destinationId> + <multiplicity>2</multiplicity> + <breakPoint> + <x>360</x> + <y>-121</y> + </breakPoint> + <breakPoint> + <x>360</x> + <y>57</y> + </breakPoint> + <breakPoint> + <x>-179</x> + <y>57</y> + </breakPoint> + <breakPoint> + <x>-179</x> + <y>139</y> + </breakPoint> + </arc> + <arc> + <sourceId>11</sourceId> + <destinationId>14</destinationId> + <multiplicity>2</multiplicity> + </arc> + <arc> + <sourceId>6</sourceId> + <destinationId>17</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>8</sourceId> + <destinationId>6</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>22</sourceId> + <destinationId>20</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>22</sourceId> + <destinationId>2</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>15</sourceId> + <destinationId>8</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>3</sourceId> + <destinationId>15</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>3</sourceId> + <destinationId>22</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>25</sourceId> + <destinationId>3</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>26</sourceId> + <destinationId>23</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>23</sourceId> + <destinationId>10</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>10</sourceId> + <destinationId>25</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>2</sourceId> + <destinationId>24</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>20</sourceId> + <destinationId>18</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>17</sourceId> + <destinationId>1</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>1</sourceId> + <destinationId>5</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>5</sourceId> + <destinationId>11</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>4</sourceId> + <destinationId>9</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>9</sourceId> + <destinationId>7</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>7</sourceId> + <destinationId>27</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>27</sourceId> + <destinationId>19</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>18</sourceId> + <destinationId>14</destinationId> + <multiplicity>1</multiplicity> + </arc> + </subnet> + <roles> + <role> + <id>5</id> + <name>Employee</name> + <transitionId>1</transitionId> + <transitionId>6</transitionId> + <transitionId>23</transitionId> + <transitionId>18</transitionId> + <transitionId>24</transitionId> + <transitionId>27</transitionId> + <transitionId>11</transitionId> + <createCase>false</createCase> + <destroyCase>false</destroyCase> + </role> + <role> + <id>6</id> + <name>Claim handler</name> + <transitionId>22</transitionId> + <transitionId>15</transitionId> + <transitionId>25</transitionId> + <createCase>false</createCase> + <destroyCase>false</destroyCase> + </role> + <role> + <id>7</id> + <name>Finance</name> + <transitionId>21</transitionId> + <transitionId>9</transitionId> + <transitionId>13</transitionId> + <transitionId>12</transitionId> + <createCase>false</createCase> + <destroyCase>false</destroyCase> + </role> + </roles> +</document> diff --git a/pne-editor/examples/start-stop-cancel.pflowx b/pne-editor/examples/start-stop-cancel.pflowx new file mode 100644 index 0000000..5162b65 --- /dev/null +++ b/pne-editor/examples/start-stop-cancel.pflowx @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document> + <id/> + <x/> + <y/> + <label/> + <subnet> + <id>0</id> + <x>-78</x> + <y>-58</y> + <label/> + <place> + <id>4</id> + <x>-6</x> + <y>-2</y> + <label/> + <tokens>0</tokens> + <isStatic>false</isStatic> + </place> + <transition> + <id>2</id> + <x>-86</x> + <y>-2</y> + <label>start</label> + </transition> + <transition> + <id>5</id> + <x>80</x> + <y>-2</y> + <label>finish</label> + </transition> + <transition> + <id>8</id> + <x>-87</x> + <y>-84</y> + <label>cancel</label> + </transition> + <arc> + <sourceId>1</sourceId> + <destinationId>2</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>2</sourceId> + <destinationId>4</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>4</sourceId> + <destinationId>5</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>5</sourceId> + <destinationId>6</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>4</sourceId> + <destinationId>8</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <sourceId>8</sourceId> + <destinationId>1</destinationId> + <multiplicity>1</multiplicity> + </arc> + <referencePlace> + <id>1</id> + <x>-171</x> + <y>-2</y> + <connectedPlaceId>3</connectedPlaceId> + </referencePlace> + <referencePlace> + <id>6</id> + <x>168</x> + <y>-2</y> + <connectedPlaceId>7</connectedPlaceId> + </referencePlace> + </subnet> +</document> diff --git a/pne-editor/lib/hamcrest-core-1.3.jar b/pne-editor/lib/hamcrest-core-1.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..9d5fe16e3dd37ebe79a36f61f5d0e1a69a653a8a GIT binary patch literal 45024 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 literal 0 HcmV?d00001 diff --git a/pne-editor/lib/javax.xml.bind.jar b/pne-editor/lib/javax.xml.bind.jar new file mode 100644 index 0000000000000000000000000000000000000000..2b5dc7e398c9f8e13ad94c8fa64525296858c0e5 GIT binary patch literal 103515 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­qiG}tV1^2GzKrl)sZwA^=dLi9%Nb*4fg zerE%u@~8V8o-%K}RC|7tF#ooY@=XUFyiL<Cola1Q$XIM`njwCCrD)LVNn%}lGi8?- zR0Ph?ym5Z2;vd7M8;|Vn*j8DpQaa}u$0^M_%jaf)`FQV!&MS@CU(04&?ylXxSj}jK zxlE7Q;w`-u{TB1jUisy@p=xXSmsjEMdk;mw7PH)&s`qL0I@>pwX20u764~0k=ANE( zrDi!ptz!M0FoEcdhyUO58#n*eeyV$YlbB6-{MX!r&yrd9Ma#E}g#Xm3ZwuLGBcOf$ z*TO8pPYEH#7u}Q|M<|-EKW+UmR@F9Qmd5k7akJ0wao%aLCc&LGEYb9?Z<gP8%f3*9 zxxG&hxm+yTyITG8wH@ixHN>q#UA|_Xb~!4oQ5m_5&(cr$pH6|;Ysr7&j?>SaH+i_8 zDg5IJw-nZ*9Z?UYa)fU5WV3EdaCmTfM_huyZI*41wVA9pdOukGV^%|FVxwRL6RX(l z<!_T6CdN;R$V(||O=bGcs%EHKV4NqogLgakozC4X`&xIizB{^|_1)pWO#F{_Gx0x6 zY<&MXu<`hZ9S0`s_<!88T(Y1cUM8iIP2{Zi`AWvc&ISb^cb<81C;Q;OyoxiYirM?l z-bxD9N;|kHI{ERvpq(=+Oc%_KyIvX3^HRa6<R-g@>5qUHE4%f6Phl|m6!~jw*FUK* z-<#eE8^kSZ7r8d!Q$5Rq&odj>{*bZlJisykxcG~F?tL9w6%(wb{*-s`@=reJxuk5H z`JN_8^@4-h$1hY!`QAN#G2(HV0P_v+J50A;#5_;t;eL2!?M9B*HRjP4<%dkeF6Y!u zS4;VBGAqa;O4aOFzS?V!%$x($YnW8$&AYHh=-osPTgAprVg4DO4_hT326kSM7See7 zwWWkh{}@NRic`GDf~t$cQK9mEUM>G7I2>K3&SA>8T;))yVxv~5|BRW3ybTXYc5X0L z37Gksb90b|kn*2cC7xE6SAtcCa!mRDPvNk3VltJmP3-gfvEAi{tk4SU))w9=-(!^5 z`b60EZfmR1;C-lU#bjJ_*Zsp~-W$&Eqj#Ksc{ek>?`VX=&dL0D7mBS^k69sPrF!Vz zga8kvGohT>Du*&WHcS?(nK$Wyo1aooYfG)C>$Qb4-5W!dEEE^c5IOntmEJcG7IT#; zlQ`xFaJqIH$O+~7WQETU;oR=gQsl8hMNn)-%Wst?aiJH%E7WyDIQx%t-2cG&MfR$I zm{0OVFAEvvJ5PjPD95O>s2*xLdU=P(+6l^rht}FP?t4%rFSgolPLJTb51e0qUO)aY zSnJ_giHEc88sG6r9h#IGvqtFLF^=y)SawxpJlc>WHGM_l5BHuAvhy9bi`B|ZTVeM{ z+pXe&`h}_P{t>H${s}ABoL9e4tGV!D?5Z5)t4gLe{QV3o@+(T-Uy?ta+GV}6Z-%w~ zhr0{CXV2T<qpH&@IPU|eznY+4IH&g3mgSR#_5}Byu*z++pBs`AyNZAI7S}Qb%}IB) z5<R3(HhZ=_)k=);u25SUTN|aiV^-PK9{I5K3%&nZ1g)EMMAX_p!L=gO<dxltn%18a z`~QCYk8~(-gM_)&*=n8Jv)LFJ4)HKB*bq^ldgd17s5mF)q~@h07P;jY<tCQEYuUMB zk@?c0BLC9XJ@z~<eEeoqQW8_i!L5@mbaOK%U&(#6<w|bYB{h``mpW|=)q0Mvn{K8V zt(hv^p{^1lz!b{C{gJ^{!$ssEGt-h)e>jf_3(a;oz?@}SZc`}qh(YO+W%0Yc&uh~6 zn(r%n{MeuI&4JHGvkF7p?AcU!P9+>YDlok*^-i1Mxp$9qrfg20Bl|q3XLBLv_tOQ% z%59vIlPesKHCr5<uD<h-bIp5^bglGYqoj`FWrb#EFMK>)$yQU|6|JK3LMV;ZVs~lq z`Bqkg|KAK5`#iMPajtlG-8a`@{+vrj$FFEMmu3A9HoPhkY-|;Odv@QQo_V4H!hyVJ zdsfeMUg;Bb_UV=$2Gy)tQEEvmZmx0Ds{WOJ)%aCRhF)gNvJzvtSHZ<ud3I}EgPuw1 zI;&kwxpiX`+X`=oRGZKkt`}dT4HTVCg%@6oaWfZ=Jvz6>&)muTTI}uXs{)%YZ<J(o zYAKqx?PJ#ISAp}GUY&jzbnJ3fO<%yGm?g16^H2G6XT&sLnSH%?$JB<J0=;ERi>pqZ z@v4|{&GozREU(h6@6(I7=t;ew=<v1VO!T#NN>?0CojE(D;rErFIWJ!nXw6?3I(6-e z*+1uO+aq^1Nz>Rb+tAZzLCKw?&B;|kvwdb>NlwqIvRWOu@yMN>S5qS|EfiUuyL$6V zJKKfNIZi+C|CcQENrP4FGT+OZzCEeS7xv!P-XUA=VIZR7_%Jt$J=l>elXbb{CAl}D z7tY?aJ9lW#+vjf>(gokdvI?7?oV!wr-FT*mWctL(6T%DF(pArV{A$x~yZk|%OxOnw zxzG<1a^W9X&Use^9b~mx`asEt)&H^Nx?gKrp0kwv*<UICAd)XPBP*;s@ag*)!L^AQ zoL66*RQcq2_RLhZ?5VLEjjmWR`F}XLV7D*x>z=bKX38BZ{;~M>Pt$<QnV<9)oRp8O zPM-FByV3M0r#0WF?~U4;?LK3Un#pbPpX(xHKd_wN(%5%u;nrz8pZ*t#Z=EL_TV(3l z>|Zzic=_X?BlYr;C&L!M2wxenc*|8y-R7O8ll7)AR8PyfZ1w-XZY2ws<Nf9HWH;&i zmD;UdYqq$~=hLR?C+jWO>i$n{y5Of@Z~S9E&&2zp7xrAxa*1!;C)(Jr5TodLB<+#k zKFzv*T@`It)|}S)`=mF>GG0<je(3tkD)YV7ZSjZ(iG5sV9|dLR_Nm=Zt&zysrNPC$ z;>C)L6(4eHncum&J0E45^SE{PeVw^`vs+6VJ(ON4TltwdT=6$?6j7X|XyrLY#Y-Ty z^ODQ+j%UrieXbs?Um~1R8LM>?of#FqCve|L<6Os7Gi`xLKt5+E>yCAYd=10v!**C+ zcoEU?{BIC%+C$Zk?j4W(CmfmoP_W*y`G@wbqxU!X{*ldnB!5HkU#I&~=^YC9j$HOR z!rk*w_1TfrK8Lh@j=et9YCcmse{<HJ!&x8YRv%{1Q5L(Y7L&UDQSr0G)7RWwRXii> zX3us37w*v6tGdFrM1I}rmz%X*uVaUsy+GNe@I&G|W~;FA+a1(<)5a{j<fX#e>J>-7 zY`e+(Z`KysFS7grWv0Jp#ko&ithuk_)<Gt%**~^VjZ%+oyZ&z8^0`$m)ukal2M?Xi zKbds-QsC>Z#R}rbrn{>-<Q?30;N-ieGk;d3Gn#A?yK^vVWBb;Hvs(?$lqK}M-E!%! ztLL=<rnys89y3OH9-36)^yNbWOKjM#-jF$q=ADVpvEFKDCHS*}En`iV%<`u074d!T z=PhsK?TBc9nx7oF{fX<wy(j+s+%8z1>tY$;+41zlw<PA*F^%feKRgkN+tDJv@nZ~Q zf41y_+K@FLxE#VcFN8APiRTN5WZ%%vQ2n3vg9GOW;cA;U=6PDu1`i7L7d#aD7R}Uq zM)i#rZ&&eON6xBSKi=xui?eI4a$b@A{m^N?$7W(j)5=&J%S86(Fa(-)D4Hd?$}Xrd zyDa)*<FB_%JF3@8E|Bn^$ur%kQzum^<krlT7n-*$E_@P|36Ju)v!x+gZ{fz&gG%pJ zL$2M6YG|Izb@|WdyBpqz?r56lDfe6Se)bBks-|n&tmPM^eiY8P5dL=6Ofqr)^4kwY zxvH$z*7}!Mm9qCOm{w%l$7SaC)2@N-o5G(rEKe(i-ufKXGi%ioTfEz#mszJ#+2=UN z?4yO#j;MGib}e1F`Le}Xqovl5mTP^944+%19jcHVzMx6&XtRaOzuPPQTy1CmXWRJO zI)~q9?{($)HkmE6%;di49oW9eJ+JTFxkX)P1N)za`}pq-t&Iq}xVU3QYB@`Jq_O&i z`e~9m&ENG=JCV8-sop!K7#LpJGB9WnS?NJK@@uWRYl5GCeSXI#Zx)*ev*s7pts)wl zOA{74G%Dpfo?fh=o57gtJbBy230F*x9-6b^rlowb@Z8`FoK2gp0tF_BB`%oVf7bHu zos!Eh<97X=V|Dl0vu8i%f4-}4eo|HQ&G!8#_TGP7^W6G=<^1<;>Hk09;AEJwZbjJ+ zsq42FO6v!H46@#qpk2PlX3s%BwVcQ6`lF?HJUxG;?9Bsrb!PUEJw8WIzcpaGe%s*0 z``$ksADhK^u3u|^d!se{gYu!fd37#t1&+z(<pzE9vKGl$u-EL)8RO_P(emsY9*Uod z-v05o)@RMC&pzz-R+8Vk_Z+OUj_Zxyxw}_=-;uTY(cAwqAF02#R{rEM&6^t@o8CC? z5Wn%^R<l1^=Ib9H|N3W#<5B6{AEwr44x35eo6;G7JpV&x{<eo@()SiUT3fc_aK6!t zT*)s#rpe|Xw|=vOx%|_Oxn_G#^WFY%`_9hWZM%Q$z1{ZR!2a8ZroDG|O>f_yeE4_H zjq|m)Ue(D}HTZvs&9gnhbMyGx_KG)&d2gSu<u~x`FL<rcFPk){{p}A8xrf&n`gw1C z)UZ2tH~Eh3x&HTs-&?xW-)<1RzWRqna&1%kzVrR^D}F4IoquTgPUlHAZOiLV%$5K6 zIMVKEe`t;0(fKzXYSqLY6%YBdvdiB2#Hz1se--DOZ?cfN`J&hDuON$it;Uo7D{Oo3 z-u;)?awcQ>e!DBOU)yf|;aGZF?{nU#Z_~c#@l4C-XsLNxdT)jKuAQgjrTKC{xpO$y zcF4WGXZAmaW$Wep(bC^8TBXM7I<=j@@3!~pJw3S<3x7`Ke*Nl|^f`BjSG>wHd;Cj! z&2Kz5pSWZDC8>Ikc;iFr=Fx9*yW5m!3w8;g==6Q1;;FGHImJ+3O^EjbTWMq7`?dx5 z-K*ERZaBx?!gMi<CHUkMQ;xLWTY{&V6ziSOALIS!A<V42V_NI&JqJzic{Kbkx*+qG zN1$D8-b{7r-AyiTY17Rwz0L1&V_L`;6{d7;D*N7reMPwi@19(47ntK%pWjfnf5%3> zZP%u9om0GE{NFmFZ{C+5o>%5RHErbM^v>S=sQLv*+g26jInz2eY`ZL-`6d3M^P`W; z-Mf#>Gkh6lc+@5Ii%C~+MNrYvEhnX2PWWv%7M$O5Tg;lf$yzk|mFLx{M+TKI&wEYq zidLW7Ya+$`WjdQrit7^oyN!HRin-Gj19Z7JZwPv~y~X27<+_76qlLtH9T{}DX3x4J z*|)^nUpcd|>0ZW!nYx{?+ionHxIN+D%V?8jB1~pnOE@RY61w*DHj{LuUHZZnp=ozr zqh}mB`eyp7<%=z|uXZb6j@V)$@oic1#YZY)o*pNaZb~<~Zn<?wsU+a>lzo>UU72&s zrC$8?ovydbWR34A|MB$FdOb<Tf#=G_Nn46ItX?M>t>kQPuFKarYnDB^rh!kJb>a8+ z8yyBK4l-0)KkH1p$r-)Q_oQg%QmZ*>W~Q?jzue)Nm{h?ulPTa<?={J$15(HIw@v<$ z9ds!r-;?3emKTTE-n+e8<L4OI^qyZZpj_N_->0^S)zd_GnQLvm!l8EIobM&4os%`M z+?^&9(dMvDdu_}fJzeg9_8q2QT~54AWwDf7_hr+`=-o>HzB%Y0caHL_Eozeu{4_zV z>lshNB9Z2KjPeJ0E`PZu{neax#*Il|_!g;4aZEcdBy#KK)C9I)zaHwcwQN53M2qFt zXXSr=2CSb0nEoX?y<0wcnvc8JT*;}k9zE1$n-V!|S=H{pQ;oBj6!o7Q++1mK;AUW1 z(<1e?5_%hA9=z}6RcKe<WEH%l{YLKMHLEp!id7~~is}nL%qq#ry~+F9(y+Qa4&8eu zdKm6~A@L=M>CUq!T#C=PsG8a~F7RiGS+0;(+L65A{&Ln^KNu$+o7*%e<-#P@l`j`2 zJoh@J^Z3k*%Y~;U&$fHK?QqUyp2gg;HF?%#mKD4yFD7*hZZO!g)6k)F&i>Az-6~8x z#xtXArmUQ$JFWeL;_F~Jqs6Lxi{GwRXZhIoEYP2O&9MX1i<;kD*|6*X)s0z8jz12J z&02V+lVJ+Ss-p)|>}TF;{$p-;VnhDD34NY!VV=!TyC#Hhws?4E@|)vRm(&O4ZgE_! z!5lM@rCGe?@O0trJHl3UUpIIrl(>9Z@12uxUVJPs*Pp!Z{2ete&OJR%Nz<=im$-4L z>dK@;f7VJ@-E#fbk(l&Y)HW`DN&7eTt`A(B_FZ7x`F>HrrF~OsqPAY@`2BVA%KYoU zq8>cjD7EqF%jer!oMPW-9Gf7%!hh|gYX#NS=E8|epI+P)UAp9&-h=B`uWk09I9KYT zqS%D|a@Rl7hiCuM-nHYxq89>h7Jm7E$N1;tkk&?Phteo_g<VRUF3EGY)M_jBDs4@x zcdKm6jf)Prmg|weR$>*GN^cf_$rqPBK35jqGuywQ?{Q7?4)sgV;$;&4p7o8~?3=oW zZwG5$>4Cf*?SE=kWjP-em;F(kQxst4(;xr9dkaf^*@3?wWZ7*veuw;7%4~Nq-tvQ} z&HcvpN};nJKT5yO<-3;YI;RTz<YU(-ZO-Cw=ib|@xN+U83yu4aUH|cM7c*Nzz|s2_ zAGZInX8$Mm|3Sm!54P+!jOvwZPB8i(ynHO#<8}Fg%^#A5Qk%CQY|MW!`^uX92Rhq( z;`m~EvqSzYW}eq5Z}lMkgU!Rm?0Z=BSN~9F-@{>Feqi;7>~l;?wmA)N?<H)%&zOH; zHeUrd$CL9P7@Y$DgnT`?VE<w17>SoJZhA!4AG+Ai&8o{&BL2&~%+)j5@#uD$A7*b# z9$5d-yFJCjl1uQDq?XH{8v^e*e{wBOO!GNo9&p6#wPA$Yd&>vLKc+M9<GUa5v6lUx zq<z3gXZE_5`oaU6KV%Z0v^?9ydHS^46;t0AYi4cOnC0}nMVIf7gneOxsnVez=OO}h zd4B%gm#3D{y#K=flk!@ZFDXpx?=t&zBj#?!$%P_pTbjkUO}tcn+v7Ud?ZXqDWQEr% z-1_&bVf}%vI@k7F7BKZGwf0VSP!mw@sbQIHGOxv3Nbc!@lNKi%>(y0{80kDUtnxWt zlqBC@d&=ey`}S!I?lN9?nBVok<UzVe&JV4a=LfWYtn2z;_Tc#sdG<R;M05_O{)u?m zFgww@vUdlI__4fDF;}I;AfM%dsXrB#%Y=NNa4Y^mYthG>F;iD?S%`#)I9cTW+9_(B z7ItoyZF-__?%hR4`Hr@9%UE!yTWfIX7HOm%Z8G?~e_OrRuE$%rUUh~XomJ8zDy{c< z`$X<JHP^!9IHsl-?|US&J<qkRRlGDv^XiFLyNrbL7N0ouNA)sSj>=8<!yDfug?M^> zpS!6{Y5nB6w;p%B)}Pcj)wD=4{A1%g3r3T7Z(j*n*4&J|8+ml{A(e{W`Ob&<`~5Q` z`*(G|X9^GC(6T#xjmJJ*L~S8oVWS4$)|SI6tXC7ZH)<LtT~o_!(m5?WMPb?lk>y1y z$F{T<l>S)!>&2_kBbU#-o5x#d_k6kvdyMm)*^}2DvN_CgdRqpE@&$b#_x3;GaeHcR zW<KRV^k>T-(+56V=XlI7nYQ3b@ZyIeiywQP3z>hjCh=^7z^Y51Ug~t2`t@Ghppn%c zbTskehf@kWU(Z;YIw2+el+$&`x2YeQc6{)0^Dpx{8PfG|W#`OKGv8gF`ND;N_fG3q z>iH8KpUx^Tj^2^I`Qa|#RTZ^eiU%3IPwtAUQ-864$5(apho8&YmFnidyD#0T;rHys zqHCYj8x3B+b-FjbYDv&XeimWxAg!}6%ReOxdFH<AX<7foyVOd>r#Wwjl)$zoE=!q( z3<}em7ghvM5PJXmAzRbViMP0FdViUptn7NqaL!O>^@{yGXXfk^d}6*b+%exv?Z6{R zh8h>0y}kRjE=n($;h=tC`--O*8XlDGXuii`ov_>`z%#!s)QkVc>a|R}T-KbqmiE*u z?=EL~r|*8=a&MVp6+Z8m3L0)E!9o`zN=(FVs9s1Z5YxJNhIw+tLo2prY3CJYupca9 zS;M?Qs?g8dVhZ=S1962bsvlZwa%_?mKkwmuq4t74$F6wy;C05|IZ`App7Bf4(NB|- zYk0qG!NGm!H&nz)NqzHJ7SOeJ;X$WK3#UHYR@vvIcF5*)P4L#0m)@8?f7^K4Ht%zw zm(GGqkGAm~+8~?owteck%)HZa5|6i8Jb%-=hH3fU$+IrktiAfzpgAga_rYan-nR>7 zO@H@HG`auahiAzKiz*rBtXre}VA10~8>Yo<2WmH+@A<ntPy59Cp7{x!8|Tc|(oyxA z?yR<^A#j7xu|ur}f>Mb_CI@vQcuhC3i5+xZvO(OL+2rz@sI0Z^r3IWhi%i2ES3htv zotv+7)`o>&n7z%J<J)0IE7Q4=U16<fKXCLKrmt&hz7mviUCzQqH*DtN4=c`<xTaTq zb7oui`;x)mjufj<DWS75O%FvQ3w32$F1jc52&Set38lR3st}R$UdUqUrpmEw;qw_w z+F!|Zrp*d*(Y~0x|7yo_?M9B(en&VhGF6oF1&VsJWPG!E`?;0oUAXw-+5~HkN;i|e zY}pkt7e3VfaO84(A}t<2wXIEERe8ms$r)lE;)*PrzetFfRJXKCNV~7xxo_>3Ki-~) zDuX_?uG%YN(p!DQ;qo^VlfNF9T&6B{x$JLZc*Sa2=ZeU%S6Vhq&nFn}>XOqd?VbKM zDa(Jt+fM%Ja*dwW2{|iYa!lbl^hDNR)0Flzc5C+w8{O1kKTtfWL%Ubld|D6Vid1EF z)2<&e9=H7!*I#zvOXijIoAaXd!yJo^y*@?#B{%IGpZBKA+j9i>e6pDG?2Y~b|D!kS zmo3hm)@HQtL}<xvKdZ=xjY{DgGkTX_bGbOHU_pk!sYkPSv=s7BSi<&_$Ni;Gzp6*p zo*QkduB;VYo9FGi@9_3<=8C_qQ$((Q7CPG;6r}6sxpMJ>ntGp*D>L`mt7*Rqd1JqL zgN)9apl{P%9-OggoV8`1ilhy1-laWCm-ZF~&E@tK%I@qfJQQ7$8S4^sb;(!nAE8{n zYfWbT_s%@`zsu(T>JQnS&+?iQuZ7QkmU%H{pZa?Kz?KQGm;@biDt~^TQ?>tq<Xu)t z)^jg+A56Lz{vbzuZ{`)_x5jUcW!{Uv+UxaukKds`yqZts6SVd?3cmAoobG;GFi!Y* za7NAkFHekH{lhb+y8o!#_U1Zgv)k*+Pbd0plunthme*N#)6KTl`r#A4zfbs*9+Yi7 zoL`zV^-{TI(dFc7eMe4HnKdo@o9{0dI3%-Jz|Kdx#oj}4kK-GUho`qof2^7G<aGRG zyVw06mW%A$bE=}r|MIU-(kz1cFEiS{JpFI<<C8QCZ~kHHqC#26&-sySmIkvWt}Fbi zxp7xO^M%e0hjup!->Kriw_H@Rrdn<Cobt^1JhOiLtXjHqmqI;%N;OwY7T3`;FN_1# zKE>HBw`2Y8#JAKgE&kD#pCSKOZqLXw=dot{JS+Ay`+{F7jXSqqdbVxn*`Bkx!XM6Q zU3z9GomkzTUgjLQGW%elg@2<~_wokgRjq2LIM;-RU2oFbDu3<L0$=$M&fcA-f~!p2 zr>-v6@pn$+OXZ$i=42===)EdSW96y9mk(DhZTDEa%3rQ|*E1RKK2vwu2G>HpIIhK= z%3%S9%tjaZDray$e_)_->|sEw@&lVQO-EleO`XBL+K``V27jUq_v`|hoWo8(tmZLq zPY}G*c65Wd`hmnb9O?x|e<Zvg*3QvdvblB1?p~Wq?JC0DSH-nzTy(XsimLtK-g;w= zeRF^7x594KHj`hRe=QYKzKj1@?Xj=x<j#M-OS08ZY%#5APuzH9`}93C+wx71uHG*^ zr}sk**ME=1pl;r-mgmbZKCAbd{HsSK)OmAATl+-A{dEH8)Y)qf3a&7J!WzM8HfL%> z#ga4AbEX6w`}1!9!_OjLbPX?=o3Gva*Zo4dm%DMSo9ET7Q#4}IT(&42yce=@4qM=# zdMVM<z1`Wt!Hr#I5++A4BrtMzvQ{e}U-$Fpv~{v`ejcB?r7>i)$+~$zr#&c)Zq_h8 zA*QcYI@@(ibYSMfWjjO5*5q|NJ$tfEYxm@hYkiJ|Ju{1L3MsU(zI*N3Ti@EWrT?!m zb6OtUSyFd^yW_*sCydh$y5uxy?hs0Q)Vk#3>I6$OCu1{5k?RLcP3mmTx|`!2+^zVt zF8b_BU6`~)NcYO7NzKu#rwf|D%Gnv1<|MXi&DICTtWhVftyA{h_Id8MCqG1k5{l<u zF8Y4xL(IA*IXgpK-WKaEX<QTY{L$VCGhfHND83c_-E!}(h}{yOy9`y|-EiI2Jl#Po zj!Sq0>$8OHrUTErZX9PyPrkmb-peaX(|GfjmZilEdNFag0?HO$%6Syje>XC6=Ix-s z%(+DZVLR8p5_{gUI$fsmSofB?HP_P>^}jz7ndCU<^3E8)Bx{Qe%v~FV&mCnb+|gWf z>Zz4`cY;pkTxpIXi!*NR5Bj;&CWt5X?Mk%zsr1Zzc3jVP?~~@S?(78tlj=C;o^kvX zk{&!GF<eTv%u`mbbFt8cf`pAd(k*I>HJ9k7UeLXeGCwr8Z*S%bN!^u_i+8VQ{S+{B z<)7X*osC;gUYVGh)aNp7wRPuCp_#9uVrL!l%<*<u@~R``W$px~gY}M~@lvZksfMyz zg?gu)nsav5izs6T@tu0t)>w&7ysrM>?6r?+uU-0VKW`PjH|5u@&PB7`q8~;+*kOA1 z>eMeED)^2bzx;V+n({2`OH~yU4}KC~wfV&I4|>jar4BQyKi<^*`c84GRrCJEFHJmz zrL8%#do$koE^8Ds<`pgs;_8k_kEyATlJa8Vom^_tX`c4FH{+XRhK8U?g@(T2hr~+? zF-b8s3bDRj!7RL~R<pi7StOD5$Ys^5yz5;-S$_LtS9`6DEZiM7%}=Jqn>STcPR+PN zWYfe|_A(v{6^m|ka?a~|x>D$&nDWu%msAdYf4Jp|%Z&Z0UOoK*^Y6a;6O@$jI`D(m z1&6h~q0crgKNzQGbh=08^QXEK(;KH9i#exN^vyEutlo6>DW4ZP99Dnfaew)T&nizI z2OIFsSKI%e=giUcudlZkCM+s>t#@$S&n5=}UETM}=T*{;HT{b1(wlU;=FE9Kvr|#D z>VemlMP|zO^Zc`YuX8S*Gx3s!|K?@l?IvDFW~M)skCVG(pAs-_Mn`jNsx`+x#}Cy# zKcBom(6!$`KzQ~EgCFxt&m6ibbi6o7v3hgD?ZVqZm-pCYy=hFGXS1~P)cb$I^48+# zP8Y9Rs&Z)Zba&6AWw}3`mrrlo{-!n1#;4LXZ}ptY`<A_F&rZzDw0q7|d+f1JX_$HC zoTuklzsz}m=hhU5&o1jWePCYnQ~AWf{zR!dChrgH9~|C)F!e|Ii$ne^`+h7xC#&sJ z(D%bCu~{#2$L*ihyKHW*Ucxyi(R5;;->m8B-_D-jFKolU@a|;)pNX!ejm4{XB%ae+ z@MXgKsp=~ov!Cy?Yt7mk|5bCw^!KavHr(OntJS)u@!{y<BGFXE1u2cLlB|+l(rubI z4WcA@Sx-r5gcKz-O=1tutZ6giOVeyM2)As1wNYtBxLVibGYW4dco%CX?st?(77jHl z=bRh4FkV~#Xr+?;9PgT$`dYJj{#my8%zdvIVZByj!I!<sarX*u7X_OJM`ecf-(Iz5 znOErf)7z@<gfL7CnRIB&?p)ESlJ9uDCbU0|xSKV<>s^o9_EqoNj%l)noPQSKD?06- z%<7#^cQ@r$2lrhKdU$6Sx7%q?sdrBeyUj91C*LfZ<gj+HjYsj8{U^R`dm8vPduGvs zhK^0XhEH$!ur^<qIr#%?3UklGG}etpY#WQzQnWTJc&}{AY2{lNa=0Ruaf;S+$JQX` z;we!pLd687&$oL|;a(8CvR(I-&<?jquKPjL4)QhKU%IBHdMfuryQQ3RAz_CTQ+pFC z#dmfEadh6f#wL1!Pha5k&Li>{X4X&OlJEV=-z_rd?rA$4e*^n&pO1nQbDkZZ>-14) z$%O9@oSHT}@!jb)HCcA3dCIYCmuB={*~BOAxwWQY!OaJHh4aeq9QyX`%-zG=p2p0$ zUUfPvGkT|qO)`J<gv;Ix`)-{1eNNIOc<osq<rzPEjz_-LiG5qBS1@h;H;FxKHqDz+ zrTIit*C05vRkTYyOj|l(uF(Hi360$+XZ@HxPwQRQR+S{fdHfsmD{nn5JLbso#7aEI z_V9$6TAlIIMl4KKpVtSdG)W3I+O{32*t>*9*x*Jfk9P@s-MS+QpJ&*pvpqCwejFlX zZ+c@z$Zo%N@oLxa`?Np#QJS}J=~bx^>;7mdo64W5%N%#?xl|+2WPR|d+4Q+Lj$Xel zty$CRC)Zq1e3PL>^3jG%yk)9fi>JuVSd(+<><oj`u{*cMY?!d}T9>8ulz^KRx^ojn zL=CiC{uz{NFO`&E8eH&k^5o;!X6<L6`!lcmy<_8BxsCQ5HI<w8cCET*XFSPuGB4jD z(bbP@Uti72uQ_6AfA2;6VQ2lt+jnktnv!#SQd;JeV>%}*ejogAzi9EY)>+qd!<ZTR z^>)l^|E06+-~XB?X3}<_G_OyX{GwUtY1E9hHKNlrt~)L+vRxCN*C6&ZTOcg2Y4()a ziT#`A_WT#Ci1?{CCm^r+`V{L2#ZUc8w5}(ZS?-URmUw95r74~)hK51jT@$mEe0yw` zbxw>fG>p?Y`h)M`ri;7RtT{Dl{`IKLv#UeyuDZR8{qvnCX{`>wg^$cszU^x%R#_5S zU^K~M0cVJO(K-K&uZKSx>n<&C5)oSdIH*@;A<v)p8Y^ci+;r)fk)iBctJV4Ktjoo9 zO0OB7DjH}$nLYLIgCM>GCQlV~Liijf7fI-a%C-7E<%n6wb13vw;ErHRzJ87S&B>=Y zh2B5@(DaF=W`T|8qguA^sefMt&J$LOJ32ihWZ7Hsc{7hJ?%v@eUN}?lkx}K_L%P04 z)U;ToGR`>7OJ!OoblsxtALFVoy1O}M9WLMdM`&L9K5@4SpIdYDUh1u~<f}MS`6#Yz zrOdqdbEfSVH~MTDx+wGcl|Og?^wmZgSA3Y?v}zB>&QtmtJo{V{KcsRs?pN8iXVQcd z*I&<HlAZD{z-zVTnTfw2#!vA|x_&}>Nm60+6wSN|I?rl%`n>3fNx!Lg;zX&R==^XY zyA?doZKqsM-0?|TBdBingPiWCrW1MfFV+9v=xp`+*2D|7EQ_oiO}{taEa7N6zF;=r zjbe_Pb-wNoPC0ML5~$*L{H>5<$I|F{qln|&`}Rcd{)3@s=P~|xbkdz8(DF>n%@3@e zUG6G2tRkJ=3jDVdZ1#E2+aY;ss(oNXb-T===p*yCFLbL6S1;z9`SR$EGsh2ZeYBHr zpN<mmA+r~4`i}4ZGons_c{gt<uV!LkNM>hX&?jaBEUzTBC@nEL6*3Dpb?WUPVMl?s zYJroDDncSQ-N$Dv*d!;wA2`wXj*&=fDr??@tVunIE6?U-ZC*Gj{PQ994-0kDtI~xw z&GgOG`{a22{^k1fe?<2G|MQ2HLH~f4gDGP?hfdkb`^jGqY`<&P=v4TA%DlkC3-fMs zbU(dR(&@l<J1g(NtuyKy<nCWzc(60^R_@BDdp)muC%9e@SDxT>a-O<Prs-~$OA9{> zpYOL`v92a8^76ZY=ksg4awB;+$n+oM-Eie^=-#@+iH56IZAz?~cX)-gvUO1Q?86H0 zG=g{j+UIW_Q?f!ZF*Sk5s_$V@;Ck=bXKsYshuZw(Yj((!o%(QN&DWeAqP#a6b)Shm ze!o`!Mql7UzT)VRJ$ZI_8o%ARwk&h^6?vhEt6Swirxt1aJH_U;v!&H}d;0d+YlnJt z{HHvrZZ{X5<=uNm>tmnwn%i^N9p-C`RlC>W&l7UY_{Z&#lEs!+kJ+uPI{N#{mPsOB zAtmKoXO(1lxNevGtghw~e6jag$+3pO65X{Ld!`kZtTxV>)BWyZ&(_eAvy$u77O(by z@IS@ENJTo&RP^r2Ia$%4AM#CnA@_Rv$%Pe4yA}y_zWaGeW7nb;i&me}Dpc9^a@Y0m zv(IcgD!jH(k+))Q`~k_&%+I<v{IdTsHHV{}#p`i(_Km#L9r+LHj(gW;&)Jl=!J*-R zOoxBsyaTK=*dOfS;6A~kGEvh*SzNLCj1yla=d=lx5pHp9+9yOKT;p1^PrNQ*t`yEw z%=f-G@%g%wmgP&|&3jV&@_FME=ZY4c1Ia0ZUMET`nrgVtPmoSfnE$!Hx=H_`XpwN7 z^7aS3pLF*)?`t>u)cnM~@}0V6dh{zh?{^&bf1dgLvt^%(cB+lS<yRpI3=9l;3=9l1 znCaLxClz$<H6+nmf6c#c$HvCy%vM&$7FNb)=Ek<}!JkWuo`h^aGbhB2P44=fD|fE! z5!$=v$R-yzHba5Xh4B+-FP=YT=JZAUQ&Up}7(8D*S9!Md^>6jmrE1d|c#~2Rk{TG? z*wPeE9y!2-w5|$tP4>EWrmZU(85ne!v942gPb~>3$}dPQDyei#MywNW4Z7`j+d*Vb zsot?ZZqFT;r+GVQu&m6hWOa4&c*q*KBxH~Exl=h$Zd^?3JrN(cQsfA;{DuBi7W-DP z_Bd#-FF%(4?996F=kNb!XSly1by1Hhv#QSQh=cBv!{(RNT-&%Rx%Z&d$$}$GXU(y4 zJ{MpwX)(R;t#xC1`Bag{?dJpR1R4W!+kU3~`+UyQ`J=|0$raCBSpJwuecSQp;g>&0 z^h#v^-<ha%OfoV=Jn75@k3H+&tX`P^-Q~je{+(8*56SHEYGK@}cS0j!M)tcs(_UNt z-E00}ozkrrT>1qeDl5a)<0lv;zjF&((OIi@bm@nk$A4#DZmwBwHgncpgGqYtJ1W?@ zcdm#}n#d~rT5MUuiyIp*99Y&W^@`{9`?pgT{xVWO{OY#j%Ys=SAKC|&sV5(8=MjBh z&)oL*`oE}ohr)MBr5e2Wa^-RC1y-#Kw_IA&x&zpycn{><ZQ5Fvzu>RRl84M^FNbii z(h@S_@D+~oSZ&y>HDOIsxLb3d>gPM&1_oDuvA*SNeO=%8v}L`jUs%*+t5E*Vxo5wW zEz{pxxA;d;j*Z~-O%hViCRNURboBjEcSLatitOt~A9nOGGBE69VqlQROom>L5l$-3 ziOCtz;<Gj=TA$fb<e%Gi+1T#5J5l9btB!o~Q87_j@{rNh#`k*5)VDd8W3Qb5q~LOh z|HI-VGgVcl<P_!IpZVUpI4%DEyf_A(#TiY?(_NS<`x1qfC9a;7IL>lhrCIQvnTqqS zBF%NJZ#hfzrrQd#X!G3p7^)Gic-W(5+ncbvo3qzhZ7#poZ+=Q%!&EIS_Gw!-Pwmlo zlh2`-G=8TqxfoqI_0HZ^*Hb<_T(Mb|qP0(X&#H`FR{wRR9=1vw965bx=YlJ@!o19s zjXa+|EL$wHC~nq~J2{q{1b6M@vRI~Z|NHt`eRqmX3xl@ny?QLB;}iYDWzw==hKBA3 z5Amew&Uo=?M)HZjD^E=LWw$qc_msZ4u-V_%Z<I)K-8<>eeeTp3L7&p1Sr-QIdFqJz z*XMuz&wg^7<3^YB=U&c#;ox<D&Y~&%lq%ikx8^xjX;?eXQBnx6V$jyTvv_fejdGb# z^o{zK!u}tzE|<K`n48}y-qaG5OXN82!o^b~pwMfl(6vRu+5RY7WiP**j`N90<}0Ti zu=x1&K2p61ipbZ8H9PZo7#JFq7#Jk6M<k>$*&0z96LVGc-@D{WgGxmQCPt?gl?eh0 zlF35TCmhX@;85{8(X{o}^oNYX?dBGrJvz3PzD>%#yEbWc=;CEtw;kgZS}C>FH)faq zwsm*SufOXKds}{gwq#oC!oN@Fm*2lr{m$}!`8&(!^UTlh`+p*tL9DY%JgUH7&+O4^ zy(bUiMB`7ps_oO0|Gx8w#ezq5J3lpa8}aY@ARrfJ_@t@rp{GTMv)+!69bJN=_X`#> z^m}bQ9%8fZQ32n)f`uIZt17&Xn#XEPU4K8Q@JMTsjb^=k=*KPGq7`nh9zWV#RO5Ga z`_mt?qW42T+KNAWI8UY~zR!L_M!m-UIu&{QX~*goJ*wn<v|Ow1*&*(Vz@y$p|5C-p zytVW8C<X4H)jWUq2kt*bLUpb2-i`N9Y`=d>cYpE2??0Nm?00S8IxKV{TW?RF`IE=K zKP$ZL?oC@=AM`O@w0`3H`p}Q&qV?e)`5V`4-L?F<z=c^pmpRsaeR*(!;FB%KXU@C1 z$@~7=-L<=JzU7mMefPGlE^qe5R2H7g$tE06@;;W$-gQ-e!JADRQ>NeUW`5TgH@|xM z^*1Hv>+fw`cFOGDhDlwUrdRu}-x{Q_IPITV<C(4h{8r7m^vJZ=_wQcoUWeWLE+3zH zNNm6R_uR|OaX+n1W@dh^;M}D#llN6wsr0p|{h5-?(;9ZGaV<N$J+W?6?Lyu=dRDAy zJ&f_U?%#HoVC9^(^QLluO!v%9ig%8Fl%BSI`|W!LYvn&k)K0seKPl|<r*9e8^X~0D z{UL%^Te!kv_Ho6@xAVWfYE0;VCmbOY^ziF$>AiM~6<d>&&P-Z!-KdK7)a09y?~SW? zFPBNZl${=;a;C>gGDh%3x2vK-HqX^W{<Tt<HCIZs#vFOBQGI#Co#@+9mr~+I3@>c4 zoaGg_X46N8Wk$245`t$jd`>c7%B~VvX)<B*BIn$0(GRokW;SX1+|k%j_NT%xQAO&? zri+X7jDG*p%`^ORuXBFVmAJ-Z9~Wim1YdkHtuHUr_=}(N1hox+e&jN(K7M%0AqSH= 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®%-D_$PX3Hg`qgKY{pvEZOba7q2+{ej)nh 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	Fly|y16Jbm!&{BXX<H<B{PL8 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 H1_lNIO;E&9 literal 0 HcmV?d00001 diff --git a/pne-editor/lib/pn-imta-initial-models-and-adapters.jar b/pne-editor/lib/pn-imta-initial-models-and-adapters.jar new file mode 100644 index 0000000000000000000000000000000000000000..0283a4ff788ff775519a5bca23d14bbca6d0b5ee GIT binary patch literal 130430 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�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%0AE?s84Sv?#~$^Y5O& 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 literal 0 HcmV?d00001 diff --git a/pne-editor/src/logger/PNEditorLogger.java b/pne-editor/src/logger/PNEditorLogger.java new file mode 100644 index 0000000..d09a1a8 --- /dev/null +++ b/pne-editor/src/logger/PNEditorLogger.java @@ -0,0 +1,98 @@ +package logger; + +import java.io.IOException; +import java.util.logging.FileHandler; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + + +public class PNEditorLogger { + + /** + * Instantiate a logger to be used by the software + */ + private final static Logger LOGGER = Logger.getLogger(PNEditorLogger.class.getName()); + + + /** + * Specify a fileName.log to write logs + * + * @param fileName + */ + public static void addFileLog(final String fileName) { + final SimpleFormatter simpleFormatter = new SimpleFormatter(); + try { + final FileHandler fileHandler = new FileHandler(fileName + ".log", true); + fileHandler.setFormatter(simpleFormatter); + LOGGER.addHandler(fileHandler); + } catch (SecurityException e) { + LOGGER.severe("Security Problem: can't add this file"); + } catch (IOException e) { + LOGGER.severe("Can't add this file"); + } + } + + + /** + * Prints on console (+files if created) logs of severe Level + * + * @param data + */ + public static void severeLogs(final String data) { + LOGGER.severe(data); + } + + /** + * Prints on console (+files if created) logs of warning Level + * + * @param data + */ + public static void warningLogs(final String data) { + LOGGER.warning(data); + } + + /** + * Prints on console (+files if created) logs of info level + * + * @param data + */ + public static void infoLogs(final String data) { + LOGGER.info(data); + } + + /** + * Prints on console (+files if created) logs of config Level + * + * @param data + */ + public static void configLogs(final String data) { + LOGGER.config(data); + } + + /** + * Prints on console (+files if created) logs of fine Level + * + * @param data + */ + public static void fineLogs(final String data) { + LOGGER.fine(data); + } + + /** + * Prints on console (+files if created) logs of finer Level + * + * @param data + */ + public static void finerLogs(final String data) { + LOGGER.finer(data); + } + + /** + * Prints on console (+files if created) logs of finest Level + * + * @param data + */ + public static void finestLogs(final String data) { + LOGGER.finest(data); + } +} diff --git a/pne-editor/src/org/petriNet/Arc.java b/pne-editor/src/org/petriNet/Arc.java new file mode 100644 index 0000000..9956578 --- /dev/null +++ b/pne-editor/src/org/petriNet/Arc.java @@ -0,0 +1,50 @@ +package org.petriNet; + +public abstract class Arc { + + private final int id; + private Place place; + private final Transition transition; + private int weight; + + public Arc(Transition transition, Place place, int weight, int id) { + this.place = place; + this.transition = transition; + // verify that the weight is not negative + if (weight >= 0) { + this.weight = weight; + } else { + System.out.println("The weight cannot be negative."); + } + this.id = id; // Assign a unique ID with the generateId method in the PetriNet class + } + + public abstract void validate(); + + public int getWeight() { + return this.weight; + } + + public int getId() { + return this.id; + } + + public Place getPlace() { + return this.place; + } + + public Transition getTransition() { + return this.transition; + } + + public void setPlace(Place place) { + this.place = place; + } + + public void setWeight(int weight) { + this.weight = weight; + } + +} + + diff --git a/pne-editor/src/org/petriNet/IncomingArc.java b/pne-editor/src/org/petriNet/IncomingArc.java new file mode 100644 index 0000000..5f66af3 --- /dev/null +++ b/pne-editor/src/org/petriNet/IncomingArc.java @@ -0,0 +1,31 @@ +package org.petriNet; + +public abstract class IncomingArc extends Arc { + + /** + * IncomingArc are incoming to a transition and outgoing from a place. + * They allow tokens to be removed from a place. + * They are therefore the abstract parent class of OutgoingArc_Simple, IncomingArc_Videur, and IncomingArc_Zero. + * This is a difference from the submitted class diagram. + */ + + public IncomingArc(Transition transition, Place place, int weight, int id) { + super(transition, place, weight, id); + } + + /** + * In the IncomingArc class, tokens are only removed from the place, + * there are no tokens to add. + * This justifies the change from the submitted class diagram. + */ + + public boolean canFire() { + return this.getPlace().getTokenCount() >= this.getWeight(); + } + + @Override + public void validate() { + // Remove the number of tokens equal to the weight of the arc + this.getPlace().removeTokens(this.getWeight()); + } +} \ No newline at end of file diff --git a/pne-editor/src/org/petriNet/IncomingArc_Simple.java b/pne-editor/src/org/petriNet/IncomingArc_Simple.java new file mode 100644 index 0000000..7c1f2e8 --- /dev/null +++ b/pne-editor/src/org/petriNet/IncomingArc_Simple.java @@ -0,0 +1,9 @@ +package org.petriNet; + +public class IncomingArc_Simple extends IncomingArc { + + public IncomingArc_Simple(Transition transition, Place place, int weight, int id) { + super(transition, place, weight, id); + } + +} diff --git a/pne-editor/src/org/petriNet/IncomingArc_Videur.java b/pne-editor/src/org/petriNet/IncomingArc_Videur.java new file mode 100644 index 0000000..d238af2 --- /dev/null +++ b/pne-editor/src/org/petriNet/IncomingArc_Videur.java @@ -0,0 +1,25 @@ +package org.petriNet; + +public class IncomingArc_Videur extends IncomingArc { + + public IncomingArc_Videur(Transition transition, Place place, int poids, int id) { + super(transition, place, poids, id); + } + + // Les arcs «videurs» qui sont actifs dès qu’il y a un jeton dans la place source et qui enlèvent + // tous les jetons présents lorsqu’ils sont activés. + + @Override + public boolean canFire() { + return this.getPlace().getTokenCount() > 0; + } + + @Override + public void validate() { + // On retire le nombre de jetons du poids de l'arc + // prendre en cond la place choisie + this.getPlace().removeTokens(this.getPlace().getTokenCount()); + } + + +} diff --git a/pne-editor/src/org/petriNet/IncomingArc_Zero.java b/pne-editor/src/org/petriNet/IncomingArc_Zero.java new file mode 100644 index 0000000..dd48bb6 --- /dev/null +++ b/pne-editor/src/org/petriNet/IncomingArc_Zero.java @@ -0,0 +1,13 @@ +package org.petriNet; + + public class IncomingArc_Zero extends IncomingArc { + + public IncomingArc_Zero(Transition transition, Place place, int weight, int id) { + super(transition, place, weight, id); + } + + @Override + public boolean canFire() { + return this.getPlace().getTokenCount() == 0; + } +} diff --git a/pne-editor/src/org/petriNet/Main.java b/pne-editor/src/org/petriNet/Main.java new file mode 100644 index 0000000..798714e --- /dev/null +++ b/pne-editor/src/org/petriNet/Main.java @@ -0,0 +1,134 @@ +package org.petriNet; + +public class Main { + + public static void main(String[] args) { + System.out.println("Running Standard Petri Network Simulation..."); + + // CR1 + PetriNet Mutex = new PetriNet(); + Arc arc; + + // CP1 + Place P1 = new Place(0, Mutex.generateId(1)); + Mutex.addPlace(P1); + + // CT1 + Transition T1 = new Transition("T1", Mutex.generateId(2)); + Mutex.addTransition(T1); + + // CP2 + Place P2 = new Place(1, Mutex.generateId(1)); + Mutex.addPlace(P2); + + // CT2 + Transition T2 = new Transition("T2", Mutex.generateId(2)); + Mutex.addTransition(T2); + + // CP5 + Place P3 = new Place(0, Mutex.generateId(1)); + Mutex.addPlace(P3); + + // CT3 + Transition T3 = new Transition("T3", Mutex.generateId(2)); + Mutex.addTransition(T3); + + // CP4 + Place P4 = new Place(0, Mutex.generateId(1)); + Mutex.addPlace(P4); + + // CT4 + Transition T4 = new Transition("T4", Mutex.generateId(2)); + Mutex.addTransition(T4); + + // CP5 + Place P5 = new Place(1, Mutex.generateId(1)); + Mutex.addPlace(P5); + + // CPT1 + // Create the simple incoming arc to T1 from P1 + arc = new IncomingArc_Simple(T1, P1, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T1.addIncomingArc((IncomingArc) arc); + + + // CTP2 + // Create the simple outgoing arc from T2 to P1 + arc = new OutgoingArc(T2, P1, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T2.addOutgoingArc((OutgoingArc) arc); + + + // CTP1 + // Create the simple outgoing arc from T1 to P2 + arc = new OutgoingArc(T1, P2, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T1.addOutgoingArc((OutgoingArc) arc); + + + // CPT2 + // Create the simple incoming arc to T2 from P2 + arc = new IncomingArc_Simple(T2, P2, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T2.addIncomingArc((IncomingArc) arc); + + + // CPT5 + // Create the simple incoming arc to T1 from P3 + arc = new IncomingArc_Simple(T1, P3, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T1.addIncomingArc((IncomingArc) arc); + + + // CTP5 + // Create the simple outgoing arc from T2 to P3 + arc = new OutgoingArc(T2, P3, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T2.addOutgoingArc((OutgoingArc) arc); + + + // CPT6 + // Create the simple incoming arc to T3 from P3 + arc = new IncomingArc_Simple(T3, P3, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T3.addIncomingArc((IncomingArc) arc); + + + // CTP6 + // Create the simple outgoing arc from T4 to P3 + arc = new OutgoingArc(T4, P3, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T4.addOutgoingArc((OutgoingArc) arc); + + + // CTP3 + // Create the simple outgoing arc from T3 to P4 + arc = new OutgoingArc(T3, P4, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T3.addOutgoingArc((OutgoingArc) arc); + + + // CPT4 + // Create the simple incoming arc to T4 from P4 + arc = new IncomingArc_Simple(T4, P4, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T4.addIncomingArc((IncomingArc) arc); + + + // CPT3 + // Create the simple incoming arc to T3 from P5 + arc = new IncomingArc_Simple(T3, P5, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T3.addIncomingArc((IncomingArc) arc); + + + // CTP4 + // Create the simple outgoing arc from T4 to P5 + arc = new OutgoingArc(T4, P5, 1, Mutex.generateId(0)); + Mutex.addArc(arc); + T4.addOutgoingArc((OutgoingArc) arc); + + + Mutex.displayState(); + } +} diff --git a/pne-editor/src/org/petriNet/OutgoingArc.java b/pne-editor/src/org/petriNet/OutgoingArc.java new file mode 100644 index 0000000..589a91e --- /dev/null +++ b/pne-editor/src/org/petriNet/OutgoingArc.java @@ -0,0 +1,15 @@ +package org.petriNet; + +public class OutgoingArc extends Arc { + + public OutgoingArc(Transition transition, Place place, int weight, int id) { + super(transition, place, weight, id); + } + + + @Override + public void validate() { + this.getPlace().addTokens(this.getWeight()); + } + +} \ No newline at end of file diff --git a/pne-editor/src/org/petriNet/PetriNet.java b/pne-editor/src/org/petriNet/PetriNet.java new file mode 100644 index 0000000..680203d --- /dev/null +++ b/pne-editor/src/org/petriNet/PetriNet.java @@ -0,0 +1,457 @@ + package org.petriNet; + + import java.util.*; + + public class PetriNet implements PetriNetService { + + // Create attributes as Lists of Places, Transitions, and Arcs + private final LinkedList<Integer> idCounters; + private List<Place> places; + private List<Transition> transitions; + private LinkedList<Arc> arcs; + private String networkState = "No transition fired"; + + // Create a constructor + public PetriNet() { + // Initialize the lists as empty + this.places = new ArrayList<>(); + this.transitions = new ArrayList<>(); + this.arcs = new LinkedList<>(); + idCounters = new LinkedList<>(); + + // Initialize the id counters for Arcs, Places, and Transitions + idCounters.add(0); + idCounters.add(0); + idCounters.add(0); + } + + // Create a method to generate unique ids + public int generateId(int index) { + int id = idCounters.get(index); + idCounters.set(index, id + 1); + return id; + } + + // Create getters and setters + public List<Place> getPlaces() { + return places; + } + + public void setPlaces(List<Place> places) { + this.places = places; + } + + public List<Transition> getTransitions() { + return transitions; + } + + public void setTransitions(List<Transition> transitions) { + this.transitions = transitions; + } + + public LinkedList<Arc> getArcs() { + return this.arcs; + } + + public void setArcs(LinkedList<Arc> arcs) { + this.arcs = arcs; + } + + @Override + public void addPlace(Place place) { + // Verify that there is no similar place in the list + for (Place place1 : this.places) { + if (place1.getId() == place.getId()) { + System.out.println("Place already exists"); + return; + } + } + this.places.add(place); + } + + @Override + public void addTransition(Transition transition) { + // Verify that there is no similar transition in the list + for (Transition transition1 : this.transitions) { + if (transition1.getId() == transition.getId()) { + System.out.println("Transition already exists"); + return; + } + } + this.transitions.add(transition); + } + + @Override + public void addArc(Arc arc) { + // Verify that there is no similar arc in the list + for (Arc arc1 : this.arcs) { + if (arc1.getPlace().getId() == arc.getPlace().getId() && + arc1.getTransition().getId() == arc.getTransition().getId() && + arc1.getClass() == arc.getClass()) { + System.out.println("Arc already exists"); + return; + } + } + this.arcs.add(arc); + } + + /** + * We add a method to create many transitions at once. + * This is an enhancement to avoid many lines of code. + * @param numberOfTransitions the number of transitions to create + * @return List<Transition> + */ + + public LinkedList<Transition> createTransitions(int numberOfTransitions) { + LinkedList<Transition> transitions = new LinkedList<>(); + // verify that the number of transitions is positive + if (numberOfTransitions <= 0) { + System.out.println("The number of transitions must be positive"); + return transitions; + } + for (int i = 0; i < numberOfTransitions; i++) { + int id = this.generateId(2); + Transition transition = new Transition("Transition " + id, id); + transitions.add(transition); + } + return transitions; + } + + /** + * We add a method to create many places at once. + * This is an enhancement to avoid many lines of code. + * @param numberOfPlaces the number of places to create + * @param numberOfTokens List<int> of tokens for each place + * @return List<Place> + */ + + public LinkedList<Place> createPlaces(int numberOfPlaces, List<Integer> numberOfTokens) { + LinkedList<Place> places = new LinkedList<>(); + + /* Verify that the number of tokens is equal to the number of places + * Verify that the number of tokens is positive + * verify that the number of places is positive + */ + + if (numberOfPlaces <= 0 || numberOfTokens.size() != numberOfPlaces || numberOfTokens.stream().anyMatch(token -> token < 0)) { + System.out.println("Error: The number of places must be positive, the number of tokens must be positive and equal to the number of places"); + return places; + } + + for (int i = 0; i < numberOfPlaces; i++) { + places.add(new Place( numberOfTokens.get(i), this.generateId(1))); + } + return places; + } + + /** + * We add a method to create many Incoming arcs at once. + * This is an enhancement to avoid many lines of code. + * If one of the types of arcs is not valid, the method will return null. + * + * @param numberOfArcs the number of Incoming Arcs to create + * @param weights List<int> of weights for each Incoming Arc + * @param places List<Place> of places for each Incoming Arc + * @param transitions List<Transition> of transitions for each Incoming Arc + * @param types_of_arcs List<String> of types for each Incoming Arc + * @return List<IncomingArc> + */ + + public LinkedList<Arc> createIncomingArcs(int numberOfArcs, List<String> types_of_arcs, List<Integer> weights, List<Place> places, List<Transition> transitions) { + LinkedList<Arc> IncomingArc = new LinkedList<>(); + + /* Verify that the number of IncomingArc is positive + * Verify that the number of weights is equal to the number of IncomingArc + * Verify that the number of weights is positive + * Verify that the number of places is equal to the number of IncomingArc + * Verify that the number of transitions is equal to the number of IncomingArc + */ + + if (numberOfArcs <= 0 || weights.size() != numberOfArcs || weights.stream().anyMatch(weight -> weight < 0) || + places.size() != numberOfArcs || transitions.size() != numberOfArcs) { + System.out.println("Error: The number of weights, places, and transitions must be positive and equal to the number of IncomingArc"); + return IncomingArc; + } + + for (int i = 0; i < numberOfArcs; i++) { + switch (types_of_arcs.get(i)) { + case "zero": + IncomingArc.add(new IncomingArc_Zero(transitions.get(i), places.get(i), weights.get(i), this.generateId(0))); + case "videur": + IncomingArc.add(new IncomingArc_Videur(transitions.get(i), places.get(i), weights.get(i), this.generateId(0))); + case "simple": + IncomingArc.add(new IncomingArc_Simple(transitions.get(i), places.get(i), weights.get(i), this.generateId(0))); + break; + case "Simple": + IncomingArc.add(new IncomingArc_Simple(transitions.get(i), places.get(i), weights.get(i), this.generateId(0))); + break; + case "Videur": + IncomingArc.add(new IncomingArc_Videur(transitions.get(i), places.get(i), weights.get(i), this.generateId(0))); + break; + case "Zero": + IncomingArc.add(new IncomingArc_Zero(transitions.get(i), places.get(i), weights.get(i), this.generateId(0))); + break; + default: + System.out.println("Error: one of he type of arc is not valid"); + return null; + } + } + return IncomingArc; + } + + /** + * We add a method to create many Outgoing arcs at once. + * This is an enhancement to avoid many lines of code. + * @param numberOfArcs the number of Outgoing Arcs to create + * @param weights List<int> of weights for each Outgoing Arc + * @param places List<Place> of places for each Outgoing Arc + * @param transitions List<Transition> of transitions for each Outgoing Arc + * @return List<Arc> + */ + + public LinkedList<Arc> createOutgoingArcs(int numberOfArcs, List<Integer> weights, List<Place> places, List<Transition> transitions) { + LinkedList<Arc> OutgoingArc = new LinkedList<>(); + + /* Verify that the number of OutgoingArc is positive + * Verify that the number of weights is equal to the number of OutgoingArc + * Verify that the number of weights is positive + * Verify that the number of places is equal to the number of OutgoingArc + * Verify that the number of transitions is equal to the number of OutgoingArc + */ + + if (numberOfArcs <= 0 || weights.size() != numberOfArcs || weights.stream().anyMatch(weight -> weight < 0) || + places.size() != numberOfArcs || transitions.size() != numberOfArcs) { + System.out.println("Error: The number of weights, places, and transitions must be positive and equal to the number of OutgoingArc"); + return OutgoingArc; + } + + for (int i = 0; i < numberOfArcs; i++) { + OutgoingArc.add(new OutgoingArc(transitions.get(i), places.get(i), weights.get(i), this.generateId(0))); + } + return OutgoingArc; + } + + @Override + public Place FindPlaceById(int id) { + for (Place place : this.places) { + if (place.getId() == id) { + return place; + } + } + System.out.println("Place not found"); + return null; + } + + @Override + public Arc FindArcById(int id) { + for (Arc arc : this.arcs) { + if (arc.getId() == id) { + return arc; + } + } + System.out.println("Arc not found"); + return null; + } + + /** + * Removing a place results in the removal of all arcs linked to it. + * Removing a transition results in the removal of all arcs linked to it. + */ + @Override + public void removePlace(Place place) { + this.places.remove(place); + // Remove all arcs linked to the place + this.arcs.removeIf(arc -> arc.getPlace().getId() == place.getId()); + } + + @Override + public void removeTransition(Transition transition) { + this.transitions.remove(transition); + // Remove all arcs linked to the transition + this.arcs.removeIf(arc -> arc.getTransition().getId() == transition.getId()); + } + + @Override + public void removeArc(Arc arc) { + this.arcs.remove(arc); + // Remove it from the list of arcs of the transition + if (arc instanceof IncomingArc) { + arc.getTransition().getIncomingArcs().remove(arc); + } else if (arc instanceof OutgoingArc) { + arc.getTransition().getOutgoingArcs().remove(arc); + } + } + + @Override + public void fireTransition(String id) { + // Set the state of the network to "Transition being validated" + this.networkState = "Transition being validated"; + + // Find the transition with the id + Transition chosenTransition = null; + for (Transition transition : this.transitions) { + if (String.valueOf(transition.getId()).equals(id)) { + chosenTransition = transition; + } + } + + // Check if the transition id is valid + if (chosenTransition == null) { + System.out.println("The transition id is not valid"); + return; + } else { + chosenTransition.fire(); + } + + // Set the state of the network to "No transition fired" + this.networkState = "No transition fired"; + } + + @Override + public void displayState() { + if (this.networkState.equals("No transition fired")) { + System.out.println("No transition fired"); + Scanner scanner = new Scanner(System.in); + while (true) { + System.out.println("Choose an option:"); + System.out.println("1. Display the network"); + System.out.println("2. Fire a transition"); + System.out.println("3. Change the number of tokens in a place"); + System.out.println("4. Change the weight of an arc"); + System.out.println("5. Change an arc to an IncomingArc_Videur or IncomingArc_Zero"); + System.out.println("6. Exit"); + String response = scanner.nextLine(); + + switch (response) { + case "1": + displayNetwork(); + break; + case "2": + System.out.println("Enter the id of the transition to fire: "); + int transitionId = getIntInput(scanner); + fireTransition(String.valueOf(transitionId)); + break; + case "3": + System.out.println("Enter the id of the place to change tokens: "); + int placeId = getIntInput(scanner); + System.out.println("Enter the new number of tokens: "); + int tokens = getIntInput(scanner); + Place place = this.FindPlaceById(placeId); + if (place == null) { + break; + } + place.setTokenCount(tokens); + break; + case "4": + System.out.println("Enter the id of the arc to change weight: "); + int arcId = getIntInput(scanner); + System.out.println("Enter the new weight: "); + int weight = getIntInput(scanner); + Arc arc = this.FindArcById(arcId); + if (arc == null) { + break; + } + arc.setWeight(weight); + break; + case "5": + System.out.println("Enter the id of the arc to change: "); + int arcToChangeId = getIntInput(scanner); + Arc arcToChange = this.FindArcById(arcToChangeId); + if (arcToChange == null) { + break; + } + if (arcToChange instanceof IncomingArc) { + System.out.println("Choose the type of arc to change to:"); + System.out.println("1. IncomingArc_Videur"); + System.out.println("2. IncomingArc_Zero"); + int arcType = getIntInput(scanner); + Transition transition = arcToChange.getTransition(); + Place placeToChange = arcToChange.getPlace(); + this.removeArc(arcToChange); + if (arcType == 1) { + IncomingArc_Videur newArc = new IncomingArc_Videur(transition, placeToChange, arcToChange.getWeight(), this.generateId(0)); + this.addArc(newArc); + transition.addIncomingArc(newArc); + System.out.println("Arc changed to IncomingArc_Videur."); + } else if (arcType == 2) { + IncomingArc_Zero newArc = new IncomingArc_Zero(transition, placeToChange, arcToChange.getWeight(), this.generateId(0)); + this.addArc(newArc); + transition.addIncomingArc(newArc); + System.out.println("Arc changed to IncomingArc_Zero."); + } else { + System.out.println("Invalid arc type."); + } + } else { + System.out.println("Arc is not an IncomingArc."); + } + break; + case "6": + return; // Exit the method + default: + System.out.println("Invalid option. Please try again."); + } + } + } else { + System.out.println("Transition being validated"); + } + } + + @Override + public void displayNetwork() { + System.out.println("Petri Net"); + System.out.println(this.places.size() + " places"); + System.out.println(this.transitions.size() + " transitions"); + System.out.println(this.arcs.size() + " arcs"); + + System.out.println("List of places:"); + // Iterate through the list of arcs to display the places + // A list for incoming arcs and a list for outgoing arcs + for (Place place : this.places) { + List<Arc> incomingArcs = new ArrayList<>(); + List<Arc> outgoingArcs = new ArrayList<>(); + for (Arc arc : this.arcs) { + // Verify if arc.getPlace() == place + if (arc.getPlace().getId() == place.getId()) { + // Verify if it's an incoming arc + if (arc instanceof IncomingArc) { + incomingArcs.add(arc); + } else if (arc instanceof OutgoingArc) { + outgoingArcs.add(arc); + } + } + } + // Display incoming/outgoing arcs for the place + System.out.println(place.getId() + " : place with " + place.getTokenCount() + " tokens, " + + incomingArcs.size() + " outgoing arc(s), " + outgoingArcs.size() + " incoming arc(s)"); + } + + System.out.println("List of transitions:"); + for (Transition transition : this.transitions) { + System.out.println(transition.getId() + " : transition " + transition.getName() + " " + transition.getIncomingArcs().size() + + " incoming arc(s), " + transition.getOutgoingArcs().size() + " outgoing arc(s)"); + } + + System.out.println("List of arcs:"); + for (Arc arc : this.arcs) { + if (arc instanceof IncomingArc) { + System.out.println(arc.getId() + " : " + + (arc instanceof IncomingArc_Videur ? "videur" : (arc instanceof IncomingArc_Zero ? "zero" : "simple arc")) + + " with weight " + arc.getWeight() + " (" + + "Place with Id " + arc.getPlace().getId() + " to " + arc.getTransition().getName() + ")"); + } else { + System.out.println(arc.getId() + " : outgoing arc with weight " + arc.getWeight() + " (" + + arc.getTransition().getName() + " to " + "Place with Id " + arc.getPlace().getId() + ")"); + } + } + } + + private int getIntInput(Scanner scanner) { + while (!scanner.hasNextInt()) { + System.out.println("Invalid input. Please enter an integer."); + scanner.next(); // discard invalid input + } + int input = scanner.nextInt(); + scanner.nextLine(); // consume the newline character + return input; + } + } \ No newline at end of file diff --git a/pne-editor/src/org/petriNet/PetriNetService.java b/pne-editor/src/org/petriNet/PetriNetService.java new file mode 100644 index 0000000..473a38e --- /dev/null +++ b/pne-editor/src/org/petriNet/PetriNetService.java @@ -0,0 +1,31 @@ +package org.petriNet; + +public interface PetriNetService { + + void addPlace(Place place); + + void addTransition(Transition transition); + + void addArc(Arc arc); + + void removePlace(Place place); + + void removeTransition(Transition transition); + + void removeArc(Arc arc); + + Place FindPlaceById(int id); + + Arc FindArcById(int id); + + void displayState(); + + /** + * Display the Petri net + * We found that this function is useful for visualizing + * the Petri net + */ + void displayNetwork(); + + void fireTransition(String id); +} diff --git a/pne-editor/src/org/petriNet/Place.java b/pne-editor/src/org/petriNet/Place.java new file mode 100644 index 0000000..77e9fde --- /dev/null +++ b/pne-editor/src/org/petriNet/Place.java @@ -0,0 +1,53 @@ +package org.petriNet; + +public class Place { + + private final int id; + private int tokenCount; + + public Place(int tokenCount, int id) { + this.id = id; + // VERIFY THAT THE NUMBER OF TOKENS IS NOT NEGATIVE + if (tokenCount >= 0) { + this.tokenCount = tokenCount; + } else { + System.out.println("The number of tokens cannot be negative."); + } + } + + public void addTokens(int tokens) { + // verify that the number of tokens is not negative + if (tokens >= 0) { + this.tokenCount += tokens; + } else { + System.out.println("The number of tokens cannot be negative."); + } + } + + public void removeTokens(int tokens) { + // verify that the number of tokens is not negative + if (tokens >= 0) { + this.tokenCount = Math.max(0, this.tokenCount - tokens); + } else { + System.out.println("The number of tokens cannot be negative."); + } + } + + public int getTokenCount() { + return this.tokenCount; + } + + public int getId() { + return id; + } + + public void setTokenCount(int tokenCount) { + if (tokenCount < 0) { + System.out.println("Token count cannot be negative."); + this.tokenCount = 0; + } else { + this.tokenCount = tokenCount; + } + } + +} diff --git a/pne-editor/src/org/petriNet/Transition.java b/pne-editor/src/org/petriNet/Transition.java new file mode 100644 index 0000000..6ce6c8d --- /dev/null +++ b/pne-editor/src/org/petriNet/Transition.java @@ -0,0 +1,105 @@ +package org.petriNet; + +import java.util.LinkedList; +import java.util.List; + +public class Transition { + + private final int id; + String name; + private LinkedList<OutgoingArc> outgoingArcs; + private LinkedList<IncomingArc> incomingArcs; + + public Transition(String name, int id) { + this.id = id; + this.name = name; + this.outgoingArcs = new LinkedList<>(); + this.incomingArcs = new LinkedList<>(); + } + + /** + * We add two methods to be able to add incoming and outgoing arcs to the transition. + * This is a difference from the submitted class diagram. + */ + + public String getName() { + return name; + } + + public int getId() { + return id; + } + + public List<OutgoingArc> getOutgoingArcs() { + return outgoingArcs; + } + + public List<IncomingArc> getIncomingArcs() { + return incomingArcs; + } + + public void setOutgoingArcs(LinkedList<OutgoingArc> outgoingArcs) { + this.outgoingArcs = outgoingArcs; + } + + public void setIncomingArcs(LinkedList<IncomingArc> incomingArcs) { + this.incomingArcs = incomingArcs; + } + + public void addOutgoingArc(OutgoingArc outgoingArc) { + // verify that the arc doesn't already exist + for (OutgoingArc existingArc : outgoingArcs) { + if (existingArc.getPlace().getId() == outgoingArc.getPlace().getId() && + existingArc.getTransition().getId() == outgoingArc.getTransition().getId() && + existingArc.getClass() == outgoingArc.getClass()) { + System.out.println("The arc already exists."); + return; + } + } + this.outgoingArcs.add(outgoingArc); + } + + public void addIncomingArc(IncomingArc incomingArc) { + // verify that the arc doesn't already exist + for (IncomingArc existingArc : incomingArcs) { + if (existingArc.getPlace().getId() == incomingArc.getPlace().getId() && + existingArc.getTransition().getId() == incomingArc.getTransition().getId() && + existingArc.getClass() == incomingArc.getClass()) { + System.out.println("The arc already exists."); + return; + } + } + this.incomingArcs.add(incomingArc); + } + + public boolean canFire() { + for (IncomingArc incomingArc : this.incomingArcs) { + if (!incomingArc.canFire()) { + System.out.println("The transition cannot fire"); + return false; + } + } + System.out.println("The transition can fire"); + return true; + } + + public void fire() { + boolean canFire = canFire(); + + if (canFire) { + for (IncomingArc incomingArc : this.getIncomingArcs()) { + incomingArc.validate(); + } + + for (OutgoingArc outgoingArc : this.getOutgoingArcs()) { + outgoingArc.validate(); + } + System.out.println("Transition fired successfully"); + } + } + + public void setName(String label) { + this.name = label; + + } +} diff --git a/pne-editor/src/org/pneditor/PNEConstantsConfiguration.java b/pne-editor/src/org/pneditor/PNEConstantsConfiguration.java new file mode 100644 index 0000000..94026f9 --- /dev/null +++ b/pne-editor/src/org/pneditor/PNEConstantsConfiguration.java @@ -0,0 +1,84 @@ +package org.pneditor; + +import java.io.File; + +public final class PNEConstantsConfiguration { + + /* + * WARNING : resources path have a "/" separator not a File.seprator. + * (Whatever the OS is) + */ + + private PNEConstantsConfiguration() { + throw new AssertionError(); + } + + /* + * resources/ + * └── pneditor + * ├── canvas + * ├── filechooser + * */ + public static final String RESOURCESDIR = "/"+"resources"+"/";// + public static final String PNEDITOR_RESOURCES = RESOURCESDIR+"pneditor"+"/"; + public static final String CANVAS_RESOURCES = PNEDITOR_RESOURCES+"canvas"+"/"; + public static final String FILECHOOSER_RESOURCES = PNEDITOR_RESOURCES+"filechooser"+"/"; + + /* + * resources/ + * */ + public static final String ICON16 = RESOURCESDIR+"icon16.png"; + public static final String ICON32 = RESOURCESDIR+"icon32.png"; + public static final String ICON48 = RESOURCESDIR+"icon48.png"; + + /* + * resources/ + * └── pneditor + * */ + public static final String ABOUT16 = PNEDITOR_RESOURCES+"About16.gif"; + public static final String ARC16 = PNEDITOR_RESOURCES+"arc16.gif"; + public static final String CONVERTTRANSITIONTOSUBNET = PNEDITOR_RESOURCES+"converttransitiontosubnet.gif"; + public static final String COPY16 = PNEDITOR_RESOURCES+"Copy16.gif"; + public static final String CUT16 = PNEDITOR_RESOURCES+"Cut16.gif"; + public static final String DELETE16 = PNEDITOR_RESOURCES+"Delete16.gif"; + public static final String EXPORT = PNEDITOR_RESOURCES+"export.gif"; + public static final String IMPORT = PNEDITOR_RESOURCES+"import.gif"; + public static final String LABEL = PNEDITOR_RESOURCES+"label.gif"; + public static final String MULTIPLICITY = PNEDITOR_RESOURCES+"multiplicity.gif"; + public static final String NEW16 = PNEDITOR_RESOURCES+"New16.gif"; + public static final String OPEN16 = PNEDITOR_RESOURCES+"Open16.gif"; + public static final String PASTE16 = PNEDITOR_RESOURCES+"Paste16.gif"; + public static final String PLACE16 = PNEDITOR_RESOURCES+"place16.gif"; + public static final String REDO16 = PNEDITOR_RESOURCES+"Redo16.gif"; + public static final String SAVE16 = PNEDITOR_RESOURCES+"Save16.gif"; + public static final String SAVEAS16 = PNEDITOR_RESOURCES+"SaveAs16.gif"; + public static final String SELECT = PNEDITOR_RESOURCES+"select.gif"; + public static final String SETARCRESETACTION = PNEDITOR_RESOURCES+"setarcresetaction.gif"; + public static final String TOKENS = PNEDITOR_RESOURCES+"tokens.gif"; + public static final String TOKEN_AND_FIRE16 = PNEDITOR_RESOURCES+"token_and_fire16.gif"; + public static final String TRANSITION16 = PNEDITOR_RESOURCES+"transition16.gif"; + public static final String UNDO16 = PNEDITOR_RESOURCES+"Undo16.gif"; + + /* + * resources/ + * └── pneditor + * ├── canvas + * */ + public static final String ARC = CANVAS_RESOURCES+"arc.gif"; + public static final String FIRE = CANVAS_RESOURCES+"fire.gif"; + public static final String PLACE = CANVAS_RESOURCES+"place.gif"; + public static final String TOKEN = CANVAS_RESOURCES+"token.gif"; + public static final String TOKEN_OR_FIRE = CANVAS_RESOURCES+"token_or_fire.gif"; + public static final String TRANSITION = CANVAS_RESOURCES+"transition.gif"; + + /* + * resources/ + * └── pneditor + * ├── filechooser + * */ + public static final String EPS = FILECHOOSER_RESOURCES+"eps.gif"; + public static final String PFLOW = FILECHOOSER_RESOURCES+"pflow.gif"; + public static final String PNG = FILECHOOSER_RESOURCES+"png.gif"; + public static final String PNML = FILECHOOSER_RESOURCES+"pnml.gif"; + +} diff --git a/pne-editor/src/org/pneditor/editor/DrawingBoard.java b/pne-editor/src/org/pneditor/editor/DrawingBoard.java new file mode 100644 index 0000000..5e6537d --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/DrawingBoard.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import org.pneditor.editor.canvas.Canvas; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class DrawingBoard extends JPanel { + + private final JScrollBar verticalScrollBar = new JScrollBar(JScrollBar.VERTICAL, 0, 10_000, 0, 10_000); + private final JScrollBar horizontalScrollBar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 10_000, 0, 10_000); + + DrawingBoard(final Canvas canvas) { + super(); + this.setLayout(new GridBagLayout()); + final GridBagConstraints constraints = new GridBagConstraints(); + + constraints.gridx = 0; + constraints.gridy = 0; + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1; + constraints.weighty = 1; + this.add(canvas, constraints); + constraints.gridx = 1; + constraints.gridy = 0; + constraints.weightx = 0; + constraints.weighty = 0; + this.add(this.verticalScrollBar, constraints); + constraints.gridx = 0; + constraints.gridy = 1; + constraints.weightx = 0; + constraints.weighty = 0; + this.add(this.horizontalScrollBar, constraints); + + this.verticalScrollBar.setUnitIncrement(30); + this.horizontalScrollBar.setUnitIncrement(30); + } + + public JScrollBar getVerticalScrollBar() { + return this.verticalScrollBar; + } + + public JScrollBar getHorizontalScrollBar() { + return this.horizontalScrollBar; + } +} diff --git a/pne-editor/src/org/pneditor/editor/LocalClipboard.java b/pne-editor/src/org/pneditor/editor/LocalClipboard.java new file mode 100644 index 0000000..5c26961 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/LocalClipboard.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor; + +import java.util.HashSet; +import java.util.Set; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicNode; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; + + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class LocalClipboard { + + private final GraphicPetriNet gPetriNet; + + LocalClipboard() { + this.gPetriNet = new GraphicPetriNet(); + } + + LocalClipboard(final String model) { + this.gPetriNet = new GraphicPetriNet(model); + } + + public void setContents(final Set<GraphicElement> elements) { + this.gPetriNet.removeElements(); + this.gPetriNet.addAll(elements); + final Set<GraphicElement> filteredElements = filterOutDisconnectedArcs(elements); + this.gPetriNet.removeElements(); + this.gPetriNet.addAll(filteredElements); + } + + public Set<GraphicElement> getContents() { + return new HashSet<GraphicElement>(this.gPetriNet.getElements()); + } + + public boolean isEmpty() { + return this.gPetriNet.getElements().isEmpty(); + } + + private Set<GraphicElement> filterOutDisconnectedArcs(final Set<GraphicElement> elements) { + final Set<GraphicElement> filteredElements = new HashSet<>(); + final Set<GraphicNode> nodes = getNodes(elements); + for (final GraphicNode node : nodes) { + final Set<GraphicArc> connectedArcEdges = this.gPetriNet.getConnectedGraphicArcs(node); + for (final GraphicArc connectedArcEdge : connectedArcEdges) { + if (nodes.contains(connectedArcEdge.getSource()) && nodes.contains(connectedArcEdge.getDestination())) { + filteredElements.add(connectedArcEdge); + } + } + } + filteredElements.addAll(nodes); + return filteredElements; + } + + public Set<GraphicNode> getNodes(final Set<GraphicElement> elements) { + final Set<GraphicNode> nodes = new HashSet<>(); + for (final GraphicElement element : elements) { + if (element.isNode()) { + nodes.add((GraphicNode) element); + } + } + return nodes; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/Main.java b/pne-editor/src/org/pneditor/editor/Main.java new file mode 100644 index 0000000..053455e --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/Main.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor; + + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class Main { + + public static void main(String[] args) { + new Root(args); + } +} diff --git a/pne-editor/src/org/pneditor/editor/MainFrame.java b/pne-editor/src/org/pneditor/editor/MainFrame.java new file mode 100644 index 0000000..3846647 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/MainFrame.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor; + +import java.awt.Color; + +import javax.swing.JFrame; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import logger.PNEditorLogger; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class MainFrame extends JFrame { + + MainFrame(final String title) { + super(title); + UIManager.getDefaults().put("ToolTip.hideAccelerator", Boolean.TRUE); + UIManager.put("swing.boldMetal", Boolean.FALSE); + UIManager.put("MenuItem.Foreground", Color.WHITE); + final String lookAndFeel = UIManager.getSystemLookAndFeelClassName(); + try { + UIManager.setLookAndFeel(lookAndFeel); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | UnsupportedLookAndFeelException e) { + PNEditorLogger.infoLogs("Couldn't load the Look and Feel"); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/Root.java b/pne-editor/src/org/pneditor/editor/Root.java new file mode 100644 index 0000000..6fc0a68 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/Root.java @@ -0,0 +1,786 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor; + +import java.awt.BorderLayout; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Point; +import java.awt.event.*; +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.prefs.Preferences; +import javax.swing.*; +import javax.swing.event.*; +import org.pneditor.editor.actions.*; +import org.pneditor.editor.actions.algorithms.BoundednessAction; +import org.pneditor.editor.actions.draw.ArcSelectToolAction; +import org.pneditor.editor.actions.draw.PlaceSelectToolAction; +import org.pneditor.editor.actions.draw.SelectionSelectToolAction; +import org.pneditor.editor.actions.draw.TokenSelectToolAction; +import org.pneditor.editor.actions.draw.TransitionSelectToolAction; +import org.pneditor.editor.actions.edit.CopyAction; +import org.pneditor.editor.actions.edit.CutAction; +import org.pneditor.editor.actions.edit.DeleteAction; +import org.pneditor.editor.actions.edit.PasteAction; +import org.pneditor.editor.actions.edit.RedoAction; +import org.pneditor.editor.actions.edit.SelectAllAction; +import org.pneditor.editor.actions.edit.UndoAction; +import org.pneditor.editor.actions.element.SetArcInhibitoryAction; +import org.pneditor.editor.actions.element.SetArcMultiplicityAction; +import org.pneditor.editor.actions.element.SetArcRegularAction; +import org.pneditor.editor.actions.element.SetArcResetAction; +import org.pneditor.editor.actions.element.SetLabelAction; +import org.pneditor.editor.actions.element.SetTokensAction; +import org.pneditor.editor.actions.file.ExportAction; +import org.pneditor.editor.actions.file.ImportAction; +import org.pneditor.editor.actions.file.NewFileAction; +import org.pneditor.editor.actions.file.OpenFileAction; +import org.pneditor.editor.actions.file.QuitAction; +import org.pneditor.editor.actions.file.SaveAction; +import org.pneditor.editor.actions.file.SaveFileAsAction; +import org.pneditor.editor.canvas.*; +import org.pneditor.editor.filechooser.EpsFileType; +import org.pneditor.editor.filechooser.FileType; +import org.pneditor.editor.filechooser.FileTypeException; +import org.pneditor.editor.filechooser.PflowFileType; +import org.pneditor.editor.filechooser.PngFileType; +import org.pneditor.editor.filechooser.ViptoolPnmlFileType; +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * This class is the main point of the application. + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public final class Root implements WindowListener, ListSelectionListener, SelectionChangedListener { + + private static final String APP_NAME = "PNEditor"; + private static final String APP_VERSION = "0.71"; + + public Root(final String[] varargs) { + loadPreferences(); + this.selection.setSelectionChangedListener(this); + + setupMainFrame(); + this.mainFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + setupFrameIcons(); + + if (varargs.length == 1) { + final String filename = varargs[0]; + final File file = new File(filename); + final FileType fileType = FileType.getAcceptingFileType(file, FileType.getAllFileTypes()); + try { + final GraphicPetriNet petriNet = fileType.load(file, getCurrentModel()); + this.setGraphicPetriNet(petriNet); + this.setCurrentFile(file); // TODO: make it DRY with OpenFileAction + this.setModified(false); + this.setCurrentDirectory(file.getParentFile()); + this.canvas.repaint(); + } catch (FileTypeException ex) { + Logger.getLogger(Root.class.getName()).log(Level.INFO, null, ex); + } + } + } + + private static final String CURRENT_DIRECTORY = "current_directory"; + + private void loadPreferences() { + final Preferences preferences = Preferences.userNodeForPackage(this.getClass()); + setCurrentDirectory(new File(preferences.get(CURRENT_DIRECTORY, System.getProperty("user.home")))); + } + + private void savePreferences() { + final Preferences preferences = Preferences.userNodeForPackage(this.getClass()); + preferences.put(CURRENT_DIRECTORY, getCurrentDirectory().toString()); + } + + // Undo manager - per application + private final UndoAction undo = new UndoAction(this); + private final RedoAction redo = new RedoAction(this); + private final UndoManager undoManager = new UndoManager(this, this.undo, this.redo); + + public UndoManager getUndoManager() { + return this.undoManager; + } + + // Current directory - per application + private File currentDirectory; + + public File getCurrentDirectory() { + return this.currentDirectory; + } + + public void setCurrentDirectory(final File currentDirectory) { + this.currentDirectory = currentDirectory; + } + + // Main frame - per application + private final MainFrame mainFrame = new MainFrame(getNewWindowTitle()); + + public Frame getParentFrame() { + return this.mainFrame; + } + + // Document - per tab + private GraphicPetriNet graphicPetriNet = new GraphicPetriNet(); + + public GraphicPetriNet getGraphicPetriNet() { + return this.graphicPetriNet; + } + + public void setGraphicPetriNet(final GraphicPetriNet graphicPetriNet) { + this.graphicPetriNet = graphicPetriNet; + getUndoManager().eraseAll(); + refreshAll(); + } + + public void updateGraphicPetriNet(final GraphicPetriNet newGraphicPetriNet) { + this.graphicPetriNet = newGraphicPetriNet; + refreshAll(); + } + + public PetriNetInterface getPetriNet() { + return this.graphicPetriNet.getPetriNet(); + } + + private String model = "initial"; + + public String getCurrentModel() { + return this.model; + } + + public void setCurrentModel(final String model) { + this.model = model; + this.mainFrame.setTitle(getNewWindowTitle()); + + for (final JMenuItem modelItem : this.modelsList) { + if (modelItem.getName().equals(getCurrentModel())) { + modelItem.setEnabled(false); + } else { + modelItem.setEnabled(true); + } + } + } + + // Clicked element - per tab + private GraphicElement clickedElement; + + public GraphicElement getClickedElement() { + return this.clickedElement; + } + + public void setClickedElement(final GraphicElement clickedElement) { + this.clickedElement = clickedElement; + enableOnlyPossibleActions(); + } + + // Selection - per tab + private final Selection selection = new Selection(); + + public Selection getSelection() { + return this.selection; + } + + @Override + public void selectionChanged() { + enableOnlyPossibleActions(); + } + + // Selection + clicked element + public Set<GraphicElement> getSelectedElementsWithClickedElement() { + final Set<GraphicElement> selectedElements = new HashSet<>(); + selectedElements.addAll(getSelection().getElements()); + if (getClickedElement() != null) { + selectedElements.add(getClickedElement()); + } + return selectedElements; + } + + // List editor - per tab + + @Override + public void valueChanged(final ListSelectionEvent e) { + enableOnlyPossibleActions(); + repaintCanvas(); + } + + // per tab + public void selectToolSelect() { + this.select.setSelected(true); + this.canvas.activeCursor = Cursor.getDefaultCursor(); + this.canvas.setCursor(this.canvas.activeCursor); + repaintCanvas(); + } + + public boolean isSelectedToolSelect() { + return this.select.isSelected(); + } + + public void selectToolPlace() { + this.place.setSelected(true); + + this.canvas.activeCursor = GraphicsTools.getCursor(PNEConstantsConfiguration.PLACE, new Point(16, 16)); + this.canvas.setCursor(this.canvas.activeCursor); + repaintCanvas(); + } + + public boolean isSelectedToolPlace() { + return this.place.isSelected(); + } + + public void selectToolTransition() { + this.transition.setSelected(true); + this.canvas.activeCursor = GraphicsTools.getCursor(PNEConstantsConfiguration.TRANSITION, new Point(16, 16)); + this.canvas.setCursor(this.canvas.activeCursor); + repaintCanvas(); + } + + public boolean isSelectedToolTransition() { + return this.transition.isSelected(); + } + + public void selectToolArc() { + this.arc.setSelected(true); + this.canvas.activeCursor = GraphicsTools.getCursor(PNEConstantsConfiguration.ARC, new Point(0, 0)); + this.canvas.setCursor(this.canvas.activeCursor); + repaintCanvas(); + } + + public boolean isSelectedToolArc() { + return this.arc.isSelected(); + } + + public void selectToolToken() { + this.token.setSelected(true); + this.canvas.activeCursor = GraphicsTools.getCursor(PNEConstantsConfiguration.TOKEN_OR_FIRE, new Point(16, 0)); + this.canvas.setCursor(this.canvas.activeCursor); + repaintCanvas(); + } + + public boolean isSelectedToolToken() { + return this.token.isSelected(); + } + + // per tab + private final Canvas canvas = new Canvas(this); + private final DrawingBoard drawingBoard = new DrawingBoard(this.canvas); + + private JPopupMenu placePopup; + private JPopupMenu transitionPopup; + private JPopupMenu arcPopup; + private JPopupMenu canvasPopup; + + public JPopupMenu getPlacePopup() { + return this.placePopup; + } + + private void setupPlacePopup() { + this.placePopup = new JPopupMenu(); + this.placePopup.add(this.setLabel); + this.placePopup.add(this.setTokens); + this.placePopup.addSeparator(); + this.placePopup.add(this.cutAction); + this.placePopup.add(this.copyAction); + this.placePopup.add(this.delete); + } + + public JPopupMenu getTransitionPopup() { + return this.transitionPopup; + } + + private void setupTransitionPopup() { + this.transitionPopup = new JPopupMenu(); + this.transitionPopup.add(this.setLabel); + this.transitionPopup.addSeparator(); + this.transitionPopup.add(this.cutAction); + this.transitionPopup.add(this.copyAction); + this.transitionPopup.add(this.delete); + } + + public JPopupMenu getArcPopup() { + return this.arcPopup; + } + + private void setupArcPopup() { + this.arcPopup = new JPopupMenu(); + this.arcPopup.add(this.setArcMultiplicity); + this.arcPopup.add(this.setArcRegular); + this.arcPopup.add(this.setArcInhibitory); + this.arcPopup.add(this.setArcReset); + + this.arcPopup.add(this.delete); + } + + public JPopupMenu getCanvasPopup() { + return this.canvasPopup; + } + + private void setupCanvasPopup() { + this.canvasPopup = new JPopupMenu(); + this.canvasPopup.add(this.pasteAction); + } + + // per application + private JToggleButton select; + private JToggleButton place; + private JToggleButton transition; + private JToggleButton arc; + private JToggleButton token; + + private Action setLabel; + private Action setTokens; + private Action setArcMultiplicity; + private Action setArcInhibitory; + private Action setArcReset; + private Action setArcRegular; + + private Action delete; + private Action cutAction; + private Action copyAction; + private Action pasteAction; + private Action selectAllAction; + + private final Set<JMenuItem> modelsList = new HashSet<>(); + + public void refreshAll() { + this.canvas.repaint(); + enableOnlyPossibleActions(); + } + + public void repaintCanvas() { + this.canvas.repaint(); + } + + private void enableOnlyPossibleActions() { + final boolean isDeletable = this.clickedElement != null || !this.selection.isEmpty(); + final boolean isCutable = isDeletable; + final boolean isCopyable = isCutable; + final boolean isPastable = !this.clipboard.isEmpty(); + final boolean isArc = this.clickedElement != null && !this.clickedElement.isNode(); + final boolean isTransition = this.clickedElement != null && this.clickedElement.isTransition(); + final boolean isPlace = this.clickedElement != null && this.clickedElement.isPlace(); + final boolean isSourceAPlace = isArc && ((GraphicArc) this.clickedElement).getArc().isSourceAPlace(); + final boolean isReset = isArc && ((GraphicArc) this.clickedElement).getArc().isReset(); + + + this.cutAction.setEnabled(isCutable); + this.copyAction.setEnabled(isCopyable); + this.pasteAction.setEnabled(isPastable); + this.selectAllAction.setEnabled(true); + this.delete.setEnabled(isDeletable); + this.setArcMultiplicity.setEnabled(!isReset); + this.setArcInhibitory.setEnabled(isSourceAPlace); + this.setArcReset.setEnabled(isSourceAPlace); + this.setArcRegular.setEnabled(isArc); + this.setTokens.setEnabled(isPlace); + this.setLabel.setEnabled(isPlace || isTransition); + this.undo.setEnabled(getUndoManager().isUndoable()); + this.redo.setEnabled(getUndoManager().isRedoable()); + + } + + @Override + public void windowClosed(final WindowEvent e) { + } + + @Override + public void windowIconified(final WindowEvent e) { + } + + @Override + public void windowDeiconified(final WindowEvent e) { + } + + @Override + public void windowActivated(final WindowEvent e) { + } + + @Override + public void windowDeactivated(final WindowEvent e) { + } + + @Override + public void windowOpened(final WindowEvent e) { + } + + @Override + public void windowClosing(final WindowEvent e) { + quitApplication(); + } + + /** + * Terminates the application + */ + public void quitApplication() { + if (!this.isModified()) { + quitNow(); + } + this.mainFrame.setState(Frame.NORMAL); + this.mainFrame.setVisible(true); + final int answer = JOptionPane.showOptionDialog(this.getParentFrame(), + "Any unsaved changes will be lost. Really quit?", "Quit", JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, null, new String[] { "Quit", "Cancel" }, "Cancel"); + if (answer == JOptionPane.YES_OPTION) { + quitNow(); + } + } + + private void quitNow() { + savePreferences(); + System.exit(0); + } + + private final JToolBar toolBar = new JToolBar(); + + private void setupFrameIcons() { + final List<Image> icons = new LinkedList<>(); + icons.add(GraphicsTools.getBufferedImage(PNEConstantsConfiguration.ICON16)); + icons.add(GraphicsTools.getBufferedImage(PNEConstantsConfiguration.ICON32)); + icons.add(GraphicsTools.getBufferedImage(PNEConstantsConfiguration.ICON48)); + this.mainFrame.setIconImages(icons); + } + + private JMenu setupAndGetFileMenu() { + + final List<FileType> openSaveFiletypes = new LinkedList<>(); + openSaveFiletypes.add(new PflowFileType()); + + final List<FileType> importFiletypes = new LinkedList<>(); + importFiletypes.add(new ViptoolPnmlFileType()); + + final List<FileType> exportFiletypes = new LinkedList<>(); + exportFiletypes.add(new ViptoolPnmlFileType()); + exportFiletypes.add(new EpsFileType()); + exportFiletypes.add(new PngFileType()); + + final Action newFile = new NewFileAction(this); + final Action openFile = new OpenFileAction(this, openSaveFiletypes); + final Action saveFile = new SaveAction(this, openSaveFiletypes); + final Action saveFileAs = new SaveFileAsAction(this, openSaveFiletypes); + final Action importFile = new ImportAction(this, importFiletypes); + final Action exportFile = new ExportAction(this, exportFiletypes); + final Action quit = new QuitAction(this); + + this.toolBar.add(newFile); + this.toolBar.add(openFile); + this.toolBar.add(saveFile); + this.toolBar.add(importFile); + this.toolBar.add(exportFile); + this.toolBar.addSeparator(); + + final JMenu fileMenu = new JMenu("File"); + fileMenu.setMnemonic('F'); + + fileMenu.add(newFile); + fileMenu.add(openFile); + fileMenu.add(saveFile); + fileMenu.add(saveFileAs); + fileMenu.add(importFile); + fileMenu.add(exportFile); + fileMenu.addSeparator(); + fileMenu.add(quit); + + return fileMenu; + } + + private JMenu setupAndGetElementMenu() { + this.setLabel = new SetLabelAction(this); + this.setTokens = new SetTokensAction(this); + this.setArcMultiplicity = new SetArcMultiplicityAction(this); + this.setArcInhibitory = new SetArcInhibitoryAction(this); + this.setArcRegular = new SetArcRegularAction(this); + this.setArcReset = new SetArcResetAction(this); + + final JMenu elementMenu = new JMenu("PetriNet"); + elementMenu.setMnemonic('P'); + + elementMenu.add(this.setLabel); + elementMenu.addSeparator(); + elementMenu.add(this.setTokens); + elementMenu.addSeparator(); + elementMenu.add(this.setArcMultiplicity); + elementMenu.add(this.setArcInhibitory); + elementMenu.add(this.setArcReset); + elementMenu.add(this.setArcRegular); + + return elementMenu; + } + + private JMenu setupAndGetEditMenu() { + this.delete = new DeleteAction(this); + this.cutAction = new CutAction(this); + this.copyAction = new CopyAction(this); + this.pasteAction = new PasteAction(this); + this.selectAllAction = new SelectAllAction(this); + + this.toolBar.add(this.cutAction); + this.toolBar.add(this.copyAction); + this.toolBar.add(this.pasteAction); + this.toolBar.addSeparator(); + + this.toolBar.add(this.undo); + this.toolBar.add(this.redo); + this.toolBar.add(this.delete); + + final JMenu editMenu = new JMenu("Edit"); + editMenu.setMnemonic('E'); + + editMenu.add(this.undo); + editMenu.add(this.redo); + editMenu.addSeparator(); + editMenu.add(this.cutAction); + editMenu.add(this.copyAction); + editMenu.add(this.pasteAction); + editMenu.add(this.selectAllAction); + editMenu.add(this.delete); + + return editMenu; + } + + private JMenu setupAndGetDrawMenu() { + + final Action selectToolSelectionAction = new SelectionSelectToolAction(this); + final Action selectToolPlaceAction = new PlaceSelectToolAction(this); + final Action selectToolTransitionAction = new TransitionSelectToolAction(this); + final Action selectToolArcAction = new ArcSelectToolAction(this); + final Action selectToolTokenAction = new TokenSelectToolAction(this); + + this.select = new JToggleButton(selectToolSelectionAction); + this.select.setSelected(true); + this.place = new JToggleButton(selectToolPlaceAction); + this.transition = new JToggleButton(selectToolTransitionAction); + this.arc = new JToggleButton(selectToolArcAction); + this.token = new JToggleButton(selectToolTokenAction); + + this.select.setText(""); + this.place.setText(""); + this.transition.setText(""); + this.arc.setText(""); + this.token.setText(""); + + this.toolBar.addSeparator(); + this.toolBar.add(this.select); + this.toolBar.add(this.place); + this.toolBar.add(this.transition); + this.toolBar.add(this.arc); + this.toolBar.add(this.token); + this.toolBar.addSeparator(); + + final ButtonGroup drawGroup = new ButtonGroup(); + drawGroup.add(this.select); + drawGroup.add(this.place); + drawGroup.add(this.transition); + drawGroup.add(this.arc); + drawGroup.add(this.token); + + final JMenu drawMenu = new JMenu("Draw"); + drawMenu.setMnemonic('D'); + + drawMenu.add(selectToolSelectionAction); + drawMenu.addSeparator(); + drawMenu.add(selectToolPlaceAction); + drawMenu.add(selectToolTransitionAction); + drawMenu.add(selectToolArcAction); + drawMenu.add(selectToolTokenAction); + + return drawMenu; + + } + + private JMenu setupAndGetChangeMenu() { + final JMenu changeMenu = new JMenu("Change model"); + changeMenu.setMnemonic('C'); + String dirName = "src/org/pneditor/petrinet/adapters"; + final File folder = new File(dirName); + if (folder != null) { + for (final File modelPath : folder.listFiles()) { + Path path = modelPath.toPath(); + final String modelString = path.getName(path.getNameCount() - 1).toFile().getName(); + final JMenuItem modelItem = changeMenu.add(new ChangeModelAction(this,modelString)); + modelItem.setName(modelString); + if (modelString.equals(getCurrentModel())) { + modelItem.setEnabled(false); + } + this.modelsList.add(modelItem); + } + } + return changeMenu; + } + + private void setupMainFrame() { + this.toolBar.setFloatable(false); + + final JMenuBar menuBar = new JMenuBar(); + this.mainFrame.setJMenuBar(menuBar); + + // asus 2012 algorithms menu + final JMenu algorithmsMenu = new JMenu("Algorithms"); + algorithmsMenu.setMnemonic('A'); + + // asus 2012 algorithms submenu items + algorithmsMenu.add(new BoundednessAction(this)); + + final JMenu helpMenu = new JMenu("Help"); + helpMenu.add(new AboutAction(this)); + + menuBar.add(setupAndGetFileMenu()); + menuBar.add(setupAndGetEditMenu()); + menuBar.add(setupAndGetDrawMenu()); + menuBar.add(setupAndGetElementMenu()); + menuBar.add(algorithmsMenu); + menuBar.add(setupAndGetChangeMenu()); + menuBar.add(helpMenu); + + setupArcPopup(); + setupCanvasPopup(); + setupPlacePopup(); + setupTransitionPopup(); + + final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true); + splitPane.setDividerSize(6); + splitPane.setOneTouchExpandable(true); + splitPane.setRightComponent(this.drawingBoard); + splitPane.setDividerLocation(120); + + this.mainFrame.add(splitPane, BorderLayout.CENTER); + this.mainFrame.add(this.toolBar, BorderLayout.NORTH); + + this.mainFrame.addWindowListener(this); + this.mainFrame.setLocation(50, 50); + this.mainFrame.setSize(700, 450); + this.mainFrame.setVisible(true); + } + + private LocalClipboard clipboard = new LocalClipboard(); + + public LocalClipboard getClipboard() { + return this.clipboard; + } + + public void updateClipboard() { + final Set<GraphicElement> elementsCopied = this.clipboard.getContents(); + this.clipboard = new LocalClipboard(getCurrentModel()); + this.clipboard.setContents(elementsCopied); + } + + private boolean isModified; + + public boolean isModified() { + return this.isModified; + } + + public void setModified(final boolean isModified) { + this.isModified = isModified; + this.mainFrame.setTitle(getNewWindowTitle()); + } + + private String getNewWindowTitle() { + String windowTitle = ""; + if (getCurrentFile() != null) { + windowTitle += getCurrentFile().getName(); + } else { + windowTitle += "Untitled"; + } + if (isModified()) { + windowTitle += " [modified]"; + } + windowTitle += " - " + getAppShortName() + " - " + (this.model != null ? this.model : "initial"); // FIXME: why null at + // the start? + return windowTitle; + } + + private File currentFile; + + public File getCurrentFile() { + return this.currentFile; + } + + public void setCurrentFile(final File currentFile) { + this.currentFile = currentFile; + this.mainFrame.setTitle(getNewWindowTitle()); + } + + public String getAppShortName() { + return APP_NAME; + } + + public String getAppLongName() { + return APP_NAME + ", version " + APP_VERSION; + } + + public DrawingBoard getDrawingBoard() { + return this.drawingBoard; + } + + /** + * Scans all classloaders for the current thread for loaded jars, and then scans + * each jar for the package name in question, listing all classes directly under + * the package name in question. Assumes directory structure in jar file and class + * package naming follow java conventions (i.e. com.example.test.MyTest would be in + * /com/example/test/MyTest.class) + */ + public Collection<Class> getClassesForPackage(String packageName) throws Exception { + String packagePath = packageName.replace(".", "/"); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Set<URL> jarUrls = new HashSet<URL>(); + + while (classLoader != null) { + if (classLoader instanceof URLClassLoader) + for (URL url : ((URLClassLoader) classLoader).getURLs()) + if (url.getFile().endsWith(".jar")) // may want better way to detect jar files + jarUrls.add(url); + + classLoader = classLoader.getParent(); + } + + Set<Class> classes = new HashSet<Class>(); + + for (URL url : jarUrls) { + JarInputStream stream = new JarInputStream(url.openStream()); // may want better way to open url connections + JarEntry entry = stream.getNextJarEntry(); + + while (entry != null) { + String name = entry.getName(); + int i = name.lastIndexOf("/"); + + if (i > 0 && name.endsWith(".class") && name.substring(0, i).equals(packagePath)) + classes.add(Class.forName(name.substring(0, name.length() - 6).replace("/", "."))); + + entry = stream.getNextJarEntry(); + } + + stream.close(); + } + + return classes; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/UndoManager.java b/pne-editor/src/org/pneditor/editor/UndoManager.java new file mode 100644 index 0000000..d52f099 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/UndoManager.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.AbstractAction; + +import org.pneditor.editor.actions.edit.RedoAction; +import org.pneditor.editor.actions.edit.UndoAction; +import org.pneditor.util.Command; + +/** + * UndoManager provides the basic undo-redo capability. + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class UndoManager { + + private List<Command> executedCommands = new ArrayList<>(); + private int currentCommandIndex = -1; + private final Root root; + private final UndoAction undoAction; + private final RedoAction redoAction; + + /** + * Constructs a new UndoManager + * + * @param root Root object + * @param undoAction action for undo button + * @param redoAction action for redo button + */ + public UndoManager(final Root root, final UndoAction undoAction, final RedoAction redoAction) { + this.root = root; + this.undoAction = undoAction; + this.redoAction = redoAction; + } + + /** + * Execute command in UndoManager. + * + * @param command command to be executed + */ + public void executeCommand(final Command command) { + final List<Command> nonRedoedCommands = new ArrayList<>(this.executedCommands.subList(this.currentCommandIndex + 1, this.executedCommands.size())); + this.executedCommands.removeAll(nonRedoedCommands); + this.executedCommands.add(command); + this.currentCommandIndex = this.executedCommands.size() - 1; + command.execute(); + refresh(); + this.root.setModified(true); + } + + /** + * Performs the undo action. + */ + public void undoCommand() { + if (isUndoable()) { + final Command command = this.executedCommands.get(this.currentCommandIndex); + command.undo(); + this.currentCommandIndex--; + refresh(); + } + this.root.setModified(true); + } + + /** + * Performs the redo action. + */ + public void redoNextCommand() { + if (isRedoable()) { + final Command command = this.executedCommands.get(this.currentCommandIndex + 1); + command.redo(); + this.currentCommandIndex++; + refresh(); + } + this.root.setModified(true); + } + + /** + * Determines if undo is possible. + * + * @return true if undo action is possible otherwise false + */ + public boolean isUndoable() { + return this.currentCommandIndex != -1; + } + + /** + * Determines if redo is possible. + * + * @return true if redo action is possible otherwise false + */ + public boolean isRedoable() { + return this.currentCommandIndex < this.executedCommands.size() - 1; + } + + /** + * Erases all commands from the undo manager. + */ + public void eraseAll() { + this.executedCommands = new ArrayList<>(); + this.currentCommandIndex = -1; + refresh(); + } + + private void refresh() { + this.root.refreshAll(); + if (isUndoable()) { + this.undoAction.putValue(AbstractAction.SHORT_DESCRIPTION, "Undo: " + this.executedCommands.get(this.currentCommandIndex).toString()); + } else { + this.undoAction.putValue(AbstractAction.SHORT_DESCRIPTION, "Undo"); + } + if (isRedoable()) { + this.redoAction.putValue(AbstractAction.SHORT_DESCRIPTION, "Redo: " + this.executedCommands.get(this.currentCommandIndex + 1).toString()); + } else { + this.redoAction.putValue(AbstractAction.SHORT_DESCRIPTION, "Redo"); + } + } + +} diff --git a/pne-editor/src/org/pneditor/editor/actions/AboutAction.java b/pne-editor/src/org/pneditor/editor/actions/AboutAction.java new file mode 100644 index 0000000..48451c7 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/AboutAction.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions; + +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class AboutAction extends AbstractAction { + + private final Root root; + + public AboutAction(final Root root) { + super(); + this.root = root; + String name = "About..."; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.ABOUT16)); + putValue(SHORT_DESCRIPTION, name); + } + + @Override + public void actionPerformed(final ActionEvent e) { + JOptionPane.showOptionDialog( + this.root.getParentFrame(), + this.root.getAppLongName() + "\n" + + "http://www.pneditor.org/\n" + + "\n" + + "Author: Martin Riesz\n" + + "Contributors:\n" + + "Milka Knapereková (boundedness algorithm)\n" + + "Ján Tančibok (reset and inhibitor arc types)\n" + + "\n" + + "Contributions are welcome. Just send a pull request on GitHub." + + "\n" + + "This program is free software: you can redistribute it and/or modify\n" + + "it under the terms of the GNU General Public License as published by\n" + + "the Free Software Foundation, either version 3 of the License, or\n" + + "(at your option) any later version.\n" + + "\n" + + "This program is distributed in the hope that it will be useful,\n" + + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + + "GNU General Public License for more details.\n" + + "You should have received a copy of the GNU General Public License\n" + + "along with this program. If not, see <http://www.gnu.org/licenses/>.", + "About", + JOptionPane.DEFAULT_OPTION, + JOptionPane.INFORMATION_MESSAGE, + null, + new String[]{"OK"}, + "OK"); + } + +} diff --git a/pne-editor/src/org/pneditor/editor/actions/ChangeModelAction.java b/pne-editor/src/org/pneditor/editor/actions/ChangeModelAction.java new file mode 100644 index 0000000..a9198bd --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/ChangeModelAction.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions; + +import java.awt.event.ActionEvent; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.AbstractAction; + +import org.pneditor.editor.Root; +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.petrinet.AbstractPlace; +import org.pneditor.petrinet.AbstractTransition; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.petrinet.UnimplementedCaseException; + +import logger.PNEditorLogger; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class ChangeModelAction extends AbstractAction { + + private final Root root; + private final String model; + + private final static String MODEL_PATH = "org.pneditor.petrinet.adapters."; + private final static String ADAPTER_PATH = ".PetriNetAdapter"; + + public ChangeModelAction(final Root root, final String model) { + super(); + this.model = model; + this.root = root; + putValue(NAME, model); + putValue(SHORT_DESCRIPTION, "Change model to " + model); + putValue(MNEMONIC_KEY, (int) (model.charAt(0))); // set the mnemonic key to the first character of the model + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.setCurrentModel(this.model); + + final Map<AbstractNode,AbstractNode> matchingNodes = new HashMap<>(); + try { + final PetriNetInterface petriNet = (PetriNetInterface) Class.forName(MODEL_PATH + this.model + ADAPTER_PATH).newInstance(); + for (final GraphicElement element : this.root.getGraphicPetriNet().getElements()) { + + if (element.isPlace()) { + final GraphicPlace gPlace = (GraphicPlace) element; + final AbstractPlace oldPlace = gPlace.getPlace(); + final AbstractPlace place = petriNet.addAbstractPlace(oldPlace.getId()); + place.setTokens(oldPlace.getTokens()); + place.setLabel(oldPlace.getLabel()); + gPlace.setPlace(place); + + matchingNodes.put(oldPlace, place); + } + + if (element.isTransition()) { + final GraphicTransition gTransition = (GraphicTransition) element; + final AbstractTransition oldTransition = gTransition.getTransition(); + final AbstractTransition transition = petriNet.addAbstractTransition(oldTransition.getId()); + transition.setLabel(oldTransition.getLabel()); + gTransition.setTransition(transition); + + matchingNodes.put(oldTransition, transition); + } + } + + for (final GraphicElement element : this.root.getGraphicPetriNet().getElements()) { + + if (!element.isNode()) { + final GraphicArc gArc = (GraphicArc) element; + final AbstractArc oldArc = gArc.getArc(); + try { + AbstractArc arc; + final AbstractNode source = matchingNodes.get(oldArc.getSource()); + final AbstractNode destination = matchingNodes.get(oldArc.getDestination()); + + if (oldArc.isReset()) { + arc = petriNet.addResArc((AbstractPlace) source, + (AbstractTransition) destination); + } else { + if (oldArc.isInhibitory()) { + arc = petriNet.addInhibArc((AbstractPlace) source, + (AbstractTransition) destination); + } else { + arc = petriNet.addRegArc(source, destination); + } + arc.setMultiplicity(oldArc.getMultiplicity()); + } + gArc.setArc(arc); + } catch (UnimplementedCaseException | ResetArcMultiplicityException e1) { + // ResetArcMultiplicityException should not happen + + } + } + } + this.root.getGraphicPetriNet().setPetriNet(petriNet); + this.root.updateClipboard(); + + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e1) { + PNEditorLogger.severeLogs(e1.getMessage()); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/algorithms/BoundednessAction.java b/pne-editor/src/org/pneditor/editor/actions/algorithms/BoundednessAction.java new file mode 100644 index 0000000..a5612bf --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/algorithms/BoundednessAction.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 milka + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.algorithms; + +import java.awt.HeadlessException; +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.petrinet.ResetArcMultiplicityException; + +import logger.PNEditorLogger; + +/** + * + * @author milka + */ +@SuppressWarnings("serial") +public class BoundednessAction extends AbstractAction { + + private final Root root; + + public BoundednessAction(final Root root) { + super(); + this.root = root; + String name = "Boundedness"; + putValue(NAME, name); + putValue(SHORT_DESCRIPTION, name); + setEnabled(true); + } + + @Override + public void actionPerformed(final ActionEvent e) { + try { + if (this.root.getPetriNet().isBounded()) { + JOptionPane.showMessageDialog(this.root.getParentFrame(), "PetriNet is NOT bounded ", "Algorithm output", JOptionPane.INFORMATION_MESSAGE); + } else { + JOptionPane.showMessageDialog(this.root.getParentFrame(), "PetriNet is bounded", "Algorithm output", JOptionPane.INFORMATION_MESSAGE); + } + } catch (HeadlessException e1) { + PNEditorLogger.warningLogs(e1.getMessage()); + } catch (ResetArcMultiplicityException e2) { + PNEditorLogger.severeLogs(e2.getMessage()); + } + } + + + +} diff --git a/pne-editor/src/org/pneditor/editor/actions/draw/ArcSelectToolAction.java b/pne-editor/src/org/pneditor/editor/actions/draw/ArcSelectToolAction.java new file mode 100644 index 0000000..86c52fd --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/draw/ArcSelectToolAction.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.draw; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class ArcSelectToolAction extends AbstractAction { + + private final Root root; + + public ArcSelectToolAction(final Root root) { + super(); + this.root = root; + String name = "Arc"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.ARC)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_A); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.selectToolArc(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/draw/PlaceSelectToolAction.java b/pne-editor/src/org/pneditor/editor/actions/draw/PlaceSelectToolAction.java new file mode 100644 index 0000000..cac70e4 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/draw/PlaceSelectToolAction.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.draw; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class PlaceSelectToolAction extends AbstractAction { + + private final Root root; + + public PlaceSelectToolAction(final Root root) { + super(); + this.root = root; + String name = "Place"; + putValue(NAME, name); + putValue(SHORT_DESCRIPTION, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.PLACE16)); + putValue(SHORT_DESCRIPTION, "Place"); + putValue(MNEMONIC_KEY, KeyEvent.VK_P); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.selectToolPlace(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/draw/SelectionSelectToolAction.java b/pne-editor/src/org/pneditor/editor/actions/draw/SelectionSelectToolAction.java new file mode 100644 index 0000000..95aac29 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/draw/SelectionSelectToolAction.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.draw; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class SelectionSelectToolAction extends AbstractAction { + + private final Root root; + + public SelectionSelectToolAction(final Root root) { + super(); + this.root = root; + String name = "Select"; + putValue(NAME, name); + putValue(SHORT_DESCRIPTION, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.SELECT)); + putValue(SHORT_DESCRIPTION, "Select"); + putValue(MNEMONIC_KEY, KeyEvent.VK_S); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.selectToolSelect(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/draw/TokenSelectToolAction.java b/pne-editor/src/org/pneditor/editor/actions/draw/TokenSelectToolAction.java new file mode 100644 index 0000000..2e562cc --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/draw/TokenSelectToolAction.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.draw; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class TokenSelectToolAction extends AbstractAction { + + private final Root root; + + public TokenSelectToolAction(final Root root) { + super(); + this.root = root; + String name = "Fire transitions / Edit tokens"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.TOKEN_AND_FIRE16)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_F); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.selectToolToken(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/draw/TransitionSelectToolAction.java b/pne-editor/src/org/pneditor/editor/actions/draw/TransitionSelectToolAction.java new file mode 100644 index 0000000..37f7314 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/draw/TransitionSelectToolAction.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.draw; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class TransitionSelectToolAction extends AbstractAction { + + private final Root root; + + public TransitionSelectToolAction(final Root root) { + super(); + this.root = root; + String name = "Transition"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.TRANSITION16)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_T); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.selectToolTransition(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/edit/CopyAction.java b/pne-editor/src/org/pneditor/editor/actions/edit/CopyAction.java new file mode 100644 index 0000000..8b7ecf3 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/edit/CopyAction.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.edit; + +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class CopyAction extends AbstractAction { + + private final Root root; + + public CopyAction(final Root root) { + super(); + this.root = root; + String name = "Copy"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.COPY16)); + putValue(SHORT_DESCRIPTION, name); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl C")); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.getClipboard().setContents(this.root.getSelectedElementsWithClickedElement()); + this.root.refreshAll(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/edit/CutAction.java b/pne-editor/src/org/pneditor/editor/actions/edit/CutAction.java new file mode 100644 index 0000000..ddaf1e0 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/edit/CutAction.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.edit; + +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.CutCommand; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class CutAction extends AbstractAction { + + private final Root root; + + public CutAction(final Root root) { + super(); + this.root = root; + String name = "Cut"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.CUT16)); + putValue(SHORT_DESCRIPTION, name); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl X")); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.getClipboard().setContents(this.root.getSelectedElementsWithClickedElement()); + this.root.getUndoManager().executeCommand(new CutCommand(this.root.getSelectedElementsWithClickedElement(),this.root.getGraphicPetriNet())); + this.root.getSelection().clear(); + this.root.setClickedElement(null); + this.root.refreshAll(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/edit/DeleteAction.java b/pne-editor/src/org/pneditor/editor/actions/edit/DeleteAction.java new file mode 100644 index 0000000..0d971a1 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/edit/DeleteAction.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.edit; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.util.Set; +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.DeleteElementsCommand; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class DeleteAction extends AbstractAction { + + private final Root root; + + public DeleteAction(final Root root) { + super(); + this.root = root; + String name = "Delete"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.DELETE16)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_D); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("DELETE")); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + final Set<GraphicElement> elements= this.root.getSelectedElementsWithClickedElement(); + + if (!elements.isEmpty()) { + this.root.getUndoManager().executeCommand(new DeleteElementsCommand(elements, this.root.getGraphicPetriNet())); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/edit/PasteAction.java b/pne-editor/src/org/pneditor/editor/actions/edit/PasteAction.java new file mode 100644 index 0000000..711daaf --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/edit/PasteAction.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.edit; + +import java.awt.event.ActionEvent; +import java.util.Set; +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.PasteCommand; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class PasteAction extends AbstractAction { + + private final Root root; + + public PasteAction(final Root root) { + super(); + this.root = root; + String name = "Paste"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.PASTE16)); + putValue(SHORT_DESCRIPTION, name); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl V")); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + final GraphicPetriNet gPetriNet = this.root.getGraphicPetriNet(); + final Set<GraphicElement> copiedElements = this.root.getClipboard().getContents(); + this.root.setClickedElement(null); + this.root.getSelection().clear(); + this.root.getUndoManager().executeCommand(new PasteCommand(copiedElements, gPetriNet, this.root)); + //TODO: getViewTranslation() + this.root.refreshAll(); + } + +} diff --git a/pne-editor/src/org/pneditor/editor/actions/edit/RedoAction.java b/pne-editor/src/org/pneditor/editor/actions/edit/RedoAction.java new file mode 100644 index 0000000..7869df9 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/edit/RedoAction.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.edit; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class RedoAction extends AbstractAction { + + private final Root root; + + public RedoAction(final Root root) { + super(); + this.root = root; + String name = "Redo"; + putValue(NAME, name); + putValue(SHORT_DESCRIPTION, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.REDO16)); + putValue(MNEMONIC_KEY, KeyEvent.VK_R); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl Y")); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.getUndoManager().redoNextCommand(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/edit/SelectAllAction.java b/pne-editor/src/org/pneditor/editor/actions/edit/SelectAllAction.java new file mode 100644 index 0000000..18599d4 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/edit/SelectAllAction.java @@ -0,0 +1,42 @@ +package org.pneditor.editor.actions.edit; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; + +import org.pneditor.editor.Root; +import org.pneditor.editor.canvas.Selection; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; + +/** + * + * @author matmas + */ +@SuppressWarnings("serial") +public class SelectAllAction extends AbstractAction { + + private final Root root; + + public SelectAllAction(final Root root) { + super(); + this.root = root; + String name = "Select All"; + putValue(NAME, name); + putValue(SHORT_DESCRIPTION, name); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl A")); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + final GraphicPetriNet petriNet = this.root.getGraphicPetriNet(); + + final Selection selection = this.root.getSelection(); + selection.clear(); + selection.addAll(petriNet.getElements()); + + this.root.refreshAll(); + } + +} diff --git a/pne-editor/src/org/pneditor/editor/actions/edit/UndoAction.java b/pne-editor/src/org/pneditor/editor/actions/edit/UndoAction.java new file mode 100644 index 0000000..44522bc --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/edit/UndoAction.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.edit; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.io.File; + +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class UndoAction extends AbstractAction { + + private final Root root; + + public UndoAction(final Root root) { + super(); + this.root = root; + String name = "Undo"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.UNDO16)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_U); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl Z")); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.getUndoManager().undoCommand(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/element/SetArcInhibitoryAction.java b/pne-editor/src/org/pneditor/editor/actions/element/SetArcInhibitoryAction.java new file mode 100644 index 0000000..2d0219d --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/element/SetArcInhibitoryAction.java @@ -0,0 +1,46 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.pneditor.editor.actions.element; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractAction; + +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.SetArcInhibitCommand; +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Amodez + */ +@SuppressWarnings("serial") +public class SetArcInhibitoryAction extends AbstractAction { + + private final Root root; + + public SetArcInhibitoryAction(final Root root) { + super(); + this.root = root; + String name = "Set inhibitor arc type"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.CONVERTTRANSITIONTOSUBNET)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_I); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (this.root.getClickedElement() != null && !this.root.getClickedElement().isNode()) { + final GraphicArc arc = (GraphicArc) this.root.getClickedElement(); + this.root.getUndoManager().executeCommand(new SetArcInhibitCommand(arc, this.root.getGraphicPetriNet())); + } + + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/element/SetArcMultiplicityAction.java b/pne-editor/src/org/pneditor/editor/actions/element/SetArcMultiplicityAction.java new file mode 100644 index 0000000..7ca39c6 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/element/SetArcMultiplicityAction.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.element; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.DeleteArcCommand; +import org.pneditor.editor.commands.SetArcMultiplicityCommand; +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +import logger.PNEditorLogger; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class SetArcMultiplicityAction extends AbstractAction { + + private final Root root; + + public SetArcMultiplicityAction(final Root root) { + super(); + this.root = root; + String name = "Set arc multiplicity"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.MULTIPLICITY)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_M); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (this.root.getClickedElement() != null && !this.root.getClickedElement().isNode()) { + final GraphicArc arc = (GraphicArc) this.root.getClickedElement(); + int multiplicity = 0; // TODO !! + try { + multiplicity = arc.getArc().getMultiplicity(); + } catch (ResetArcMultiplicityException e1) { + PNEditorLogger.severeLogs(e1.getMessage()); + } + final String response = JOptionPane.showInputDialog(this.root.getParentFrame(), "Multiplicity:", + multiplicity); + if (response != null) { + try { + multiplicity = Integer.parseInt(response); + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(this.root.getParentFrame(), ex.getMessage() + " is not a number"); + } + } + + try { + if (arc.getArc().getMultiplicity() != multiplicity) { + if (multiplicity < 1) { + this.root.getUndoManager() + .executeCommand(new DeleteArcCommand(arc, this.root.getGraphicPetriNet())); + } else { + this.root.getUndoManager().executeCommand(new SetArcMultiplicityCommand(arc, multiplicity)); + } + } + } catch (ResetArcMultiplicityException e1) { + PNEditorLogger.severeLogs(e1.getMessage()); + } + + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/element/SetArcRegularAction.java b/pne-editor/src/org/pneditor/editor/actions/element/SetArcRegularAction.java new file mode 100644 index 0000000..1ca33fa --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/element/SetArcRegularAction.java @@ -0,0 +1,46 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.pneditor.editor.actions.element; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractAction; + +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.SetArcRegularCommand; +import org.pneditor.editor.gpetrinet.GraphicArc; +//import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author jan.tancibok + */ +@SuppressWarnings("serial") +public class SetArcRegularAction extends AbstractAction { + + private final Root root; + + public SetArcRegularAction(final Root root) { + super(); + this.root = root; + String name = "Set regular arc type"; + putValue(NAME, name); + // putValue(SMALL_ICON, + // GraphicsTools.getIcon(PNEConstantsConfiguration.SETARCRESETACTION)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_R); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (this.root.getClickedElement() != null && !this.root.getClickedElement().isNode()) { + final GraphicArc arc = (GraphicArc) this.root.getClickedElement(); + this.root.getUndoManager().executeCommand(new SetArcRegularCommand(arc, this.root.getGraphicPetriNet())); + } + + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/element/SetArcResetAction.java b/pne-editor/src/org/pneditor/editor/actions/element/SetArcResetAction.java new file mode 100644 index 0000000..9652e2b --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/element/SetArcResetAction.java @@ -0,0 +1,46 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.pneditor.editor.actions.element; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractAction; + +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.SetArcResetCommand; +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author jan.tancibok + */ +@SuppressWarnings("serial") +public class SetArcResetAction extends AbstractAction { + + private final Root root; + + public SetArcResetAction(final Root root) { + super(); + this.root = root; + String name = "Set reset arc type"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.SETARCRESETACTION)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_R); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (this.root.getClickedElement() != null && !this.root.getClickedElement().isNode()) { + final GraphicArc arc = (GraphicArc) this.root.getClickedElement(); + this.root.getUndoManager().executeCommand(new SetArcResetCommand(arc, this.root.getGraphicPetriNet())); + + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/element/SetLabelAction.java b/pne-editor/src/org/pneditor/editor/actions/element/SetLabelAction.java new file mode 100644 index 0000000..bb267e9 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/element/SetLabelAction.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.element; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.SetLabelCommand; +import org.pneditor.editor.gpetrinet.GraphicNode; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class SetLabelAction extends AbstractAction { + + private final Root root; + + public SetLabelAction(final Root root) { + super(); + this.root = root; + String name = "Set label"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.LABEL)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_L); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (this.root.getClickedElement() != null + && this.root.getClickedElement().isNode()) { + final GraphicNode clickedNode = (GraphicNode) this.root.getClickedElement(); + final String newLabel = JOptionPane.showInputDialog(this.root.getParentFrame(), "New label:", clickedNode.getNode().getLabel()); + + if (newLabel != null && !newLabel.equals(clickedNode.getNode().getLabel())) { + this.root.getUndoManager().executeCommand(new SetLabelCommand(clickedNode, newLabel)); + } + + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/element/SetTokensAction.java b/pne-editor/src/org/pneditor/editor/actions/element/SetTokensAction.java new file mode 100644 index 0000000..37b88f7 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/element/SetTokensAction.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.element; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; + +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.SetTokensCommand; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class SetTokensAction extends AbstractAction { + + private final Root root; + + public SetTokensAction(final Root root) { + super(); + this.root = root; + String name = "Set tokens"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.TOKENS)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_T); + setEnabled(false); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (this.root.getClickedElement() != null && this.root.getClickedElement().isPlace()) { + final GraphicPlace place = (GraphicPlace) this.root.getClickedElement(); + int tokens = place.getPlace().getTokens(); + + final String response = JOptionPane.showInputDialog(this.root.getParentFrame(), "Tokens:", tokens); + if (response != null) { + try { + tokens = Integer.parseInt(response); + } catch (NumberFormatException exception) { + JOptionPane.showMessageDialog(this.root.getParentFrame(), + exception.getMessage() + " is not a number"); + } + + if (tokens < 0) { + tokens = place.getPlace().getTokens(); // restore old value + JOptionPane.showMessageDialog(this.root.getParentFrame(), "Number of tokens must be non-negative"); + // TODO : check with model? + } + } + + if (place.getPlace().getTokens() != tokens) { + this.root.getUndoManager().executeCommand(new SetTokensCommand(place, tokens)); + } + + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/file/ExportAction.java b/pne-editor/src/org/pneditor/editor/actions/file/ExportAction.java new file mode 100644 index 0000000..22f3775 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/file/ExportAction.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.file; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.editor.filechooser.FileChooserDialog; +import org.pneditor.editor.filechooser.FileType; +import org.pneditor.editor.filechooser.FileTypeException; +import org.pneditor.util.GraphicsTools; +import org.pneditor.util.StringTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class ExportAction extends AbstractAction { + + private final Root root; + private final List<FileType> fileTypes; + + public ExportAction(final Root root, final List<FileType> fileTypes) { + super(); + this.root = root; + this.fileTypes = fileTypes; + String name = "Export..."; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.EXPORT)); + putValue(SHORT_DESCRIPTION, name); + } + + @Override + public void actionPerformed(final ActionEvent e) { + final FileChooserDialog chooser = new FileChooserDialog(); + + if (this.root.getCurrentFile() != null) { + chooser.setSelectedFile(new File(StringTools.getExtensionCutOut(this.root.getCurrentFile().getName()))); + } + + for (final FileType fileType : this.fileTypes) { + chooser.addChoosableFileFilter(fileType); + } + chooser.setAcceptAllFileFilterUsed(false); + chooser.setCurrentDirectory(this.root.getCurrentDirectory()); + + if (chooser.showDialog(this.root.getParentFrame(), "Export") == JFileChooser.APPROVE_OPTION) { + final File file = chooser.getSelectedFile(); + final FileType chosenFileType = (FileType) chooser.getFileFilter(); + + if (!file.exists() || JOptionPane.showOptionDialog( + this.root.getParentFrame(), + "Selected file already exists. Overwrite?", + "Export to " + file.getName(), + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + new String[]{"Overwrite", "Cancel"}, + "Cancel") == JOptionPane.YES_OPTION) { + try { + chosenFileType.save(this.root.getGraphicPetriNet(), file); + } catch (FileTypeException ex) { + JOptionPane.showMessageDialog(this.root.getParentFrame(), ex.getMessage()); + } + } + this.root.setCurrentDirectory(chooser.getCurrentDirectory()); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/file/ImportAction.java b/pne-editor/src/org/pneditor/editor/actions/file/ImportAction.java new file mode 100644 index 0000000..57e5088 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/file/ImportAction.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.file; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.editor.filechooser.FileChooserDialog; +import org.pneditor.editor.filechooser.FileType; +import org.pneditor.editor.filechooser.FileTypeException; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class ImportAction extends AbstractAction { + + private final Root root; + private final List<FileType> fileTypes; + + public ImportAction(final Root root, final List<FileType> fileTypes) { + super(); + this.root = root; + this.fileTypes = fileTypes; + String name = "Import..."; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.IMPORT)); + putValue(SHORT_DESCRIPTION, name); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (!this.root.isModified() || JOptionPane.showOptionDialog( + this.root.getParentFrame(), + "Any unsaved changes will be lost. Continue?", + "Import...", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + new String[]{"Import...", "Cancel"}, + "Cancel") == JOptionPane.YES_OPTION) { + final FileChooserDialog chooser = new FileChooserDialog(); + + for (final FileType fileType : this.fileTypes) { + chooser.addChoosableFileFilter(fileType); + } + chooser.setAcceptAllFileFilterUsed(false); + chooser.setCurrentDirectory(this.root.getCurrentDirectory()); + + if (chooser.showDialog(this.root.getParentFrame(), "Import") == JFileChooser.APPROVE_OPTION) { + final File file = chooser.getSelectedFile(); + final FileType chosenFileType = (FileType) chooser.getFileFilter(); + try { + final GraphicPetriNet petriNet = chosenFileType.load(file, this.root.getCurrentModel()); + this.root.setGraphicPetriNet(petriNet); + } catch (FileTypeException ex) { + JOptionPane.showMessageDialog(this.root.getParentFrame(), ex.getMessage()); + } + this.root.setCurrentFile(null); + this.root.setCurrentDirectory(chooser.getCurrentDirectory()); + } + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/file/NewFileAction.java b/pne-editor/src/org/pneditor/editor/actions/file/NewFileAction.java new file mode 100644 index 0000000..0f01efb --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/file/NewFileAction.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.file; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class NewFileAction extends AbstractAction { + + private final Root root; + + public NewFileAction(final Root root) { + super(); + this.root = root; + String name = "New"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.NEW16)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_N); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (!this.root.isModified() || JOptionPane.showOptionDialog( + this.root.getParentFrame(), + "Any unsaved changes will be lost. Continue?", + "New file", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + new String[]{"New file", "Cancel"}, + "Cancel") == JOptionPane.YES_OPTION) { + this.root.setGraphicPetriNet(new GraphicPetriNet(this.root.getCurrentModel())); + this.root.setClickedElement(null); + this.root.refreshAll(); + this.root.getUndoManager().eraseAll(); + this.root.setCurrentFile(null); + this.root.setModified(false); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/file/OpenFileAction.java b/pne-editor/src/org/pneditor/editor/actions/file/OpenFileAction.java new file mode 100644 index 0000000..993fd63 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/file/OpenFileAction.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.file; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.io.File; +import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.editor.filechooser.FileChooserDialog; +import org.pneditor.editor.filechooser.FileType; +import org.pneditor.editor.filechooser.FileTypeException; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class OpenFileAction extends AbstractAction { + + private final Root root; + private final List<FileType> fileTypes; + + public OpenFileAction(final Root root, final List<FileType> fileTypes) { + super(); + this.root = root; + this.fileTypes = fileTypes; + String name = "Open..."; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.OPEN16)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_O); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (!this.root.isModified() || JOptionPane.showOptionDialog( + this.root.getParentFrame(), + "Any unsaved changes will be lost. Continue?", + "Open file...", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + new String[]{"Open...", "Cancel"}, + "Cancel") == JOptionPane.YES_OPTION) { + final FileChooserDialog chooser = new FileChooserDialog(); + + for (final FileType fileType : this.fileTypes) { + chooser.addChoosableFileFilter(fileType); + } + chooser.setAcceptAllFileFilterUsed(false); + chooser.setCurrentDirectory(this.root.getCurrentDirectory()); + + if (chooser.showOpenDialog(this.root.getParentFrame()) == JFileChooser.APPROVE_OPTION) { + + final File file = chooser.getSelectedFile(); + final FileType chosenFileType = (FileType) chooser.getFileFilter(); + + try { + final GraphicPetriNet petriNet = chosenFileType.load(file, this.root.getCurrentModel()); + this.root.setGraphicPetriNet(petriNet); + this.root.setCurrentFile(file); + this.root.setModified(false); + } catch (FileTypeException ex) { + JOptionPane.showMessageDialog(this.root.getParentFrame(), ex.getMessage()); + } + + } + this.root.setCurrentDirectory(chooser.getCurrentDirectory()); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/file/QuitAction.java b/pne-editor/src/org/pneditor/editor/actions/file/QuitAction.java new file mode 100644 index 0000000..f8b3e55 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/file/QuitAction.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.file; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; +import org.pneditor.editor.Root; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class QuitAction extends AbstractAction { + + private final Root root; + + public QuitAction(final Root root) { + super(); + this.root = root; + String name = "Quit"; + putValue(NAME, name); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_Q); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl Q")); + } + + @Override + public void actionPerformed(final ActionEvent e) { + this.root.quitApplication(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/actions/file/SaveAction.java b/pne-editor/src/org/pneditor/editor/actions/file/SaveAction.java new file mode 100644 index 0000000..cb13cc2 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/file/SaveAction.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.file; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.io.File; +import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.JOptionPane; +import javax.swing.KeyStroke; +import org.pneditor.editor.Root; +import org.pneditor.editor.filechooser.FileType; +import org.pneditor.editor.filechooser.FileTypeException; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class SaveAction extends AbstractAction { + + private final Root root; + private final List<FileType> fileTypes; + + public SaveAction(final Root root, final List<FileType> fileTypes) { + super(); + this.root = root; + this.fileTypes = fileTypes; + String name = "Save"; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.SAVE16)); + putValue(SHORT_DESCRIPTION, name); + putValue(MNEMONIC_KEY, KeyEvent.VK_S); + putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl S")); + } + + @Override + public void actionPerformed(final ActionEvent e) { + final File file = this.root.getCurrentFile(); + if (file != null) { + try { + final FileType fileType = FileType.getAcceptingFileType(file, this.fileTypes); + fileType.save(this.root.getGraphicPetriNet(), file); + this.root.setModified(false); + } catch (FileTypeException ex) { + JOptionPane.showMessageDialog(this.root.getParentFrame(), ex.getMessage()); + } + } else { + new SaveFileAsAction(this.root, this.fileTypes).actionPerformed(e); + } + + } + +} diff --git a/pne-editor/src/org/pneditor/editor/actions/file/SaveFileAsAction.java b/pne-editor/src/org/pneditor/editor/actions/file/SaveFileAsAction.java new file mode 100644 index 0000000..fb29deb --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/actions/file/SaveFileAsAction.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.actions.file; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import org.pneditor.editor.Root; +import org.pneditor.util.GraphicsTools; +import org.pneditor.editor.filechooser.FileChooserDialog; +import org.pneditor.editor.filechooser.FileType; +import org.pneditor.editor.filechooser.FileTypeException; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class SaveFileAsAction extends AbstractAction { + + private final Root root; + private final List<FileType> fileTypes; + + public SaveFileAsAction(final Root root, final List<FileType> fileTypes) { + super(); + this.root = root; + this.fileTypes = fileTypes; + String name = "Save as..."; + putValue(NAME, name); + putValue(SMALL_ICON, GraphicsTools.getIcon(PNEConstantsConfiguration.SAVEAS16)); + putValue(SHORT_DESCRIPTION, name); + } + + @Override + public void actionPerformed(final ActionEvent e) { + final FileChooserDialog chooser = new FileChooserDialog(); + + if (this.root.getCurrentFile() != null) { + chooser.setSelectedFile(this.root.getCurrentFile()); + } + + for (final FileType fileType : this.fileTypes) { + chooser.addChoosableFileFilter(fileType); + } + chooser.setAcceptAllFileFilterUsed(false); + chooser.setCurrentDirectory(this.root.getCurrentDirectory()); + chooser.setDialogTitle("Save as..."); + + if (chooser.showSaveDialog(this.root.getParentFrame()) == JFileChooser.APPROVE_OPTION) { + final File file = chooser.getSelectedFile(); + final FileType chosenFileType = (FileType) chooser.getFileFilter(); + + if (!file.exists() || JOptionPane.showOptionDialog( + this.root.getParentFrame(), + "Selected file already exists. Overwrite?", + "Save as " + file.getName(), + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + new String[]{"Overwrite", "Cancel"}, + "Cancel") == JOptionPane.YES_OPTION) { + try { + chosenFileType.save(this.root.getGraphicPetriNet(), file); + } catch (FileTypeException ex) { + JOptionPane.showMessageDialog(this.root.getParentFrame(), ex.getMessage()); + } + } + this.root.setCurrentFile(file); + this.root.setModified(false); + } + this.root.setCurrentDirectory(chooser.getCurrentDirectory()); + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/ArcFeature.java b/pne-editor/src/org/pneditor/editor/canvas/ArcFeature.java new file mode 100644 index 0000000..e72f6b4 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/ArcFeature.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Graphics; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; + +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.AddArcCommand; +import org.pneditor.editor.gpetrinet.*; +import org.pneditor.util.Colors; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +class ArcFeature implements Feature { + + private final Canvas canvas; + private final Root root; + + private GraphicNode sourceElement; + private PreviewArc connectingArc; + private final List<GraphicElement> backgroundElements = new ArrayList<>(); + private boolean started; + private GraphicPetriNet graphicPetriNet; + + ArcFeature(final Canvas canvas) { + this.canvas = canvas; + this.root = canvas.getRoot(); + } + + @Override + public void mousePressed(final MouseEvent event) { + final int mouseButton = event.getButton(); + + if (mouseButton == MouseEvent.BUTTON1 && this.root.isSelectedToolArc() && this.root.getClickedElement() != null + && this.root.getClickedElement().isNode() && !this.started) { + + final int x = event.getX(); + final int y = event.getY(); + + this.graphicPetriNet = this.root.getGraphicPetriNet(); + this.sourceElement = (GraphicNode) this.graphicPetriNet.getElementByXY(x, y); + this.connectingArc = new PreviewArc(this.sourceElement); + this.backgroundElements.add(this.connectingArc); + this.started = true; + } + } + + @Override + public void mouseDragged(final int x, final int y) { + if (this.root.getGraphicPetriNet() != this.graphicPetriNet) { + cancelDragging(); + } + if (this.started) { + final GraphicElement element = this.root.getGraphicPetriNet().getElementByXY(x, y); + final GraphicNode targetElement = element != null && element.isNode() ? (GraphicNode) element : null; + + if (targetElement != null && (this.sourceElement.isPlace() && !targetElement.isPlace() + || !this.sourceElement.isPlace() && targetElement.isPlace())) { + this.connectingArc.setEnd(targetElement.getCenter().x, targetElement.getCenter().y); + this.connectingArc.setDestination(targetElement); + } else { + this.connectingArc.setEnd(x, y); + this.connectingArc.setSource(null); + this.connectingArc.setDestination(null); + } + this.root.repaintCanvas(); + } + } + + @Override + public void mouseMoved(final int x, final int y) { + mouseDragged(x, y); + } + + @Override + public void mouseReleased(final int x, final int y) { + if (this.root.getGraphicPetriNet() != this.graphicPetriNet) { + cancelDragging(); + } + + if (this.started) { + final GraphicElement element = this.root.getGraphicPetriNet().getElementByXY(x, y); + this.connectingArc.setEnd(x, y); + final GraphicNode targetElement = element != null && element.isNode() ? (GraphicNode) element : null; + + if (this.sourceElement != targetElement) { + if (targetElement != null) { + if (this.sourceElement.isPlace() && !targetElement.isPlace() + || !this.sourceElement.isPlace() && targetElement.isPlace()) { + + this.root.getUndoManager().executeCommand( + new AddArcCommand(this.root.getGraphicPetriNet(), this.sourceElement, targetElement)); + + // last element added to GraphicPetriNet is the arc + this.root.setClickedElement(this.root.getGraphicPetriNet().getLastArcAdded()); + + } + } + cancelDragging(); + } + } + } + + @Override + public void setHoverEffects(final int x, final int y) { + if (this.root.isSelectedToolArc()) { + final GraphicElement targetElement = this.root.getGraphicPetriNet().getElementByXY(x, y); + final List<GraphicElement> highlightedElements = canvas.getHighlightedElements(); + if (this.started) { // Connecting to something... + if (targetElement == null) { // Connecting to air + highlightedElements.add(this.sourceElement); + this.sourceElement.setHighlightColor(Colors.POINTING); + this.root.repaintCanvas(); + } else { // Connecting to solid element + if (this.sourceElement.isPlace() && targetElement.isTransition() + || this.sourceElement.isTransition() && targetElement.isPlace()) { + highlightedElements.add(this.sourceElement); + highlightedElements.add(targetElement); + this.sourceElement.setHighlightColor(Colors.CONNECTING); + targetElement.setHighlightColor(Colors.CONNECTING); + this.root.repaintCanvas(); + } else if (this.sourceElement == targetElement) { + highlightedElements.add(this.sourceElement); + this.sourceElement.setHighlightColor(Colors.POINTING); + this.root.repaintCanvas(); + } else if (targetElement.isNode()) { // Wrong combination + highlightedElements.add(this.sourceElement); + highlightedElements.add(targetElement); + this.sourceElement.setHighlightColor(Colors.DISALLOWED); + targetElement.setHighlightColor(Colors.DISALLOWED); + this.root.repaintCanvas(); + } + } + } else { + if (targetElement != null) { + highlightedElements.add(targetElement); + targetElement.setHighlightColor(Colors.POINTING); + this.root.repaintCanvas(); + } + } + } + } + + @Override + public void drawBackground(final Graphics g) { + for (final GraphicElement element : this.backgroundElements) { + element.draw(g, this.root.getPetriNet()); + } + } + + @Override + public void drawForeground(final Graphics g) { + } + + @Override + public void setCursor(final int x, final int y) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + private void cancelDragging() { + this.backgroundElements.remove(this.connectingArc); + this.started = false; + this.root.repaintCanvas(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/Canvas.java b/pne-editor/src/org/pneditor/editor/canvas/Canvas.java new file mode 100644 index 0000000..c85797b --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/Canvas.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Graphics2D; +import java.awt.RenderingHints; + +import java.awt.event.*; +import java.util.ArrayList; +import java.util.List; +import javax.swing.*; +import org.pneditor.editor.Root; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.util.Point; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class Canvas extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener { + + private final List<GraphicElement> highlightedElements = new ArrayList<>(); + private Cursor alternativeCursor; + public Cursor activeCursor; + public List<Feature> features = new ArrayList<>(); + private final Root root; + private final ScrollingFeature scrollingFeature; + private boolean scrollingFeatureInstalled; + + public Canvas(final Root root) { + super(); + this.root = root; + setBackground(Color.white); + addMouseListener(this); + addMouseMotionListener(this); + addMouseWheelListener(this); + + this.features.add(new ClickFeature(this)); + this.features.add(new PanningFeature(this)); + this.scrollingFeature = new ScrollingFeature(this); + this.features.add(this.scrollingFeature); + this.features.add(new DraggingFeature(this)); + this.features.add(new SelectionDrawingFeature(this)); + this.features.add(new TokenFeature(this)); + this.features.add(new EdgeZigzagFeature(this)); + this.features.add(new PlaceTransitionMakerFeature(this)); + this.features.add(new PopupMenuFeature(this)); + this.features.add(new ArcFeature(this)); + this.features.add(new PetriNetFeature(this)); + } + + public Root getRoot() { + return this.root; + } + + public int getTranslationX() { + return this.root.getGraphicPetriNet().getViewTranslation().x + getWidth() / 2; + } + + public int getTranslationY() { + return this.root.getGraphicPetriNet().getViewTranslation().y + getHeight() / 2; + } + + public Point getViewTranslation() { + return new Point(this.root.getGraphicPetriNet().getViewTranslation()); + } + + public void setViewTranslation(final Point newViewTranslation) { + this.root.getGraphicPetriNet().setViewTranslation(newViewTranslation.getPoint()); + } + + @Override + public void paintComponent(final Graphics g) { + if (!this.scrollingFeatureInstalled) { + this.root.getDrawingBoard().getHorizontalScrollBar().addAdjustmentListener(this.scrollingFeature); + this.root.getDrawingBoard().getVerticalScrollBar().addAdjustmentListener(this.scrollingFeature); + this.scrollingFeatureInstalled = true; + } + + final Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + super.paintComponent(g); + g.translate(getTranslationX(), getTranslationY()); + + for (final Feature f : this.features) { + f.drawBackground(g); + } + for (final Feature f : this.features) { + f.drawMainLayer(g); + } + for (final Feature f : this.features) { + f.drawForeground(g); + } + } + + @Override + public void mouseWheelMoved(final MouseWheelEvent e) { + if (e.getWheelRotation() == 1) { + if (this.root.isSelectedToolPlace()) { + this.root.selectToolTransition(); + } else if (this.root.isSelectedToolTransition()) { + this.root.selectToolArc(); + } else if (this.root.isSelectedToolArc()) { + this.root.selectToolToken(); + } else { + this.root.selectToolPlace(); // if selectToolToken is selected, or default case + } + } else if (e.getWheelRotation() == -1) { + if (this.root.isSelectedToolTransition()) { + this.root.selectToolPlace(); + } else if (this.root.isSelectedToolArc()) { + this.root.selectToolTransition(); + } else if (this.root.isSelectedToolToken()) { + this.root.selectToolArc(); + } else { + this.root.selectToolToken(); // if selectToolPlace is selected or default case + } + } + repaint(); + setHoverEffects(e.getX(), e.getY()); + } + + @Override + public void mousePressed(final MouseEvent event) { + final int x = event.getX() - getTranslationX(); + final int y = event.getY() - getTranslationY(); + final MouseEvent mouseEvent = new MouseEvent((Component) event.getSource(), event.getID(), event.getWhen(), + event.getModifiers(), x, y, event.getXOnScreen(), event.getYOnScreen(), event.getClickCount(), + event.isPopupTrigger(), event.getButton()); + + this.root.setClickedElement(this.root.getGraphicPetriNet().getElementByXY(x, y)); + + for (final Feature f : this.features) { + f.mousePressed(mouseEvent); + } + + if (mouseEvent.getButton() == MouseEvent.BUTTON3 && this.root.getClickedElement() == null) { + // The user did not click on a shape. + this.root.selectToolSelect(); + } + + setCursor(x, y); + setHoverEffects(x, y); + } + + @Override + public void mouseDragged(final MouseEvent event) { + final int x = event.getX() - getTranslationX(); + final int y = event.getY() - getTranslationY(); + + for (final Feature f : this.features) { + f.mouseDragged(x, y); + } + + setHoverEffects(x, y); + } + + @Override + public void mouseReleased(final MouseEvent evt) { + final int x = evt.getX() - getTranslationX(); + final int y = evt.getY() - getTranslationY(); + + for (final Feature f : this.features) { + f.mouseReleased(x, y); + } + + setHoverEffects(x, y); + setCursor(x, y); + } + + @Override + public void mouseMoved(final MouseEvent evt) { + final int x = evt.getX() - getTranslationX(); + final int y = evt.getY() - getTranslationY(); + + for (final Feature f : this.features) { + f.mouseMoved(x, y); + } + + setHoverEffects(x, y); + setCursor(x, y); + } + + void setHoverEffects(final int x, final int y) { + if (!this.highlightedElements.isEmpty()) { + for (final GraphicElement element : this.highlightedElements) { + element.setHighlightColor(null); + } + this.highlightedElements.clear(); + repaint(); + } + for (final Feature f : this.features) { + f.setHoverEffects(x, y); + } + } + + void setCursor(final int x, final int y) { + this.alternativeCursor = null; + + for (final Feature f : this.features) { + f.setCursor(x, y); + } + + Cursor cursor; + if (this.alternativeCursor != null) { + cursor = this.alternativeCursor; + } else { + cursor = this.activeCursor; + } + + if (getCursor() != cursor) { + setCursor(cursor); + } + } + + @Override + public void mouseEntered(final MouseEvent evt) { + } + + @Override + public void mouseExited(final MouseEvent evt) { + } + + @Override + public void mouseClicked(final MouseEvent evt) { + } + + Cursor getAlternativeCursor() { + return alternativeCursor; + } + + void setAlternativeCursor(final Cursor cursor) { + this.alternativeCursor = cursor; + } + + List<GraphicElement> getHighlightedElements() { + return highlightedElements; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/ClickFeature.java b/pne-editor/src/org/pneditor/editor/canvas/ClickFeature.java new file mode 100644 index 0000000..121cc57 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/ClickFeature.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.event.MouseEvent; +import org.pneditor.editor.Root; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.util.Colors; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +class ClickFeature implements Feature { + + private final Root root; + + private Color previousColor; + + ClickFeature(final Canvas canvas) { + this.root = canvas.getRoot(); + } + + + @Override + public void drawBackground(final Graphics g) { + final GraphicElement element = this.root.getClickedElement(); + if (element != null) { + this.previousColor = element.getColor(); + element.setColor(Colors.SINGLESELECTED); + } + } + + @Override + public void drawForeground(final Graphics g) { + final GraphicElement element = this.root.getClickedElement(); + if (element != null) { + element.setColor(this.previousColor); + } + } + + @Override + public void setHoverEffects(final int x, final int y) { + } + + @Override + public void mousePressed(final MouseEvent event) { + } + + @Override + public void mouseDragged(final int x, final int y) { + } + + @Override + public void mouseReleased(final int x, final int y) { + } + + @Override + public void setCursor(final int x, final int y) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/DraggingFeature.java b/pne-editor/src/org/pneditor/editor/canvas/DraggingFeature.java new file mode 100644 index 0000000..d5ac15b --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/DraggingFeature.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Graphics; + +import java.awt.Cursor; +import java.awt.Point; +import java.awt.event.MouseEvent; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.MoveElementCommand; +import org.pneditor.editor.commands.MoveElementsCommand; +import org.pneditor.editor.gpetrinet.GraphicElement; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +class DraggingFeature implements Feature { + + private final Canvas canvas; + private final Root root; + + DraggingFeature(final Canvas canvas) { + this.canvas = canvas; + this.root = canvas.getRoot(); + } + + private GraphicElement draggedElement; + private Point deltaPosition; + private int prevDragX; // During dragging, these record the x and y coordinates of the + private int prevDragY; // previous position of the mouse. + + @Override + public void mousePressed(final MouseEvent event) { + final boolean doubleclick = event.getClickCount() == 2; + if (!doubleclick) { + final int mouseButton = event.getButton(); + if (mouseButton == MouseEvent.BUTTON1 + && this.root.getClickedElement() != null + && (this.root.isSelectedToolSelect() + || this.root.isSelectedToolPlace() + || this.root.isSelectedToolTransition()) + && this.root.getClickedElement().isNode()) { + if (!this.root.getSelection().contains(this.root.getClickedElement())) { + this.root.getSelection().clear(); + } + final int x = event.getX(); + final int y = event.getY(); + this.draggedElement = this.root.getGraphicPetriNet().getElementByXY(x, y); + this.deltaPosition = new Point(); + this.prevDragX = x; + this.prevDragY = y; + } + } + } + + @Override + public void mouseDragged(final int x, final int y) { + if (this.draggedElement != null) { + doTheMoving(x, y); + this.canvas.repaint(); // redraw canvas to show shape in new position + this.deltaPosition.translate(x - this.prevDragX, y - this.prevDragY); + this.prevDragX = x; + this.prevDragY = y; + } + } + + @Override + public void mouseReleased(final int x, final int y) { + if (this.draggedElement != null) { + doTheMoving(x, y); + this.deltaPosition.translate(x - this.prevDragX, y - this.prevDragY); + saveTheMoving(); + this.canvas.repaint(); + this.draggedElement = null; // Dragging is finished. + } + } + + private void doTheMoving(final int mouseX, final int mouseY) { + if (this.root.getSelection().isEmpty()) { + this.draggedElement.moveBy(mouseX - this.prevDragX, mouseY - this.prevDragY); + } else { + for (final GraphicElement selectedElement : this.root.getSelection()) { + selectedElement.moveBy(mouseX - this.prevDragX, mouseY - this.prevDragY); + } + } + } + + private void saveTheMoving() { + if (!this.deltaPosition.equals(new Point(0, 0))) { + if (this.root.getSelection().isEmpty()) { + this.draggedElement.moveBy(-this.deltaPosition.x, -this.deltaPosition.y); //move back to original position + this.root.getUndoManager().executeCommand(new MoveElementCommand(this.draggedElement, this.deltaPosition)); + } else { + for (final GraphicElement selectedElement : this.root.getSelection()) { + selectedElement.moveBy(-this.deltaPosition.x, -this.deltaPosition.y); //move back to original positions + } + this.root.getUndoManager().executeCommand(new MoveElementsCommand(this.root.getSelection().getElements(), this.deltaPosition)); + } + } + } + + @Override + public void setCursor(final int x, final int y) { + + if (this.root.isSelectedToolSelect() + || this.root.isSelectedToolPlace() + || this.root.isSelectedToolTransition()) { + + final GraphicElement element = this.root.getGraphicPetriNet().getElementByXY(x, y); + if (element != null && element.isNode()) { + this.canvas.setAlternativeCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + } + } + } + + @Override + public void drawForeground(final Graphics g) { + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void setHoverEffects(final int x, final int y) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/EdgeZigzagFeature.java b/pne-editor/src/org/pneditor/editor/canvas/EdgeZigzagFeature.java new file mode 100644 index 0000000..15d9bdb --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/EdgeZigzagFeature.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Graphics; + +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.SetEdgeZigzagPointCommand; +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.util.Colors; +import org.pneditor.util.GraphicsTools; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +class EdgeZigzagFeature implements Feature { + + private final Canvas canvas; + private final Root root; + + private Point activeBreakPoint; + private boolean started; + private final VisualHandle visualHandle = new VisualHandle(); + private final List<VisualHandle> foregroundVisualElements = new ArrayList<>(); + + private Point startingMouseLocation; + private List<Point> oldBreakPoints; + private GraphicArc arc; + + EdgeZigzagFeature(final Canvas canvas) { + this.canvas = canvas; + this.root = canvas.getRoot(); + this.visualHandle.setColor(Colors.POINTING); + this.visualHandle.setSize(GraphicArc.NEARTOLERANCE, GraphicArc.NEARTOLERANCE); + } + + + @Override + public void mousePressed(final MouseEvent event) { + final int mouseButton = event.getButton(); + + if (mouseButton == MouseEvent.BUTTON1 + && this.root.getClickedElement() != null + && (this.root.isSelectedToolSelect() + || this.root.isSelectedToolPlace() + || this.root.isSelectedToolTransition() + || this.root.isSelectedToolArc() + || this.root.isSelectedToolToken() && !(this.root.getClickedElement().isPlace())) + && !this.root.getClickedElement().isNode()) { + if (!this.root.getSelection().contains(this.root.getClickedElement())) { + this.root.getSelection().clear(); + } + final int x = event.getX(); + final int y = event.getY(); + + this.arc = (GraphicArc) this.root.getGraphicPetriNet().getElementByXY(x, y); + + this.oldBreakPoints = this.arc.getBreakPointsCopy(); + this.startingMouseLocation = new Point(x, y); + this.activeBreakPoint = this.arc.addOrGetBreakPoint(new Point(this.startingMouseLocation)); + this.started = true; + } + } + + @Override + public void mouseDragged(final int x, final int y) { + if (this.started) { + this.activeBreakPoint.move(x, y); + this.canvas.repaint(); + } + } + + @Override + public void mouseReleased(final int x, final int y) { + if (this.started) { + this.arc.cleanupUnecessaryBreakPoints(); + + boolean change = false; + if (this.oldBreakPoints.size() != this.arc.getBreakPoints().size()) { + change = true; + } else { + for (int i = 0; i < this.arc.getBreakPoints().size(); i++) { + if (!this.arc.getBreakPoints().get(i).equals(this.oldBreakPoints.get(i))) { + change = true; + break; + } + } + } + if (change) { + this.arc.setBreakPoints(this.oldBreakPoints); + final Point targetLocation = new Point(x, y); + this.root.getUndoManager().executeCommand(new SetEdgeZigzagPointCommand(this.arc, this.startingMouseLocation, targetLocation)); + } + this.started = false; + } + } + + @Override + public void setHoverEffects(final int x, final int y) { + if (this.root.isSelectedToolSelect() + || this.root.isSelectedToolPlace() + || this.root.isSelectedToolTransition() + || this.root.isSelectedToolArc() + || this.root.isSelectedToolToken()) { + final GraphicElement element = this.root.getGraphicPetriNet().getElementByXY(x, y); + boolean drawHandle = false; + if (element != null && !element.isNode()) { + final GraphicArc anArc = (GraphicArc) element; + for (final Point breakPoint : anArc.getBreakPoints()) { + final Point mousePos = new Point(x, y); + if (GraphicsTools.isPointNearPoint(breakPoint, mousePos, GraphicArc.NEARTOLERANCE)) { + if (!this.foregroundVisualElements.contains(this.visualHandle)) { + this.foregroundVisualElements.add(this.visualHandle); + } + this.visualHandle.setCenter(breakPoint.x, breakPoint.y); + drawHandle = true; + + break; + } + } + } + if (!drawHandle) { + this.foregroundVisualElements.remove(this.visualHandle); + } + + if (element != null) { + this.canvas.getHighlightedElements().add(element); + element.setHighlightColor(Colors.POINTING); + this.canvas.repaint(); + } + } + } + + @Override + public void drawForeground(final Graphics g) { + for (final VisualHandle element : this.foregroundVisualElements) { + element.draw(g); + } + } + + @Override + public void setCursor(final int x, final int y) { + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/Feature.java b/pne-editor/src/org/pneditor/editor/canvas/Feature.java new file mode 100644 index 0000000..2999a0f --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/Feature.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Graphics; +import java.awt.event.MouseEvent; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public interface Feature { + + void drawForeground(Graphics g); + + void drawMainLayer(Graphics g); + + void drawBackground(Graphics g); + + void mousePressed(MouseEvent event); + + void mouseDragged(int x, int y); + + void mouseReleased(int x, int y); + + void mouseMoved(int x, int y); + + void setHoverEffects(int x, int y); + + void setCursor(int x, int y); +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/PanningFeature.java b/pne-editor/src/org/pneditor/editor/canvas/PanningFeature.java new file mode 100644 index 0000000..0688919 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/PanningFeature.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Cursor; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.event.MouseEvent; +import org.pneditor.editor.Root; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +class PanningFeature implements Feature { + + private final Canvas canvas; + private final Root root; + + private int prevDragX; + private int prevDragY; + private boolean panning; + + PanningFeature(final Canvas canvas) { + this.canvas = canvas; + this.root = canvas.getRoot(); + } + + @Override + public void mousePressed(final MouseEvent event) { + + final int mouseButton = event.getButton(); + + if (mouseButton == MouseEvent.BUTTON2 + || mouseButton == MouseEvent.BUTTON1 && event.isControlDown()) { + + final int realX = event.getX() + this.canvas.getTranslationX(); + final int realY = event.getY() + this.canvas.getTranslationY(); + + this.prevDragX = realX; + this.prevDragY = realY; + this.panning = true; + } + } + + @Override + public void mouseDragged(final int x, final int y) { + if (this.panning) { + final int realX = x + this.canvas.getTranslationX(); + final int realY = y + this.canvas.getTranslationY(); + + doThePanning(realX, realY); + this.canvas.repaint(); + this.prevDragX = realX; + this.prevDragY = realY; + } + } + + @Override + public void mouseReleased(final int x, final int y) { + if (this.panning) { + final int realX = x + this.canvas.getTranslationX(); + final int realY = y + this.canvas.getTranslationY(); + + doThePanning(realX, realY); + this.canvas.repaint(); + this.panning = false; + } + } + + private void doThePanning(final int mouseX, final int mouseY) { + final Point viewTranslation = this.root.getGraphicPetriNet().getViewTranslation(); + viewTranslation.translate(mouseX - this.prevDragX, mouseY - this.prevDragY); + this.root.getGraphicPetriNet().setViewTranslation(viewTranslation); + } + + @Override + public void setCursor(final int x, final int y) { + if (this.panning) { + this.canvas.setAlternativeCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + } + } + + @Override + public void drawForeground(final Graphics g) { + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void setHoverEffects(final int x, final int y) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/PetriNetFeature.java b/pne-editor/src/org/pneditor/editor/canvas/PetriNetFeature.java new file mode 100644 index 0000000..9474f7a --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/PetriNetFeature.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Graphics; +import java.awt.event.MouseEvent; +import org.pneditor.editor.Root; + + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class PetriNetFeature implements Feature { + + private final Root root; + + public PetriNetFeature(final Canvas canvas) { + this.root = canvas.getRoot(); + } + + @Override + public void drawMainLayer(final Graphics g) { + this.root.getGraphicPetriNet().draw(g); + } + + @Override + public void drawForeground(final Graphics g) { + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void mousePressed(final MouseEvent event) { + } + + @Override + public void mouseDragged(final int x, final int y) { + } + + @Override + public void mouseReleased(final int x, final int y) { + } + + @Override + public void setHoverEffects(final int x, final int y) { + } + + @Override + public void setCursor(final int x, final int y) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } + +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/PlaceTransitionMakerFeature.java b/pne-editor/src/org/pneditor/editor/canvas/PlaceTransitionMakerFeature.java new file mode 100644 index 0000000..ee909a2 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/PlaceTransitionMakerFeature.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Graphics; +import java.awt.event.MouseEvent; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.AddPlaceCommand; +import org.pneditor.editor.commands.AddTransitionCommand; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class PlaceTransitionMakerFeature implements Feature { + + private final Root root; + + public PlaceTransitionMakerFeature(final Canvas canvas) { + this.root = canvas.getRoot(); + } + + @Override + public void mousePressed(final MouseEvent event) { + final int mouseButton = event.getButton(); + + if (mouseButton == MouseEvent.BUTTON1 && this.root.getClickedElement() == null) { + final int x = event.getX(); + final int y = event.getY(); + if (this.root.isSelectedToolPlace()) { + this.root.getSelection().clear(); + this.root.getUndoManager().executeCommand(new AddPlaceCommand(x, y, this.root.getGraphicPetriNet())); + this.root.setClickedElement(this.root.getGraphicPetriNet().getLastElementAdded()); + } else if (this.root.isSelectedToolTransition()) { + this.root.getSelection().clear(); + this.root.getUndoManager() + .executeCommand(new AddTransitionCommand(x, y, this.root.getGraphicPetriNet())); + this.root.setClickedElement(this.root.getGraphicPetriNet().getLastElementAdded()); + } + + } + + } + + @Override + public void drawForeground(final Graphics g) { + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void mouseDragged(final int x, final int y) { + } + + @Override + public void mouseReleased(final int x, final int y) { + } + + @Override + public void setHoverEffects(final int x, final int y) { + } + + @Override + public void setCursor(final int x, final int y) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/PopupMenuFeature.java b/pne-editor/src/org/pneditor/editor/canvas/PopupMenuFeature.java new file mode 100644 index 0000000..c334d4a --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/PopupMenuFeature.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Graphics; +import java.awt.event.MouseEvent; +import javax.swing.JPopupMenu; +import org.pneditor.editor.Root; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class PopupMenuFeature implements Feature { + + private final Canvas canvas; + private final Root root; + + public PopupMenuFeature(final Canvas canvas) { + this.canvas = canvas; + this.root = canvas.getRoot(); + } + + @Override + public void mousePressed(final MouseEvent event) { + final int mouseButton = event.getButton(); + if (mouseButton == MouseEvent.BUTTON3) { + final int realX = event.getX() + this.canvas.getTranslationX(); + final int realY = event.getY() + this.canvas.getTranslationY(); + + if (this.root.getClickedElement() != null + && (this.root.isSelectedToolSelect() + || this.root.isSelectedToolPlace() + || this.root.isSelectedToolTransition() + || this.root.isSelectedToolArc() + || (this.root.isSelectedToolToken() && !this.root.getClickedElement().isPlace()))) { + //if token selected, right click disallowed on Place (because it's removing tokens normally) + if (this.root.getClickedElement().isPlace()) { + showPopup(this.root.getPlacePopup(), realX, realY); + if (!this.root.getSelection().contains(this.root.getClickedElement())) { + this.root.getSelection().clear(); + } + } else if (this.root.getClickedElement().isTransition()) { + showPopup(this.root.getTransitionPopup(), realX, realY); + if (!this.root.getSelection().contains(this.root.getClickedElement())) { + this.root.getSelection().clear(); + } + } else if (!this.root.getClickedElement().isNode()) { + showPopup(this.root.getArcPopup(), realX, realY); + if (!this.root.getSelection().contains(this.root.getClickedElement())) { + this.root.getSelection().clear(); + } + } + } + + if (this.root.getClickedElement() == null + && this.root.isSelectedToolSelect()) { + showPopup(this.root.getCanvasPopup(), realX, realY); + } + } + } + + private void showPopup(final JPopupMenu popupMenu, final int clickedX, final int clickedY) { + popupMenu.show(this.canvas, clickedX - 10, clickedY - 2); + } + + @Override + public void drawForeground(final Graphics g) { + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void mouseDragged(final int x, final int y) { + } + + @Override + public void mouseReleased(final int x, final int y) { + } + + @Override + public void setHoverEffects(final int x, final int y) { + } + + @Override + public void setCursor(final int x, final int y) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } + +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/ScrollingFeature.java b/pne-editor/src/org/pneditor/editor/canvas/ScrollingFeature.java new file mode 100644 index 0000000..3a399aa --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/ScrollingFeature.java @@ -0,0 +1,162 @@ +package org.pneditor.editor.canvas; + +import java.awt.Cursor; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import javax.swing.JScrollBar; + +import org.pneditor.editor.Root; +import org.pneditor.util.Point; + +/** + * + * @author matmas + */ +public class ScrollingFeature implements Feature, MouseListener, MouseMotionListener, AdjustmentListener { + + private final Canvas canvas; + private final Root root; + private int prevDragX; + private int prevDragY; + private boolean scrolling; + + public ScrollingFeature(final Canvas canvas) { + this.canvas = canvas; + this.root = canvas.getRoot(); + canvas.addMouseListener(this); + canvas.addMouseMotionListener(this); + } + + @Override + public void mousePressed(final MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON2 + || e.getButton() == MouseEvent.BUTTON1 && e.isControlDown()) { + this.prevDragX = e.getX(); + this.prevDragY = e.getY(); + this.scrolling = true; + } + } + + @Override + public void mouseDragged(final MouseEvent e) { + if (this.scrolling) { + doTheScrolling(e.getX(), e.getY()); + this.prevDragX = e.getX(); + this.prevDragY = e.getY(); + } + } + + @Override + public void mouseReleased(final MouseEvent e) { + if (this.scrolling) { + doTheScrolling(e.getX(), e.getY()); + this.scrolling = false; + } + } + + private void doTheScrolling(final int mouseX, final int mouseY) { + final Point viewTranslation = this.canvas.getViewTranslation(); + this.canvas.setViewTranslation(viewTranslation.getTranslated(mouseX - this.prevDragX, mouseY - this.prevDragY)); + this.canvas.repaint(); + } + + @Override + public void drawForeground(final Graphics g) { + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void drawMainLayer(final Graphics g) { + final Rectangle petriNetBounds = this.root.getGraphicPetriNet().getBounds(); + final Rectangle canvasBounds = this.canvas.getBounds(); + + final JScrollBar horizontalScrollBar = this.root.getDrawingBoard().getHorizontalScrollBar(); + final JScrollBar verticalScrollBar = this.root.getDrawingBoard().getVerticalScrollBar(); + + canvasBounds.translate(-this.canvas.getViewTranslation().getX(), -this.canvas.getViewTranslation().getY()); // to account for translation + petriNetBounds.translate(this.canvas.getWidth() / 2, this.canvas.getHeight() / 2); // [0, 0] is in center + + // Union of the two rectangles: + if (!petriNetBounds.isEmpty()) { + petriNetBounds.add(canvasBounds); + } + + horizontalScrollBar.setEnabled(false); + horizontalScrollBar.setMinimum(petriNetBounds.x); + horizontalScrollBar.setMaximum(petriNetBounds.x + petriNetBounds.width); + horizontalScrollBar.setVisibleAmount(canvasBounds.width); + horizontalScrollBar.setValue(-this.canvas.getViewTranslation().getX()); + horizontalScrollBar.setEnabled(true); + + verticalScrollBar.setEnabled(false); + verticalScrollBar.setMinimum(petriNetBounds.y); + verticalScrollBar.setMaximum(petriNetBounds.y + petriNetBounds.height); + verticalScrollBar.setVisibleAmount(canvasBounds.height); + verticalScrollBar.setValue(-this.canvas.getViewTranslation().getY()); + verticalScrollBar.setEnabled(true); + } + + @Override + public void mouseClicked(final MouseEvent e) { + } + + @Override + public void mouseEntered(final MouseEvent e) { + } + + @Override + public void mouseExited(final MouseEvent e) { + } + + @Override + public void mouseMoved(final MouseEvent e) { + } + + @Override + public void adjustmentValueChanged(final AdjustmentEvent e) { + final JScrollBar scrollBar = (JScrollBar) e.getSource(); + if (!this.scrolling && scrollBar.isEnabled()) { + final int value = e.getValue(); + Point viewTranslation = this.canvas.getViewTranslation(); + if (e.getSource() == this.root.getDrawingBoard().getHorizontalScrollBar()) { + viewTranslation = new Point(-value, viewTranslation.getY()); + } + if (e.getSource() == this.root.getDrawingBoard().getVerticalScrollBar()) { + viewTranslation = new Point(viewTranslation.getX(), -value); + } + this.canvas.setViewTranslation(viewTranslation); + this.canvas.repaint(); + } + } + + @Override + public void mouseDragged(final int x, final int y) { + } + + @Override + public void mouseReleased(final int x, final int y) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } + + @Override + public void setHoverEffects(final int x, final int y) { + } + + @Override + public void setCursor(final int x, final int y) { + if (this.scrolling) { + this.canvas.setAlternativeCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/Selection.java b/pne-editor/src/org/pneditor/editor/canvas/Selection.java new file mode 100644 index 0000000..46cd064 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/Selection.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.pneditor.editor.gpetrinet.GraphicElement; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class Selection implements Iterable<GraphicElement> { + + private final Set<GraphicElement> selectedElements = new HashSet<>(); + private SelectionChangedListener selectionChangedListener; + + public void setSelectionChangedListener(final SelectionChangedListener selectionChangedListener) { + this.selectionChangedListener = selectionChangedListener; + } + + public void clear() { + this.selectedElements.clear(); + selectionChanged(); + } + + public void add(final GraphicElement element) { + this.selectedElements.add(element); + selectionChanged(); + } + + public void addAll(final Collection<? extends GraphicElement> elements) { + this.selectedElements.addAll(elements); + selectionChanged(); + } + + public boolean isEmpty() { + return this.selectedElements.isEmpty(); + } + + public boolean contains(final GraphicElement element) { + return this.selectedElements.contains(element); + } + + public void selectionChanged() { + if (this.selectionChangedListener != null) { + this.selectionChangedListener.selectionChanged(); + } + } + + @Override + public Iterator<GraphicElement> iterator() { + return this.selectedElements.iterator(); + } + + public Set<GraphicElement> getElements() { + return this.selectedElements; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/SelectionChangedListener.java b/pne-editor/src/org/pneditor/editor/canvas/SelectionChangedListener.java new file mode 100644 index 0000000..420778f --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/SelectionChangedListener.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public interface SelectionChangedListener { + + void selectionChanged(); +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/SelectionDrawingFeature.java b/pne-editor/src/org/pneditor/editor/canvas/SelectionDrawingFeature.java new file mode 100644 index 0000000..5c92200 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/SelectionDrawingFeature.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.Graphics; +import java.awt.event.MouseEvent; +import java.util.HashSet; +import java.util.Set; +import org.pneditor.editor.Root; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.util.Colors; + + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +class SelectionDrawingFeature implements Feature { + + private final Canvas canvas; + private final Root root; + + private boolean selecting; + private final VisualSelection visualSelection = new VisualSelection(); + private final Set<GraphicElement> previousSelection = new HashSet<>(); + + SelectionDrawingFeature(Canvas canvas) { + this.canvas = canvas; + this.root = canvas.getRoot(); + } + + @Override + public void mousePressed(final MouseEvent event) { + + final int mouseButton = event.getButton(); + + if (mouseButton == MouseEvent.BUTTON1 + && this.root.getClickedElement() == null + && this.root.isSelectedToolSelect()) { + final int x = event.getX(); + final int y = event.getY(); + this.selecting = true; + this.visualSelection.setStart(x, y); + this.visualSelection.setEnd(x, y); + this.canvas.repaint(); + if (event.isShiftDown()) { + this.previousSelection.addAll(this.root.getSelection().getElements()); + } else { + this.root.getSelection().clear(); + this.previousSelection.clear(); + } + } + } + + @Override + public void mouseDragged(final int x, final int y) { + if (this.selecting) { + this.visualSelection.setEnd(x, y); + this.canvas.repaint(); + } + } + + @Override + public void mouseReleased(final int x, final int y) { + if (this.selecting) { + this.selecting = false; + this.canvas.repaint(); + } + } + + @Override + public void setHoverEffects(final int x, final int y) { + for (final GraphicElement selectedElement : this.root.getSelection()) { + this.canvas.getHighlightedElements().add(selectedElement); + selectedElement.setHighlightColor(Colors.SELECTED); + } + + if (this.selecting) { + this.root.getSelection().clear(); + this.root.getSelection().addAll(this.previousSelection); + for (final GraphicElement visualElement : this.root.getGraphicPetriNet().getElements()) { + if (this.visualSelection.containsPoint(visualElement.getCenter().x, visualElement.getCenter().y)) { + addElementToSelection(visualElement); + } + } + this.canvas.repaint(); + } + } + + private void addElementToSelection(final GraphicElement element) { + this.canvas.getHighlightedElements().add(element); + element.setHighlightColor(Colors.SELECTED); + + this.root.getSelection().add(element); + } + + @Override + public void drawForeground(final Graphics g) { + if (this.selecting) { + this.visualSelection.draw(g); + } + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void setCursor(final int x, final int y) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/TokenFeature.java b/pne-editor/src/org/pneditor/editor/canvas/TokenFeature.java new file mode 100644 index 0000000..a7dd0d8 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/TokenFeature.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + +import java.awt.BasicStroke; +import java.awt.Cursor; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.event.MouseEvent; +import org.pneditor.editor.Root; +import org.pneditor.editor.commands.AddTokenCommand; +import org.pneditor.editor.commands.FireTransitionCommand; +import org.pneditor.editor.commands.RemoveTokenCommand; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.util.Colors; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +import logger.PNEditorLogger; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +class TokenFeature implements Feature { + + private final Canvas canvas; + private final Root root; + + private final Cursor tokenCursor; + private final Cursor fireCursor; + + TokenFeature(final Canvas canvas) { + this.canvas = canvas; + this.root = canvas.getRoot(); + this.tokenCursor = GraphicsTools.getCursor(PNEConstantsConfiguration.TOKEN, new Point(16, 0)); + this.fireCursor = GraphicsTools.getCursor(PNEConstantsConfiguration.FIRE, new Point(16, 0)); + } + + @Override + public void mousePressed(final MouseEvent event) { + + if (this.root.getClickedElement() != null && this.root.isSelectedToolToken()) { + final int x = event.getX(); + final int y = event.getY(); + final int mouseButton = event.getButton(); + final GraphicElement targetElement = this.root.getGraphicPetriNet().getElementByXY(x, y); + + if (targetElement.isPlace()) { + final GraphicPlace place = (GraphicPlace) targetElement; + if (mouseButton == MouseEvent.BUTTON1) { + this.root.getUndoManager().executeCommand(new AddTokenCommand(place)); + } else if (mouseButton == MouseEvent.BUTTON3 && place.getPlace().getTokens() > 0) { + this.root.getUndoManager().executeCommand(new RemoveTokenCommand(place)); + } + + } else if (targetElement.isTransition()) { + final GraphicTransition transition = (GraphicTransition) targetElement; + if (mouseButton == MouseEvent.BUTTON1) { + try { + final PetriNetInterface petriNet = this.root.getPetriNet(); + if (petriNet.isEnabled(transition.getTransition())) { + this.root.getUndoManager().executeCommand( + new FireTransitionCommand(transition, this.root.getGraphicPetriNet())); + } + } catch (ResetArcMultiplicityException e) { + PNEditorLogger.severeLogs(e.getMessage()); + } + } + } + } + } + + @Override + public void setHoverEffects(final int x, final int y) { + final GraphicElement targetElement = this.root.getGraphicPetriNet().getElementByXY(x, y); + + if (this.root.isSelectedToolToken() && targetElement != null) { + if (targetElement.isPlace()) { + this.canvas.getHighlightedElements().add(targetElement); + targetElement.setHighlightColor(Colors.POINTING); + this.canvas.repaint(); + } else if (targetElement.isTransition()) { + try { + final PetriNetInterface petriNet = this.root.getPetriNet(); + if (petriNet.isEnabled(((GraphicTransition) targetElement).getTransition())) { + this.canvas.getHighlightedElements().add(targetElement); + targetElement.setHighlightColor(Colors.PERMITTED); + this.canvas.repaint(); + } else { + this.canvas.getHighlightedElements().add(targetElement); + targetElement.setHighlightColor(Colors.DISALLOWED); + this.canvas.repaint(); + } + } catch (ResetArcMultiplicityException e) { + PNEditorLogger.severeLogs(e.getMessage()); + } + } + } + } + + @Override + public void drawForeground(final Graphics g) { + + if (this.root.isSelectedToolToken()) { + for (final GraphicElement element : this.root.getGraphicPetriNet().getElements()) { + if (element.isTransition()) { + final GraphicTransition transition = (GraphicTransition) element; + try { + final PetriNetInterface petriNet = this.root.getPetriNet(); + if (petriNet.isEnabled(transition.getTransition())) { + g.setColor(Colors.PERMITTED); + } else { + g.setColor(Colors.DISALLOWED); + } + } catch (ResetArcMultiplicityException e) { + PNEditorLogger.severeLogs(e.getMessage()); + } + ((Graphics2D) g).setStroke(new BasicStroke(2f)); + g.drawRect(transition.getStart().x + 1, transition.getStart().y + 1, transition.getWidth() - 3, + transition.getHeight() - 3); + ((Graphics2D) g).setStroke(new BasicStroke(1f)); + } + } + } + } + + @Override + public void setCursor(final int x, final int y) { + final GraphicElement targetElement = this.root.getGraphicPetriNet().getElementByXY(x, y); + + if (this.root.isSelectedToolToken() && targetElement != null) { + if (targetElement.isPlace()) { + this.canvas.setAlternativeCursor(this.tokenCursor); + } else if (targetElement.isTransition()) { + this.canvas.setAlternativeCursor(this.fireCursor); + } + } + + } + + @Override + public void drawBackground(final Graphics g) { + } + + @Override + public void mouseDragged(final int x, final int y) { + } + + @Override + public void mouseReleased(final int x, final int y) { + } + + @Override + public void drawMainLayer(final Graphics g) { + } + + @Override + public void mouseMoved(final int x, final int y) { + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/VisualHandle.java b/pne-editor/src/org/pneditor/editor/canvas/VisualHandle.java new file mode 100644 index 0000000..c34976c --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/VisualHandle.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + + +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.petrinet.PetriNetInterface; + +import java.awt.Graphics; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ + +class VisualHandle extends GraphicElement { + + public void draw(final Graphics g) { + g.setColor(this.color); + g.drawRect(Math.min(getStart().x, getEnd().x), Math.min(getStart().y, getEnd().y), getWidth(), getHeight()); + } + + @Override + public void draw(final Graphics g, final PetriNetInterface petriNet) { + draw(g); + } + + @Override + public boolean isNode() { + return false; + } + + @Override + public boolean isPlace() { + return false; + } + + @Override + public boolean isTransition() { + return false; + } +} diff --git a/pne-editor/src/org/pneditor/editor/canvas/VisualSelection.java b/pne-editor/src/org/pneditor/editor/canvas/VisualSelection.java new file mode 100644 index 0000000..4412507 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/canvas/VisualSelection.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.canvas; + + +import java.awt.Graphics; + +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.util.GraphicsTools; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ + +class VisualSelection extends GraphicElement { + + + public void draw(final Graphics g) { + g.setColor(this.color); + GraphicsTools.setDashedStroke(g); + g.drawRect(Math.min(getStart().x, getEnd().x), Math.min(getStart().y, getEnd().y), getWidth(), getHeight()); + GraphicsTools.setDefaultStroke(g); + } + + @Override + public void draw(final Graphics g, final PetriNetInterface petriNet) { + draw(g); + } + + @Override + public boolean isNode() { + return false; + } + + @Override + public boolean isPlace() { + return false; + } + + @Override + public boolean isTransition() { + return false; + } +} diff --git a/pne-editor/src/org/pneditor/editor/commands/AddArcCommand.java b/pne-editor/src/org/pneditor/editor/commands/AddArcCommand.java new file mode 100644 index 0000000..25953e8 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/AddArcCommand.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.petrinet.UnimplementedCaseException; +import org.pneditor.editor.gpetrinet.GraphicNode; +import org.pneditor.util.Command; + +import logger.PNEditorLogger; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class AddArcCommand implements Command { + + final private GraphicPetriNet gPetriNet; + final private GraphicNode source; + final private GraphicNode destination; + private AbstractArc createdArc; + private GraphicArc representation; + + public AddArcCommand(final GraphicPetriNet gPetriNet, final GraphicNode source, final GraphicNode destination) { + this.gPetriNet = gPetriNet; + this.source = source; + this.destination = destination; + } + + @Override + public void execute() { + try { + this.createdArc = this.gPetriNet.getPetriNet().addRegArc(this.source.getNode(), this.destination.getNode()); + } catch (UnimplementedCaseException e) { + PNEditorLogger.infoLogs(e.getMessage()); + // do nothing, that means something is not implemented + // and that the rest should not happen + } + if (this.createdArc != null) { + this.representation = new GraphicArc(this.createdArc); + this.representation.setSource(this.source); + this.representation.setDestination(this.destination); + this.gPetriNet.addElement(this.representation); + } + } + + @Override + public void undo() { + new DeleteArcCommand(this.representation, this.gPetriNet).execute(); + } + + @Override + public void redo() { + int oldMultiplicity = 0; + try { + oldMultiplicity = this.createdArc.getMultiplicity(); // in case the initial multiplicity is the same in the actual model, + // we save the old one, and give it back when adding again the arc + execute(); + if (oldMultiplicity > 0) { + this.createdArc.setMultiplicity(oldMultiplicity); + } + + } catch (ResetArcMultiplicityException e) { + execute(); //forget about the multiplicity issue + } + } + + @Override + public String toString() { + return "Add arc"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/AddPlaceCommand.java b/pne-editor/src/org/pneditor/editor/commands/AddPlaceCommand.java new file mode 100644 index 0000000..f260eaa --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/AddPlaceCommand.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.petrinet.AbstractPlace; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class AddPlaceCommand implements Command { + + final private GraphicPetriNet gPetriNet ; + final private int x, y; + private AbstractPlace createdPlace; + private GraphicPlace representation; + + public AddPlaceCommand(final int x, final int y, final GraphicPetriNet gPetriNet) { + this.x = x; + this.y = y; + this.gPetriNet = gPetriNet; + } + + @Override + public void execute() { + this.createdPlace = this.gPetriNet.getPetriNet().addAbstractPlace(); + this.representation = new GraphicPlace(this.createdPlace, this.x, this.y); + this.gPetriNet.addElement(this.representation); + } + + @Override + public void undo() { + new DeletePlaceCommand(this.representation, this.gPetriNet).execute(); + } + + @Override + public void redo() { + final AbstractPlace newPlace = this.gPetriNet.getPetriNet().addAbstractPlace(); + newPlace.setLabel(this.createdPlace.getLabel()); // in case of a given name on construction, we put it back + newPlace.setTokens(this.createdPlace.getTokens()); // same as before, except with tokens + this.representation.setPlace(newPlace); + this.gPetriNet.addElement(this.representation); + } + + @Override + public String toString() { + return "Add place"; + } + + public AbstractPlace getCreatedPlace() { + return this.createdPlace; + } +} diff --git a/pne-editor/src/org/pneditor/editor/commands/AddTokenCommand.java b/pne-editor/src/org/pneditor/editor/commands/AddTokenCommand.java new file mode 100644 index 0000000..ae910d1 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/AddTokenCommand.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.petrinet.AbstractPlace; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class AddTokenCommand implements Command { + + private AbstractPlace place; + final private GraphicPlace gPlace; + + public AddTokenCommand(GraphicPlace gPlace) { + this.gPlace = gPlace; + } + + @Override + public void execute() { + this.place = this.gPlace.getPlace(); + this.place.addToken(); + } + + @Override + public void undo() { + this.place = this.gPlace.getPlace(); + this.place.removeToken(); + } + + @Override + public void redo() { + execute(); + } + + @Override + public String toString() { + return "Add token"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/AddTransitionCommand.java b/pne-editor/src/org/pneditor/editor/commands/AddTransitionCommand.java new file mode 100644 index 0000000..e8a8757 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/AddTransitionCommand.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.petrinet.AbstractTransition; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class AddTransitionCommand implements Command { + + final private int x, y; + private AbstractTransition createdTransition; + final private GraphicPetriNet gPetriNet; + private GraphicTransition representation; + + public AddTransitionCommand(int x, int y, GraphicPetriNet gPetriNet) { + this.x = x; + this.y = y; + this.gPetriNet = gPetriNet; + } + + @Override + public void execute() { + this.createdTransition = this.gPetriNet.getPetriNet().addAbstractTransition(); + this.representation = new GraphicTransition(this.createdTransition, this.x, this.y); + this.gPetriNet.addElement(this.representation); + } + + @Override + public void undo() { + new DeleteTransitionCommand(this.representation, this.gPetriNet).execute(); + } + + @Override + public void redo() { + final AbstractTransition newTransition = this.gPetriNet.getPetriNet().addAbstractTransition(); + newTransition.setLabel(this.createdTransition.getLabel()); // in case of a given name on construction, + //we put it back (different models for instance) + this.representation.setTransition(newTransition); + this.gPetriNet.addElement(this.representation); + } + + @Override + public String toString() { + return "Add transition"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/CutCommand.java b/pne-editor/src/org/pneditor/editor/commands/CutCommand.java new file mode 100644 index 0000000..b5ba2eb --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/CutCommand.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import java.util.Set; + +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class CutCommand implements Command { + + final private Command deleteElements; + + public CutCommand(final Set<GraphicElement> elementsToDelete, final GraphicPetriNet petriNet) { + this.deleteElements = new DeleteElementsCommand(elementsToDelete, petriNet); + } + + @Override + public void execute() { + this.deleteElements.execute(); + } + + @Override + public void undo() { + this.deleteElements.undo(); + } + + @Override + public void redo() { + this.deleteElements.redo(); + } + + @Override + public String toString() { + return "Cut"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/DeleteArcCommand.java b/pne-editor/src/org/pneditor/editor/commands/DeleteArcCommand.java new file mode 100644 index 0000000..b830a2e --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/DeleteArcCommand.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class DeleteArcCommand implements Command { + + final private GraphicArc gArc; + final private GraphicPetriNet gPetriNet; + private boolean isAlreadyDeleted; + + public DeleteArcCommand(final GraphicArc gArc, final GraphicPetriNet gPetriNet) { + this.gPetriNet = gPetriNet; + this.gArc = gArc; + } + + @Override + public void execute() { + this.isAlreadyDeleted = !this.gPetriNet.getArcs().contains(this.gArc); + if (!this.isAlreadyDeleted) { + this.gPetriNet.getPetriNet().removeAbstractArc(this.gArc.getArc()); + this.gPetriNet.removeElement(this.gArc); + } + } + + @Override + public void undo() { + if (!this.isAlreadyDeleted) { + AbstractNode source = gArc.getSource().getNode(); + AbstractNode destination = gArc.getDestination().getNode(); + this.gPetriNet.getPetriNet().addArcAgain(this.gArc.getArc(), source, destination); + this.gPetriNet.addElement(this.gArc); + } + } + + @Override + public void redo() { + this.isAlreadyDeleted = !this.gPetriNet.getArcs().contains(this.gArc); + if (!this.isAlreadyDeleted) { + this.gPetriNet.getPetriNet().removeAbstractArc(this.gArc.getArc()); + this.gPetriNet.removeElement(this.gArc); + } + } + + @Override + public String toString() { + return "Delete arc"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/DeleteElementCommand.java b/pne-editor/src/org/pneditor/editor/commands/DeleteElementCommand.java new file mode 100644 index 0000000..45edc87 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/DeleteElementCommand.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class DeleteElementCommand implements Command { + + private Command deleteElement; + + public DeleteElementCommand(final GraphicElement element, final GraphicPetriNet petriNet) { + if (element.isPlace()) { + this.deleteElement = new DeletePlaceCommand((GraphicPlace) element, petriNet); + } else if (element.isTransition()) { + this.deleteElement = new DeleteTransitionCommand((GraphicTransition) element, petriNet); + } else if (!element.isNode()) { + this.deleteElement = new DeleteArcCommand((GraphicArc) element, petriNet); + } + } + + @Override + public void execute() { + if (this.deleteElement != null) { + this.deleteElement.execute(); + } + } + + @Override + public void undo() { + if (this.deleteElement != null) { + this.deleteElement.undo(); + } + } + + @Override + public void redo() { + if (this.deleteElement != null) { + this.deleteElement.redo(); + } + } + + @Override + public String toString() { + return this.deleteElement.toString(); + } +} \ No newline at end of file diff --git a/pne-editor/src/org/pneditor/editor/commands/DeleteElementsCommand.java b/pne-editor/src/org/pneditor/editor/commands/DeleteElementsCommand.java new file mode 100644 index 0000000..092f783 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/DeleteElementsCommand.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import java.util.HashSet; +import java.util.Set; + +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.Command; + +/** + * Delete clicked and selected elements + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class DeleteElementsCommand implements Command { + + private Set<Command> deleteAllElements = new HashSet<>(); + + public DeleteElementsCommand(final Set<GraphicElement> elementsToDelete, final GraphicPetriNet petriNet) { + for (final GraphicElement element : elementsToDelete) { + this.deleteAllElements.add(new DeleteElementCommand(element, petriNet)); + } + } + + @Override + public void execute() { + for (final Command deleteElement : this.deleteAllElements) { + deleteElement.execute(); + } + } + + @Override + public void undo() { + for (final Command deleteElement : this.deleteAllElements) { + deleteElement.undo(); + } + } + + @Override + public void redo() { + for (final Command deleteElement : this.deleteAllElements) { + deleteElement.redo(); + } + } + + @Override + public String toString() { + if (this.deleteAllElements.size() == 1) { + return this.deleteAllElements.iterator().next().toString(); + } + return "Delete elements"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/DeletePlaceCommand.java b/pne-editor/src/org/pneditor/editor/commands/DeletePlaceCommand.java new file mode 100644 index 0000000..2df663d --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/DeletePlaceCommand.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import java.util.HashSet; +import java.util.Set; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.petrinet.AbstractPlace; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class DeletePlaceCommand implements Command { + + final private Set<Command> deleteAllArcEdges = new HashSet<>(); + final private GraphicPetriNet gPetriNet; + final private GraphicPlace gPlace; + final private Set<GraphicArc> connectedArcs; + + public DeletePlaceCommand(final GraphicPlace gPlace, final GraphicPetriNet gPetriNet) { + this.gPetriNet = gPetriNet; + this.gPlace = gPlace; + this.connectedArcs = gPetriNet.getConnectedGraphicArcs(gPlace); + for (final GraphicArc arc : this.connectedArcs) { + this.deleteAllArcEdges.add(new DeleteArcCommand(arc, gPetriNet)); + } + + } + + @Override + public void execute() { + for (final Command deleteArc : this.deleteAllArcEdges) { + deleteArc.execute(); + } + this.gPetriNet.removeElement(this.gPlace); + this.gPetriNet.getPetriNet().removeAbstractPlace(this.gPlace.getPlace()); + + } + + @Override + public void undo() { + final AbstractPlace place = this.gPetriNet.getPetriNet().addAbstractPlace(); + place.setLabel(this.gPlace.getLabel()); + place.setTokens(this.gPlace.getPlace().getTokens()); + this.deleteAllArcEdges.clear(); + this.gPetriNet.addElement(this.gPlace); + this.gPlace.setPlace(place); + for (final GraphicArc arc : this.connectedArcs) { + if (arc.getSource() == this.gPlace) { + this.deleteAllArcEdges.add(new AddArcCommand(this.gPetriNet, this.gPlace, arc.getDestination())); + } + else { + this.deleteAllArcEdges.add(new AddArcCommand(this.gPetriNet, arc.getSource(), this.gPlace)); + } + } + for (final Command addArc : this.deleteAllArcEdges) { + addArc.execute(); + } + } + + @Override + public void redo() { + for (final Command addArc : this.deleteAllArcEdges) { + addArc.undo(); + } + this.gPetriNet.removeElement(this.gPlace); + this.gPetriNet.getPetriNet().removeAbstractPlace(this.gPlace.getPlace()); + } + + @Override + public String toString() { + return "Delete place node"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/DeleteTransitionCommand.java b/pne-editor/src/org/pneditor/editor/commands/DeleteTransitionCommand.java new file mode 100644 index 0000000..0858599 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/DeleteTransitionCommand.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import java.util.HashSet; +import java.util.Set; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.petrinet.AbstractTransition; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class DeleteTransitionCommand implements Command { + + final private GraphicTransition gTransition; + final private GraphicPetriNet gPetriNet; + final private Set<Command> deleteAllArcEdges = new HashSet<>(); + final private Set<GraphicArc> connectedArcs; + + public DeleteTransitionCommand(final GraphicTransition gTransition, final GraphicPetriNet gPetriNet) { + this.gTransition = gTransition; + this.gPetriNet = gPetriNet; + this.connectedArcs = gPetriNet.getConnectedGraphicArcs(gTransition); + for (final GraphicArc arc : this.connectedArcs) { + this.deleteAllArcEdges.add(new DeleteArcCommand(arc, gPetriNet)); + } + } + + @Override + public void execute() { + for (final Command deleteArc : this.deleteAllArcEdges) { + deleteArc.execute(); + } + this.gPetriNet.removeElement(this.gTransition); + this.gPetriNet.getPetriNet().removeAbstractTransition(this.gTransition.getTransition()); + } + + @Override + public void undo() { + final AbstractTransition transition = this.gPetriNet.getPetriNet().addAbstractTransition(); + transition.setLabel(this.gTransition.getLabel()); + this.deleteAllArcEdges.clear(); + this.gPetriNet.addElement(this.gTransition); + this.gTransition.setTransition(transition); + for (final GraphicArc arc : this.connectedArcs) { + if (arc.getSource() == this.gTransition) { + this.deleteAllArcEdges.add(new AddArcCommand(this.gPetriNet, this.gTransition, arc.getDestination())); + } + else { + this.deleteAllArcEdges.add(new AddArcCommand(this.gPetriNet, arc.getSource(), this.gTransition)); + } + } + for (final Command addArc : this.deleteAllArcEdges) { + addArc.execute(); + } + } + + @Override + public void redo() { + for (final Command addArc : this.deleteAllArcEdges) { + addArc.undo(); + } + this.gPetriNet.removeElement(this.gTransition); + this.gPetriNet.getPetriNet().removeAbstractTransition(this.gTransition.getTransition()); + } + + @Override + public String toString() { + return "Delete transition node"; + } +} diff --git a/pne-editor/src/org/pneditor/editor/commands/FireTransitionCommand.java b/pne-editor/src/org/pneditor/editor/commands/FireTransitionCommand.java new file mode 100644 index 0000000..6ea421e --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/FireTransitionCommand.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.util.Command; + +import logger.PNEditorLogger; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class FireTransitionCommand implements Command { + + final private GraphicTransition transition; + final private GraphicPetriNet gPetriNet; + final private Map<GraphicPlace,Integer> firedPlaces = new HashMap<>(); + + public FireTransitionCommand(final GraphicTransition gTransition, final GraphicPetriNet gPetriNet) { + this.transition = gTransition; + this.gPetriNet = gPetriNet; + } + + @Override + public void execute() { //TODO: Temporary solution to remove the undoFire from the PetriNet + for (final GraphicPlace place : this.gPetriNet.getPlaces()) { + this.firedPlaces.put(place, place.getPlace().getTokens()); + } + try { + this.gPetriNet.getPetriNet().fire(this.transition.getTransition()); + } catch (ResetArcMultiplicityException e) { + PNEditorLogger.severeLogs(e.getMessage()); + } + + final Iterator<Entry<GraphicPlace, Integer>> iter = this.firedPlaces.entrySet().iterator(); //to avoid ConcurrentModificationExceptions + while (iter.hasNext()) { + final Map.Entry<GraphicPlace, Integer> pair = iter.next(); + if (pair.getKey().getPlace().getTokens() == pair.getValue()) { + iter.remove(); + } + } + } + + @Override + public void undo() { + for (final Map.Entry<GraphicPlace, Integer> entry : this.firedPlaces.entrySet()) { + entry.getKey().getPlace().setTokens(entry.getValue()); + } + } + + @Override + public void redo() { + execute(); + } + + @Override + public String toString() { + return "Fire transition"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/MoveElementCommand.java b/pne-editor/src/org/pneditor/editor/commands/MoveElementCommand.java new file mode 100644 index 0000000..fbe88c8 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/MoveElementCommand.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import java.awt.Point; + +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class MoveElementCommand implements Command { + + private final GraphicElement element; + private final Point deltaPosition; + + public MoveElementCommand(final GraphicElement element, final Point deltaPosition) { + this.element = element; + this.deltaPosition = deltaPosition; + } + + @Override + public void execute() { + this.element.moveBy(this.deltaPosition.x, this.deltaPosition.y); + } + + @Override + public void undo() { + this.element.moveBy(-this.deltaPosition.x, -this.deltaPosition.y); + } + + @Override + public void redo() { + execute(); + } + + @Override + public String toString() { + return "Move element"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/MoveElementsCommand.java b/pne-editor/src/org/pneditor/editor/commands/MoveElementsCommand.java new file mode 100644 index 0000000..5bdbe95 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/MoveElementsCommand.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import java.awt.Point; +import java.util.HashSet; +import java.util.Set; + +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class MoveElementsCommand implements Command { + + private final Set<Command> moveElements = new HashSet<>(); + + public MoveElementsCommand(final Set<GraphicElement> elements, final Point deltaPosition) { + for (final GraphicElement element : elements) { + this.moveElements.add(new MoveElementCommand(element, deltaPosition)); + } + } + + @Override + public void execute() { + for (final Command moveElement : this.moveElements) { + moveElement.execute(); + } + } + + @Override + public void undo() { + for (final Command moveElement : this.moveElements) { + moveElement.undo(); + } + } + + @Override + public void redo() { + for (final Command moveElement : this.moveElements) { + moveElement.redo(); + } + } + + @Override + public String toString() { + if (this.moveElements.size() == 1) { + return this.moveElements.iterator().next().toString(); + } + return "Move elements"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/PasteCommand.java b/pne-editor/src/org/pneditor/editor/commands/PasteCommand.java new file mode 100644 index 0000000..8412541 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/PasteCommand.java @@ -0,0 +1,105 @@ +package org.pneditor.editor.commands; + +import java.awt.Point; +import java.awt.Rectangle; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.pneditor.editor.Root; +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicNode; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class PasteCommand implements Command { + + private final GraphicPetriNet gPetriNet; + private final Set<GraphicElement> elementsToCopy; + private Set<GraphicElement> elementsPasted; + private final Root root; + + public PasteCommand(final Set<GraphicElement> elementsToCopy, final GraphicPetriNet gPetriNet, final Root root) { + this.gPetriNet = gPetriNet; + this.elementsToCopy = elementsToCopy; + this.root = root; + } + + @Override + public void execute() { + this.elementsPasted = cloneElements(this.elementsToCopy); + this.gPetriNet.addAll(this.elementsPasted); + this.root.getSelection().addAll(this.elementsPasted); + final Point translation = calculateTranslationToCenter(this.elementsPasted, this.gPetriNet); + for (final GraphicElement element : this.elementsPasted) { + element.moveBy(translation.x, translation.y); + } + } + + @Override + public void undo() { + this.gPetriNet.removeAll(this.elementsPasted); + } + + @Override + public void redo() { + execute(); + } + + @Override + public String toString() { + return "Paste"; + } + + private Point calculateTranslationToCenter(final Set<GraphicElement> elements, final GraphicPetriNet petriNet) { + final Point viewTranslation = petriNet.getViewTranslation(); + final GraphicPetriNet tempPetriNet = new GraphicPetriNet(this.root.getCurrentModel()); + tempPetriNet.addAll(elements); + final Rectangle bounds = tempPetriNet.getBounds(); + + final Point result = new Point(); + result.translate(Math.round(-(float) bounds.getCenterX()), Math.round(-(float) bounds.getCenterY())); + result.translate(-viewTranslation.x, -viewTranslation.y); + return result; + } + + + private Set<GraphicElement> cloneElements(final Set<GraphicElement> copiedElements) { + final PetriNetInterface petriNet = this.gPetriNet.getPetriNet(); + final Map<GraphicNode, GraphicNode> nodes = new HashMap<>(); + final Set<GraphicElement> pastedElements = new HashSet<>(); + + for (final GraphicElement element : copiedElements) { + if (element.isNode()) { + GraphicNode gNodeClone; + final GraphicNode gNode = (GraphicNode) element; + if (gNode.isPlace()) { + gNodeClone = ((GraphicPlace) gNode).getClone(petriNet.clonePlace(((GraphicPlace) gNode).getPlace())); + } else { + gNodeClone = ((GraphicTransition) gNode).getClone(petriNet.cloneTransition(((GraphicTransition) gNode).getTransition())); + } + pastedElements.add(gNodeClone); + nodes.put(gNode, gNodeClone); + } + } + for (final GraphicElement element : copiedElements) { + if (!element.isNode()) { + final GraphicArc gArc = (GraphicArc) element; + final GraphicNode source = nodes.get(gArc.getSource()); + final GraphicNode destination = nodes.get(gArc.getDestination()); + pastedElements.add(gArc.getClone(petriNet.cloneArc(gArc.getArc(), source.getNode(), destination.getNode()),source,destination)); + } + } + return pastedElements; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/RemoveTokenCommand.java b/pne-editor/src/org/pneditor/editor/commands/RemoveTokenCommand.java new file mode 100644 index 0000000..9b99cf2 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/RemoveTokenCommand.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class RemoveTokenCommand implements Command { + + final private GraphicPlace gPlace; + + public RemoveTokenCommand(final GraphicPlace gPlace) { + this.gPlace = gPlace; + } + + @Override + public void execute() { + this.gPlace.getPlace().removeToken(); + } + + @Override + public void undo() { + this.gPlace.getPlace().addToken(); + } + + @Override + public void redo() { + execute(); + } + + @Override + public String toString() { + return "Remove token"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/SetArcInhibitCommand.java b/pne-editor/src/org/pneditor/editor/commands/SetArcInhibitCommand.java new file mode 100644 index 0000000..ddcc518 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/SetArcInhibitCommand.java @@ -0,0 +1,98 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.petrinet.AbstractPlace; +import org.pneditor.petrinet.AbstractTransition; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.petrinet.UnimplementedCaseException; +import org.pneditor.util.Command; + +import logger.PNEditorLogger; + +/** + * + * @author Amodez + */ +public class SetArcInhibitCommand implements Command { + + private final GraphicArc gArc; + private AbstractArc oldArc; + private AbstractArc newArc; + private final boolean isNotInhibitory; + private final GraphicPetriNet gPetriNet; + private PetriNetInterface petriNet; + + public SetArcInhibitCommand(final GraphicArc gArc, final GraphicPetriNet gPetriNet) { + this.gArc = gArc; + this.oldArc = gArc.getArc(); + this.gPetriNet = gPetriNet; + this.isNotInhibitory = !this.oldArc.isInhibitory(); + } + + @Override + public void execute() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotInhibitory) { + this.petriNet.removeAbstractArc(this.oldArc); + try { + if (this.oldArc.isReset()) { + this.newArc = this.petriNet.addInhibArc((AbstractPlace) this.oldArc.getSource(), + (AbstractTransition) this.oldArc.getDestination()); + } + if (this.oldArc.isRegular()) { + this.newArc = this.petriNet.addInhibArc((AbstractPlace) this.oldArc.getSource(), + (AbstractTransition) this.oldArc.getDestination()); + this.newArc.setMultiplicity(this.oldArc.getMultiplicity()); + } + } catch (ResetArcMultiplicityException e) { + // should not happen + PNEditorLogger.severeLogs(e.getMessage()); + } catch (UnimplementedCaseException e) { + // should not happen since we're manipulating new objects, except if a behavior + // is not implemented + PNEditorLogger.warningLogs(e.getMessage()); + } + this.gArc.setArc(this.newArc); + + } + + } + + @Override + public void undo() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotInhibitory) { + this.petriNet.removeAbstractArc(gArc.getArc()); + final AbstractNode source = gArc.getSource().getNode(); + final AbstractNode destination = gArc.getDestination().getNode(); + oldArc = this.petriNet.addArcAgain(this.oldArc, source, destination); + this.gArc.setArc(this.oldArc); + } + } + + @Override + public void redo() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotInhibitory) { + this.petriNet.removeAbstractArc(gArc.getArc()); + final AbstractNode source = gArc.getSource().getNode(); + final AbstractNode destination = gArc.getDestination().getNode(); + newArc = this.petriNet.addArcAgain(this.newArc, source, destination); + this.gArc.setArc(this.newArc); + } + } + + @Override + public String toString() { + return "Set arc type to inhibitor arc"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/SetArcMultiplicityCommand.java b/pne-editor/src/org/pneditor/editor/commands/SetArcMultiplicityCommand.java new file mode 100644 index 0000000..3ec4385 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/SetArcMultiplicityCommand.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.util.Command; + +import logger.PNEditorLogger; + +/** + * Set multiplicity to clicked arc + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class SetArcMultiplicityCommand implements Command { + + private final GraphicArc gArc; + private final int newMultiplicity; + private int oldMultiplicity; + + public SetArcMultiplicityCommand(final GraphicArc gArc, final int newMultiplicity) { + this.gArc = gArc; + this.newMultiplicity = newMultiplicity; + } + + @Override + public void execute() { + try { + this.oldMultiplicity = this.gArc.getArc().getMultiplicity(); + this.gArc.getArc().setMultiplicity(this.newMultiplicity); + } catch (ResetArcMultiplicityException e) { + PNEditorLogger.severeLogs(e.getMessage()); + } + } + + @Override + public void undo() { + try { + this.gArc.getArc().setMultiplicity(this.oldMultiplicity); + } catch (ResetArcMultiplicityException e) { + PNEditorLogger.severeLogs(e.getMessage()); + } + } + + @Override + public void redo() { + execute(); + } + + @Override + public String toString() { + return "Set arc multiplicity"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/SetArcRegularCommand.java b/pne-editor/src/org/pneditor/editor/commands/SetArcRegularCommand.java new file mode 100644 index 0000000..f1c1531 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/SetArcRegularCommand.java @@ -0,0 +1,86 @@ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.petrinet.UnimplementedCaseException; +import org.pneditor.util.Command; + +import logger.PNEditorLogger; + +public class SetArcRegularCommand implements Command { + + private final GraphicArc gArc; + private PetriNetInterface petriNet; + private AbstractArc oldArc; + private AbstractArc newArc; + private final boolean isNotRegular; + private final GraphicPetriNet gPetriNet; + + public SetArcRegularCommand(final GraphicArc gArc, final GraphicPetriNet gPetriNet) { + this.gArc = gArc; + this.gPetriNet = gPetriNet; + this.oldArc = gArc.getArc(); + this.isNotRegular = !this.oldArc.isRegular(); + } + + @Override + public void execute() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotRegular && this.oldArc.isSourceAPlace()) { + this.petriNet.removeAbstractArc(this.oldArc); + try { + if (this.oldArc.isReset()) { + this.newArc = this.petriNet.addRegArc(this.oldArc.getSource(), + this.oldArc.getDestination()); + } + if (this.oldArc.isInhibitory()) { + this.newArc = this.petriNet.addRegArc(this.oldArc.getSource(), + this.oldArc.getDestination()); + this.newArc.setMultiplicity(this.oldArc.getMultiplicity()); + } + } catch (ResetArcMultiplicityException e) { + // should not happen + PNEditorLogger.severeLogs(e.getMessage()); + } catch (UnimplementedCaseException e) { + // should not happen since we're manipulating new objects, except if a behavior + // is not implemented + PNEditorLogger.warningLogs(e.getMessage()); + } + this.gArc.setArc(this.newArc); + } + } + + @Override + public void undo() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotRegular) { + this.petriNet.removeAbstractArc(gArc.getArc()); + final AbstractNode source = gArc.getSource().getNode(); + final AbstractNode destination = gArc.getDestination().getNode(); + oldArc = this.petriNet.addArcAgain(this.oldArc, source, destination); + this.gArc.setArc(this.oldArc); + } + } + + @Override + public void redo() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotRegular) { + this.petriNet.removeAbstractArc(gArc.getArc()); + final AbstractNode source = gArc.getSource().getNode(); + final AbstractNode destination = gArc.getDestination().getNode(); + newArc = this.petriNet.addArcAgain(this.newArc, source, destination); + this.gArc.setArc(this.newArc); + } + } + + @Override + public String toString() { + return "Set arc type to reset arc"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/SetArcResetCommand.java b/pne-editor/src/org/pneditor/editor/commands/SetArcResetCommand.java new file mode 100644 index 0000000..2894efe --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/SetArcResetCommand.java @@ -0,0 +1,81 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.petrinet.AbstractPlace; +import org.pneditor.petrinet.AbstractTransition; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.petrinet.UnimplementedCaseException; +import org.pneditor.util.Command; + +import logger.PNEditorLogger; + +/** + * + * @author jan.tancibok + */ +public class SetArcResetCommand implements Command { + + private final GraphicArc gArc; + private PetriNetInterface petriNet; + private AbstractArc oldArc; + private AbstractArc newArc; + private final boolean isNotReset; + private final GraphicPetriNet gPetriNet; + + + public SetArcResetCommand(final GraphicArc gArc, final GraphicPetriNet gPetriNet) { + this.gArc = gArc; + this.oldArc = gArc.getArc(); + this.gPetriNet = gPetriNet; + this.isNotReset = !this.oldArc.isReset(); + } + + @Override + public void execute() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotReset) { + this.petriNet.removeAbstractArc(this.oldArc); + try { + this.newArc = this.petriNet.addResArc((AbstractPlace) this.oldArc.getSource(), (AbstractTransition) this.oldArc.getDestination()); + } catch (UnimplementedCaseException e) { + PNEditorLogger.infoLogs(e.getMessage()); // should not happen + } + this.gArc.setArc(this.newArc); + } + } + + @Override + public void undo() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotReset) { + this.petriNet.removeAbstractArc(gArc.getArc()); + final AbstractNode source = gArc.getSource().getNode(); + final AbstractNode destination = gArc.getDestination().getNode(); + oldArc = this.petriNet.addArcAgain(this.oldArc, source, destination); + this.gArc.setArc(this.oldArc); + } + } + + @Override + public void redo() { + this.petriNet = this.gPetriNet.getPetriNet(); + if (this.isNotReset) { + this.petriNet.removeAbstractArc(gArc.getArc()); + final AbstractNode source = gArc.getSource().getNode(); + final AbstractNode destination = gArc.getDestination().getNode(); + newArc = this.petriNet.addArcAgain(this.newArc, source, destination); + this.gArc.setArc(this.newArc); + } + } + @Override + public String toString() { + return "Set arc type to reset arc"; + } +} diff --git a/pne-editor/src/org/pneditor/editor/commands/SetEdgeZigzagPointCommand.java b/pne-editor/src/org/pneditor/editor/commands/SetEdgeZigzagPointCommand.java new file mode 100644 index 0000000..bbaacef --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/SetEdgeZigzagPointCommand.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import java.awt.Point; +import java.util.List; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.util.Command; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class SetEdgeZigzagPointCommand implements Command { + + private final GraphicArc gArc; + private final Point startingLocation; + private final Point targetLocation; + private final List<Point> oldBreakPoints; + + public SetEdgeZigzagPointCommand(final GraphicArc gArc, final Point startingLocation, final Point targetLocation) { + this.gArc = gArc; + this.startingLocation = new Point(startingLocation); + this.targetLocation = new Point(targetLocation); + this.oldBreakPoints = this.gArc.getBreakPointsCopy(); + } + + @Override + public void execute() { + this.gArc.addOrGetBreakPoint(new Point(this.startingLocation)).setLocation(this.targetLocation); + this.gArc.cleanupUnecessaryBreakPoints(); + } + + @Override + public void undo() { + this.gArc.setBreakPoints(this.oldBreakPoints); + } + + @Override + public void redo() { + execute(); + } + + @Override + public String toString() { + return "Set arc break point"; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/SetLabelCommand.java b/pne-editor/src/org/pneditor/editor/commands/SetLabelCommand.java new file mode 100644 index 0000000..9e58c6a --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/SetLabelCommand.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicNode; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.util.Command; + +/** + * Set label to clicked element + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class SetLabelCommand implements Command { + + private AbstractNode node; + private String newLabel; + private String oldLabel; + private GraphicNode gNode; + + public SetLabelCommand(GraphicNode gNode, String newLabel) { + this.gNode = gNode; + this.newLabel = newLabel; + this.oldLabel = gNode.getLabel(); + } + + @Override + public void execute() { + this.node = this.gNode.getNode(); + this.node.setLabel(this.newLabel); + } + + @Override + public void undo() { + this.node = this.gNode.getNode(); + this.node.setLabel(this.oldLabel); + } + + @Override + public void redo() { + execute(); + } + + @Override + public String toString() { + return "Set label to " + this.newLabel; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/commands/SetTokensCommand.java b/pne-editor/src/org/pneditor/editor/commands/SetTokensCommand.java new file mode 100644 index 0000000..f119038 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/commands/SetTokensCommand.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.commands; + +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.util.Command; + +/** + * Set tokens to clicked place node + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class SetTokensCommand implements Command { + + private final GraphicPlace gPlace; + + private final int newValue; + private final int oldValue; + + public SetTokensCommand(final GraphicPlace gPlace, final int tokens) { + this.gPlace = gPlace; + this.newValue = tokens; + this.oldValue = gPlace.getPlace().getTokens(); + } + + @Override + public void execute() { + this.gPlace.getPlace().setTokens(this.newValue); + } + + @Override + public void undo() { + this.gPlace.getPlace().setTokens(this.oldValue); + } + + @Override + public void redo() { + this.gPlace.getPlace().setTokens(this.newValue); + } + + @Override + public String toString() { + return "Set tokens"; + } +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/EpsFileType.java b/pne-editor/src/org/pneditor/editor/filechooser/EpsFileType.java new file mode 100644 index 0000000..c2ac147 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/EpsFileType.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileNotFoundException; +import javax.swing.Icon; + +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.EPSGraphics2D; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class EpsFileType extends FileType { + + @Override + public String getExtension() { + return "eps"; + } + + @Override + public String getName() { + return "Encapsulated PostScript"; + } + + @Override + public Icon getIcon() { + return GraphicsTools.getIcon(PNEConstantsConfiguration.EPS); + } + + @Override + public GraphicPetriNet load(File file, String model) throws FileTypeException { + throw new UnsupportedOperationException("Loading not supported."); + } + + @Override + public BufferedImage getPreview(final File file) { + return null; + } + + @Override + public void save(final GraphicPetriNet petriNet, final File file) throws FileTypeException { + try { + final EPSGraphics2D epsGraphics2d = new EPSGraphics2D(); + for (final GraphicElement element : petriNet.getElements()) { + element.draw(epsGraphics2d, petriNet.getPetriNet()); + + } + epsGraphics2d.writeToFile(file); + } catch (FileNotFoundException ex) { + throw new FileTypeException(ex.getMessage()); + } + } + + +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/FileChooserDialog.java b/pne-editor/src/org/pneditor/editor/filechooser/FileChooserDialog.java new file mode 100644 index 0000000..07c8a9d --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/FileChooserDialog.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.io.File; +import javax.swing.JFileChooser; +import javax.swing.filechooser.FileFilter; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class FileChooserDialog extends JFileChooser { + + private final Sidebar sidebar = new Sidebar(this); + + public FileChooserDialog() { + super(); + setFileView(new FileIconView()); + setAccessory(this.sidebar); + } + + @Override + public File getSelectedFile() { + final File file = super.getSelectedFile(); + if (file == null) { + return null; + } else if (file.exists() && getFileFilter().getDescription().equals("All Files")) { + return file; + } else if (getFileFilter().accept(file)) { + return file; + } else { + return new File(file.getAbsolutePath() + "." + ((FileType) getFileFilter()).getExtension()); + } + } + + @Override + public void addChoosableFileFilter(final FileFilter filter) { + super.addChoosableFileFilter(filter); + if (getChoosableFileFilters().length > 1) { // first filter is always "All files" + setFileFilter(getChoosableFileFilters()[1]); + } + } + + public Sidebar getSidebar() { + return this.sidebar; + } +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/FileIconView.java b/pne-editor/src/org/pneditor/editor/filechooser/FileIconView.java new file mode 100644 index 0000000..174670c --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/FileIconView.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.io.File; +import javax.swing.Icon; +import javax.swing.filechooser.FileView; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class FileIconView extends FileView { + + @Override + public Icon getIcon(final File file) { + if (file.isDirectory()) { + return super.getIcon(file); + } + final FileType fileType = FileType.getAcceptingFileType(file, FileType.getAllFileTypes()); + if (fileType != null) { + return fileType.getIcon(); + } + return super.getIcon(file); + } + +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/FileType.java b/pne-editor/src/org/pneditor/editor/filechooser/FileType.java new file mode 100644 index 0000000..0b5b906 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/FileType.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import javax.swing.Icon; +import javax.swing.filechooser.FileFilter; + +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.StringTools; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public abstract class FileType extends FileFilter { + + public static Set<FileType> getAllFileTypes() { + final Set<FileType> allFileTypes = new HashSet<>(); + allFileTypes.add(new EpsFileType()); + allFileTypes.add(new PflowFileType()); + allFileTypes.add(new PngFileType()); + allFileTypes.add(new ViptoolPnmlFileType()); + return allFileTypes; + } + + public abstract String getExtension(); + + public abstract String getName(); + + public abstract void save(GraphicPetriNet petriNet, File file) throws FileTypeException; + + public abstract GraphicPetriNet load(File file, String model) throws FileTypeException; + + public abstract Icon getIcon(); + + public BufferedImage getPreview(File file) { + try { + final GraphicPetriNet gPetriNet = load(file, null); //TODO: may need to add the model for the load if models are different + return gPetriNet.getPreview(); + } catch (FileTypeException ex) { + return null; + } + } + + @Override + public String getDescription() { + return getName() + " (*." + getExtension() + ")"; + } + + @Override + public boolean accept(final File file) { + if (file.isDirectory()) { //Show also directories in the filters + return true; + } + + final String extension = StringTools.getExtension(file); + return extension != null && extension.equals(getExtension()); + } + + public static FileType getAcceptingFileType(final File file, final Collection<FileType> fileTypes) { + for (final FileType fileType : fileTypes) { + if (fileType.accept(file)) { + return fileType; + } + } + return null; + } +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/FileTypeException.java b/pne-editor/src/org/pneditor/editor/filechooser/FileTypeException.java new file mode 100644 index 0000000..6f87508 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/FileTypeException.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class FileTypeException extends Exception { + + public FileTypeException(final String message) { + super(message); + } + +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/PflowFileType.java b/pne-editor/src/org/pneditor/editor/filechooser/PflowFileType.java new file mode 100644 index 0000000..d48edea --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/PflowFileType.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.io.File; +import java.io.IOException; +import javax.swing.Icon; +import javax.xml.bind.JAXBException; + +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.save.xml.DocumentExporter; +import org.pneditor.save.xml.DocumentImporter; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class PflowFileType extends FileType { + + @Override + public String getName() { + return "PetriFlow"; + } + + @Override + public String getExtension() { + return "pflow"; + } + + @Override + public Icon getIcon() { + return GraphicsTools.getIcon(PNEConstantsConfiguration.PFLOW); + } + + + @Override + public void save(final GraphicPetriNet petriNet, final File file) throws FileTypeException { + try { + new DocumentExporter(petriNet).writeToFile(file); + } catch (JAXBException ex) { + if (!file.exists()) { + throw new FileTypeException("File not found."); + } else if (file.canRead()) { + throw new FileTypeException("Selected file is not compatible."); + } else { + throw new FileTypeException("File can not be read."); + } + } + } + + @Override + public GraphicPetriNet load(final File file, final String model) throws FileTypeException { + try { + final GraphicPetriNet petriNet = new DocumentImporter().readFromFile(file, model); + petriNet.setViewTranslationToCenter(); + return petriNet; + } catch (JAXBException ex) { + if (!file.exists()) { + throw new FileTypeException("File not found."); + } else if (file.canRead()) { + throw new FileTypeException("Selected file is not compatible."); + } else { + throw new FileTypeException("File can not be read."); + } + } catch (IOException ex) { + throw new FileTypeException(ex.getMessage()); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/PngFileType.java b/pne-editor/src/org/pneditor/editor/filechooser/PngFileType.java new file mode 100644 index 0000000..eef2190 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/PngFileType.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.swing.Icon; + +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class PngFileType extends FileType { + + @Override + public String getExtension() { + return "png"; + } + + @Override + public String getName() { + return "Portable Network Graphics"; + } + + @Override + public Icon getIcon() { + return GraphicsTools.getIcon(PNEConstantsConfiguration.PNG); + } + + @Override + public GraphicPetriNet load(final File file, final String model) throws FileTypeException { + throw new UnsupportedOperationException("Loading not supported."); + } + + @Override + public BufferedImage getPreview(final File file) { + BufferedImage image = null; + try { + image = ImageIO.read(file); + } catch (IOException ex) { + } + return image; + } + + @Override + public void save(final GraphicPetriNet petriNet, final File file) throws FileTypeException { + try { + final BufferedImage bufferedImage = petriNet.getPreview(); + ImageIO.write(bufferedImage, "png", file); + } catch (IOException ex) { + throw new FileTypeException(ex.getMessage()); + } + } + +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/Preview.java b/pne-editor/src/org/pneditor/editor/filechooser/Preview.java new file mode 100644 index 0000000..427664b --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/Preview.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.SystemColor; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JPanel; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class Preview extends JPanel implements PropertyChangeListener { + + /** + * + */ + private static final long serialVersionUID = 6657841190121747227L; + private ImageIcon thumbnail; + private File file; + public static final int PREFERRED_WIDTH = 200; + public static final int PREFERRED_HEIGHT = 200; + + public Preview(final JFileChooser fileChooser) { + super(); + setPreferredSize(new Dimension(Preview.PREFERRED_WIDTH, Preview.PREFERRED_HEIGHT)); + fileChooser.addPropertyChangeListener(this); + } + + @Override + public void propertyChange(final PropertyChangeEvent e) { + final String propertyName = e.getPropertyName(); + boolean update = false; + + //If the directory changed, don't show an image. + if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(propertyName)) { + this.file = null; + update = true; + + //If a file became selected, find out which one. + } else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(propertyName)) { + this.file = (File) e.getNewValue(); + update = true; + } + + //Update the preview accordingly. + if (update) { + this.thumbnail = null; + if (isShowing()) { + loadImage(); + repaint(); + } + } + } + + private void loadImage() { + if (this.file == null) { + this.thumbnail = null; + return; + } + final FileType fileType = FileType.getAcceptingFileType(this.file, FileType.getAllFileTypes()); + if (fileType == null) { + this.thumbnail = null; + return; + } + final BufferedImage image = fileType.getPreview(this.file); + if (image == null) { + this.thumbnail = null; + return; + } + if (image.getWidth() > image.getHeight()) { + this.thumbnail = new ImageIcon(image.getScaledInstance(Preview.PREFERRED_WIDTH, -1, Image.SCALE_SMOOTH), ""); + } else { + this.thumbnail = new ImageIcon(image.getScaledInstance(-1, Preview.PREFERRED_HEIGHT, Image.SCALE_SMOOTH), ""); + } + + } + + @Override + protected void paintComponent(final Graphics g) { + if (this.thumbnail == null) { + loadImage(); + setBackground(SystemColor.control); + super.paintComponent(g); + } else { + setBackground(Color.white); + super.paintComponent(g); + int x = getWidth() / 2 - this.thumbnail.getIconWidth() / 2; + int y = getHeight() / 2 - this.thumbnail.getIconHeight() / 2; + + if (y < 0) { + y = 0; + } + if (x < 0) { + x = 0; + } + this.thumbnail.paintIcon(this, g, x, y); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/Sidebar.java b/pne-editor/src/org/pneditor/editor/filechooser/Sidebar.java new file mode 100644 index 0000000..e233d82 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/Sidebar.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +@SuppressWarnings("serial") +public class Sidebar extends JPanel implements ActionListener, PropertyChangeListener { + + private final JFileChooser fileChooser; + private final JButton delete = new JButton("Delete file", GraphicsTools.getIcon(PNEConstantsConfiguration.DELETE16)); + + public Sidebar(final JFileChooser fileChooser) { + super(); + this.fileChooser = fileChooser; + final Preview preview = new Preview(fileChooser); + setLayout(new BorderLayout()); + add(preview, BorderLayout.CENTER); + add(this.delete, BorderLayout.NORTH); + this.delete.addActionListener(this); + fileChooser.addPropertyChangeListener(this); + } + + @Override + public void actionPerformed(final ActionEvent e) { + if (e.getSource() == this.delete) { + final File selectedFile = this.fileChooser.getSelectedFile(); + if (selectedFile != null && JOptionPane.showOptionDialog( + this.fileChooser, + "Delete " + selectedFile.getName() + "?\nThis action is irreversible!", + "Delete", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + new String[]{"Delete permanently", "Cancel"}, + "Cancel") == JOptionPane.YES_OPTION) { + selectedFile.delete(); + this.fileChooser.setSelectedFile(new File("")); + this.fileChooser.rescanCurrentDirectory(); + } + } + } + + @Override + public void propertyChange(final PropertyChangeEvent evt) { + this.delete.setEnabled(this.fileChooser.getSelectedFile() != null); + } + +} diff --git a/pne-editor/src/org/pneditor/editor/filechooser/ViptoolPnmlFileType.java b/pne-editor/src/org/pneditor/editor/filechooser/ViptoolPnmlFileType.java new file mode 100644 index 0000000..764ffa2 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/filechooser/ViptoolPnmlFileType.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.filechooser; + +import java.io.File; +import java.io.IOException; +import javax.swing.Icon; +import javax.xml.bind.JAXBException; + +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.save.xml.DocumentExporter; +import org.pneditor.save.xml.DocumentImporter; +import org.pneditor.util.GraphicsTools; +import org.pneditor.PNEConstantsConfiguration; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class ViptoolPnmlFileType extends FileType { + + @Override + public String getName() { + return "PNML Viptool dialect"; + } + + @Override + public String getExtension() { + return "pnml"; + } + + @Override + public Icon getIcon() { + return GraphicsTools.getIcon(PNEConstantsConfiguration.PNML); + } + + + @Override + public void save(final GraphicPetriNet petriNet, final File file) throws FileTypeException { + try { + new DocumentExporter(petriNet).writeToFile(file); + } catch (JAXBException ex) { + if (!file.exists()) { + throw new FileTypeException("File not found."); + } else if (file.canRead()) { + throw new FileTypeException("Selected file is not compatible."); + } else { + throw new FileTypeException("File can not be read."); + } + } + } + + @Override + public GraphicPetriNet load(final File file, final String model) throws FileTypeException { + try { + final GraphicPetriNet petriNet = new DocumentImporter().readFromFile(file, model); + petriNet.setViewTranslationToCenter(); + return petriNet; + } catch (JAXBException ex) { + if (!file.exists()) { + throw new FileTypeException("File not found."); + } else if (file.canRead()) { + throw new FileTypeException("Selected file is not compatible."); + } else { + throw new FileTypeException("File can not be read."); + } + } catch (IOException ex) { + throw new FileTypeException(ex.getMessage()); + } + } +} diff --git a/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicArc.java b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicArc.java new file mode 100644 index 0000000..bfa17fe --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicArc.java @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.gpetrinet; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Point; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.util.GraphicsTools; +import org.pneditor.util.GraphicsTools.HorizontalAlignment; +import org.pneditor.util.GraphicsTools.VerticalAlignment; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class GraphicArc extends GraphicElement { + + private AbstractArc arc; + private final List<Point> breakPoints = new LinkedList<>(); + private GraphicNode destination; + private GraphicNode source; + + public GraphicArc() { + super(); + } + + public GraphicArc(final AbstractArc arc) { + super(); + this.arc = arc; + } + + public GraphicArc getClone(final AbstractArc arcToClone, final GraphicNode newSource, final GraphicNode newDestination) { + final GraphicArc gArcClone = new GraphicArc(arcToClone); + gArcClone.source = newSource; + gArcClone.destination = newDestination; + return gArcClone; + } + + public AbstractArc getArc() { + return this.arc; + } + + @Override + public boolean isNode() { + return false; + } + + public List<Point> getBreakPoints() { + return Collections.unmodifiableList(this.breakPoints); + } + + public List<Point> getBreakPointsCopy() { + final List<Point> newBreakPoints = new LinkedList<>(); + for (final Point breakPoint : this.breakPoints) { + newBreakPoints.add(breakPoint.getLocation()); // getLocation because Point is mutable + } + return newBreakPoints; + } + + public void setBreakPoints(final List<Point> breakPoints) { + this.breakPoints.clear(); + for (final Point breakPoint : breakPoints) { + this.breakPoints.add(breakPoint.getLocation()); // getLocation because Point is mutable + } + } + + public void draw(final Graphics g) { + this.color = Color.BLACK; + g.setColor(this.color); + drawSegmentedLine(g); + final Point arrowTip = computeArrowTipPoint(); + if (this.arc.isReset()) { + drawArrowDouble(g, arrowTip); + } else { + try { + if (this.arc.getMultiplicity() >= 2) { + drawMultiplicityLabel(g, arrowTip, this.arc.getMultiplicity()); + } + } catch (ResetArcMultiplicityException e) { + // not happening + } + if (this.arc.isInhibitory()) { + drawCircle(g, arrowTip); + } else { + drawArrow(g, arrowTip); + } + } + + } + + @Override + public void draw(final Graphics g, final PetriNetInterface petriNet) { + draw(g); + } + + protected void drawArrow(final Graphics g, final Point arrowTip) { + final Point lastBreakPoint = getLastBreakPoint(); + GraphicsTools.drawArrow(g, lastBreakPoint.x, lastBreakPoint.y, arrowTip.x, arrowTip.y); + } + + protected void drawArrowDouble(final Graphics g, final Point arrowTip) { + final Point lastBreakPoint = getLastBreakPoint(); + /* + * int dx =lastBreakPoint.x - arrowTip.x; int dy =lastBreakPoint.y - arrowTip.y; + * int px = 8; int py = (int) ((dy/dx) * px); GraphicsTools.drawArrow(g, + * lastBreakPoint.x, lastBreakPoint.y, arrowTip.x, arrowTip.y); + */ + GraphicsTools.drawArrowDouble(g, lastBreakPoint.x, lastBreakPoint.y, arrowTip.x, arrowTip.y); + } + + protected void drawCircle(final Graphics g, final Point arrowTip) { + final Point lastBreakPoint = getLastBreakPoint(); + GraphicsTools.drawCircle(g, lastBreakPoint.x, lastBreakPoint.y, arrowTip.x, arrowTip.y); + } + + protected void drawMultiplicityLabel(final Graphics g, final Point arrowTip, final int multiplicity) { + final Point labelPoint = getLabelPoint(arrowTip); + GraphicsTools.drawString(g, Integer.toString(multiplicity), labelPoint.x, labelPoint.y, + HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM); + } + + protected void drawSegmentedLine(final Graphics g) { + g.setColor(this.color); + Point previous = getStart(); + for (final Point breakPoint : getBreakPoints()) { + g.drawLine(previous.x, previous.y, breakPoint.x, breakPoint.y); + previous = breakPoint; + } + g.drawLine(previous.x, previous.y, getEnd().x, getEnd().y); + } + + protected final Point computeArrowTipPoint() { + Point arrowTip = new Point(getEnd()); + if (getDestination() != null) { // Thanks to http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html + int x0 = getLastBreakPoint().x; + int y0 = getLastBreakPoint().y; + final int x1 = getEnd().x; + final int y1 = getEnd().y; + + int dy = y1 - y0; + int dx = x1 - x0; + int stepx, stepy; + + if (dy < 0) { + dy = -dy; + stepy = -1; + } else { + stepy = 1; + } + if (dx < 0) { + dx = -dx; + stepx = -1; + } else { + stepx = 1; + } + dy <<= 1; + dx <<= 1; + + if (dx > dy) { + int fraction = dy - (dx >> 1); + while (x0 != x1) { + if (fraction >= 0) { + y0 += stepy; + fraction -= dx; + } + x0 += stepx; + fraction += dy; + if (getDestination().containsPoint(x0, y0)) { + return arrowTip; + } + arrowTip = new Point(x0, y0); + } + } else { + int fraction = dx - (dy >> 1); + while (y0 != y1) { + if (fraction >= 0) { + x0 += stepx; + fraction -= dy; + } + y0 += stepy; + fraction += dx; + if (getDestination().containsPoint(x0, y0)) { + return arrowTip; + } + arrowTip = new Point(x0, y0); + } + } + } + return arrowTip; + } + + protected Point getLastBreakPoint() { + Point last = getStart(); + for (final Point breakPoint : this.breakPoints) { + last = breakPoint; + } + return last; + } + + protected Point getLabelPoint(final Point arrowTip) { + final Point labelPoint = new Point(); + if (this.breakPoints.isEmpty()) { + labelPoint.x = getStart().x + (arrowTip.x - getStart().x) * 2 / 3; + labelPoint.y = getStart().y + (arrowTip.y - getStart().y) * 2 / 3 - 3; + } else { + final Point lastBreakPoint = this.breakPoints.get(this.breakPoints.size() - 1); + labelPoint.x = lastBreakPoint.x + (arrowTip.x - lastBreakPoint.x) * 1 / 2; + labelPoint.y = lastBreakPoint.y + (arrowTip.y - lastBreakPoint.y) * 1 / 2 - 3; + } + return labelPoint; + } + + public GraphicNode getDestination() { + return this.destination; + } + + public void setDestination(final GraphicNode destination) { + this.destination = destination; + } + + public GraphicNode getSource() { + return this.source; + } + + public void setSource(final GraphicNode source) { + this.source = source; + } + + public static final int NEARTOLERANCE = 10; + + @Override + public boolean containsPoint(final int x, final int y) { + final Point testPos = new Point(x, y); + Point previous = getStart(); + for (final Point breakPoint : this.breakPoints) { + if (GraphicsTools.isPointNearSegment(previous, breakPoint, testPos, NEARTOLERANCE)) { + return true; + } + previous = breakPoint; + } + return GraphicsTools.isPointNearSegment(previous, getEnd(), testPos, NEARTOLERANCE); + } + + public Point addOrGetBreakPoint(final Point newPoint) { + for (final Point breakPoint : this.breakPoints) { + if (GraphicsTools.isPointNearPoint(newPoint, breakPoint, NEARTOLERANCE)) { + return breakPoint; + } + } + + if (this.breakPoints.isEmpty()) { + this.breakPoints.add(newPoint); + } else { + Point previous = getStart(); + for (int i = 0; i < this.breakPoints.size(); i++) { + if (GraphicsTools.isPointNearSegment(previous, this.breakPoints.get(i), newPoint, NEARTOLERANCE)) { + this.breakPoints.add(i, newPoint); + return newPoint; + } + previous = this.breakPoints.get(i); + } + if (GraphicsTools.isPointNearSegment(previous, getEnd(), newPoint, NEARTOLERANCE)) { + this.breakPoints.add(newPoint); + } + } + return newPoint; + } + + public void addDistantBreakPointToEnd(final Point newPoint) { + this.breakPoints.add(newPoint); + } + + public void addDistantBreakPointToBeginning(final Point newPoint) { + this.breakPoints.add(0, newPoint); + } + + public void cleanupUnecessaryBreakPoints() { + Point previous = getStart(); + for (int i = 0; i < this.breakPoints.size(); i++) { + final Point current = this.breakPoints.get(i); + final Point next = i < (this.breakPoints.size() - 1) ? this.breakPoints.get(i + 1) : getEnd(); + final int tolerance = Math.round(0.1f * (float) previous.distance(next)); + if (GraphicsTools.isPointNearSegment(previous, next, current, tolerance)) { + this.breakPoints.remove(i--); + } else { + previous = this.breakPoints.get(i); + } + } + } + + @Override + public Point getStart() { + return getSource() == null ? super.getStart() : getSource().getCenter(); + } + + @Override + public Point getEnd() { + return getDestination() == null ? super.getEnd() : getDestination().getCenter(); + } + + @Override + public boolean isPlace() { + return false; + } + + @Override + public boolean isTransition() { + return false; + } + + public void setArc(final AbstractArc arc) { + this.arc = arc; + } + +} diff --git a/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicElement.java b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicElement.java new file mode 100644 index 0000000..bb7f85e --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicElement.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.gpetrinet; + +import java.awt.*; + +import org.pneditor.petrinet.PetriNetInterface; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public abstract class GraphicElement { + + private Point start = new Point(); + private Point end = new Point(); + private Point center = new Point(); + + protected Color color = Color.black; + protected Color highlightColor; + + + public Point getStart() { + if (this.start == null) { + this.start = new Point(); + } + return this.start; + } + + public Point getEnd() { + if (this.end == null) { + this.end = new Point(); + } + return this.end; + } + + public void setStart(final int x, final int y) { + if (this.start == null) { + this.start = new Point(); + } + this.start.x = x; + this.start.y = y; + } + + public void setEnd(final int x, final int y) { + if (this.end == null) { + this.end = new Point(); + } + this.end.x = x; + this.end.y = y; + } + + public int getWidth() { + return Math.abs(getEnd().x - getStart().x); + } + + public int getHeight() { + return Math.abs(getEnd().y - getStart().y); + } + + private int getCenterX() { + return getStart().x + (getEnd().x - getStart().x) / 2; + } + + private int getCenterY() { + return getStart().y + (getEnd().y - getStart().y) / 2; + } + + public Point getCenter() { + if (this.center == null) { + this.center = new Point(); + } + if (this.center.x != getCenterX()) { + this.center.x = getCenterX(); + } + if (this.center.y != getCenterY()) { + this.center.y = getCenterY(); + } + return this.center; + } + + public void setCenter(final int x, final int y) { + moveBy(x - getCenter().x, y - getCenter().y); + } + + public void setCenter(final Point center) { + setCenter(center.x, center.y); + } + + public void setSize(final int width, final int height) { + final Point prevCenter = getCenter(); + setEnd(getStart().x + width, getStart().y + height); + setCenter(prevCenter.x, prevCenter.y); + } + + public void moveBy(final int dx, final int dy) { + setStart(getStart().x + dx, getStart().y + dy); + setEnd(getEnd().x + dx, getEnd().y + dy); + } + + public void setColor(final Color color) { + this.color = color; + } + + public Color getColor() { + return this.color; + } + + public void setHighlightColor(final Color color) { + this.highlightColor = color; + } + + public Color getHighlightColor() { + return highlightColor; + } + + public boolean containsPoint(final int x, final int y) { + final int l = Math.min(getStart().x, getEnd().x); + final int t = Math.min(getStart().y, getEnd().y); + final int w = Math.abs(getWidth()); + final int h = Math.abs(getHeight()); + return x >= l && x < l + w && y >= t && y < t + h; + + } + + public abstract void draw(Graphics g, PetriNetInterface petriNet); + + public abstract boolean isNode(); + + public abstract boolean isPlace(); + + public abstract boolean isTransition(); + +} diff --git a/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicNode.java b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicNode.java new file mode 100644 index 0000000..1651ced --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicNode.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.gpetrinet; + +import java.awt.Graphics; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.util.GraphicsTools; +import org.pneditor.util.GraphicsTools.HorizontalAlignment; +import org.pneditor.util.GraphicsTools.VerticalAlignment; + +/** + * Transition, Place, ReferencePlace, Subnet are subclasses of Node + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public abstract class GraphicNode extends GraphicElement { + + + public GraphicNode() { + super(); + setSize(32, 32); + } + + protected void drawLabel(final Graphics g) { + if (getLabel() != null && !getLabel().equals("")) { + GraphicsTools.drawString(g, getLabel(), getCenter().x, getEnd().y, + HorizontalAlignment.CENTER, VerticalAlignment.TOP); + } + } + + public abstract String getLabel(); + + public abstract AbstractNode getNode(); + + @Override + public boolean isNode() { + return true; + } +} + diff --git a/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicPetriNet.java b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicPetriNet.java new file mode 100644 index 0000000..2ce4413 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicPetriNet.java @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.gpetrinet; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import org.pneditor.util.CachedGraphics2D; + +import logger.PNEditorLogger; + +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.PetriNetInterface; + +/** + * PetriNet class stores reference to the root subnet and manages a view of + * currently opened subnet in form of a stack. Default view is only the root + * subnet opened. Opening and closing subnets does not influence anything other + * and serves only for informational purposes. + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class GraphicPetriNet { + + private final List<GraphicElement> elements = new LinkedList<>(); + private Point viewTranslation = new Point(0, 0); + private PetriNetInterface petriNet; + private final String modelPath = "org.pneditor.petrinet.adapters."; + private String model = "initial"; + private final String modelAdapterPath = ".PetriNetAdapter"; + + /** + * Constructor. Creates a new Petri net with empty root subnet. + */ + public GraphicPetriNet() { + try { + this.petriNet = (PetriNetInterface) Class.forName(this.modelPath + this.model + this.modelAdapterPath) + .newInstance(); + } catch (InstantiationException e) { + PNEditorLogger.severeLogs("Cannot instantiate this class"); + } catch (IllegalAccessException e) { + PNEditorLogger.severeLogs("Cannot access this class"); + } catch (ClassNotFoundException e) { + PNEditorLogger.severeLogs("Cannot find this class"); + } + } + + public GraphicPetriNet(final String model) { + if (model != null) { + this.model = model; + } + try { + this.petriNet = (PetriNetInterface) Class.forName(this.modelPath + this.model + this.modelAdapterPath) + .newInstance(); + } catch (InstantiationException e) { + PNEditorLogger.severeLogs("Cannot instantiate this class"); + } catch (IllegalAccessException e) { + PNEditorLogger.severeLogs("Cannot access this class"); + } catch (ClassNotFoundException e) { + PNEditorLogger.severeLogs("Cannot find this class"); + } + } + + public Point getViewTranslation() { + return new Point(this.viewTranslation); + } + + public void setViewTranslation(final Point viewTranslation) { + this.viewTranslation = new Point(viewTranslation); + } + + public void setViewTranslationToCenter() { + final int centerX = Math.round((float) getBounds().getCenterX()); + final int centerY = Math.round((float) getBounds().getCenterY()); + final Point center = new Point(-centerX, -centerY); + setViewTranslation(center); + } + + public List<GraphicElement> getElements() { + return Collections.unmodifiableList(this.elements); + } + + public GraphicElement getElementByXY(final int x, final int y) { + for (int i = this.elements.size() - 1; i >= 0; i--) { // Check elements from front to back. + final GraphicElement element = this.elements.get(i); + if (element.containsPoint(x, y)) { + return element; + } + } + return null; + } + + public void addElement(final GraphicElement element) { + if (!element.isNode()) { + this.elements.add(0, element); // background + } else { + this.elements.add(element); + } + } + + public void removeElement(final GraphicElement element) { + this.elements.remove(element); + } + + public void removeElements() { + this.elements.clear(); + } + + public void addAll(final Set<GraphicElement> elementsToAdd) { + for (final GraphicElement element : elementsToAdd) { + addElement(element); + } + } + + public void removeAll(final Set<GraphicElement> elementsToRemove) { + for (final GraphicElement element : elementsToRemove) { + removeElement(element); + } + } + + public Set<GraphicArc> getArcs() { + final Set<GraphicArc> arcs = new HashSet<>(); + for (final GraphicElement element : this.elements) { + if (!element.isNode()) { + final GraphicArc arc = (GraphicArc) element; + arcs.add(arc); + } + } + return arcs; + } + + public Set<GraphicPlace> getPlaces() { + final Set<GraphicPlace> places = new HashSet<>(); + for (final GraphicElement element : this.elements) { + if (element.isPlace()) { + final GraphicPlace place = (GraphicPlace) element; + places.add(place); + } + } + return places; + } + + public Rectangle getBounds() { + Rectangle bounds = null; + + for (final GraphicElement element : this.elements) { + if (bounds == null) { + bounds = new Rectangle(element.getStart().x, element.getStart().y, element.getWidth(), + element.getHeight()); + } + bounds.add(element.getStart().x, element.getStart().y); + bounds.add(element.getEnd().x, element.getEnd().y); + bounds.add(element.getStart().x, element.getEnd().y); + bounds.add(element.getEnd().x, element.getStart().y); + if (!element.isNode()) { + final GraphicArc arc = (GraphicArc) element; + for (final Point breakPoint : arc.getBreakPoints()) { + bounds.add(breakPoint); + } + } + } + if (bounds == null) { + bounds = new Rectangle(); + } + bounds.width++; + bounds.height++; + return bounds; + } + + public void draw(final Graphics g) { + + for (final GraphicElement element : this.elements) { + if (element.highlightColor != null) { + final Color previousColor = element.getColor(); + + element.setColor(element.highlightColor); + element.draw(g, this.petriNet); // TODO + + element.setColor(previousColor); + } else { + element.draw(g, this.petriNet); // TODO + } + } + } + + public PetriNetInterface getPetriNet() { + return this.petriNet; + } + + public void setPetriNet(final PetriNetInterface petriNet) { + this.petriNet = petriNet; + } + + public Set<GraphicArc> getConnectedGraphicArcs(final GraphicNode node) { + final Set<GraphicArc> graphicArcs = new HashSet<>(); + for (final GraphicElement element : this.elements) { + if (!element.isNode()) { + final AbstractArc arc = ((GraphicArc) element).getArc(); + if (arc.getSource().equals(node.getNode()) || arc.getDestination().equals(node.getNode())) { + graphicArcs.add((GraphicArc) element); + } + } + } + return graphicArcs; + } + + /** + * Returns an preview image of the subnet with specified marking. Scale image: + * image.getScaledInstance(preferredWidth, preferredHeight, Image.SCALE_SMOOTH) + * Save image: ImageIO.write(image, "png", file); + */ + + public BufferedImage getPreview() { + final CachedGraphics2D cachedGraphics = new CachedGraphics2D(); + cachedGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + for (final GraphicElement element : getElements()) { + element.draw(cachedGraphics, getPetriNet()); + } + final Rectangle bounds = cachedGraphics.getIntegerBounds(); + int width = bounds.width; + int height = bounds.height; + width = Math.max(width, 1); + height = Math.max(height, 1); + final BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + final Graphics2D imageGraphics = (Graphics2D) bufferedImage.getGraphics(); + imageGraphics.fillRect(0, 0, width, height); // paint the background white + imageGraphics.translate(-bounds.x, -bounds.y); + cachedGraphics.applyToGraphics(imageGraphics); + return bufferedImage; + } + + public GraphicElement getLastElementAdded() { + return ((LinkedList<GraphicElement>) this.elements).getLast(); + } + + public GraphicElement getLastArcAdded() { + return ((LinkedList<GraphicElement>) this.elements).getFirst(); + } +} diff --git a/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicPlace.java b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicPlace.java new file mode 100644 index 0000000..f29959b --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicPlace.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.gpetrinet; + +import java.awt.*; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.petrinet.AbstractPlace; +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.util.GraphicsTools; +import org.pneditor.util.GraphicsTools.HorizontalAlignment; +import org.pneditor.util.GraphicsTools.VerticalAlignment; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class GraphicPlace extends GraphicNode { + + AbstractPlace place; + + public GraphicPlace(final AbstractPlace place, final int x, final int y) { + super(); + this.place = place; + setCenter(x,y); + } + + public GraphicPlace() { + super(); + } + + @Override + public boolean containsPoint(final int x, final int y) { + // Check whether (x,y) is inside this oval, using the + // mathematical equation of an ellipse. + final double rx = getWidth() / 2.0; // horizontal radius of ellipse + final double ry = getHeight() / 2.0; // vertical radius of ellipse + final double cx = getStart().x + rx; // x-coord of center of ellipse + final double cy = getStart().y + ry; // y-coord of center of ellipse + return (ry * (x - cx)) * (ry * (x - cx)) + (rx * (y - cy)) * (rx * (y - cy)) <= rx * rx * ry * ry; + } + + + public AbstractPlace getPlace() { + return this.place; + } + + @Override + public AbstractNode getNode() { + return this.place; + } + + @Override + public void draw(final Graphics g, final PetriNetInterface petriNet) { + drawPlaceBackground(g); + drawPlaceBorder(g); + drawLabel(g); + drawTokens(g, this.place.getTokens()); + } + + protected void drawPlaceBackground(final Graphics g) { + g.setColor(Color.white); + g.fillOval(getStart().x, getStart().y, getWidth(), getHeight()); + } + + protected void drawPlaceBorder(final Graphics g) { + g.setColor(this.color); + g.drawOval(getStart().x, getStart().y, getWidth() - 1, getHeight() - 1); + } + + protected void drawTokens(final Graphics g, final int tokens) { + g.setColor(this.color); + final int x = getCenter().x; + final int y = getCenter().y; + final int tokenSpacing = getWidth() / 5; + + if (tokens > 9) { + GraphicsTools.drawString(g, Integer.toString(tokens), x, y, HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + } else { + + if (tokens % 2 == 1) { + drawTokenAsDot(g, x, y); + if (tokens > 2) { + drawTokenAsDot(g, x - tokenSpacing, y + tokenSpacing); + drawTokenAsDot(g, x + tokenSpacing, y - tokenSpacing); + } + if (tokens > 4) { + drawTokenAsDot(g, x - tokenSpacing, y - tokenSpacing); + drawTokenAsDot(g, x + tokenSpacing, y + tokenSpacing); + } + if (tokens > 6) { + drawTokenAsDot(g, x - tokenSpacing, y); + drawTokenAsDot(g, x + tokenSpacing, y); + } + if (tokens > 8) { + drawTokenAsDot(g, x, y - tokenSpacing); + drawTokenAsDot(g, x, y + tokenSpacing); + } + + } else { + if (tokens > 1) { + drawTokenAsDot(g, x - tokenSpacing, y + tokenSpacing); + drawTokenAsDot(g, x + tokenSpacing, y - tokenSpacing); + } + if (tokens > 3) { + drawTokenAsDot(g, x - tokenSpacing, y - tokenSpacing); + drawTokenAsDot(g, x + tokenSpacing, y + tokenSpacing); + } + if (tokens > 5) { + drawTokenAsDot(g, x - tokenSpacing, y); + drawTokenAsDot(g, x + tokenSpacing, y); + } + if (tokens == 8) { + drawTokenAsDot(g, x, y - tokenSpacing); + drawTokenAsDot(g, x, y + tokenSpacing); + } + } + } + } + + private void drawTokenAsDot(final Graphics g, final int x, final int y) { + final int tokenSize = getWidth() / 6; + g.fillOval(x - tokenSize / 2, y - tokenSize / 2, tokenSize, tokenSize); + } + + @Override + public String getLabel() { + return this.place.getLabel(); + } + + @Override + public boolean isPlace() { + return true; + } + + public void setPlace(final AbstractPlace place) { + this.place = place; + } + + public GraphicPlace getClone(final AbstractPlace placeCloned) { + final GraphicPlace clone = new GraphicPlace(); + clone.setCenter(this.getCenter()); + clone.setPlace(placeCloned); + return clone; + } + + @Override + public boolean isTransition() { + return false; + } +} diff --git a/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicTransition.java b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicTransition.java new file mode 100644 index 0000000..ca3cce4 --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/gpetrinet/GraphicTransition.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.gpetrinet; + +import java.awt.Color; +import java.awt.Graphics; + +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.petrinet.AbstractTransition; +import org.pneditor.petrinet.PetriNetInterface; +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class GraphicTransition extends GraphicNode { + + AbstractTransition transition; + + public GraphicTransition(final AbstractTransition transition , final int x, final int y){ + this.transition = transition; + setCenter(x,y); + } + + public GraphicTransition() { + // TODO Auto-generated constructor stub + } + + public AbstractTransition getTransition() { + return this.transition; + } + + @Override + public AbstractNode getNode() { + return this.transition; + } + + public void draw(final Graphics g) { + g.setColor(Color.white); + g.fillRect(getStart().x, getStart().y, getWidth(), getHeight()); + g.setColor(this.color); + g.drawRect(getStart().x, getStart().y, getWidth() - 1, getHeight() - 1); + drawLabel(g); + } + + @Override + public void draw(final Graphics g, final PetriNetInterface petriNet) { + draw(g); + } + + @Override + public String getLabel() { + return this.transition.getLabel(); + } + + @Override + public boolean isPlace() { + return false; + } + + public void setTransition(final AbstractTransition transition) { + this.transition = transition; + } + + public GraphicTransition getClone(final AbstractTransition transitionCloned) { + final GraphicTransition clone = new GraphicTransition(); + clone.setCenter(this.getCenter()); + clone.setTransition(transitionCloned); + return clone; + } + + @Override + public boolean isTransition() { + return true; + } +} diff --git a/pne-editor/src/org/pneditor/editor/gpetrinet/PreviewArc.java b/pne-editor/src/org/pneditor/editor/gpetrinet/PreviewArc.java new file mode 100644 index 0000000..f377a5d --- /dev/null +++ b/pne-editor/src/org/pneditor/editor/gpetrinet/PreviewArc.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.editor.gpetrinet; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Point; + +import org.pneditor.petrinet.PetriNetInterface; +import org.pneditor.util.GraphicsTools; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class PreviewArc extends GraphicElement { + + private GraphicNode destination; + private GraphicNode source; + + public PreviewArc(GraphicNode source) { + setSource(source); + setStart(source.getCenter().x, source.getCenter().y); + setEnd(source.getCenter().x, source.getCenter().y); + } + + @Override + public final boolean isNode() { + return false; + } + + public final void draw(Graphics g) { + this.color = Color.BLACK; + g.setColor(this.color); + drawSegmentedLine(g); + Point arrowTip = computeArrowTipPoint(); + drawArrow(g, arrowTip); + + } + + @Override + public final void draw(Graphics g, PetriNetInterface petriNet) { + draw(g); + } + + protected final void drawArrow(Graphics g, Point arrowTip) { + GraphicsTools.drawArrow(g, getStart().x, getStart().y, arrowTip.x, arrowTip.y); + } + + protected final void drawSegmentedLine(Graphics g) { + g.setColor(this.color); + Point previous = getStart(); + g.drawLine(previous.x, previous.y, getEnd().x, getEnd().y); + } + + protected final Point computeArrowTipPoint() { + Point arrowTip = new Point(getEnd()); + if (getDestination() != null) { // Thanks to http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html + int x0 = getStart().x; + int y0 = getStart().y; + int x1 = getEnd().x; + int y1 = getEnd().y; + + int dy = y1 - y0; + int dx = x1 - x0; + int stepx, stepy; + + if (dy < 0) { + dy = -dy; + stepy = -1; + } else { + stepy = 1; + } + if (dx < 0) { + dx = -dx; + stepx = -1; + } else { + stepx = 1; + } + dy <<= 1; + dx <<= 1; + + if (dx > dy) { + int fraction = dy - (dx >> 1); + while (x0 != x1) { + if (fraction >= 0) { + y0 += stepy; + fraction -= dx; + } + x0 += stepx; + fraction += dy; + if (getDestination().containsPoint(x0, y0)) { + return arrowTip; + } + arrowTip = new Point(x0, y0); + } + } else { + int fraction = dx - (dy >> 1); + while (y0 != y1) { + if (fraction >= 0) { + x0 += stepx; + fraction -= dy; + } + y0 += stepy; + fraction += dx; + if (getDestination().containsPoint(x0, y0)) { + return arrowTip; + } + arrowTip = new Point(x0, y0); + } + } + } + return arrowTip; + } + + public final GraphicNode getDestination() { + return this.destination; + } + + public final void setDestination(GraphicNode destination) { + this.destination = destination; + } + + public final GraphicNode getSource() { + return this.source; + } + + public final void setSource(GraphicNode source) { + this.source = source; + } + + @Override + public final Point getStart() { + return getSource() != null ? getSource().getCenter() : super.getStart(); + } + + @Override + public final Point getEnd() { + return getDestination() != null ? getDestination().getCenter() : super.getEnd(); + } + + @Override + public final boolean isPlace() { + return false; + } + + @Override + public final boolean isTransition() { + return false; + } + +} diff --git a/pne-editor/src/org/pneditor/petrinet/AbstractArc.java b/pne-editor/src/org/pneditor/petrinet/AbstractArc.java new file mode 100644 index 0000000..551ae2d --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/AbstractArc.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.petrinet; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public abstract class AbstractArc { + + public abstract AbstractNode getSource(); + + public abstract AbstractNode getDestination(); + + public boolean isSourceAPlace() { + return getSource().isPlace(); + } + + public abstract boolean isReset(); + + public abstract boolean isRegular(); + + public abstract boolean isInhibitory(); + + public abstract int getMultiplicity() throws ResetArcMultiplicityException; + + public abstract void setMultiplicity(int multiplicity) throws ResetArcMultiplicityException; + +} diff --git a/pne-editor/src/org/pneditor/petrinet/AbstractNode.java b/pne-editor/src/org/pneditor/petrinet/AbstractNode.java new file mode 100644 index 0000000..d2f364c --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/AbstractNode.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.petrinet; + +/** + * Transition, Place, ReferencePlace, Subnet are subclasses of Node + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public abstract class AbstractNode { + + private int id; + private String label; + + public AbstractNode(final String label) { + this.label = label; + } + + public final int getId() { + return this.id; + } + + protected final void setId(final int id) { + this.id = id; + } + + public String getLabel() { + return this.label; + } + + public void setLabel(final String label) { + this.label = label; + } + + public abstract boolean isPlace(); + +} diff --git a/pne-editor/src/org/pneditor/petrinet/AbstractPlace.java b/pne-editor/src/org/pneditor/petrinet/AbstractPlace.java new file mode 100644 index 0000000..7ee36e7 --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/AbstractPlace.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.petrinet; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public abstract class AbstractPlace extends AbstractNode { + + public AbstractPlace(final String label) { + super(label); + } + + public abstract void addToken(); + + public abstract void removeToken(); + + public abstract int getTokens(); + + public abstract void setTokens(int tokens); + + @Override + public boolean isPlace() { + return true; + } + +} \ No newline at end of file diff --git a/pne-editor/src/org/pneditor/petrinet/AbstractTransition.java b/pne-editor/src/org/pneditor/petrinet/AbstractTransition.java new file mode 100644 index 0000000..12f8e83 --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/AbstractTransition.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.petrinet; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public abstract class AbstractTransition extends AbstractNode { + + public AbstractTransition(final String label) { + super(label); + } + + @Override + public boolean isPlace() { + return false; + } +} diff --git a/pne-editor/src/org/pneditor/petrinet/Boundedness.java b/pne-editor/src/org/pneditor/petrinet/Boundedness.java new file mode 100644 index 0000000..b25135f --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/Boundedness.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2012 milka + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.petrinet; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author milka + */ +public class Boundedness { + + final private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + final private PetriNetInterface petriNet; + private Stack<Map<AbstractPlace, Integer>> markingsStack; + private boolean isUnboundedness; + + public Boundedness(final PetriNetInterface petriNet) { + this.petriNet = petriNet; + } + + public boolean isBounded() throws ResetArcMultiplicityException { + + this.isUnboundedness = false; + + final Map<AbstractPlace, Integer> initMap = initFill(); + this.markingsStack = new Stack<>(); + this.markingsStack.push(initMap); + + final Set<AbstractTransition> executableTransitions = getAllEnabledTransitions(initMap); + for (final AbstractTransition t : executableTransitions) { + if (checkBranchBoundedness(initMap, t)) { + this.markingsStack.pop(); + } + } + return this.isUnboundedness; + } + + private boolean checkBranchBoundedness(final Map<AbstractPlace, Integer> marking, + final AbstractTransition transition) throws ResetArcMultiplicityException { + + if (this.isUnboundedness) { + return false; + } + + final Map<AbstractPlace, Integer> newMarking = new ConcurrentHashMap<>(marking); + fire(newMarking, transition); + + for (final Map<AbstractPlace, Integer> oldMarking : this.markingsStack) { + if (isOmega(newMarking, oldMarking)) { + this.isUnboundedness = true; + return false; + } + } + + if (!this.markingsStack.contains(newMarking)) { + this.markingsStack.push(newMarking); + final Set<AbstractTransition> executableTransitions = getAllEnabledTransitions(newMarking); + for (final AbstractTransition t : executableTransitions) { + if (checkBranchBoundedness(newMarking, t)) { + this.markingsStack.pop(); + } + } + return true; + } + + return false; + + } + + private boolean isOmega(final Map<AbstractPlace, Integer> newMarking, + final Map<AbstractPlace, Integer> oldMarking) { + + boolean isOneSharplyHigher = false; + + for (final AbstractPlace newMarkingAbstractPlace : newMarking.keySet()) { + + final int newTokens = newMarking.get(newMarkingAbstractPlace); + + AbstractPlace oldMarkingAbstractPlace = null; + for (final AbstractPlace place : oldMarking.keySet()) { + if (place.equals(newMarkingAbstractPlace)) { + oldMarkingAbstractPlace = place; + break; + } + } + + final int oldTokens = oldMarking.get(oldMarkingAbstractPlace); + + if (newTokens < oldTokens) { + return false; + } else if (newTokens > oldTokens) { + isOneSharplyHigher = true; + } + + } + return isOneSharplyHigher; + } + + private Map<AbstractPlace, Integer> initFill() { + final Map<AbstractPlace, Integer> marking = new ConcurrentHashMap<>(); + for (final AbstractPlace place : this.petriNet.getPlaces()) { + marking.put(place, place.getTokens()); + } + return marking; + } + + private boolean fire(final Map<AbstractPlace, Integer> marking, final AbstractTransition transition) + throws ResetArcMultiplicityException { + boolean success; + this.lock.writeLock().lock(); + try { + if (isEnabled(marking, transition)) { + for (final AbstractArc arc : this.petriNet.getConnectedArcs(transition)) { + if (arc.isSourceAPlace()) { + if (arc.isReset()) { // reset arc consumes them all + marking.put((AbstractPlace) arc.getSource(), 0); + } + if (arc.isRegular()) { + marking.put((AbstractPlace) arc.getSource(), + marking.get(arc.getSource()) - arc.getMultiplicity()); + } + + } + } + for (final AbstractArc arc : this.petriNet.getConnectedArcs(transition)) { + if (!arc.isSourceAPlace()) { + marking.put((AbstractPlace) arc.getDestination(), + marking.get(arc.getDestination()) + arc.getMultiplicity()); + } + } + success = true; + } else { + success = false; + } + } finally { + this.lock.writeLock().unlock(); + } + return success; + } + + private boolean isEnabled(final Map<AbstractPlace, Integer> marking, final AbstractTransition transition) + throws ResetArcMultiplicityException { + boolean isEnabled = true; + this.lock.readLock().lock(); + try { + for (final AbstractArc arc : this.petriNet.getConnectedArcs(transition)) { + if (arc.isSourceAPlace() && !arc.isReset()) { + // reset arc is always fireable + // but can be blocked by other arcs + + if (arc.isRegular()) { + if (marking.get(arc.getSource()) < arc.getMultiplicity()) {// normal arc + isEnabled = false; + break; + } + } else { + if (marking.get(arc.getSource()) >= arc.getMultiplicity()) {// inhibitory arc + isEnabled = false; + break; + } + } + + } + } + } finally { + this.lock.readLock().unlock(); + } + return isEnabled; + } + + public Set<AbstractTransition> getAllEnabledTransitions(final Map<AbstractPlace, Integer> marking) + throws ResetArcMultiplicityException { + final Set<AbstractTransition> enabledTransitions = new HashSet<>(); + this.lock.readLock().lock(); + try { + for (final AbstractTransition transition : this.petriNet.getTransitions()) { + if (isEnabled(marking, transition)) { + enabledTransitions.add(transition); + } + } + } finally { + this.lock.readLock().unlock(); + } + return enabledTransitions; + } +} diff --git a/pne-editor/src/org/pneditor/petrinet/PetriNetInterface.java b/pne-editor/src/org/pneditor/petrinet/PetriNetInterface.java new file mode 100644 index 0000000..99c1976 --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/PetriNetInterface.java @@ -0,0 +1,207 @@ +package org.pneditor.petrinet; + +import java.util.HashSet; +import java.util.Set; + +import logger.PNEditorLogger; + +public abstract class PetriNetInterface { + + /* + * Stocking the elements of the PetriNet, used for the Boundedness algorithm. + * The id is used for saving petriNets + */ + private final Set<AbstractPlace> places = new HashSet<>(); + private final Set<AbstractTransition> transitions = new HashSet<>(); + private final Set<AbstractArc> arcs = new HashSet<>(); + private int nextId = 1; + + /* + * Interface that adapters must implement (+ the element specific methods) + */ + + public abstract AbstractPlace addPlace(); + + public abstract AbstractTransition addTransition(); + + public abstract AbstractArc addRegularArc(AbstractNode source, AbstractNode destination) + throws UnimplementedCaseException; + + public abstract AbstractArc addInhibitoryArc(AbstractPlace place, AbstractTransition transition) + throws UnimplementedCaseException; + + public abstract AbstractArc addResetArc(AbstractPlace place, AbstractTransition transition) + throws UnimplementedCaseException; + + public abstract void removePlace(AbstractPlace place); + + public abstract void removeTransition(AbstractTransition transition); + + public abstract void removeArc(AbstractArc arc); + + public abstract boolean isEnabled(AbstractTransition transition) throws ResetArcMultiplicityException; + + public abstract void fire(AbstractTransition transition) throws ResetArcMultiplicityException; + + /* + * Methods used by the software, not defined by the models. It mostly concerns + * stocking the elements, and adding the ID + */ + + public final AbstractPlace addAbstractPlace() { // template pattern + final AbstractPlace place = addPlace(); + this.places.add(place); + place.setId(this.nextId++); + return place; + } + + public final AbstractPlace addAbstractPlace(final int id) { // template pattern + final AbstractPlace place = addPlace(); + this.places.add(place); + place.setId(id); + if (id >= this.nextId) { + this.nextId = id + 1; + } + return place; + } + + public final AbstractTransition addAbstractTransition() { // template pattern + final AbstractTransition transition = addTransition(); + this.transitions.add(transition); + transition.setId(this.nextId++); + return transition; + } + + public final AbstractTransition addAbstractTransition(final int id) { // template pattern + final AbstractTransition transition = addTransition(); + this.transitions.add(transition); + transition.setId(id); + if (id >= this.nextId) { + this.nextId = id + 1; + } + return transition; + } + + public final AbstractArc addArcAgain(final AbstractArc arc, final AbstractNode source, final AbstractNode destination) { + AbstractArc newArc = null; + try { + if (arc.isReset()) { + newArc = addResArc((AbstractPlace) source, (AbstractTransition) destination); + } else { + if (arc.isInhibitory()) { + newArc = addInhibArc((AbstractPlace) source, (AbstractTransition) destination); + } else { + newArc = addRegArc(source, destination); + } + + newArc.setMultiplicity(arc.getMultiplicity()); + } + } catch (ResetArcMultiplicityException e) { + // should not happen + PNEditorLogger.severeLogs(e.getMessage()); + } catch (UnimplementedCaseException e) { + // should not happen since we're manipulating new objects, except if a behavior + // is not implemented + PNEditorLogger.warningLogs(e.getMessage()); + } + return newArc; + } + + public final AbstractArc addRegArc(final AbstractNode source, final AbstractNode destination) + throws UnimplementedCaseException { + final AbstractArc arc = addRegularArc(source, destination); + this.arcs.add(arc); + return arc; + } + + public final AbstractArc addInhibArc(final AbstractPlace place, final AbstractTransition transition) + throws UnimplementedCaseException { + final AbstractArc arc = addInhibitoryArc(place, transition); + this.arcs.add(arc); + return arc; + } + + public final AbstractArc addResArc(final AbstractPlace place, final AbstractTransition transition) + throws UnimplementedCaseException { + final AbstractArc arc = addResetArc(place, transition); + this.arcs.add(arc); + return arc; + } + + public final void removeAbstractPlace(final AbstractPlace place) { + removePlace(place); + this.places.remove(place); + } + + public final void removeAbstractTransition(final AbstractTransition transition) { + removeTransition(transition); + this.transitions.remove(transition); + } + + public final void removeAbstractArc(final AbstractArc arc) { + removeArc(arc); + this.arcs.remove(arc); + } + + public final boolean isBounded() throws ResetArcMultiplicityException { + return new Boundedness(this).isBounded(); + } + + public final AbstractPlace clonePlace(final AbstractPlace place) { + final AbstractPlace placeClone = addAbstractPlace(); + placeClone.setLabel(place.getLabel()); + placeClone.setTokens(place.getTokens()); + return placeClone; + } + + public final AbstractTransition cloneTransition(final AbstractTransition transition) { + final AbstractTransition transitionClone = addAbstractTransition(); + transitionClone.setLabel(transition.getLabel()); + return transitionClone; + } + + public final AbstractArc cloneArc(final AbstractArc arc, final AbstractNode source, final AbstractNode destination) { + AbstractArc newArc = null; + try { + if (arc.isReset()) { + newArc = addResArc((AbstractPlace) source, (AbstractTransition) destination); + } else { + if (arc.isInhibitory()) { + newArc = addInhibArc((AbstractPlace) source, (AbstractTransition) destination); + } else { + newArc = addRegArc(source, destination); + } + newArc.setMultiplicity(arc.getMultiplicity()); + } + } catch (UnimplementedCaseException | ResetArcMultiplicityException e) { + // should never happen because source and destination are new objects + // and ResetArcMultiplicity sould not happen as well + PNEditorLogger.severeLogs(e.getMessage()); + } + return newArc; + } + + /* + * Methods for the Boundedness algorithm + * + */ + + public Set<AbstractPlace> getPlaces() { + return this.places; + } + + public Set<AbstractTransition> getTransitions() { + return this.transitions; + } + + public Set<AbstractArc> getConnectedArcs(final AbstractTransition transition) { + final Set<AbstractArc> connectedArcs = new HashSet<>(); + for (final AbstractArc arc : this.arcs) { + if (arc.getSource().equals(transition) || arc.getDestination().equals(transition)) { + connectedArcs.add(arc); + } + } + return connectedArcs; + } + +} diff --git a/pne-editor/src/org/pneditor/petrinet/ResetArcMultiplicityException.java b/pne-editor/src/org/pneditor/petrinet/ResetArcMultiplicityException.java new file mode 100644 index 0000000..deeada8 --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/ResetArcMultiplicityException.java @@ -0,0 +1,9 @@ +package org.pneditor.petrinet; + +@SuppressWarnings("serial") +public class ResetArcMultiplicityException extends Exception { + + public ResetArcMultiplicityException() { + super("A reset arc can not have multiplicity. This exception should never happen"); + } +} diff --git a/pne-editor/src/org/pneditor/petrinet/UnimplementedCaseException.java b/pne-editor/src/org/pneditor/petrinet/UnimplementedCaseException.java new file mode 100644 index 0000000..c098921 --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/UnimplementedCaseException.java @@ -0,0 +1,9 @@ +package org.pneditor.petrinet; + +@SuppressWarnings("serial") +public class UnimplementedCaseException extends Exception { + + public UnimplementedCaseException(String msg) { + super(msg); + } +} diff --git a/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/ArcAdapter.java b/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/ArcAdapter.java new file mode 100644 index 0000000..3b7da0a --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/ArcAdapter.java @@ -0,0 +1,60 @@ +package org.pneditor.petrinet.adapters.Bouzazi; + +import org.petriNet.Arc; +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.AbstractNode; +import org.pneditor.petrinet.ResetArcMultiplicityException; + +public class ArcAdapter extends AbstractArc { + + private Arc arc; + + public ArcAdapter(Arc arc) { + this.arc = arc; + } + + @Override + public AbstractNode getSource() { + return new PlaceAdapter(arc.getPlace()); + } + + @Override + public AbstractNode getDestination() { + return new TransitionAdapter(null, arc.getTransition()); + } + + @Override + public boolean isReset() { + return arc instanceof org.petriNet.IncomingArc_Videur; + } + + @Override + public boolean isRegular() { + return arc instanceof org.petriNet.IncomingArc_Simple; + } + + @Override + public boolean isInhibitory() { + return arc instanceof org.petriNet.IncomingArc_Zero; + } + + @Override + public int getMultiplicity() throws ResetArcMultiplicityException { + if (isReset()) { + throw new ResetArcMultiplicityException(); + } + return arc.getWeight(); + } + + @Override + public void setMultiplicity(int multiplicity) throws ResetArcMultiplicityException { + if (isReset()) { + throw new ResetArcMultiplicityException(); + } + arc.setWeight(multiplicity); + } + + public Arc getArc() { + return arc; + } +} diff --git a/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/PetriNetAdapter.java b/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/PetriNetAdapter.java new file mode 100644 index 0000000..04377ab --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/PetriNetAdapter.java @@ -0,0 +1,113 @@ +package org.pneditor.petrinet.adapters.Bouzazi; + +import org.petriNet.*; +import org.pneditor.petrinet.*; + +public class PetriNetAdapter extends PetriNetInterface { + + private PetriNet pn = new PetriNet(); + + @Override + public AbstractPlace addPlace() { + Place newPlace = new Place(0, pn.generateId(1)); // Initializing with 0 tokens + pn.addPlace(newPlace); // Adding to the underlying PetriNet + return new PlaceAdapter(newPlace); + } + + @Override + public AbstractTransition addTransition() { + Transition t = new Transition("Transition", pn.generateId(2)); + pn.addTransition(t); // Adding to the underlying PetriNet + return new TransitionAdapter(pn, t); + } + + @Override + public AbstractArc addRegularArc(AbstractNode source, AbstractNode destination) { + if (source instanceof PlaceAdapter && destination instanceof TransitionAdapter) { + Place place = ((PlaceAdapter) source).getPlace(); + Transition transition = ((TransitionAdapter) destination).getTransition(); + Arc arc = new IncomingArc_Simple(transition, place, 1, pn.generateId(3)); + pn.addArc(arc); // Add to the PetriNet + return new ArcAdapter(arc); + } else if (source instanceof TransitionAdapter && destination instanceof PlaceAdapter) { + Transition transition = ((TransitionAdapter) source).getTransition(); + Place place = ((PlaceAdapter) destination).getPlace(); + Arc arc = new OutgoingArc(transition, place, 1, pn.generateId(3)); + pn.addArc(arc); // Add to the PetriNet + return new ArcAdapter(arc); + } else { + // Handle invalid case without throwing exception, just return null or log + System.out.println("Invalid source and destination for regular arc."); + return null; + } + } + + @Override + public AbstractArc addInhibitoryArc(AbstractPlace place, AbstractTransition transition) { + if (place instanceof PlaceAdapter && transition instanceof TransitionAdapter) { + Place p = ((PlaceAdapter) place).getPlace(); + Transition t = ((TransitionAdapter) transition).getTransition(); + Arc arc = new IncomingArc_Zero(t, p, 1, pn.generateId(3)); + pn.addArc(arc); // Add to the PetriNet + return new ArcAdapter(arc); + } else { + System.out.println("Invalid place or transition for inhibitory arc."); + return null; + } + } + + @Override + public AbstractArc addResetArc(AbstractPlace place, AbstractTransition transition) { + if (place instanceof PlaceAdapter && transition instanceof TransitionAdapter) { + Place p = ((PlaceAdapter) place).getPlace(); + Transition t = ((TransitionAdapter) transition).getTransition(); + Arc arc = new IncomingArc_Videur(t, p, 1, pn.generateId(3)); + pn.addArc(arc); // Add to the PetriNet + return new ArcAdapter(arc); + } else { + System.out.println("Invalid place or transition for reset arc."); + return null; + } + } + + @Override + public void removePlace(AbstractPlace place) { + if (place instanceof PlaceAdapter) { + Place p = ((PlaceAdapter) place).getPlace(); + pn.removePlace(p); // Remove the place from the PetriNet + } + } + + @Override + public void removeTransition(AbstractTransition transition) { + if (transition instanceof TransitionAdapter) { + Transition t = ((TransitionAdapter) transition).getTransition(); + pn.removeTransition(t); // Remove the transition from the PetriNet + } + } + + @Override + public void removeArc(AbstractArc arc) { + if (arc instanceof ArcAdapter) { + Arc a = ((ArcAdapter) arc).getArc(); + pn.removeArc(a); // Remove the arc from the PetriNet + } + } + + @Override + public boolean isEnabled(AbstractTransition transition) { + if (transition instanceof TransitionAdapter) { + Transition t = ((TransitionAdapter) transition).getTransition(); + return t.canFire(); + } + return false; + } + + @Override + public void fire(AbstractTransition transition) { + if (transition instanceof TransitionAdapter) { + Transition t = ((TransitionAdapter) transition).getTransition(); + t.fire(); // Execute the transition in the underlying PetriNet + } + } +} diff --git a/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/PlaceAdapter.java b/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/PlaceAdapter.java new file mode 100644 index 0000000..8623bcc --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/PlaceAdapter.java @@ -0,0 +1,38 @@ +package org.pneditor.petrinet.adapters.Bouzazi; + +import org.petriNet.Place; +import org.pneditor.petrinet.AbstractPlace; + +public class PlaceAdapter extends AbstractPlace { + + private Place place; + + public PlaceAdapter(Place place) { + super("Place " + place.getId()); // Using the ID for a unique name + this.place = place; + } + + @Override + public void addToken() { + place.addTokens(1); // Add a single token to the place + } + + @Override + public void removeToken() { + place.removeTokens(1); // Remove a single token from the place + } + + @Override + public int getTokens() { + return place.getTokenCount(); // Return the current token count + } + + @Override + public void setTokens(int tokens) { + place.setTokenCount(tokens); // Update the token count in the place + } + + public Place getPlace() { + return place; // Expose the adapted Place object + } +} diff --git a/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/TransitionAdapter.java b/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/TransitionAdapter.java new file mode 100644 index 0000000..94ab367 --- /dev/null +++ b/pne-editor/src/org/pneditor/petrinet/adapters/Bouzazi/TransitionAdapter.java @@ -0,0 +1,30 @@ +package org.pneditor.petrinet.adapters.Bouzazi; + +import org.petriNet.PetriNet; +import org.petriNet.Transition; +import org.pneditor.petrinet.AbstractTransition; + +public class TransitionAdapter extends AbstractTransition { + + private final Transition transition; + + public TransitionAdapter(PetriNet pn, Transition t) { + super(t.getName()); // Initialize the AbstractTransition with the name from Transition + this.transition = t; + } + + // Expose the wrapped Transition + public Transition getTransition() { + return transition; + } + + @Override + public String getLabel() { + return transition.getName(); + } + + @Override + public void setLabel(String label) { + transition.setName(label); + } +} diff --git a/pne-editor/src/org/pneditor/petrinet/adapters/imta/.trick b/pne-editor/src/org/pneditor/petrinet/adapters/imta/.trick new file mode 100644 index 0000000..e69de29 diff --git a/pne-editor/src/org/pneditor/petrinet/adapters/initial/.trick b/pne-editor/src/org/pneditor/petrinet/adapters/initial/.trick new file mode 100644 index 0000000..e69de29 diff --git a/pne-editor/src/org/pneditor/petrinet/models/imta/.trick b/pne-editor/src/org/pneditor/petrinet/models/imta/.trick new file mode 100644 index 0000000..e69de29 diff --git a/pne-editor/src/org/pneditor/petrinet/models/initial/.trick b/pne-editor/src/org/pneditor/petrinet/models/initial/.trick new file mode 100644 index 0000000..e69de29 diff --git a/pne-editor/src/org/pneditor/save/xml/DocumentExporter.java b/pne-editor/src/org/pneditor/save/xml/DocumentExporter.java new file mode 100644 index 0000000..bc6ac2b --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/DocumentExporter.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + +import java.awt.Point; +import java.awt.Rectangle; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicElement; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.ResetArcMultiplicityException; + +import logger.PNEditorLogger; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public final class DocumentExporter { + + private final XmlDocument xmlDocument = new XmlDocument(); + + public DocumentExporter(final GraphicPetriNet petriNet) { + this.xmlDocument.petriNet = getXmlPetriNet(petriNet); + final Rectangle bounds = petriNet.getBounds(); + this.xmlDocument.left = bounds.x; + this.xmlDocument.top = bounds.y; + } + + public void writeToFile(final File file) throws JAXBException { + final JAXBContext ctx = JAXBContext.newInstance(XmlDocument.class); + final Marshaller marshaller = ctx.createMarshaller(); + marshaller.setProperty("jaxb.formatted.output", true); + try { + marshaller.marshal(this.xmlDocument, Files.newOutputStream(Paths.get(file.toURI()))); + } catch (IOException e) { + PNEditorLogger.severeLogs(e.getMessage()); + } + } + + public XmlPetriNet getXmlPetriNet(final GraphicPetriNet petriNet) { + final XmlPetriNet xmlPetriNet = new XmlPetriNet(); + xmlPetriNet.label = "PetriNet"; + for (final GraphicElement element : petriNet.getElements()) { + if (element.isTransition()) { + xmlPetriNet.addTransition(getXmlTransition((GraphicTransition) element)); + } else if (element.isPlace()) { + xmlPetriNet.addPlace(getXmlPlace((GraphicPlace) element)); + } else if (!element.isNode()) { + xmlPetriNet.addArc(getXmlArc((GraphicArc) element)); + } + } + return xmlPetriNet; + } + + private XmlPlace getXmlPlace(final GraphicPlace place) { + final XmlPlace xmlPlace = new XmlPlace(); + xmlPlace.id = place.getPlace().getId(); + xmlPlace.x = place.getCenter().x; + xmlPlace.y = place.getCenter().y; + xmlPlace.label = place.getLabel(); + xmlPlace.tokens = place.getPlace().getTokens(); + return xmlPlace; + } + + private XmlTransition getXmlTransition(final GraphicTransition transition) { + final XmlTransition xmlTransition = new XmlTransition(); + xmlTransition.id = transition.getTransition().getId(); + xmlTransition.x = transition.getCenter().x; + xmlTransition.y = transition.getCenter().y; + xmlTransition.label = transition.getLabel(); + return xmlTransition; + } + + private XmlArc getXmlArc(final GraphicArc gArc) { + final AbstractArc arc = gArc.getArc(); + final XmlArc xmlArc = new XmlArc(); + xmlArc.sourceId = arc.getSource().getId(); + xmlArc.destinationId = arc.getDestination().getId(); + xmlArc.type = arc.isRegular() ? "regular" : arc.isInhibitory() ? "inhibitory" : "reset"; + if (!arc.isReset()) { + try { + xmlArc.multiplicity = arc.getMultiplicity(); + } catch (ResetArcMultiplicityException e) { + PNEditorLogger.severeLogs(e.getMessage()); + } + } + final List<Point> breakPoints = gArc.getBreakPoints(); + for (final Point point : breakPoints) { + final XmlPoint xmlPoint = new XmlPoint(); + xmlPoint.x = point.x; + xmlPoint.y = point.y; + xmlArc.breakPoints.add(xmlPoint); + } + return xmlArc; + } +} diff --git a/pne-editor/src/org/pneditor/save/xml/DocumentImporter.java b/pne-editor/src/org/pneditor/save/xml/DocumentImporter.java new file mode 100644 index 0000000..545d92b --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/DocumentImporter.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + +import java.awt.Point; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.pneditor.editor.gpetrinet.GraphicArc; +import org.pneditor.editor.gpetrinet.GraphicNode; +import org.pneditor.editor.gpetrinet.GraphicPetriNet; +import org.pneditor.editor.gpetrinet.GraphicPlace; +import org.pneditor.editor.gpetrinet.GraphicTransition; +import org.pneditor.petrinet.AbstractArc; +import org.pneditor.petrinet.AbstractPlace; +import org.pneditor.petrinet.AbstractTransition; +import org.pneditor.petrinet.ResetArcMultiplicityException; +import org.pneditor.petrinet.UnimplementedCaseException; + +import logger.PNEditorLogger; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class DocumentImporter { + + private XmlDocument xmlDocument; + final private Map<Integer, GraphicNode> nodeReferences = new HashMap<>(); + + public GraphicPetriNet readFromFile(final File file, final String model) + throws JAXBException, FileNotFoundException, IOException { + final JAXBContext ctx = JAXBContext.newInstance(XmlDocument.class); + final Unmarshaller unmarshaller = ctx.createUnmarshaller(); + final InputStream fileInputStream = Files.newInputStream(Paths.get(file.toURI())); + this.xmlDocument = (XmlDocument) unmarshaller.unmarshal(fileInputStream); + fileInputStream.close(); + return getPetriNet(model); + } + + private GraphicPetriNet getPetriNet(final String model) { + return getNewPetriNet(this.xmlDocument.petriNet, model); + } + + private GraphicPetriNet getNewPetriNet(final XmlPetriNet xmlPetriNet, final String model) { + final GraphicPetriNet gPetriNet = new GraphicPetriNet(model); + for (final XmlPlace xmlPlace : xmlPetriNet.places) { + addNewPlace(xmlPlace, gPetriNet); + } + for (final XmlTransition xmlTransition : xmlPetriNet.transitions) { + addNewTransition(xmlTransition, gPetriNet); + } + for (final XmlArc xmlArc : xmlPetriNet.arcs) { + addNewArc(xmlArc, gPetriNet); + } + return gPetriNet; + } + + private void addNewArc(final XmlArc xmlArc, final GraphicPetriNet gPetriNet) { + AbstractArc arc = null; + try { + if ("regular".equals(xmlArc.type)) { + arc = gPetriNet.getPetriNet().addRegArc(this.nodeReferences.get(xmlArc.sourceId).getNode(), + this.nodeReferences.get(xmlArc.destinationId).getNode()); + arc.setMultiplicity(xmlArc.multiplicity); + } else if ("reset".equals(xmlArc.type)) { + arc = gPetriNet.getPetriNet().addResArc( + ((GraphicPlace) this.nodeReferences.get(xmlArc.sourceId)).getPlace(), + ((GraphicTransition) this.nodeReferences.get(xmlArc.destinationId)).getTransition()); + } else if ("inhibitory".equals(xmlArc.type)) { + arc = gPetriNet.getPetriNet().addInhibArc( + ((GraphicPlace) this.nodeReferences.get(xmlArc.sourceId)).getPlace(), + ((GraphicTransition) this.nodeReferences.get(xmlArc.destinationId)).getTransition()); + arc.setMultiplicity(xmlArc.multiplicity); + } + + + final GraphicArc gArc = new GraphicArc(arc); + gArc.setDestination(this.nodeReferences.get(xmlArc.destinationId)); + gArc.setSource(this.nodeReferences.get(xmlArc.sourceId)); + final List<Point> breakPoints = new LinkedList<>(); + for (final XmlPoint xmlPoint : xmlArc.breakPoints) { + breakPoints.add(new Point(xmlPoint.x, xmlPoint.y)); + } + gArc.setBreakPoints(breakPoints); + gPetriNet.addElement(gArc); + } catch (ResetArcMultiplicityException | UnimplementedCaseException e) { + // should not happen since we're manipulating new objects, except if a behavior + // is not implemented, which would return UnimplementedCaseException + PNEditorLogger.severeLogs(e.getMessage()); + } + + } + + private void addNewPlace(final XmlPlace xmlPlace, final GraphicPetriNet gPetriNet) { + final AbstractPlace createdPlace = gPetriNet.getPetriNet().addAbstractPlace(xmlPlace.id); + createdPlace.setLabel(xmlPlace.label); + createdPlace.setTokens(xmlPlace.tokens); + final GraphicPlace representation = new GraphicPlace(createdPlace, xmlPlace.x, xmlPlace.y); + representation.setPlace(createdPlace); + gPetriNet.addElement(representation); + + this.nodeReferences.put(xmlPlace.id, representation); + } + + private void addNewTransition(final XmlTransition xmlTransition, final GraphicPetriNet gPetriNet) { + final AbstractTransition createdTransition = gPetriNet.getPetriNet().addAbstractTransition(xmlTransition.id); + createdTransition.setLabel(xmlTransition.label); + final GraphicTransition representation = new GraphicTransition(createdTransition, xmlTransition.x, xmlTransition.y); + representation.setTransition(createdTransition); + gPetriNet.addElement(representation); + + this.nodeReferences.put(xmlTransition.id, representation); + } +} diff --git a/pne-editor/src/org/pneditor/save/xml/XmlArc.java b/pne-editor/src/org/pneditor/save/xml/XmlArc.java new file mode 100644 index 0000000..d0cefd8 --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/XmlArc.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + +import java.util.LinkedList; +import java.util.List; +import javax.xml.bind.annotation.XmlElement; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class XmlArc { + + @XmlElement(name = "sourceId") + public int sourceId; + + @XmlElement(name = "destinationId") + public int destinationId; + + @XmlElement(name = "breakPoint") + public List<XmlPoint> breakPoints = new LinkedList<>(); + + @XmlElement(name = "type") + public String type; + + @XmlElement(name = "multiplicity") + public int multiplicity; +} diff --git a/pne-editor/src/org/pneditor/save/xml/XmlDocument.java b/pne-editor/src/org/pneditor/save/xml/XmlDocument.java new file mode 100644 index 0000000..4d843b9 --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/XmlDocument.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ + +@XmlRootElement(name = "document") +public class XmlDocument { + + @XmlElement(name = "left") + public int left; + + @XmlElement(name = "top") + public int top; + + @XmlElement(name = "petriNet") + public XmlPetriNet petriNet; + +} diff --git a/pne-editor/src/org/pneditor/save/xml/XmlNode.java b/pne-editor/src/org/pneditor/save/xml/XmlNode.java new file mode 100644 index 0000000..313e3bb --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/XmlNode.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + +import javax.xml.bind.annotation.XmlElement; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class XmlNode { + + @XmlElement(name = "id") + public int id; + + @XmlElement(name = "label") + public String label; + + @XmlElement(name = "x") + public int x; + + @XmlElement(name = "y") + public int y; +} diff --git a/pne-editor/src/org/pneditor/save/xml/XmlPetriNet.java b/pne-editor/src/org/pneditor/save/xml/XmlPetriNet.java new file mode 100644 index 0000000..809736b --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/XmlPetriNet.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + +import java.util.LinkedList; +import java.util.List; +import javax.xml.bind.annotation.XmlElement; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class XmlPetriNet { + + @XmlElement(name = "label") + public String label; + + @XmlElement(name = "place") + public List<XmlPlace> places = new LinkedList<>(); + + @XmlElement(name = "transition") + public List<XmlTransition> transitions = new LinkedList<>(); + + @XmlElement(name = "arc") + public List<XmlArc> arcs = new LinkedList<>(); + + + public void addPlace(final XmlPlace place) { + places.add(place); + } + + public void addArc(final XmlArc arc) { + arcs.add(arc); + } + + public void addTransition(final XmlTransition transition) { + transitions.add(transition); + } + +} diff --git a/pne-editor/src/org/pneditor/save/xml/XmlPlace.java b/pne-editor/src/org/pneditor/save/xml/XmlPlace.java new file mode 100644 index 0000000..de812f3 --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/XmlPlace.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + +import javax.xml.bind.annotation.XmlElement; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class XmlPlace extends XmlNode { + + @XmlElement(name = "tokens") + public int tokens; + +} diff --git a/pne-editor/src/org/pneditor/save/xml/XmlPoint.java b/pne-editor/src/org/pneditor/save/xml/XmlPoint.java new file mode 100644 index 0000000..545acb5 --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/XmlPoint.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + +import javax.xml.bind.annotation.XmlElement; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class XmlPoint { + + @XmlElement(name = "y") + public int y; + + @XmlElement(name = "x") + public int x; + +} diff --git a/pne-editor/src/org/pneditor/save/xml/XmlTransition.java b/pne-editor/src/org/pneditor/save/xml/XmlTransition.java new file mode 100644 index 0000000..7aeeee1 --- /dev/null +++ b/pne-editor/src/org/pneditor/save/xml/XmlTransition.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.save.xml; + + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class XmlTransition extends XmlNode { + +} diff --git a/pne-editor/src/org/pneditor/util/CachedGraphics2D.java b/pne-editor/src/org/pneditor/util/CachedGraphics2D.java new file mode 100644 index 0000000..2863ac9 --- /dev/null +++ b/pne-editor/src/org/pneditor/util/CachedGraphics2D.java @@ -0,0 +1,538 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.util; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.RenderingHints.Key; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class CachedGraphics2D extends Graphics2D { + + final private Graphics graphics = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).getGraphics(); + private Font currentFont = new Font(null); + private Color currentColor = Color.white; + final private List<Drawable> toBeDrawn = new ArrayList<>(); + private float currentLineWidth = 1; + final private Rectangle integerBounds = new Rectangle(-1, -1); + final private Rectangle2D realBounds = new Rectangle2D.Float(0, 0, -1, -1); + + public Rectangle getIntegerBounds() { + Rectangle result = new Rectangle(this.integerBounds); + result.width++; + result.height++; + return result; + } + + public Rectangle2D getRealBounds() { + return this.realBounds; + } + + public void applyToGraphics(final Graphics2D g) { + for (final Drawable drawable : this.toBeDrawn) { + drawable.draw(g); + } + } + + private void addPointToBounds(final int x, final int y) { + final int excess = (int) Math.ceil(this.currentLineWidth / 2 - 0.5f); + this.integerBounds.add(x + excess, y + excess); + this.integerBounds.add(x - excess, y - excess); + this.integerBounds.add(x + excess, y - excess); + this.integerBounds.add(x - excess, y + excess); + final double realExcess = this.currentLineWidth / 2; + addPointToRectangle2D(this.realBounds, x + realExcess, y + realExcess); + addPointToRectangle2D(this.realBounds, x - realExcess, y - realExcess); + addPointToRectangle2D(this.realBounds, x + realExcess, y - realExcess); + addPointToRectangle2D(this.realBounds, x - realExcess, y + realExcess); + } + + private void addPointToRectangle2D(final Rectangle2D rectangle, final double x, final double y) { + if (rectangle.getWidth() < 0 || rectangle.getHeight() < 0) { + rectangle.setRect(x, y, 0, 0); + } else { + rectangle.add(x, y); + } + } + + private void addRectangleToBounds(final int x, final int y, final int width, final int height) { + addPointToBounds(x, y); + addPointToBounds(x + width, y + height); + addPointToBounds(x, y + height); + addPointToBounds(x + width, y); + } + + private interface Drawable { + + void draw(Graphics2D g); + } + + @Override + public void drawLine(final int x1, final int y1, final int x2, final int y2) { + addPointToBounds(x1, y1); + addPointToBounds(x2, y2); + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.drawLine(x1, y1, x2, y2); + } + }); + } + + @Override + public void fillRect(final int x, final int y, final int width, final int height) { + addRectangleToBounds(x, y, width - 1, height - 1); + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.fillRect(x, y, width, height); + } + }); + } + + @Override + public void drawPolygon(final int[] xPoints, final int[] yPoints, final int nPoints) { + for (int i = 0; i < nPoints; i++) { + addPointToBounds(xPoints[i], yPoints[i]); + } + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.drawPolygon(xPoints, yPoints, nPoints); + } + }); + } + + @Override + public void fillPolygon(final int[] xPoints, final int[] yPoints, final int nPoints) { + for (int i = 0; i < nPoints; i++) { + addPointToBounds(xPoints[i], yPoints[i]); + } + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.fillPolygon(xPoints, yPoints, nPoints); + } + }); + } + + @Override + public Color getColor() { + return this.currentColor; + } + + @Override + public void setColor(final Color c) { + this.currentColor = c; + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.setColor(c); + } + }); + } + + @Override + public void drawOval(final int x, final int y, final int width, final int height) { + addRectangleToBounds(x, y, width, height); + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.drawOval(x, y, width, height); + } + }); + } + + @Override + public void fillOval(final int x, final int y, final int width, final int height) { + addRectangleToBounds(x, y, width - 1, height - 1); + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.fillOval(x, y, width, height); + } + }); + } + + @Override + public void setStroke(final Stroke s) { + if (s instanceof BasicStroke) { + final BasicStroke stroke = (BasicStroke) s; + this.currentLineWidth = stroke.getLineWidth(); + } + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.setStroke(s); + } + }); + } + + @Override + public void drawString(final String str, final int x, final int y) { + final Rectangle stringBounds = getFontMetrics(this.currentFont).getStringBounds(str, this.graphics).getBounds(); + addRectangleToBounds(x, y - stringBounds.height, stringBounds.width, stringBounds.height); + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.drawString(str, x, y); + } + }); + } + + @Override + public Font getFont() { + return this.currentFont; + } + + @Override + public void setFont(final Font font) { + this.currentFont = font; + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.setFont(font); + } + }); + } + + @Override + public FontMetrics getFontMetrics(final Font f) { + return this.graphics.getFontMetrics(f); + } + + @Override + public void setRenderingHint(final Key hintKey, final Object hintValue) { + this.toBeDrawn.add(new Drawable() { + @Override + public void draw(final Graphics2D g) { + g.setRenderingHint(hintKey, hintValue); + } + }); + } + + //########################// NOT SUPPORTED YET //#########################// + + @Override + public void draw(final Shape s) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final AffineTransform xform, final ImageObserver obs) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawImage(final BufferedImage img, final BufferedImageOp op, final int x, final int y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawRenderedImage(final RenderedImage img, final AffineTransform xform) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawRenderableImage(final RenderableImage img, final AffineTransform xform) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawString(final String str, final float x, final float y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawString(final AttributedCharacterIterator iterator, final int x, final int y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawString(final AttributedCharacterIterator iterator, final float x, final float y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawGlyphVector(final GlyphVector g, final float x, final float y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void fill(final Shape s) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hit(final Rectangle rect, final Shape s, final boolean onStroke) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public GraphicsConfiguration getDeviceConfiguration() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setComposite(final Composite comp) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setPaint(final Paint paint) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getRenderingHint(final Key hintKey) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setRenderingHints(final Map<?, ?> hints) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void addRenderingHints(final Map<?, ?> hints) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public RenderingHints getRenderingHints() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void translate(final int x, final int y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void translate(final double tx, final double ty) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void rotate(final double theta) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void rotate(final double theta, final double x, final double y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void scale(final double sx, final double sy) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void shear(final double shx, final double shy) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void transform(final AffineTransform tx) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTransform(final AffineTransform tx) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AffineTransform getTransform() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Paint getPaint() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Composite getComposite() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setBackground(final Color color) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Color getBackground() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Stroke getStroke() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clip(final Shape s) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public FontRenderContext getFontRenderContext() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Graphics create() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setPaintMode() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setXORMode(final Color c1) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Rectangle getClipBounds() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clipRect(final int x, final int y, final int width, final int height) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setClip(final int x, final int y, final int width, final int height) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Shape getClip() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setClip(final Shape clip) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void copyArea(final int x, final int y, final int width, final int height, final int dx, final int dy) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clearRect(final int x, final int y, final int width, final int height) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawRoundRect(final int x, final int y, final int width, final int height, final int arcWidth, final int arcHeight) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void fillRoundRect(final int x, final int y, final int width, final int height, final int arcWidth, final int arcHeight) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawArc(final int x, final int y, final int width, final int height, final int startAngle, final int arcAngle) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void fillArc(final int x, final int y, final int width, final int height, final int startAngle, final int arcAngle) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawPolyline(final int[] xPoints, final int[] yPoints, final int nPoints) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int x, final int y, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int x, final int y, final int width, final int height, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int x, final int y, final Color bgcolor, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int x, final int y, final int width, final int height, final Color bgcolor, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int dx1, final int dy1, final int dx2, final int dy2, final int sx1, final int sy1, final int sx2, final int sy2, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int dx1, final int dy1, final int dx2, final int dy2, final int sx1, final int sy1, final int sx2, final int sy2, final Color bgcolor, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void dispose() { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/pne-editor/src/org/pneditor/util/Colors.java b/pne-editor/src/org/pneditor/util/Colors.java new file mode 100644 index 0000000..48f5897 --- /dev/null +++ b/pne-editor/src/org/pneditor/util/Colors.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.util; + +import java.awt.Color; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class Colors { + + public static final Color CONNECTING = Color.GREEN; + public static final Color DISALLOWED = Color.RED; + public static final Color PERMITTED = Color.GREEN; + public static final Color SELECTED = Color.LIGHT_GRAY; + public static final Color SINGLESELECTED = Color.GRAY; + public static final Color POINTING = Color.BLUE; +} diff --git a/pne-editor/src/org/pneditor/util/Command.java b/pne-editor/src/org/pneditor/util/Command.java new file mode 100644 index 0000000..17d7a95 --- /dev/null +++ b/pne-editor/src/org/pneditor/util/Command.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.util; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public interface Command { + + void execute(); + + void undo(); + + void redo(); +} diff --git a/pne-editor/src/org/pneditor/util/EPSGraphics2D.java b/pne-editor/src/org/pneditor/util/EPSGraphics2D.java new file mode 100644 index 0000000..5aef4a5 --- /dev/null +++ b/pne-editor/src/org/pneditor/util/EPSGraphics2D.java @@ -0,0 +1,635 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.util; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.RenderingHints.Key; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class EPSGraphics2D extends Graphics2D { + + private static final String APP_NAME = "PNEditor"; + private final Graphics graphics = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).getGraphics(); + private Font currentFont = new Font(null); + private final ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); + private final PrintStream out = new PrintStream(this.arrayOutputStream); + private final CachedGraphics2D cachedGraphics = new CachedGraphics2D(); + private Color currentColor = Color.black; + + public void writeToFile(final File file) throws FileNotFoundException { + final PrintStream fileOut = new PrintStream(file); + fileOut.println("%!PS-Adobe-3.0 EPSF-3.0"); + fileOut.println("%%Creator: " + APP_NAME); + fileOut.println("%%Pages: 1"); + fileOut.println("%%Orientation: Portrait"); + final Rectangle2D bounds = xy(this.cachedGraphics.getRealBounds()); + fileOut.println("%%BoundingBox: " + + (long) Math.floor(bounds.getMinX()) + " " + + (long) Math.floor(bounds.getMinY()) + " " + + (long) Math.ceil(bounds.getMaxX()) + " " + + (long) Math.ceil(bounds.getMaxY())); + fileOut.println("%%HiResBoundingBox: " + + bounds.getMinX() + " " + + bounds.getMinY() + " " + + bounds.getMaxX() + " " + + bounds.getMaxY()); + fileOut.println("%%EndComments"); + fileOut.println("%%Page: 1 1"); + fileOut.println("0 0 0 setrgbcolor"); + fileOut.println("[] 0 setdash"); + fileOut.println("1 setlinewidth"); + fileOut.println("0 setlinejoin"); + fileOut.println("0 setlinecap"); + fileOut.println("gsave [1 0 0 1 0 0] concat"); + fileOut.println("/Times-Bold findfont"); + fileOut.println("12 scalefont"); + fileOut.println("setfont"); + fileOut.print(this.arrayOutputStream.toString()); + fileOut.println("grestore"); + fileOut.println("showpage"); + fileOut.println("%%EOF"); + fileOut.close(); + } + + private double x(final double x) { + return x; + } + + private double y(final double y) { + return -y; + } + + private Rectangle2D xy(final Rectangle2D rectangle) { + final Rectangle2D result = new Rectangle2D.Double(); + final double x1 = x(rectangle.getX()); + final double y1 = y(rectangle.getY()); + final double x2 = x(rectangle.getMaxX()); + final double y2 = y(rectangle.getMaxY()); + result.setFrameFromDiagonal(x1, y1, x2, y2); + return result; + } + + private void newPath() { + this.out.println("newpath"); + } + + private void closePath() { + this.out.println("closepath"); + } + + private void stroke() { + this.out.println("stroke"); + } + + private void fill() { + this.out.println("fill"); + } + + private void moveTo(final double x, final double y) { + this.out.println(x(x) + " " + y(y) + " moveto"); + } + + private void lineTo(final double x, final double y) { + this.out.println(x(x) + " " + y(y) + " lineto"); + } + + private void curveTo(final double x1, final double y1, final double x2, final double y2, final double x3, final double y3) { + this.out.println(x(x1) + " " + y(y1) + " " + x(x2) + " " + y(y2) + " " + x(x3) + " " + y(y3) + " curveto"); + } + + private void circle(final double centerX, final double centerY, final double radius) { + this.out.println(x(centerX) + " " + y(centerY) + " " + radius + " 0 360 arc"); + } + + private void setColor(final double red, final double green, final double blue) { + this.out.println(red + " " + green + " " + blue + " setrgbcolor"); + } + + @Override + public void drawLine(final int x1, final int y1, final int x2, final int y2) { + this.cachedGraphics.drawLine(x1, y1, x2, y2); + this.out.println(); + this.out.println("% begin drawLine"); + newPath(); + moveTo(x1, y1); + lineTo(x2, y2); + stroke(); + this.out.println("% end drawLine"); + this.out.println(); + } + + private void makeRectanglePath(final int x, final int y, final int width, final int height) { + newPath(); + moveTo(x, y); + lineTo(x + width, y); + lineTo(x + width, y + height); + lineTo(x, y + height); + closePath(); + } + + @Override + public void drawRect(final int x, final int y, final int width, final int height) { + this.cachedGraphics.drawRect(x, y, width, height); + this.out.println(); + this.out.println("% begin drawRect"); + makeRectanglePath(x, y, width + 1, height + 1); + stroke(); + this.out.println("% end drawRect"); + this.out.println(); + } + + @Override + public void fillRect(final int x, final int y, final int width, final int height) { + this.cachedGraphics.fillRect(x, y, width, height); + this.out.println(); + this.out.println("% begin fillRect"); + makeRectanglePath(x, y, width, height); + fill(); + this.out.println("% end fillRect"); + this.out.println(); + } + + private void makePolygonPath(final int[] xPoints, final int[] yPoints, final int nPoints) { + newPath(); + moveTo(xPoints[0], yPoints[0]); + for (int i = 1; i < nPoints; i++) { + lineTo(xPoints[i], yPoints[i]); + } + closePath(); + } + + @Override + public void drawPolygon(final int[] xPoints, final int[] yPoints, final int nPoints) { + this.cachedGraphics.drawPolygon(xPoints, yPoints, nPoints); + this.out.println(); + this.out.println("% begin drawPolygon"); + makePolygonPath(xPoints, yPoints, nPoints); + stroke(); + this.out.println("% end drawPolygon"); + this.out.println(); + } + + @Override + public void fillPolygon(final int[] xPoints, final int[] yPoints, final int nPoints) { + this.cachedGraphics.fillPolygon(xPoints, yPoints, nPoints); + this.out.println(); + this.out.println("% begin fillPolygon"); + makePolygonPath(xPoints, yPoints, nPoints); + fill(); + this.out.println("% end fillPolygon"); + this.out.println(); + } + + @Override + public Color getColor() { + return this.currentColor; + } + + @Override + public void setColor(final Color c) { + final double red = (double) c.getRed() / 255; + final double green = (double) c.getGreen() / 255; + final double blue = (double) c.getBlue() / 255; + setColor(red, green, blue); + this.currentColor = c; + } + + private void makeOvalPath(final int x, final int y, final int width, final int height) { + newPath(); + if (width == height) { + final double radius = (double) width / 2; + final double centerX = x + radius; + final double centerY = y + radius; + circle(centerX, centerY, radius); + closePath(); + } else { + final double kappa = 0.552_284_749_8; + final double lHorizontal = kappa * width / 2; + final double lVertical = kappa * height / 2; + final double halfWidth = (double) width / 2; + final double halfHeight = (double) height / 2; + moveTo(x + halfWidth, y); + curveTo(x + halfWidth + lHorizontal, y, + x + width, y + lVertical, + x + width, y + halfHeight); + curveTo(x + width, y + halfHeight + lVertical, + x + halfWidth + lHorizontal, y + height, + x + halfWidth, y + height); + curveTo(x + lHorizontal, y + height, + x, y + halfHeight + lVertical, + x, y + halfHeight); + curveTo(x, y + lVertical, + x + lHorizontal, y, + x + halfWidth, y); + closePath(); + } + } + + @Override + public void drawOval(final int x, final int y, final int width, final int height) { + this.cachedGraphics.drawOval(x, y, width, height); + this.out.println(); + this.out.println("% begin drawOval"); + makeOvalPath(x, y, width + 1, height + 1); + stroke(); + this.out.println("% end drawOval"); + this.out.println(); + } + + @Override + public void fillOval(final int x, final int y, final int width, final int height) { + this.cachedGraphics.fillOval(x, y, width, height); + this.out.println(); + this.out.println("% begin fillOval"); + makeOvalPath(x, y, width, height); + fill(); + this.out.println("% end fillOval"); + this.out.println(); + } + + @Override + public void setStroke(final Stroke s) { + this.cachedGraphics.setStroke(s); + if (s instanceof BasicStroke) { + final BasicStroke stroke = (BasicStroke) s; + final double currentLineWidth = stroke.getLineWidth(); + final float[] dashArray = stroke.getDashArray(); + final int lineCap = stroke.getEndCap(); + final int lineJoin = stroke.getLineJoin(); + this.out.println(currentLineWidth + " setlinewidth"); + this.out.println(lineCap + " setlinecap"); + this.out.println(lineJoin + " setlinejoin"); + if (dashArray != null) { + final float dashPhase = stroke.getDashPhase(); + this.out.print("["); + for (final float d : dashArray) { + this.out.print(d + " "); + } + this.out.println("] " + dashPhase + " setdash"); + } else { + this.out.println("[] 0 setdash"); + } + } else { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + @Override + public void drawString(final String str, final int x, final int y) { + this.cachedGraphics.drawString(str, x, y); + final String fileStr = str.replace("(", "\\(").replace(")", "\\)"); + moveTo(x, y); + this.out.println("(" + fileStr + ") show"); + } + + @Override + public Font getFont() { + return this.currentFont; + } + + @Override + public FontMetrics getFontMetrics(final Font f) { + return this.graphics.getFontMetrics(f); + } + + @Override + public void setFont(final Font font) { + this.cachedGraphics.setFont(font); + this.out.println("/Times-Bold findfont"); +// System.out.println("/" + font.getFamily() + "-" + font.getStyle() + " findfont"); + this.out.println(font.getSize() + (2 * font.getSize() / 12) + " scalefont"); + this.out.println("setfont"); + this.currentFont = font; + } + + //########################// NOT SUPPORTED YET //#########################// + @Override + public void draw(final Shape s) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final AffineTransform xform, final ImageObserver obs) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawImage(final BufferedImage img, final BufferedImageOp op, final int x, final int y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawRenderedImage(final RenderedImage img, final AffineTransform xform) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawRenderableImage(final RenderableImage img, final AffineTransform xform) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawString(final String str, final float x, final float y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawString(final AttributedCharacterIterator iterator, final int x, final int y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawString(final AttributedCharacterIterator iterator, final float x, final float y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawGlyphVector(final GlyphVector g, final float x, final float y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void fill(final Shape s) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hit(final Rectangle rect, final Shape s, final boolean onStroke) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public GraphicsConfiguration getDeviceConfiguration() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setComposite(final Composite comp) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setPaint(final Paint paint) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setRenderingHint(final Key hintKey, final Object hintValue) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getRenderingHint(final Key hintKey) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setRenderingHints(final Map<?, ?> hints) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void addRenderingHints(final Map<?, ?> hints) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public RenderingHints getRenderingHints() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void translate(final int x, final int y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void translate(final double tx, final double ty) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void rotate(final double theta) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void rotate(final double theta, final double x, final double y) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void scale(final double sx, final double sy) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void shear(final double shx, final double shy) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void transform(final AffineTransform tx) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTransform(final AffineTransform tx) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AffineTransform getTransform() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Paint getPaint() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Composite getComposite() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setBackground(final Color color) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Color getBackground() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Stroke getStroke() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clip(final Shape s) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public FontRenderContext getFontRenderContext() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Graphics create() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setPaintMode() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setXORMode(final Color c1) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Rectangle getClipBounds() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clipRect(final int x, final int y, final int width, final int height) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setClip(final int x, final int y, final int width, final int height) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Shape getClip() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setClip(final Shape clip) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void copyArea(final int x, final int y, final int width, final int height, final int dx, final int dy) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clearRect(final int x, final int y, final int width, final int height) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawRoundRect(final int x, final int y, final int width, final int height, final int arcWidth, final int arcHeight) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void fillRoundRect(final int x, final int y, final int width, final int height, final int arcWidth, final int arcHeight) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawArc(final int x, final int y, final int width, final int height, final int startAngle, final int arcAngle) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void fillArc(final int x, final int y, final int width, final int height, final int startAngle, final int arcAngle) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void drawPolyline(final int[] xPoints, final int[] yPoints, final int nPoints) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int x, final int y, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int x, final int y, final int width, final int height, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int x, final int y, final Color bgcolor, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int x, final int y, final int width, final int height, final Color bgcolor, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int dx1, final int dy1, final int dx2, final int dy2, final int sx1, final int sy1, final int sx2, final int sy2, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean drawImage(final Image img, final int dx1, final int dy1, final int dx2, final int dy2, final int sx1, final int sy1, final int sx2, final int sy2, final Color bgcolor, final ImageObserver observer) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void dispose() { + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/pne-editor/src/org/pneditor/util/GraphicsTools.java b/pne-editor/src/org/pneditor/util/GraphicsTools.java new file mode 100644 index 0000000..5642e37 --- /dev/null +++ b/pne-editor/src/org/pneditor/util/GraphicsTools.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.util; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class GraphicsTools { + + //PNEConstantsConfiguration.RESOURCESDIR already ends with a File.separator + //private final static String RESOURCESDIR = File.separator+org.pneditor.PNEConstantsConfiguration.RESOURCESDIR; + + public static ImageIcon getIcon(final String fileName) { + return new ImageIcon(GraphicsTools.class.getResource(fileName)); + //return new ImageIcon(GraphicsTools.class.getResource(RESOURCESDIR + fileName)); + } + + public static Cursor getCursor(final String fileName, final Point center) { + final Toolkit tk = Toolkit.getDefaultToolkit(); + //final Image image = tk.getImage(GraphicsTools.class.getResource(RESOURCESDIR + fileName)); + final Image image = tk.getImage(GraphicsTools.class.getResource(fileName)); + return tk.createCustomCursor(image, center, fileName); + } + + public static BufferedImage getBufferedImage(final String fileName) { + try { + return ImageIO.read(GraphicsTools.class.getResource(fileName)); + } catch (IOException ex) { + Logger.getLogger(GraphicsTools.class.getName()).log(Level.SEVERE, null, ex); //TODO: change this + return new BufferedImage(1, 1, IndexColorModel.TRANSLUCENT); + } + } + + public static void setDashedStroke(final Graphics g) { + final float dash1[] = {4.0f}; + final BasicStroke dashed = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 4.0f, dash1, 0.0f); + ((Graphics2D) g).setStroke(dashed); + } + + public static void setDefaultStroke(final Graphics g) { + final BasicStroke defaultStroke = new BasicStroke(); + ((Graphics2D) g).setStroke(defaultStroke); + } + + + public enum HorizontalAlignment { + + LEFT, + RIGHT, + CENTER + } + + public enum VerticalAlignment { + + TOP, + CENTER, + BOTTOM + } + + public static void drawString(final Graphics g, final String str, final int x, final int y, + final HorizontalAlignment horizontalAlignment, + final VerticalAlignment verticalAlignment) { + final int textWidth = g.getFontMetrics().stringWidth(str); + final int textHeight = g.getFontMetrics().getAscent(); + int resultX = x; + int resultY = y; + + // if horizontalAligment is left, do nothing + if (horizontalAlignment == HorizontalAlignment.CENTER) { + resultX -= textWidth / 2; + } else if (horizontalAlignment == HorizontalAlignment.RIGHT) { + resultX -= textWidth; + } + + // if verticalAligment is bottom, do nothing + if (verticalAlignment == VerticalAlignment.TOP) { + resultY += textHeight; + } else if (verticalAlignment == VerticalAlignment.CENTER) { + resultY += textHeight / 2 - 1; + } + + + final Color previousColor = g.getColor(); + g.setColor(new Color(1f, 1f, 1f, 0.7f)); +// g.setColor(new Color(0.7f, 0.7f, 1f, 0.7f)); //debug with this + g.fillRect(resultX, resultY - textHeight + 1, textWidth, g.getFontMetrics().getHeight() - 1); + g.setColor(previousColor); + g.drawString(str, resultX, resultY); + } + + //Jan Tancibok Inhibitor arc, Taken from http://stackoverflow.com/questions/21465570/two-points-and-then-finds-the-smallest-circle-and-the-smallest-rectangle-contain?rq=1 + public static void drawCircle(final Graphics g, final int xCenter, final int yCenter, final int x2, final int y2) { + final Graphics2D g2d = (Graphics2D) g; + g2d.setStroke(new BasicStroke(1f)); + + final double aDir = Math.atan2(xCenter - x2, yCenter - y2); + final int i2 = 9; //diameter + + final int x1 = x2 + xCor(i2, aDir); + final int y1 = y2 + yCor(i2, aDir); + + final double diameter = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); + final int cx = ((x2 + x1) / 2); + final int cy = (y2 + y1) / 2; + final int tlCornerx = (int) (cx - diameter / 2); + final int tlCornery = (int) (cy - diameter / 2); + + g2d.drawOval(tlCornerx, tlCornery, (int) diameter, (int) diameter); + g2d.fillOval(tlCornerx, tlCornery, (int) diameter, (int) diameter); + } + + //Taken from http://forum.java.sun.com/thread.jspa?threadID=378460&tstart=135 + public static void drawArrow(final Graphics g, final int xCenter, final int yCenter, final int x, final int y) { + final Graphics2D g2d = (Graphics2D) g; + final double aDir = Math.atan2(xCenter - x, yCenter - y); + //g2d.drawLine(x, y, xCenter, yCenter); + g2d.setStroke(new BasicStroke(1f)); // make the arrow head solid even if dash pattern has been specified + final Polygon tmpPoly = new Polygon(); + final int i1 = 12; + final int i2 = 6; // make the arrow head the same size regardless of the length + tmpPoly.addPoint(x, y); // arrow tip + tmpPoly.addPoint(x + xCor(i1, aDir + 0.5), y + yCor(i1, aDir + 0.5)); + tmpPoly.addPoint(x + xCor(i2, aDir), y + yCor(i2, aDir)); + tmpPoly.addPoint(x + xCor(i1, aDir - 0.5), y + yCor(i1, aDir - 0.5)); + tmpPoly.addPoint(x, y); // arrow tip + g2d.drawPolygon(tmpPoly); + g2d.fillPolygon(tmpPoly); // remove this line to leave arrow head unpainted + } + + //Jan Tancibok Reset arc + public static void drawArrowDouble(final Graphics g, final int xCenter, final int yCenter, final int x, final int y) { + final Graphics2D g2d = (Graphics2D) g; + final double aDir = Math.atan2(xCenter - x, yCenter - y); + //g2d.drawLine(x, y, xCenter, yCenter); + g2d.setStroke(new BasicStroke(1f)); // make the arrow head solid even if dash pattern has been specified + final Polygon tmpPoly = new Polygon(); + int i1 = 12; + final int i2 = 6; // make the arrow head the same size regardless of the length length + tmpPoly.addPoint(x, y); // arrow tip + tmpPoly.addPoint(x + xCor(i1, aDir + 0.5), y + yCor(i1, aDir + 0.5)); + tmpPoly.addPoint(x + xCor(i2, aDir), y + yCor(i2, aDir)); + tmpPoly.addPoint(x + xCor(i1, aDir - 0.5), y + yCor(i1, aDir - 0.5)); + tmpPoly.addPoint(x, y); // arrow tip + g2d.drawPolygon(tmpPoly); + g2d.fillPolygon(tmpPoly); + + i1 = 24; + final int move = 6; + final int dmove = 12; + tmpPoly.addPoint(x + xCor(i2 + move, aDir), y + yCor(i2 + move, aDir)); // arrow tip + tmpPoly.addPoint(x + xCor(i1, aDir - 0.25), y + yCor(i1, aDir - 0.25)); + tmpPoly.addPoint(x + xCor(i2 + dmove, aDir), y + yCor(i2 + dmove, aDir)); + tmpPoly.addPoint(x + xCor(i1, aDir + 0.25), y + yCor(i1, aDir + 0.25)); + tmpPoly.addPoint(x + xCor(i2 + move, aDir), y + yCor(i2 + move, aDir)); // arrow tip + g2d.drawPolygon(tmpPoly); + g2d.fillPolygon(tmpPoly);// remove this line to leave arrow head unpainted + } + + private static int yCor(final int len, final double dir) { + return (int) (len * Math.cos(dir)); + } + + private static int xCor(final int len, final double dir) { + return (int) (len * Math.sin(dir)); + } + + public static boolean isPointNearSegment(final Point from, final Point to, final Point testPos, final int nearTolerance) { + final Rectangle r = new Rectangle(testPos.x - nearTolerance / 2, testPos.y - nearTolerance / 2, nearTolerance, nearTolerance); + return r.intersectsLine(from.x, from.y, to.x, to.y); + } + + public static boolean isPointNearPoint(final Point from, final Point testPos, final int nearTolerance) { + final Rectangle r1 = new Rectangle(from.x - nearTolerance / 2, from.y - nearTolerance / 2, nearTolerance, nearTolerance); + final Rectangle r2 = new Rectangle(testPos.x, testPos.y, 1, 1); + return r2.intersects(r1); + } +} diff --git a/pne-editor/src/org/pneditor/util/Point.java b/pne-editor/src/org/pneditor/util/Point.java new file mode 100644 index 0000000..9905d9b --- /dev/null +++ b/pne-editor/src/org/pneditor/util/Point.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.util; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class Point { + + private java.awt.Point point; + + public Point(final int x, final int y) { + this.point = new java.awt.Point(x, y); + } + + public Point(final java.awt.Point point) { + this.point = point; + } + + public Point() { + this(0, 0); + } + + public int getX() { + return this.point.x; + } + + public int getY() { + return this.point.y; + } + + public double distance(final Point pointTo) { + return this.point.distance(pointTo.point); + } + + public Point getTranslated(final int dx, final int dy) { + return new Point(getX() + dx, getY() + dy); + } + + public Point getTranslated(final Point pointToTranslate) { + return new Point(getX() + pointToTranslate.getX(), getY() + pointToTranslate.getY()); + } + + public Point getNegative() { + return new Point(-getX(), -getY()); + } + + public java.awt.Point getPoint() { + return new java.awt.Point(this.point); + } + + @Override + public String toString() { + return "[" + this.point.x + ", " + this.point.y + "]"; + } + + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Point other = (Point) obj; + if (this.point != other.point && (this.point == null || !this.point.equals(other.point))) { //TODO: check + return false; + } + return true; + } + + @Override + public int hashCode() { + return 33 + (this.point != null ? this.point.hashCode() : 0); + } + +} diff --git a/pne-editor/src/org/pneditor/util/StringTools.java b/pne-editor/src/org/pneditor/util/StringTools.java new file mode 100644 index 0000000..15825dc --- /dev/null +++ b/pne-editor/src/org/pneditor/util/StringTools.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.util; + +import java.io.File; +import java.util.Locale; + +/** + * This class contains some simple string management functions. + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class StringTools { + + /** + * Returns extension of a file i.e. from File("example.html.txt") returns + * "txt" + * + * @param file file to get the extension from + * @return extension of the file + */ + public static String getExtension(final File file) { + return getExtension(file.getName()); + } + + private static String getExtension(final String filename) { + String ext = null; + final int i = filename.lastIndexOf('.'); + + if (i > 0 && i < filename.length() - 1) { + ext = filename.substring(i + 1).toLowerCase(Locale.ENGLISH); + } + if (ext != null) { + return ext; + } + return ""; + } + + public static String getExtensionCutOut(final String filename) { + final String extension = getExtension(filename); + return filename.substring(0, filename.length() - 1 - extension.length()); + } +} diff --git a/pne-editor/src/org/pneditor/workflow/WorkflowLogger.java b/pne-editor/src/org/pneditor/workflow/WorkflowLogger.java new file mode 100644 index 0000000..157cb4a --- /dev/null +++ b/pne-editor/src/org/pneditor/workflow/WorkflowLogger.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008-2010 Martin Riesz <riesz.martin at gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.pneditor.workflow; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Date; + +import org.pneditor.petrinet.models.initial.Transition; + +/** + * + * @author Martin Riesz <riesz.martin at gmail.com> + */ +public class WorkflowLogger { + + private static String defaultLogDirectory = System.getProperty("user.home") + File.separator+"logs"; + + public static void log(final String dirName, final String workflowFilename, final String caseId, final Transition transition, final String userId) throws IOException { + final File directory = new File(dirName); + if (!directory.exists()) { + directory.mkdirs(); + } + final File file = new File(dirName + File.separator + workflowFilename + ".log"); + final OutputStream fileOutputStream = Files.newOutputStream(Paths.get(file.toURI())); + final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); + final PrintStream out = new PrintStream(bufferedOutputStream); + out.println(caseId + " " + new Date().getTime() + " " + userId + " " + transition.getLabel()); + bufferedOutputStream.close(); + fileOutputStream.close(); + } + + public static void log(final String workflowFilename, final String caseId, final Transition transition, final String userId) throws IOException { + log(defaultLogDirectory, workflowFilename, caseId, transition, userId); + } + +} diff --git a/pne-editor/src/resources/icon16.png b/pne-editor/src/resources/icon16.png new file mode 100644 index 0000000000000000000000000000000000000000..d81727230644f550b4681ae5265967058a6022b7 GIT binary patch literal 664 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7Sc;uILpV4%IBGajIv5xj zI14-?iy0Ugr9qgn_q*Ry1_lPn64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xh zq!<{OL_J*`Lo9k*Cmr+-2^2Y2pMI}rkNU9*6Pq4+WC)8o8Y*v-@KA~o-?B<UeDej@ z-HiX+5?T(lKB^ap*qJxEJ6&b!6(yyak}qb?5;WGxKW6Ti@7Mi(%Q80Gf*sROTi&;Q z{@X4vv}k9{DU-85U6c%Y9$5Gt{JiI6jotrw!iNfC%}q^AzGPLsdbl$re)&wPj@jn! z>%NF?ue(>h>&K&~KYsl9R>&ZD+2r~1clRw@H?tiTjfii1#1*_<uRL<&38sdQ7@>*( z$`~%XC>i=xGM8P8tobIhD)rsH9b69n;qE~$X^rd$gav<ctXcKyVu&CEU)F~G+*gfq zYMV}}y?HN``HP`+f#kLRwx8)t#|ybiV!V@&HqX~ie^_E4QCRn8D)*{c!V@hIFuVPG zeBkq*lRKBDPQRzZv+Us^37%y$>;J9|%XQn#uqrC#>e(`x6AOF7bT$<nGn({c|B5So zTvyXfX3w9QIWf>Buf4%rm*Kc*%I3(kDMk!G_VG6)N-*5m=DX!?M7_J(<iw;Trf>V4 zE0q=YEEe9y&LnjEoobQbiq%=19JA({-iYMCvgy$SwT186jJ6%q_`p%2tkf^v%hqo9 z@U``iO)_&7Z|rASow)7TLVvB<jls_IADBlmhLl>X6o~Cux9al72%Q@@yV(DE^vV8Y zQNA{hIrQ(HPZw+j-tb%~w##_u>$I?B6W6v}_UXI0e}{e$?a>nPx{+`HLHcCevwi!Q T{+hwSz`)??>gTe~DWM4fa&RDG literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/icon32.png b/pne-editor/src/resources/icon32.png new file mode 100644 index 0000000000000000000000000000000000000000..ab227c3f4a1620add321edec3a25b4a5228bd32f GIT binary patch literal 1473 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}EX7WqAsieW95oy%9SjT% zoCO|{#S9Eg<{-@Yoz3MC0|SF(iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$ zQVa~NcAhSdArY->r{!h@r;8k~KkvJ~GIN&c+R01umg&sRkd!#4bLdLx{3yZHN9~3= zGk5$<{c%wIRDpqbO0?wNFU<z(9)%h`oktaek4^BM>!VTUF*i@vBwBe}W_b1+-^)vU zi|5x?Oxic|*s*U14nMv3`NN$5w&yMXe-;n&O1pKinO$0W;)#bDCcD%opPa%Rp)>7x z-1_aepMTyeXI=J2ecA;VJ_iGdD~BEyxSL4by|<};e%SVPV%snCE%Q9nartIx|2E;} zKKWNqdDrc)PdAV-na%@Jo_A-*#qFiui=Q93r?%w@M^C?#73(FIg^hWKugJ>$|Hd?Z zeVqJ_J(ZtNEoBH~65wmM-j<j7MW*V%tO1*XA&)2XB~Jt61(6Qh7vGGP$-2e1>?LRE z_YwwcG42CN5^l*BGIqbdiqGc|{O`|bz@})&@ljEtnq}n<rpYr|RHWmor%ryZw}!9u z?#rBvj2DqS47x&{GI=-m`(K`<{ObH;XD*jFj5b{d3f5O0lUworqvDp7o@sk`Z}G@~ z|L~5Z6US_UN8XA@*j*Vr+!klQx^{JywZD{sSo05oml5`F!}BiIJr#So@OSV*$!^C> z3)WrpH@UUnOnQ&x4(2!PHb)sWPNo<=&08)j$G6I)UtJ-!;M;Zkiub#BXI*z`vd!Pe zbXw-re7{F}(T;ZvPPGbbZ@lUd`R&YGr;bqLq&riB=FKx_W|*;TRhcpKGnJG}Sx<A6 zmRc!I4y!X}zT|S*gi)pOq-1(pLrB?Lb~CXv4M&qIWsDzb-*F1Qx^8NN>+(uxQy-NC zCD+eY`Y+5jyg0Q!vO|({j$gWu*G^B4jm$rIRxs*$YxXm6DDGp-VP&k?d+*)3b=BHZ zO!|#^?Ae+(VqTor4bSvn9#W95dL!o4`r9w}NFRH=_7}H<S7ji_N97NO7s53j#9Xei zi_gB@8N6(z^?`Rx?b4^_u}^2$ifeg#_0`KyE8g>&FWcI)?c3*N>v!!kEuS#ONO!4? z(o&mH9tOpwOLp%3nUs)wHoAS*wzKQLeQeoPyw>G!rP!VD=k<zT&L7}UKR;L7!)2%T zgrIlx^8Gm*?!UiZ`SaCRJD<zN3o@l=xw5bR%&BIwHdW^Tzw~u~%Bl-4OMkWQ{&~4c zvf+)vtCuf3zS-Znx2b%3SorJXZ!b8`I?}^3x4tbi+djW4{zL4i>sNF#By?4nmF`>Y zlkcp#a{vBzHM2h_dK<dBx@K%&wW@mR`d^=uj(s#{oKbv0vcZXc%Jk`{9TX;9pYErv zcd^uVy}bz6N~wq*Rwl-EvAfNFKmMWN({u324kb(9W}($dL92_iqHAmaK4Ltx$tQ|; zi;K?sc?Vv#1es3>(+X-<WtrgVzx{(v71M5Q>uZ<0!l#KGI1^|m-`}%)dHR{nDGnTk zLKPe`Q-l2cSAPtg`faB|P#agqMbTdWK7aP>ZxzliGTy*-gL#i`%Z~uBO2GhDb9es) zo&zsFyoqF5C9&3TLx0nhn}snq%(xWKr9>CWZs4hq%n*0_V`nyP?YEMwY4Z|FB;0;Y zT_p7~{Jmzfm;VZ;ss3jVoL&AywDZYj;g?fRohZ-`32R>bh|`wQ|763IPg|xGmFF?W z9$@)k{$bsePo?dL7yhd0o9D27<*M~-!p>V(F)d_V^g`-~_z#hcsX>0L7YME9GH~|y zxw~_*()xK0+Z#268m1J*$GP`Ce4}?YYiCycvl(|;BW)Y+F8wCXoe+20Fs3iXAvIOb z)-iMGE&VO3DvK_ix~VeR-9MpxWv!)vj;e4}iR*gHNgMTZ#6)C{b8p=9IAWH<(kKsy jh7)UF9^-Cx`oq76Z?06o^NB?a3=9mOu6{1-oD!M<H#ngT literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/icon48.png b/pne-editor/src/resources/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..a599ef868f9038b480b32ed5fffc9f1bd87c8f32 GIT binary patch literal 2310 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 literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/About16.gif b/pne-editor/src/resources/pneditor/About16.gif new file mode 100644 index 0000000000000000000000000000000000000000..04da95eb831806d5586b246423126eb2b477eb7b GIT binary patch literal 644 zcmZ?wbhEHb6krfwc=n%xfq~)w|NrODJ-B!G{n917ckVcM>g2tXC+?m&e&@>N=ZT3E z^YZ37IC#yNv2O0%%{z8nT)uqYqD9+%eZvnQzP)bUk!{<~Y~6bL;KA$r_g~$&@5<i2 zmv`^JxPAMXty@nWJ$n1_;hX#SU)i_s@}^D4jvl>r<jBo~2e0nme|hiTi>FUNICSXR z&71EoUw(e%$o0dAuU)$I^y0-Q7cM+LdGhwLV>hl|eR1m4ooCN}K6voy=FQjFuD!T$ z;o-S+_s^WUd;0X9d-vYoz5DLYowpx9{@;J#+Ogwz&R=-CZTpE&pFT~SHm$F(kC&JC zz<~oG?+tFO_>+Z^fx(kO2jompoG`HWHF!2Px3so;Fm!bAxihwQ8abGmYHP6wx%D+M zC}?w9*>dTrDa(1xZ1Qm8P&H;^w$@iv;q`Ex?JUc#X~AV@W1ue2Fv~+gN{mgH+tSX& zKyX{Lhq$6BKbNqjz2T)64-rWj4IOird+j0;tV*5R+g6G=9(n)af%K6NEez5;vwnI0 z2>iir;2_w<Ak4?b!l3xi-#NdavM4h>qeQ{Tz`#HusZt@hG*7`dGr1_gxU#q;HMdwt w!80#ePr)%KM<EELuvj4|wK%n?EHy=sm&?n?O~E}#AuP2>!BEeDmy5v~06tvqqyPW_ literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Add16.gif b/pne-editor/src/resources/pneditor/Add16.gif new file mode 100644 index 0000000000000000000000000000000000000000..0fc47e193cf88cea7e6718e602e71f560cfad5cd GIT binary patch literal 238 zcmZ?wbhEHb6krfw*!-X2|NsBbp8bFN^#9YR|IVEGf9A~7EnCiP-h5`o@`KBk9q8^} z(%rSVp<yNi1H*v>2N)O_6o0ZXGBEHl=rAxaFo4W(VDY$c(o;Kk!IFfE1EOgLZI=WR zI4U|W?|IL9ewvDw)OV&;*SGdcC3tN4nB^f_I3s9cLFZgn=C7u`v;EjLKl!X%7kPp4 z0MFzp$t(<t|NNcv3o45;(=$pGj0_A66p|_xf=lxhd^3}a@{22rOHy--brd}FlJyiE pb8-}dKnjZ$f>Mi9i^@_{^mw_veB2b=gA~G2ixdp?40yR1tO3<LV6OlG literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Copy16.gif b/pne-editor/src/resources/pneditor/Copy16.gif new file mode 100644 index 0000000000000000000000000000000000000000..fa986813a821559ca5120bf8dfaa3c38cd474190 GIT binary patch literal 288 zcmZ?wbhEHb6krfwIP#z2|NsBbpZ|aU?Ekap|DQek|Mc1ar%(UgzyI^@-EX&Vf4O?~ z{pHJV&z$*x=FGFro6l_CbY|1$Gn+P@*|_oah7BjztUb1B)sYn|4lP}}Z_%RN^B3%# zIdc;O1H*v>2N+;L@h1x-1A`2M4oCoGrvs~(f_h(yWnM$GR>*=p)m6DAxm^qmyF9Kf zSTgIanp12*uOzb=b3hs2b;gR*k!z2<dFi!RG4R?uGlk@f48EH#KNaE*-lKd=r6#*m zkwNjFzjJ;;Wl?5&Mu~!vfq{WSQl&z0X`X^_W^z$}ab<ByYHqQPf@fZ`o`PdejzSPf kVX;C`YH?~&S!#+NFPE2(n}U0gLRe~%f}x%PFBgL~0JxNcr2qf` literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Cut16.gif b/pne-editor/src/resources/pneditor/Cut16.gif new file mode 100644 index 0000000000000000000000000000000000000000..14b73a8577fa6d300ddf6ea8b1f999ee214f822f GIT binary patch literal 652 zcmZ?wbhEHb6krfw*!-V?fq~)w|NjRL9567LSW$81)2C0<r%&(d>f+_)1<7Gx#h)yU z3=B*RIv^R484N5w0Vh1QSyu$GG@YHvk`-Dm5p+GWNot11Y{}y%x{lV|$^2GjBj1*C zP(qNIuYgH`heJ!fMALz5($0gXN2a*VUwzVBQ=(n7@sN@4(~U|D)^D#}eR=oJ`<pj! zE?Ke!moq@NgE7QCj7aWbD?QLq;Gx5pePYR`ur(LwT~J@lreI~L?(=4<lkaMGDW78( zQ$iN4pSrAbYmDjyciFUDqs5_5oyD#6HPuuU#bj$4O?kSyyF=W)C-~GcOqn{3p|691 ziA_LIh?$pzon>Z-v52q`D>oM>AOEt6-U*D;w@-1~<>JU-y>R~aty?~S{IGcL>;QlN z^0Kl&zkk1b`*z>nz5oCJ|NZ;-w{PD*efo6w?%nn4*Som5K)eQVKLe8c*{3zsH#N7k zGSrvz3wHH%_jS|@icA&}m^xK}UtmIcUQKX*ZdpES89OV>gsS`nHD&d6%T{F1S-ZYm zscv)is{C~wO3G4o+0`q{JNEB5BrjIS;<9SHlAP38N%6WpC(4)9pAoxpt8~@UE!S^W zmtMS6md(mu|LB!V<*N7WM>l+_begm5D4&4hhIR6C9<4%ryO<yJ9c~v;W@BPd{O9kS zUr<?;nVwOiU}RumppaCl5L}w4;G3CTlwVv~T#}kwtfSzWm#nAYn3JOr1X5V65R_V+ eT2z*rqQ}eS<>RK{9;6VKTBKm8XTZzFU=0BM!05C9 literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Delete16.gif b/pne-editor/src/resources/pneditor/Delete16.gif new file mode 100644 index 0000000000000000000000000000000000000000..d9d1a338f4dea468baac6c6ad2a763b4af4d5b5e GIT binary patch literal 208 zcmZ?wbhEHb6krfwSoELa|NsAI&YYP!b7opvnz6Al0|Uc>0|yuw7!-f9FfuT(G3YQb zFff4BGB7)3?7EYuVkf$KYEO%7i#Ri5%5~GU1K(N??Cfwd;9z-uz$n-JM@+Z5!<p^Q zyrmBF489ld4U+Z$7}{kazIIL7p->eD2E~8=&iMtEMVaXtB??9c1_laAl?uV7c?!On z$wm3amBl5gxy3pPo_Wc73XVBB3PB)+#R@^G#i>PQsVREATwXqI3hqG)VW~w5hI$6P HTnyF#Awoxk literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/New16.gif b/pne-editor/src/resources/pneditor/New16.gif new file mode 100644 index 0000000000000000000000000000000000000000..3513dfddbb9402244b189c1886e738051f83b256 GIT binary patch literal 426 zcmZ?wbhEHb6krfwxcZ-gfq~)w|NjRL9JqD;&+Qw3PMvsj?#zd?r{AAB_3rk~zc;V{ zK7I1twJSfbU;VXv*TbVn-W)&n_TYhM`}aNBxA*ap!!HjXdVc=gmn)ZlT)Oz}*3G}? z&;MVy?%JkJH#cs)v48*bg9l$6KK$y!g>Um0oLac(%*s_)wr+c{W$V37oA0dOaDB(l zhtp>sUbN)widC0Cefo6x@ZoLSw(;`vg4{$jR{Y7r$iTqFpaaqY@)HAFi9=(7hmKUg zJA=>3mc21<5!wcGnV9q+haMH0%P=c@i>uU3Gr3f6>4>QT^6jp%Q<hmR@Lb^_AiQ3N zUr2&m(j!PfP@Kb=AxD&los-F6itbeBAYL}+nbVmVdl}idM3}OIyl474O`pHeIb_q6 zEi*iv7?T(s85IBdJLeZv7G<VqlqeV(7#JudRVoCR<|+7QCKu%wR~DC~<`(NHc;+SR sDLCfjC<K8N7Apj$7N-`KrKafda(Vf<DYyqIgrycK80s1Daxqu~09gODqyPW_ literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Open16.gif b/pne-editor/src/resources/pneditor/Open16.gif new file mode 100644 index 0000000000000000000000000000000000000000..fabd5676f96cf46b62fe3c91fce204c2339b64ea GIT binary patch literal 228 zcmZ?wbhEHb6krfw*!-X2|NsC0pPl(~_t@t<N6+kCcV^41Gn;3vnc22_M%(Hctuwo- z(~ON77#I#5IKTh~ia%Kx85npObU-|i84fIV8%}zzPEp7{%eC!_QkQ7*ycg{2M7A-u zKVTGICQv9S(&V}Mzyg68w^jsc&Rx~0c&ErZo?GoUCtu6bCr4$2lo%BM`8($qR2F5X zXOt)y85kHSBvmQ|m*y$>W+oTq7grXSq~;duD0t>2>nS+q<R}Dz6c#H4r52|am8GWW Z@p5_jxGA^?DTJjKDH!S*@NzL&0{~bDRk#2E literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Paste16.gif b/pne-editor/src/resources/pneditor/Paste16.gif new file mode 100644 index 0000000000000000000000000000000000000000..f118c7eab8c450001b762d80446f6b7b9f5222c3 GIT binary patch literal 298 zcmZ?wbhEHb6krfwIP#z2|Ns9_&+oc>a@(Dg+pZkic;(QBGiT16*|Yl0?lq_PtU0`O z`N7Rgx6JEYH?wu^%+{ro8<tLLnA=l5r>A;KYgu1IQCeDBvY}y|u`vS!!+`?_7%+h1 zPZmZ721y1TkPOI92iA}TwZ0V3qy{5d!H*FQonZ}$7pBczxb6ZA&kQ|hW(KXpv0aOj zIK4H()_*jSTz^buW7CzSj2Y5t9lK_nZGXjaG-m4+r764F!?(%pbFfW*`8&}t%2|;? z@t?nQenDkXW_m`6f{}rNfkINHLU3uGf^TMWQGRh{aY<@!v5tagUb3EoV@{4j5J+LM iLQraPYEfBgiXJbQmyer*dyqm{YLSAWo&hfxgEasbc6Cqy literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Preferences16.gif b/pne-editor/src/resources/pneditor/Preferences16.gif new file mode 100644 index 0000000000000000000000000000000000000000..32b77eee23246aea9b62b83c954d325b0fcc14b2 GIT binary patch literal 207 zcmZ?wbhEHb6krfwSoELa|NsAI&YVe0o0*oD#=yXE;J^U}Fi`x-!pOkD%Af<{fz&cE zJ4WofV<jMToNY%7!!HKTmQW6roe_~crlzs8DVZO*cuX`rFF3G7d|FHoJBNg;&cT%x zF&n43-8g6X+E;eh>HOUu3=E3@{GIa)DvL7HGfEVU3=9kuk}4H~OY;<bGn0$*iz|yu zQge%S6g=~i^%NX)auk9<3X2tjQj1fI%2HGGc)7fM+!Wk{6v9%A6b$tYc)1v?0sl2b A3IG5A literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Redo16.gif b/pne-editor/src/resources/pneditor/Redo16.gif new file mode 100644 index 0000000000000000000000000000000000000000..8fdd814c2f412a1d3de25534f056137fc26f8f1e GIT binary patch literal 201 zcmZ?wbhEHb6krfwSj52a|Ns9pXa3Ked4_?3;lP0d3^1VhlZBCifrUW_Bmh#&z-;ZY z>(0H$Ck0g(nzV4WUvoO487DALDTQkWhrv8<hAZ5&n`>WspNZNl+V<%~Z4e(<*U{t) zZD)_=aIH~eU{L($@0?#yS(KTcQKDdEU|^t-RH+bLny28KnOu}#Tv=R_np>=+;F*`K sr{I{AqYwmASga6~TAW%`mYSl+%jM<crr;i=5SCh`V5n!n%f(;~0H3u&+5i9m literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Remove16.gif b/pne-editor/src/resources/pneditor/Remove16.gif new file mode 100644 index 0000000000000000000000000000000000000000..c1b4ca11db482031fb59ece38e8f5b5798cd3663 GIT binary patch literal 213 zcmZ?wbhEHb6krfwSoELa|Ns974jedt{`|ao^YZfYY;A3Md3hNa7!-f9FfuSOGUzZc zFff4BGBCSK?7EXBz>=XdRrtk%?d$l(L{ylIgjP<=2xe$95Xfg<x2kpS`<Qe^*ZysX zbKDr_2X2x0=OYng*zw9oT~O!6q77lHaqSfo85k7*`8($qR2F5XXOt)y85kHSBvmQ| zm*y$>W+oTq7grXSq~;duD0t>2>nS+q<R}Dz6c#H4r52|am8GWW@p5_jxGA^?DTJjK NDH!S*@NzL&0|2s+M_B*> literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Save16.gif b/pne-editor/src/resources/pneditor/Save16.gif new file mode 100644 index 0000000000000000000000000000000000000000..954f1accde64db9e98e9a6e528b459f3027b018c GIT binary patch literal 206 zcmZ?wbhEHb6krfwSoELa|NsAI&YVe0OJiVQIB?(q0}LqsWMO1rU}4Y!34qixFgtkc zy7Mppgy(GrrWZSJiaJ`bh;!=1d(2YnS{bu?O4QnuN7UcgRP2<z{o4F6LrCMpl`|Z* z8V{*=ImH?+GVKVP$iSfZ&)+$}pt2}4J)=ay$iTorA*oU!xHM0}H#4~?zqqovBsI5K xN5L~MSx><+Cr2R&q_9{aD784Xs4O)_kC)5K$4$XKNFgk>NWoCgfR~HG8UTL*MS%bS literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/SaveAs16.gif b/pne-editor/src/resources/pneditor/SaveAs16.gif new file mode 100644 index 0000000000000000000000000000000000000000..8d3929c8aa7d56483d4d3b218e840ca56506561a GIT binary patch literal 255 zcmZ?wbhEHb6krfw*!-V?fq~)w|NjRL9566Qw6)Fq^y$<2^XJc;IdkaHq5b>!=jG)k zCMNRo@`BWXvEok_Mg|5Z1|1L&WCjCEWWWi}*DO4*WwbcF15$hhYeH5kuw7vD@T~0? zOg=jMSsMRo@d-(WGOyHDT}%s}aKW#|v7}2##hd;93eAc-hIW@9R|MyHC~vH=7Mv)Y z7i_xKC3?%pO{w~w3=E3@{GIa)DvL7HGfEVU3=9kuk}4H~OY;<bGn0$*iz|yuQge%S w6g=~i^%NX)auk9<3X2tjQj1fI%2HGGc)7fM+!Wk{6v9%A6b$tYc)1v?0b*HM6951J literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/Undo16.gif b/pne-editor/src/resources/pneditor/Undo16.gif new file mode 100644 index 0000000000000000000000000000000000000000..25cbc64796c7eddd97af39b2fbddf6a36f0c6234 GIT binary patch literal 137 zcmZ?wbhEHb6krfwIK;s4|Ns9pXa3Ked4>VZ{tp9+{{)?jQWHy3QxwWGOEMJPJ$(Zh z6o0ZXGBB_(=rAxaFn|nTV7Bzwb;nL`5~HfLVt`irkH}-D_tLqNn5Rfb7`|pWv-H`T h(_Q=K{?0L-w`khOm0rs(@@i}rNDEj#WdZ|(H2~v$Ib#3- literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/addrole.gif b/pne-editor/src/resources/pneditor/addrole.gif new file mode 100644 index 0000000000000000000000000000000000000000..a55d2a36e8282021094e9b799c60a9695440d3ff GIT binary patch literal 138 zcmZ?wbhEHb6krfwIK<Atz`(%8#U(5(Y-(z1W@eV1o!#Bt{r~@e#eag%MX8A;sVNHO znI#zt?w-B@42nNl7`YhO8FWC}Kn5@{TUG4Zb78{X8x32xTw-!56fCcuSx|a2G0sUV oD&<(^%S0Xr0}08(sFsfR>^Tx0>i3x1x9~_bE>m6L!N6b*0QGn*Q2+n{ literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/addtorole16.gif b/pne-editor/src/resources/pneditor/addtorole16.gif new file mode 100644 index 0000000000000000000000000000000000000000..b35b2752131848d62c17c14d570a14dd9c7b4204 GIT binary patch literal 111 zcmZ?wbhEHb6krfwIK<Atz`(%A$0r~lASWjm5D>6n!Ga4HF8u%hUk4-uQp3P(!?Ej5 zm4Vk!wce{v4LkGPzm*0v^0<0<H5>Unx;Srx_{<DlNfrSCwyv`Z2^>w*(d!)}WSROJ Mf|W}mL^&C(0U|>pWB>pF literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/arc16.gif b/pne-editor/src/resources/pneditor/arc16.gif new file mode 100644 index 0000000000000000000000000000000000000000..77e6c48b22fb6bb16f0a0b1dc0bae63a84e1c0c5 GIT binary patch literal 295 zcmZ?wbhEHb6krfwSgOpxz`(%B$jHmfD<dOgWo6~)=;-0$;p5}u@9!TP8X6lLo0F51 zmzP&wUf$5q(A?bI+1c6C(=%bhglW^J&6qJ`&YU@G*RI{LVZ+|Ndk-8qaO~KzvuDqq zKY#wxrAt??T)A`S&i(uMA3l8e`t|Gov;m4gSs1w(>=|@GJ^}fOfz9Q>`~nXhss0mB z3La*dX`bX@Fi`NABFW-l5ctnwPQ&7&4;6xa^F1yG<Xv*|c{u5fh<xXS@*j>4-<-wR Pq#B%fT01&j92u+udxx)Y literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/arc.gif b/pne-editor/src/resources/pneditor/canvas/arc.gif new file mode 100644 index 0000000000000000000000000000000000000000..d6128c07470b1a2da41968d2c4c05e498c323b86 GIT binary patch literal 129 zcmZ?wbhEHbRA5kGXkcVuU|{(F|G(ltLFb~>#FEq$h4Rdj3<Y;j-v9>1pDc`A42%pq zAVnbM3{1`~{bHxz&c8I<#3gj|<Xy(^D%)9G?(Ue9*0%H&*Is#>lk<5W8|%KR`D4v$ gx;F7_gr<_T-IAi2O-xI#toqt@HfwuK9wUP_0IU`-tN;K2 literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/fire.gif b/pne-editor/src/resources/pneditor/canvas/fire.gif new file mode 100644 index 0000000000000000000000000000000000000000..35553866b63d13dc5117a38100c74e32ba7a374d GIT binary patch literal 217 zcmZ?wbhEHbRA5kGXc1tL5aIdq;l&Xb4}+GN4=+4S3`+JG<Y<%}!6nW>B2fIv!pOzI z&!7X+2eOlaHSB?MU&>F0v{maIcJI@9b!dyl{EWZ%%GS-^6ZpYg<X6Y><oE5`yxl98 zPYKKMEx#5Wwk`G7CbMOie~3=r=efC{Hmp6=>;1OZ>u$gQv8V3*```Z?8k?Gv6d9}m D49iS= literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/fullrole.gif b/pne-editor/src/resources/pneditor/canvas/fullrole.gif new file mode 100644 index 0000000000000000000000000000000000000000..113b95af4daad79110a3e7aab6e6c9688778fa52 GIT binary patch literal 139 zcmZ?wbhEHb<YVAtc+3C-TwGkj!ou?M@}{PyW@cvD+1cIQ-47l-`2YVuNE#I@{$yd~ zV&G@c0SSZ5U|_K@IO(Zv>L6il_(NK~X8r+H<;)_v3bh&E<X8j*+FM0bA{C|_TJT*` XM2%g^aQX^OPZrMyo?Lr$1R1OWUq>On literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/mixedrole.gif b/pne-editor/src/resources/pneditor/canvas/mixedrole.gif new file mode 100644 index 0000000000000000000000000000000000000000..792b1cbcd027674342cc96d4902bd245603b11c5 GIT binary patch literal 166 zcmZ?wbhEHb<YVAtc+APbz`(%8#U(5(EH5u_YHDg`W|p0u-QC^&;K76c*nr|cLFb~> z#FEq$h4Rdj3<Y;j-v9>1pDc`A4Ezi_Amcy=GqBhhob=Q-b&#+&v^a2#lVO4k)AR{y ytEv{9NSswA<lrD97Bq!{Wm&@l5jF?Tq<|R>4Qfx_o0{V|CNY%E-W;jKU=08SDn0iA literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/partialrole.gif b/pne-editor/src/resources/pneditor/canvas/partialrole.gif new file mode 100644 index 0000000000000000000000000000000000000000..579b2bdc03b010a5bfba2348b7c8f8fe13d46371 GIT binary patch literal 172 zcmZ?wbhEHb<YVAtc+3C-TwGkj!ou?M@}{PyW@cvD+1Vu}CEeZKQ>IKgdGh3`Q>Pw0 zc<}%Ke~?lJ2E~7Z&PAz-C8;S2<(VZJ3hti10St;iSs1w(_!)FSYCr}vu()hE>8Wk% zAYonTb>J9h=M;_@=UE!h8yC$!D(1w%*cjo%DARqEF(4s;i<#BcP{T)nA=Q=fhABt; Tl|}_lhJ6nT6pnT>FjxZs(N#4m literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/partialrole2.gif b/pne-editor/src/resources/pneditor/canvas/partialrole2.gif new file mode 100644 index 0000000000000000000000000000000000000000..792b1cbcd027674342cc96d4902bd245603b11c5 GIT binary patch literal 166 zcmZ?wbhEHb<YVAtc+APbz`(%8#U(5(EH5u_YHDg`W|p0u-QC^&;K76c*nr|cLFb~> z#FEq$h4Rdj3<Y;j-v9>1pDc`A4Ezi_Amcy=GqBhhob=Q-b&#+&v^a2#lVO4k)AR{y ytEv{9NSswA<lrD97Bq!{Wm&@l5jF?Tq<|R>4Qfx_o0{V|CNY%E-W;jKU=08SDn0iA literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/place.gif b/pne-editor/src/resources/pneditor/canvas/place.gif new file mode 100644 index 0000000000000000000000000000000000000000..0bc14cb5751b51e6b04ef28c0d35a8030fdc88bc GIT binary patch literal 374 zcmZ?wbhEHbRA5kGSgOFlz`(%H&d$%zFD@=FFE6jIuCA}IZ*FdGZ*TAJ?(XmJA08ea zA0MBdo}QndUtV5bUtize-rnEeKYjZ2`Sa&5U%q_(`t{qlZ{NRv|MBC;&!0bk{rdI$ z_wPS{{`~#>_us#NXSl*ZQ>6Hlg^`Ovo<RrX6Of-6*d`z7FYpjy>N}BKcv419{6fa2 zn=WqRN3<t-*|_ZtV)*{}XkTkUswjhPy7;T4o3TFKyK{{H%BpYw?w#qE)8JcBUfJr? zRM*v(6xY`sRyE1FZ0fY>6K9pqnLE2>!NU3lWs8=1t(aTjwscz0{0)Vj8`d_jZzwC; mx~tu%xO#W?&XB_)sWVHD$4prtRh#Y~-hQ#cGdS6i!5RRfz?8ZG literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/token.gif b/pne-editor/src/resources/pneditor/canvas/token.gif new file mode 100644 index 0000000000000000000000000000000000000000..68dff14d7c6be853f2b012f65382eb47f0fa2981 GIT binary patch literal 117 zcmZ?wbhEHbRA5kGXkdT>#h)yUTnvm1Iv_qshJnear(bfxTmDD0CwO+9jnz57wsano z+|!C#O1sQ5r|wPpeR1>bQ;8)X_vSahsZzeQLAYn7i>J>f&q^`j1Fybxoz2>QXWe&h PzV72sHr<S2V6X-N93L%I literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/token_or_fire.gif b/pne-editor/src/resources/pneditor/canvas/token_or_fire.gif new file mode 100644 index 0000000000000000000000000000000000000000..116d562298a425dd66f3c259565dbbc30885a6e6 GIT binary patch literal 211 zcmZ?wbhEHbRA5kGXc1tL5aIdq;l&Xb4}+GN4=+4S3`+JG<Y<%}!6nW>B2fIv!pOzI z&!7X+2eOlaHQ<4AU&>F0v{maIcJI@9b!dyl{EWZ%%GS-^6ZpYg<X6Y>5W}!&rpeYX xK3{L%y6%$Pv{|-+-gotM|ENwpZ6+4geRtjc4?Al7*57{rV^7`r_w~*U)&LswN4Nk0 literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/canvas/transition.gif b/pne-editor/src/resources/pneditor/canvas/transition.gif new file mode 100644 index 0000000000000000000000000000000000000000..bce10117d110f6864f634e79e4010e8dc436d0c9 GIT binary patch literal 153 zcmZ?wbhEHbRA5kGSjfb{z`!tT)~skSQ2Zz8T$GwvlA5AWo>`Ki;O^-gz@Ye(g^`Pa zi9rXX6r_oPDYT`3<?M(2i|3qUY218o5Bu%bMc){&cN9IHx$V%aT?KQ_eaX0=xNddA z{@;wX%NDw4ocS=xJGuA=i(7SY?ANlTsmaljMn8WU9rZK1qO&#N+8eINy#68#4AuZE C0zHfX literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/closesubnet.gif b/pne-editor/src/resources/pneditor/closesubnet.gif new file mode 100644 index 0000000000000000000000000000000000000000..f5b2b7a3170ddc0ad2c20cbea588223d50b39317 GIT binary patch literal 97 zcmZ?wbhEHb6krfwSjfo0z`*by1{8m?Fmf?4G3bCqLGlbtMpN<|x?i1XXbHHe@;OKI sM}DEhf{C3AdX+QVG)`@L$vyr2raHCSB{xf%zL_0pe_doF!oXk+0N)NK(*OVf literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/converttransitiontosubnet.gif b/pne-editor/src/resources/pneditor/converttransitiontosubnet.gif new file mode 100644 index 0000000000000000000000000000000000000000..56111b9632510b94f8861bc0b2ee46f2ef8ba940 GIT binary patch literal 100 zcmZ?wbhEHb6krfwSjfo0z`*by1{8m?Fmf?4G3bCqLGlbtrY-f0v<3K?6HXs(U$!ZH wdsX6nm$pl3Im?c>-Tb|7%B;DY4?iqccKmhs@C^-%BNGmGR!lH(U}Ufc08u$9nE(I) literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/deleterole.gif b/pne-editor/src/resources/pneditor/deleterole.gif new file mode 100644 index 0000000000000000000000000000000000000000..112d3cd88d7409ab50c33a4deb3b1e114d40f55c GIT binary patch literal 132 zcmZ?wbhEHb6krfwIK<Atz`(%8#U(5(Y-(z1W@eV1o!#Bt{r~@e#eag%MX8A;sVNHO znI#zt?w-B@42nNl7`YhO8FWC}Kn5@{n^f$&^Y25W<>FY@jw0iy6CE<Ad2miMZw%ZP idyIjlSy1q?i%rEkbGG{@woTwvXLfsF!Kop{U=0AjQYfAP literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/export.gif b/pne-editor/src/resources/pneditor/export.gif new file mode 100644 index 0000000000000000000000000000000000000000..6450b2e65c68b4a2c8afad8a67111e9104ef885b GIT binary patch literal 156 zcmZ?wbhEHb6krfwIK;-lz`&4}mNs+dOye^QXU?4Y|DWMM7%2V|bS_FwEJ;mKD9<d( zP;mG34Pa3G$->CRz|Nop(gresf!U{G)rEiEGZR*A7W6s9crkuk>3l)Gr~|dVoE<Kz z;mbwt{D_r*8M9LV%8@O%SaMzZCVtE?bCR0>o+C<-tM%Z5Wr7v^<MS@<vidYfz?F%? F8URSVJ_7&% literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/filechooser/eps.gif b/pne-editor/src/resources/pneditor/filechooser/eps.gif new file mode 100644 index 0000000000000000000000000000000000000000..42e46be7df27a12c84d9b9825bd81858ed6338df GIT binary patch literal 599 zcmZ?wbhEHb6krfwIOf5?z`(%9#-^mCs;;iCZ(wX<V(Q@F5)qLQ6`dF#pPZbW+T7CH z-qGLNH)+!3sk7#sT)uq$s#QC8?>V?<&&mD!@9#TsfB%8|2M;|sbm-xs!w-%gdvx^J z<D<tPojmpA)Tt-u&ObYM{`vXy&(B?We&x!w%U51rzVhnIm6w;VzPx<()s?F+uUvg~ z^VXaD_ut=t@czluPfwqIeERg$t5;uMzxw*>^_N$#zrKF`_5J(r?>~J1@ZtNHFTcKg z{rTnVudiQ!e*OCE=Z`->e*XFS^Y_o6fByXW`{&QUzkmMz{qqk*{QdWThycZZg3d*$ zi6yBi3gww484B*6z5xu1KUo;L80r~xK+yw=C<gZV4fXX5Ev+q09UTl}q9UR_?VU{w z;*t_mB^dY_CN)dTNG+6_HG2|+><T$qxwbi7N(u_{8{{`BuA8i;siLB;s-dN+wxe15 z*l|I2riqhvbac;gFtBh7A7L=i)6-{T;JImV-Nev{lR?1P^zn6bb0G#^v$qx&*R5^2 tSZyq=Ep4o>H?T-PP~Z@dcdTRC8J6PFAn4x4A?bAF#MUqgR#qkkYXI$-hCl!S literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/filechooser/file.gif b/pne-editor/src/resources/pneditor/filechooser/file.gif new file mode 100644 index 0000000000000000000000000000000000000000..c401de63c94ec51299bed7e2017dfd02743c6f3b GIT binary patch literal 368 zcmZ?wbhEHb6krfwxXJ(m|NsC0`{(c9KmUII`1AG4uMh8kyngj{|Ni@j4m~_|>dE=@ z&#zp0dH??Vr%yjUefsg$tFNzLe|`1p%lr4=KYaN9<;$<HUw?i1^7HH0pFe;8`Sa)B z&!4~l{Q0~8!2N@V9vnLS;OMc(M~^)^dFsimIVblWxPR{a^K<8)UB2?_%GFnwue`i+ z_2tc5Z*SgubM*M5a~Gc9fAIdv(@&SLzPfz%<*V0UU%mcv@4@@`AAY?5@cqfNPhY<N z`ttSXkDq`3{QdXm@8AFb|1&T!DE?$&WMHsk&;j`b<R=EUUWfVo4mv`u9x4l*ohHmU zzC_@`PnA`i2RIaDo1zvLc<i3a<dV_qk@!R_cIhO}yh-|Zg4?vFPMVvfp~X|-tkc%s zrmfw=z{{)OH^J1Dw};QbfPaR?biN*AA$EZUCV~rk%vZ9R39l3p>9G`J6_*gT6qT^* gk(QLSmXv1MFWJK^Wh-SPB_qXT+mn0A$&tYt0N&=<f&c&j literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/filechooser/pflow.gif b/pne-editor/src/resources/pneditor/filechooser/pflow.gif new file mode 100644 index 0000000000000000000000000000000000000000..2e131c71846f5de678029acb53a852f0c444b7a4 GIT binary patch literal 387 zcmZ?wbhEHb6krfwSjqqb0s?}9f<i(<Lb0(a@d>GEX&D(AnVFfHQ>ILrHRt61{rC4B zxWE6v{ey=d96I#y(BTJ1k3Bki?D5g#k4~O?a_ZERbLXF(JOBLr`RC^@Jil_~<&~>1 zuUvg~^VXZ2x8B~r|Nh>C_fMaGdiCndtJh!OfB634!}qUWetr4+^UK#?U%&qP@$=8m zpTB?p{PX9}-#>r;{r&Uz@1K7l;_tuz|Nny=M+hta6Lc<0O)N=GQ7F$W$xv|j^bKH8 z{K>+|#bD2%1JVuhC<9yff&2UpIzp`;Dhm!q7|b}nMBqV#%_{x|CIwk9wTT5TyQeZ~ zyx>}z^hC>edN*s{#N<1{zS0M7zL?A)%V6AM+$bkk;Vj>5%)!9OqR`Wz*xb*_$-p|T zLAjZUvxSpMsf$6yW#M8b)#VzRYHSQM8Q9d9YwPG}u`@8UYw0XE&@<FC($m$`H(Xww J>*UB_4FG!kuGs(p literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/filechooser/png.gif b/pne-editor/src/resources/pneditor/filechooser/png.gif new file mode 100644 index 0000000000000000000000000000000000000000..6b48693f3770868968c53d60752efe067c900057 GIT binary patch literal 599 zcmZ?wbhEHb6krfwIOfg3z`(%5!lI_8sjjZ2rKJr9I+2lakx_BcG4U}m39+#Wv2ls< z@kt2@iOntj?d=oWJ0^B@PwwuX)Yms<)|`{O_Z;7|=lFpGC-(2Zf8gNBeFyIEKXCux zp$CT!Jv?;y!O>%njvjk_^!THbr=FZT_2lf?b7#+<KY#w>`3o1%oqu-j{PXkYpP#$% z{PLBTm#@6Ka^>aat1mBKeRbvP%PUu3-MsbY{{8p&AH09^^wZO)pI*KC^6K^1_aDB0 z`0)M9mtSAL{`~Uw*VnH<zkdDo^T(ebKmYvv`TOV3KY#xG{qyJF-#>r<{`vRk@8AD} z8z}x0bS_FwEJ;mKD9<d(P;mG34Pa3G$->CRP|u(PiXKozF|f~XsIO;eX>Doh=wOhM zmXz*k?`&d_m6w|;#~{iusaa7;VWGmT*^?NQSEwkfw9V<#(bCe~pt(tV-DG_uU0nk` zLt`WT9nB`kO!)bkm>3z4FqoQ}nF<IpGoL+gVJ;-x!oe;ke%{JbM5Kk2OG@IrwKWS1 z5BGZ;oAdULY^;2|_O=c+Hp)RuW_AiWb@6C^(m6RXO~X&ZvdQJ-<}e9XRwf2(08(yx Ar~m)} literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/filechooser/pnml.gif b/pne-editor/src/resources/pneditor/filechooser/pnml.gif new file mode 100644 index 0000000000000000000000000000000000000000..b6470e7362b1bb0eac40974e894260b5475ea563 GIT binary patch literal 579 zcmZ?wbhEHb6krfwc*Xz%|NsC0`{(c9KmUII`1AG4uMh8k?B9R?(4mK?PCYq){`r+F zFJ)yF3JYsapT2wg^c^p+fQ*cS`}g0=%E})*cIn!+N7t@BtgUU%%`JNM>WiM9fuCRC z`}f~JeE9z5%df9re|`D#^Xu22KY#xD^XK2spTGb7`MdwX{ey=d96J2q=&{E~k3Bkh z>dCA*C-)t=fA0MAbLXF3zVhnI)t7trp1pbN&C%nJ&Ruw3SX6ue!TTpqKP4sSUcUPB z)$6Zr?tb?kynp}U$NLZ8uU>!T<sI<l>#r|ge`@RK|M>YwPF~^9-+zDp{{8>|KgfH7 z8!P@~VPs(NWY7UQ6BH*5><bz^JsDbBTbepL7}Rvxb$i-7n;6tJIHqzi=rBxb)-=&t zs5NW$BnIsjoZ6gibGl6R^z=9AZ{k`vncI-p(#pWb%#eFWvyre1zp*jD3lHBB20;OH zA)za_j)E6N+@!=TEF7fVL@!uNic36~7Jq)h{sWtx%m-Q73r_N^3W{=0a*AyZ%8E`d gf`Td>5+aPb2RKxe`+77Cofw2N)*5kfu`pNz08R?oJOBUy literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/import.gif b/pne-editor/src/resources/pneditor/import.gif new file mode 100644 index 0000000000000000000000000000000000000000..bceb6878e33b972519aaad07b9c3289dc2970015 GIT binary patch literal 183 zcmZ?wbhEHb6krfwc+A7Vz`&4ZY&^58dgjcTYi70?pJ6z&W!9O!>&~1x^X2Zb|Ig0+ z|IhFr2`K&(bS_FwEJ;mKD9<d(P;mG34Pa3G$->CRz|WuqG7e-g1B?HMlb);hT4YOA zZFi6`Qeh5ph!pB9^h(l^I`w<WDy|(NRUGVMXH$0@HaN8^3O1db*DkEL+*ndD;!RSZ bhC-0Ru>>ErddY`tthmeUTwl1eFjxZs`*%vf literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/label.gif b/pne-editor/src/resources/pneditor/label.gif new file mode 100644 index 0000000000000000000000000000000000000000..60d4e6eff1c2f39162607588aba9f4490a814313 GIT binary patch literal 100 zcmZ?wbhEHb6krfwSjfo0z`*by1{D7ZIv1rTmZYXAlxLP?D7bt21~4f8WMSlDU}De# uDFta_U{aXUzw-23-bHgv+PaIkIs86Q8>Nwy!dbQ=a_c4L<C|g_7_0#e(<CDR literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/layout.gif b/pne-editor/src/resources/pneditor/layout.gif new file mode 100644 index 0000000000000000000000000000000000000000..3fee08c888f8f67002e033a822006ee341d956d1 GIT binary patch literal 143 zcmZ?wbhEHb6krfwIK<4rz`&rYs=9yw{{N^z@t>e`QEFmIYKlU6W=V#EyQgmegW^vX zMlJ>x1|5(#kO2(L_8uFq+|q7RU@GA6*?UA_(iUFs)Wqq>G<%9S3bvf>_g?%%H{EpJ ip<OrhI40icT6xjiY^BbWh3B5{++?b|P}zWy!5RQ=x;oSV literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/layout.xcf b/pne-editor/src/resources/pneditor/layout.xcf new file mode 100644 index 0000000000000000000000000000000000000000..276aee00f24ed124a7a1fd436ad33985264ae8bc GIT binary patch literal 1317 zcmYe#%q>u;NKR8o%gjk-U|?VnfMO6^kb!}Lk&%IcL70Jofx~G60|N*%FffQPFfg!y z#26SD#Gq`DI#C7&Mt=qd240Y{y2<&uxv6<2Ad^6nLe530i6yBi3gww484B*6z5yT^ z0kG1{+{E-$-Snc&6p$Dr0|O(6MsZ1HPO3s?UP)?EacXi&W`16=CYMH9dUAeFevyI( zn9?muPfAoU&@%u7EDS@al%^(^MiLgSFnI;s43O4};)2BF%)E33V<VV>TpE?w1fgQO zrFoep3YmGy8L1#wSLCOq6{nWK9jM8rQHd!85kb`o3J)k|+{M7a;s@n`C|F#9LYK=g zwOqj`u`;y?B*O$E7#JAXppo+*8d;!71F7bOii4DKA+foU*gQyVUL-a@)GUx*5N1b` zgCz`RkOTxXWk6_n%3@()V5&hCW9k9%1sMLQ?pI}CV)*@^;XlKF#{Y~AfA;_1&%nmO z1Y)Af)iX3PF#Ts|_yrOMDQ0K*1yT%Qf(_zl7z!r-Qr-V!zbXSG!=L{Q4F8$`|J(nc z@&CX53``7v|AYBIK>Q#7IWc6=buu#i`_I4uBA7q~GV43YY*3&wurT}thb|<XnEpeR zLM>-v0I3AK=s)v+W{{g8&H-5ubqK0B^M59WAO9H`z<Qu%2Pj>FB9z-HF*!TED8Doh voUO4XMvyXECq`Ii0HxEfAPbS4$;`mO3bG$0405&r0|Tohh*QtV@E?W&$QM6y literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/log.gif b/pne-editor/src/resources/pneditor/log.gif new file mode 100644 index 0000000000000000000000000000000000000000..bc278f9ae9b15c27ba6bc9b0541b7836bae74fd5 GIT binary patch literal 677 zcmZ?wbhEHb6krfwc=n%xfq~)w|NjRL9GK9zeeuF`Qz!3ks9#lIw|v^vBW<ngXU#l5 zp?_Cf>za9UPfeY&zqe;=Pxt0&Q}-`gcy98fT?^))nm_O4oY_Za&Nwh}!nW<(o-SK@ zVb1KsE0$kew)FhGxkoo{xV>)eja4fzFI#$U$>P(C7M`3v>%gXsx7V(@x^>IFHLEXg z-*$iHigUYnJ>InO#-81e*R8#@bI1KtCqJ~eZ>_Fg+S0P2zkhFc_l}7Z_jhz`nmYAR zclXxz_6-vz?CR;+I)DC|nKO^fm~nW{oa0lc?pwb6%7O)_XU#gYXwlhu^G-~kzQ3nu z<FsjeSFE_SY}th+OU|xZb!E?<m+RNxT)q0rv14C0Z@zoz(A!O$Zf)Fn<II^KCr*62 zbm{Njy-#-RxOeE#%fp9X-nj9<qjO7d->#LbE`9p+sjsh(mzNh5UR1@3KUo+V7?>Dz zK&FD?gn@m115;CTOKVFCLq}I<GGn_DhZ&ctou!mxN^et&<eVV?@Q}!eIJcCfCI$-z zXWj%8J}Xz7V1_=XIVt8s4&LqxzQKvho02+M9OBuyIh_P_wlyEKR}>A9)d<uJJ2IQW zPsGOB!&Xc<=HiaIF7iHF>QSMw26tC6sL6=)%dsk}8on%Y71*fA+9{^JZO@Ce9JW4Y zW(f_?ASUN!(M&z6w^n!vD;hF7bn$dvoN&^yk%2++pTBc{L1j^9dPa$Yk%57MLQ<td zaA}@`Z)S2)esN`SNosDfj)G@ivYvutPL4tlNMW%;P-<~%QCVt=9xs=dkDG#fkV05$ Nk%FO~0WTMWH2^_#Bg6mz literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/multiplicity.gif b/pne-editor/src/resources/pneditor/multiplicity.gif new file mode 100644 index 0000000000000000000000000000000000000000..c0d55fd08b992ab5d3f62fa0dc205c42af72f928 GIT binary patch literal 306 zcmZ?wbhEHb6krfwSgOpxz`(%B$jHmfD<dOgWo6~)=;-0$;p5}u@9!TP8X6lLo0F51 zmzP&wUf$5q(A?bI+1c6C(=%bhglW^J&6qJ`&YU@G*RI{LVZ+|Ndk-8qaO~KzvuDqq zKY#wxrAt??T)A`S&i(uMA3l8e`t|Gov;m4gSs1w(>=|@GJ^}fOfzAKG`~nXhseTXT zgqbo-bIv~cyuBb|t;kD*O)>&1w-VVH1$+)U3#dO>A!BoB>70&&KQ3Kv#mVAHT;iUx auKb*efzI+A0v*m`Y*M{WJd>Oq8LR=kJg$uZ literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/opensubnet.gif b/pne-editor/src/resources/pneditor/opensubnet.gif new file mode 100644 index 0000000000000000000000000000000000000000..2a077358fad80dc5224f6257333e387cf7194d8e GIT binary patch literal 89 zcmZ?wbhEHb6krfwSjYeZ|Ns97Q49=<KUo;L7?>DzKwOYK1Cv%uf965i2RFLfo!E`{ lne01VIZ4e<IVf$(a*w5!dlO!4TIhCs`Pr^h{Td7m)&S>M8~y+Q literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/place16.gif b/pne-editor/src/resources/pneditor/place16.gif new file mode 100644 index 0000000000000000000000000000000000000000..0667de9a324f5a104ec853a301aea1f1101091f5 GIT binary patch literal 148 zcmZ?wbhEHb6krfwIK;}pz`$T`Za#hb^zGZXU%!6+KMW}T6Lc<0O)N=GQ7F$W$xv|j z^bKH8{K>+|#lX&>1JVXEfPvYiV%3FxAGRoP2rfLT*7d*X7{lRov1X2v<&s{Gx6@YF tv@s;kc3J#>UL0@4fukLgoTtA{nvkP;py~3VTm}(tH<3cCB@<W}tN{R2I)(rM literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/removefromrole16.gif b/pne-editor/src/resources/pneditor/removefromrole16.gif new file mode 100644 index 0000000000000000000000000000000000000000..39c35eee59616b3c19327ec8a4ed67c3d4f4a9a3 GIT binary patch literal 132 zcmZ?wbhEHb6krfwIK<Atz`(F##fr6S*KXRh>G0vh_wL<$|Ni~||Nj;L2|5?0CYGe8 zD3oWGWGJ|M`UWuQfRuwYGBDe4?7CBB;PrD^>(_I8Za$P^^Kms0xog6brnOer)a&U> kCpJNj7Dab9#%|RQol3hDy9G{iOx^uVN2N4El#{_40RJd6G5`Po literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/replacesubnet.gif b/pne-editor/src/resources/pneditor/replacesubnet.gif new file mode 100644 index 0000000000000000000000000000000000000000..140f67c3098bf038f9980a2b2eecd3feae011f24 GIT binary patch literal 180 zcmZ?wbhEHb6krfwc+9}?|NsC0&(3_gd+hU_qi6Q6JF{ihna#7-%xqgdqiyw!)|p+^ zX~xD35M>~x{}ulUIv1rTmZYXAlxLP?D7bt21~4f8WMO1r;AhZbU|?VX8O*@q^WmiC z^sOPA_BOKfIJC|$=Wtz7_$G|ymGd<D$z4(o8b^LEGn8z2&Mm?+SMb2~q_q(y{K-LF fTODTJIWtQ%Z)0RO@0^WJ%O7e~Ub*AKz+epkB->B5 literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/replacetransitionbysubnet.gif b/pne-editor/src/resources/pneditor/replacetransitionbysubnet.gif new file mode 100644 index 0000000000000000000000000000000000000000..140f67c3098bf038f9980a2b2eecd3feae011f24 GIT binary patch literal 180 zcmZ?wbhEHb6krfwc+9}?|NsC0&(3_gd+hU_qi6Q6JF{ihna#7-%xqgdqiyw!)|p+^ zX~xD35M>~x{}ulUIv1rTmZYXAlxLP?D7bt21~4f8WMO1r;AhZbU|?VX8O*@q^WmiC z^sOPA_BOKfIJC|$=Wtz7_$G|ymGd<D$z4(o8b^LEGn8z2&Mm?+SMb2~q_q(y{K-LF fTODTJIWtQ%Z)0RO@0^WJ%O7e~Ub*AKz+epkB->B5 literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/savesubnetas.gif b/pne-editor/src/resources/pneditor/savesubnetas.gif new file mode 100644 index 0000000000000000000000000000000000000000..296fd5ad98e77db1c9d4d77fbc45122984d5e3fb GIT binary patch literal 151 zcmZ?wbhEHb6krfwIK;s4|Ns9pXU?Rhr7?in|6xG!pP+M5YGO%hib8p2Nrr;Er*8m* z;!hSv1_l-e9R>yl29N;^%<dkW?|jK;VAR?iaQ1-v1bGHerthr}ca(BZaLZE-U$1uO vN9^R{$Dh?so?&{!P~$$&N6AJ`)PDI>PYI*xS9;hiFC1#Sd8U6N1A{dH;3_`c literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/select.gif b/pne-editor/src/resources/pneditor/select.gif new file mode 100644 index 0000000000000000000000000000000000000000..8e8b1153b48da7eef94866fa40abe5c275424cdc GIT binary patch literal 89 zcmZ?wbhEHb6krfwSjfom|Nnmm7*PDl!pOzI#GnHb0Le2jX-yGYcAD|zBSwF-sI`R> kQTH+vG<u)3+IB22SQoKZRmFYH;X^aGz5OGo$-rO@0MsQL5C8xG literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/setarcresetaction.gif b/pne-editor/src/resources/pneditor/setarcresetaction.gif new file mode 100644 index 0000000000000000000000000000000000000000..6c37e3ab870332670d18d7662900af64b624c4bb GIT binary patch literal 116 zcmZ?wbhEHb6krfwSjfo0z`*by1{D7ZIv1rTmZYXAlxLP?D7bt21~4f8WMSlDU}De# zDFta_U@~Z_U!*O-&zx}jX#28F;oGYc@4K{JO3PVxJdKkz*n=lq?(frz$?s<GQ~p_Z LAR<4Afx#L8XLBnC literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/staticplace.gif b/pne-editor/src/resources/pneditor/staticplace.gif new file mode 100644 index 0000000000000000000000000000000000000000..550a831b142ed220e1ecbdbd678ffdb6001457cb GIT binary patch literal 132 zcmZ?wbhEHb6krfwIK;-lz`!6aEuE5*($Udz@#4jA-@g3^1I3>#j9d)t3_2hcAhit4 zo)uLW_60N=a7Z$`Xm<T{Q_K)hXjoyWH+g!Us~WGql?hK^a|`neYv=Qh-1lS{uWNrZ fc<aXR#;*ElqJ#+dF{zD3=5cr2K830<FjxZsv3@OV literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/synthesize.gif b/pne-editor/src/resources/pneditor/synthesize.gif new file mode 100644 index 0000000000000000000000000000000000000000..ccb97868ac00454f3955be7705bae5bcf432c655 GIT binary patch literal 580 zcmZ?wbhEHb6krfwIOfVwUtizS($d=6I(^#o=`&`mT)A@9s#R4dUsRubv1iYoigUO3 z?%i8@`Aq5Mvqd-d72nvGe|LTU-3<kI*XKN1m<vLSavm?tdNw8V`J}Aple3;rNq^Il z{-!nkO<Ve#_Vl+c>2F(8KUAiCEKB)Vp8Byg<zr<kh*6R9sWjzNSt<xsBz?_F{FasU zEhFh$X41E;#P1o2-!qfGrzd^SNcx@`_bV#yS9IL(sJP$J@xP<uf5*iAiHrxKsQ5q8 z=g*&i`0(MQM~^;z`t<4Z=l??uDE<?4E=o--Nlj5G&n(GMaQE~LU{L(Y!pOx?&!EG= zz`y{CC<gYPhWe%^1~w-rHiqWz?yma2o}Ru56PqVboy5UDWd;Km*PN*gygUmhGVt*) z>lG9d5Ln$Wx>-b6Y#D=;xTKWiK8ZODa<WHc6cps8r6({bs;aANt0^mKX{u;+G3e;% z8W@-w>6z;58JZX~Fqm7KSy))x+gVxI+S%B2F|n|5J2<(tu`o_raG-&qo{5pc8UPX` BWSsy2 literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/synthesize.xcf b/pne-editor/src/resources/pneditor/synthesize.xcf new file mode 100644 index 0000000000000000000000000000000000000000..14d4e2f150c9aafb507e5d5fc598e1656e42664e GIT binary patch literal 1325 zcmYe#%q>u;NKR8o%gjk-U|?VnfMO6^kb!}Lk&%IcL70Jofx~G60|N*%FffQPFfgz% zFfi~lFffQg*&ubI3=E9^3=9msAY*lt^K)}k^GZM_fh2{Ti&7IyQd1PlGfOfQ+&z5* zKr#YgrJ1>j>8ZNuMVToeF-8UkMh=bQlFFP^h0MH?)S}|l<dV$%ykbo*jkNUS{G9wE z1r0EzTa=!Zs9>OH00vkXhEOR@O)iZjELvgm3b+{{trf)uiOHFH=?cb1Fax<XDzOPd z#dJ&aGD{RP^O7@CL9VXIPfIIKErB~wlS`u#QwSo0sudI-P|UcCfq^9q$^lWZxB`VP zmtShRf=^;)Y7t0=2}Ce3Ft9-*=RYU{p=^+9PAD6sj0=g)jl||bV)G)gL6Ob@(g?-u zNOG`*!3>pSU|?X%fU;q(Wno}oszDWF>H+at>wm9$^k`MRc0FS)Z~fous(PM!#tPng z#!}w;zeUCM-1Wcn3-a^pIqR8o8FM)5*|Pp+*0a`grnA)lO-)H<N@Yy>otl!GQqNe= znDj3(2~030{Yp$qs;`e@j$@906&D{L7gt~3I(^mN^N&7#dU$@%%IPijFpH(@84vQ- zGalisXFSPU&v=fvp7AnoJ>w0Ydgi-a^(>G6J+5c3|NH#ebC&09^(=3g-ZH*nssH!k zBjd+^pFT2vWc>8^<0p{iUzxr!e*gXL`?qi38NV~u|M~U%*Kfw(jDHw^Gyh?%|JXVM zWcz2Z?bA?f|Ib_h_xm@Hw_otqGv4N{|9kcfh_{cY{@;f6jO)4TnHDiE<fvzy@^|u- z$&8c#O{!<D|JUBe*v8b#)WTBFSjkkuSk6?&Sjtq-lEs+$CnGa6gE8Y*dVPI#bQELM z-xv`2Ix;FUvc4YK8Pi+pSr}OVb20q>&%p4X0h4C_&&`0qTnw!LIT+agvoUb~XJO#} z&&0s{{~yDDIS|1EN^7X)2)9#Wa&~%AerX;!dt*zKp!lbCqJ(7%P<s6fvJhI-ff6P& a0|P6lxC04;_yP<JtcoB`JtM<^7zO~~Pe`f& literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/token_and_fire16.gif b/pne-editor/src/resources/pneditor/token_and_fire16.gif new file mode 100644 index 0000000000000000000000000000000000000000..79c94f14256e18c868eb86e76c5b75878b30a93d GIT binary patch literal 166 zcmZ?wbhEHb6krfwc+ADXz`(%5!XhUpXKZX76ckinUw`!I(Rc6O{rdIm|NsC085q!z z;!hSvE(U%E9gt3t84N7JA8eJH6pUV*H#o8x<VZ5gcvdk;Xi9i8igYSY@NZCYn6JQi zN84=mT@SS>U9FER9QLjdQCJw^vofd4iz#R8o!;r@&mJDT__i{dFZ;rStzmcPx+ybQ F0|2B@JBa`Q literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/tokens.gif b/pne-editor/src/resources/pneditor/tokens.gif new file mode 100644 index 0000000000000000000000000000000000000000..5c45fce0221936e03c42711d759b72a340c8cbc0 GIT binary patch literal 157 zcmZ?wbhEHb6krfwIK;-lz`$T`ZeCwsKYjZ2?c29szkdBc7%2V|bS_FwEJ;mKD9<d( zP;mG34Pa3G$->CRz|Nop(gresf!ViW)rEZ@witLxE<9@1^S}8R!;y5U7LJnT3><D6 ztjnKQ+>DaelQD0-yOKd<R)^KSY;mRwJlmt(F1@^(A~eZ>HKJgh()!IsCtZ*9>8UU> GSOWkj?>oZ) literal 0 HcmV?d00001 diff --git a/pne-editor/src/resources/pneditor/transition16.gif b/pne-editor/src/resources/pneditor/transition16.gif new file mode 100644 index 0000000000000000000000000000000000000000..b98da190ba2efcad71cfc32bbfbe641c5731c1c5 GIT binary patch literal 86 zcmZ?wbhEHb6krfwXkcVuU|{(F|G(ltLFb~>#FEq$h4Rdj3<Y;j-v9<3kR(VM1Cv5a nf9Aor`{tz-?#q%smzbX4I9X$&_yNZZueEDdYHbQ+V6X-NXeS(M literal 0 HcmV?d00001 diff --git a/src/main/java/org/petriNet/Main.java b/src/main/java/org/petriNet/Main.java index 40a4ca4..798714e 100644 --- a/src/main/java/org/petriNet/Main.java +++ b/src/main/java/org/petriNet/Main.java @@ -35,7 +35,7 @@ public class Main { // CP4 Place P4 = new Place(0, Mutex.generateId(1)); - Mutex.addPlace(P4); + Mutex.addPlace(P4); // CT4 Transition T4 = new Transition("T4", Mutex.generateId(2)); -- GitLab