diff --git a/docs/SpaceNet 2-5 Quick Start.pdf b/docs/SpaceNet 2-5 Quick Start.pdf new file mode 100644 index 0000000..a4c03a1 Binary files /dev/null and b/docs/SpaceNet 2-5 Quick Start.pdf differ diff --git a/docs/SpaceNet 2-5 User Guide.pdf b/docs/SpaceNet 2-5 User Guide.pdf new file mode 100644 index 0000000..74ca78a Binary files /dev/null and b/docs/SpaceNet 2-5 User Guide.pdf differ diff --git a/docs/completed_quick_start_1.xml b/docs/completed_quick_start_1.xml new file mode 100644 index 0000000..d7d569d --- /dev/null +++ b/docs/completed_quick_start_1.xml @@ -0,0 +1,1356 @@ + + Quick Start Scenario 1 + A sample scenario analyzing the transportation feasibility of a lunar mission. + 2019-07-01 21:05:16.51 EDT + docs\completed_quick_start_1.xml + SpaceNet User + LUNAR + + + + 1 + KSC + Kennedy Space Center + + + + EARTH + 28.6 + -80.6 + + + 2 + PAC + Pacific Ocean Splash-down + + + + EARTH + 35.0 + -117.9 + + + 3 + LSP + Lunar South Pole + + + + MOON + -89.9 + -180.0 + + + 4 + LEO + Low Earth Orbit + + + + EARTH + 28.5 + 296.0 + 296.0 + + + 5 + LLPO + Low Lunar Polar Orbit + + + + MOON + 90.0 + 100.0 + 100.0 + + + + + 1 + KSC-LEO + Earth Ascent + + + + + + 0.25 + + + 1 + + + + OMS + 9500.0 + + + + + 2 + LEO-LLPO + Lunar Orbit Injection + + + + + + 4.0 + + + 2 + + + + OMS + 3150.0 + + + 3 + + + + RCS + 2.0 + + + 4 + + + + RCS + 2.0 + + + 5 + + + + OMS + 950.0 + + + + + 3 + LLPO-LSP + Lunar Descent + + + + + + 0.5 + + + 6 + + + + OMS + 2030.0 + + + 7 + + + + RCS + 11.0 + + + + + 4 + LSP-LLPO + Lunar Ascent + + + + + + 0.5 + + + 8 + + + + OMS + 1875.0 + + + 9 + + + + RCS + 31.0 + + + + + 5 + LLPO-PAC + Trans-Earth Injection + + + + + + 4.0 + + + 10 + + + + OMS + 612.3 + + + 11 + + + + OMS + 276.5 + + + 12 + + + + OMS + 333.6 + + + 13 + + + + RCS + 3.2 + + + 14 + + + + RCS + 3.2 + + + 15 + + + + RCS + 5.0 + + + + + + + 1 + PBAN Solid + Solid rocket fuel + COS105 + UNPRESSURIZED + kg + 1.0 + 0.0 + 0.0 + + + 2 + LH2/LOX + Liquid oxygen/liquid hydrogen cryogenic fuel + COS101 + UNPRESSURIZED + kg + 1.0 + 0.0 + 0.0 + + + 3 + MMH/N2O4 + Hypergolic fuel + COS102 + UNPRESSURIZED + kg + 1.0 + 0.0 + 0.0 + + + + + 1 + Ares I First Stage + PROPULSIVE_VEHICLE + + + 2 + Ares I Upper Stage + PROPULSIVE_VEHICLE + + + 3 + Orion SM + PROPULSIVE_VEHICLE + + + 4 + Orion CM + PROPULSIVE_VEHICLE + + + 5 + Orion LAS + CARRIER + + + 6 + Ares V SRBs + PROPULSIVE_VEHICLE + + + 7 + Ares V Core + PROPULSIVE_VEHICLE + + + 8 + EDS + PROPULSIVE_VEHICLE + + + 9 + Altair DM + PROPULSIVE_VEHICLE + + + 10 + Altair AM + PROPULSIVE_VEHICLE + + + 12 + Crew Member + CREW_MEMBER + + + 13 + Notional Cargo + ELEMENT + + + 14 + Lunar Surface Samples + ELEMENT + + + + 2010-12-15 21:09:39.408 EST + docs\quick_start_1.xls + + + + + + + + + + + + + + + + + + + + + + + + + Lunar Sortie + 2019-07-01 00:00:00.0 EDT + + + + 1444385270617722880 + Lunar | Create Elements + + 1 + + + + + 1 + Lunar | Ares I First Stage + Ares I Launch Vehicle, First Propulsive Stage + 1 + COS9021 + UNPRESSURIZED + 0.0 + 105000.0 + 0.0 + + + + + + + + + + 0.0 + 0.0 + UNPRESSURIZED + 0 + 267.0 + 0.0 + + -1820064951 + Lunar | Ares I First Stage OMS Fuel Tank + + 2 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 620000.0 + 620000.0 + + + + 2 + Lunar | Ares I Upper Stage + Ares I Launch Vehicle, Second Propulsive Stage + 4 + COS9021 + UNPRESSURIZED + 0.0 + 12000.0 + 0.0 + + + + + + + + + + 0.0 + 0.0 + UNPRESSURIZED + 0 + 448.0 + 0.0 + + -760661015 + Lunar | Ares I Upper Stage OMS Fuel Tank + + 5 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 125000.0 + 125000.0 + + + + 4 + Lunar | Orion CM + Orion Crew Module + 10 + COS9022 + UNPRESSURIZED + 0.0 + 8000.0 + 0.0 + + + + + + + + + + 100.0 + 0.0 + UNPRESSURIZED + 4 + 0.0 + 301.0 + + -337703527 + Lunar | Orion CM RCS Fuel Tank + + 12 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 175.0 + 175.0 + + + + 5 + Lunar | Orion LAS + Orion Launch Abort System + 13 + COS9021 + UNPRESSURIZED + 0.0 + 6000.0 + 0.0 + + + + + + + + + + 0.0 + 0.0 + UNPRESSURIZED + 0 + + + 3 + Lunar | Orion SM + Orion Service Module + 7 + COS9022 + UNPRESSURIZED + 0.0 + 3000.0 + 0.0 + + + + + + + + + + 0.0 + 0.0 + UNPRESSURIZED + 0 + 328.0 + 301.0 + + -1159906898 + Lunar | Orion SM OMS Fuel Tank + + 8 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 10000.0 + 10000.0 + + + + + + + + 2428245564171849728 + Lunar | Create Elements + + 2 + + + + + 12 + Lunar | Crew Member A + Crew Member + 14 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 12 + Lunar | Crew Member B + Crew Member + 15 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 12 + Lunar | Crew Member C + Crew Member + 16 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 12 + Lunar | Crew Member D + Crew Member + 17 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + + + + 719824631704404992 + Lunar | Space Transport + + 3 + + + + + + + + + + + + + + Burn + + + + Stage + + + + Stage + + + + Burn + + + + Stage + + + + + + + 7977228362746739712 + Lunar | Create Elements + + 1 + + + + + 10 + Lunar | Altair AM + Altair Ascent Module + 30 + COS9024 + UNPRESSURIZED + 0.0 + 3000.0 + 0.0 + + + + + + + + + + 100.0 + 0.0 + UNPRESSURIZED + 4 + 320.0 + 300.0 + + -2035201050 + Lunar | Altair AM OMS Fuel Tank + + 31 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 3000.0 + 3000.0 + + + + + 9 + Lunar | Altair DM + Altair Descent Module + 27 + COS9023 + UNPRESSURIZED + 0.0 + 12000.0 + 0.0 + + + + + + + + + + 500.0 + 0.0 + UNPRESSURIZED + 0 + 448.0 + 300.0 + + -1267893505 + Lunar | Altair DM OMS Fuel Tank + + 28 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 24900.0 + 24900.0 + + + -930154983 + Lunar | Altair DM RCS Fuel Tank + + 29 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 425.0 + 425.0 + + + + 7 + Lunar | Ares V Core + Ares V Launch Vehicle, Core Engine + 21 + COS9021 + UNPRESSURIZED + 0.0 + 175000.0 + 0.0 + + + + + + + + + + 0.0 + 0.0 + UNPRESSURIZED + 0 + 414.0 + 0.0 + + -652427582 + Lunar | Ares V Core OMS Fuel Tank + + 22 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 1587000.0 + 1587000.0 + + + + 6 + Lunar | Ares V SRBs + Ares V Launch Vehicle, Solid Rocket Boosters + 18 + COS9021 + UNPRESSURIZED + 0.0 + 210000.0 + 0.0 + + + + + + + + + + 0.0 + 0.0 + UNPRESSURIZED + 0 + 270.0 + 0.0 + + -179502667 + Lunar | Ares V SRBs OMS Fuel Tank + + 19 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 1375000.0 + 1375000.0 + + + + 8 + Lunar | EDS + Earth Departure System + 24 + COS9022 + UNPRESSURIZED + 0.0 + 26000.0 + 0.0 + + + + + + + + + + 0.0 + 0.0 + UNPRESSURIZED + 0 + 448.0 + 0.0 + + -1805548954 + Lunar | EDS OMS Fuel Tank + + 25 + COS0 + UNPRESSURIZED + 0.0 + 0.0 + 0.0 + + + + + + + + + 253000.0 + 253000.0 + + + + + + + 7170097875789301760 + Lunar | Create Elements + + 2 + + + + + 13 + Lunar | Notional Cargo + Cargo + 33 + COS6 + UNPRESSURIZED + 0.0 + 500.0 + 0.0 + + + + + + + + + + + + 5250195997488295936 + Lunar | Space Transport + + 3 + + + + + + + + + + + + + + Burn + + + + Stage + + + + Burn + + + + Stage + + + + Burn + + + + + + + 576646182749045760 + Lunar | Space Transport + + 1 + + + + + + + + + + + + + + Burn + + + + Stage + + + + + + Burn + + + + + + Burn + + + + + + Burn + + + + + + + 6202974527973099520 + Lunar | Move Elements + + 1 + + + + + + + + + + + + 9043923827929866240 + Lunar | Space Transport + + 2 + + + + + + + + + + + Burn + + + + + + Burn + + + + + + + 3118135789392433152 + Lunar | Crewed Exploration + + 1 + + + 7.0 + 5.0 + 8.0 + + + + + + + + + + + + + + + + + + + 4111001225752953856 + Lunar | Create Elements + + 1 + + + + + 14 + Lunar | Lunar Surface Samples + Lunar Surface Samples + 34 + COS6 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + + + + + + 2931197969439678464 + Lunar | Space Transport + + 2 + + + + + + + + + + Burn + + + + + + Burn + + + + + + + 9154850374619037696 + Lunar | Move Elements + + 1 + + + + + + + + + + + + + 7851826860478834688 + Lunar | Space Transport + + 2 + + + + + + + + + + + Burn + + + + + + Burn + + + + + + Burn + + + + + + Burn + + + + + + Burn + + + + + + Stage + + + + Burn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.05 + 0.01 + 0.01 + 1.0E-6 + false + true + NONE + 0.0 + false + + true + true + \ No newline at end of file diff --git a/docs/completed_quick_start_2.xml b/docs/completed_quick_start_2.xml new file mode 100644 index 0000000..d9b102c --- /dev/null +++ b/docs/completed_quick_start_2.xml @@ -0,0 +1,1178 @@ + + Quick Start Scenario 2 + A sample scenario analyzing the feasibility of a lunar outpost. + 2019-07-01 00:00:00.0 EDT + docs\completed_quick_start_2.xml + SpaceNet User + LUNAR + + + + 1 + KSC + Kennedy Space Center + + + + EARTH + 28.6 + -80.6 + + + 2 + PAC + Pacific Ocean Splash-down + + + + EARTH + 35.0 + -117.9 + + + 3 + LSP + Lunar South Pole + + + + MOON + -89.9 + -180.0 + + + + + 1 + Crewed Delivery + Crewed Delivery Flight + + + + + + 7.5 + 4 + 500.0 + + + 2 + Crewed Return + Crewed Return Flight + + + + + + 5.5 + 4 + 100.0 + + + 3 + Cargo Delivery + Cargo Delivery Flight + + + + + + 7.5 + 0 + 12000.0 + + + + + 1 + Habitat Spare + + COS401 + PRESSURIZED + kg + 10.0 + 0.0 + 0.0 + + + 2 + Power Supply Spare + + COS401 + UNPRESSURIZED + kg + 10.0 + 0.0 + 0.0 + + + + + 1 + Crewed Lander + CARRIER + + + 2 + Crewed Return Capsule + CARRIER + + + 3 + Cargo Lander + CARRIER + + + 4 + Crew Member + CREW_MEMBER + + + 5 + Crew Habitat + CARRIER + + + 6 + Power Supply Unit + ELEMENT + + + + 2010-12-15 21:31:22.216 EST + docs\quick_start_2.xls + + + + + + + + + + + + + + + + + + + + + Automated Check-out Mission + 2019-07-01 00:00:00.0 EDT + + + + 4639932823903235072 + Autom | Create Elements + + 1 + + + + + 1 + Autom | Crewed Lander + Abstracted lander for delivering crew to the lunar surface + 1 + COS9021 + UNPRESSURIZED + 0.0 + 12000.0 + 0.0 + + + + + + + 1 + Crew Lander Active + + ACTIVE + + + + + + 2 + Crew Lander Decommissioned + + DECOMMISSIONED + + + + + + + + + + 400.0 + 0.0 + UNPRESSURIZED + 4 + + + 2 + Autom | Crewed Return Capsule + Abstracted return capsule for returning crew to Earth + 2 + COS9022 + UNPRESSURIZED + 0.0 + 3000.0 + 0.0 + + + + + + + 4 + Crew Return Active + + ACTIVE + + + + + + 3 + Crew Return Dormant + + DORMANT + + + + + + + + + + 100.0 + 0.0 + UNPRESSURIZED + 4 + + + + + + 2925014944735876096 + Autom | Flight Transport + + 2 + + + + + + + + + + + + + + + + + 7-Day Surface Exploration + 2019-12-01 00:00:00.0 EST + + + + 3669724500634301440 + 7-Day | Create Elements + + 1 + + + + + 1 + 7-Day | Crewed Lander + Abstracted lander for delivering crew to the lunar surface + 3 + COS9021 + UNPRESSURIZED + 0.0 + 12000.0 + 0.0 + + + + + + + 1 + Crew Lander Active + + ACTIVE + + + + + + 2 + Crew Lander Decommissioned + + DECOMMISSIONED + + + + + + + + + + 400.0 + 0.0 + UNPRESSURIZED + 4 + + + 2 + 7-Day | Crewed Return Capsule + Abstracted return capsule for returning crew to Earth + 4 + COS9022 + UNPRESSURIZED + 0.0 + 3000.0 + 0.0 + + + + + + + 4 + Crew Return Active + + ACTIVE + + + + + + 3 + Crew Return Dormant + + DORMANT + + + + + + + + + + 100.0 + 0.0 + UNPRESSURIZED + 4 + + + + + + 1330965799576294400 + 7-Day | Create Elements + + 2 + + + + + 4 + 7-Day | Crew Member A + Crew member + 5 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 4 + 7-Day | Crew Member B + Crew member + 6 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 4 + 7-Day | Crew Member C + Crew member + 7 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 4 + 7-Day | Crew Member D + Crew member + 8 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + + + + 5188379700888718336 + 7-Day | Flight Transport + + 3 + + + + + + + + + + 4040106176097217536 + 7-Day | Crewed Exploration + + 1 + + + 7.0 + 5.0 + 8.0 + + + + + + + + + + + + + + + + + + + 6274764893272707072 + 7-Day | Move Elements + + 1 + + + + + + + + + + + + 6140646384994852864 + 7-Day | Flight Transport + + 2 + + + + + + + + + 1911508840678014976 + 7-Day | Remove Elements + + 1 + + + + + + + + + + + -666370899 + Crew Consumables Demand Model + + + 0.0 + 0.42 + 4.0 + true + 3.6 + 0.6875 + 0.05556 + 0.76389 + 1.61667 + 3.85714 + 0.07875 + 2.21429 + 0.27778 + 1.8 + 2.3 + 10.0 + 5.0 + 107.0 + 0.3625 + 20.0 + 0.1 + 25.0 + 20.0 + 5.0 + 0.05 + 0.05 + + + + + + + + + Habitat Delivery + 2020-03-01 00:00:00.0 EST + + + + 8718256138996466688 + Habit | Create Elements + + 1 + + + + + 3 + Habit | Cargo Lander + Abstracted lander for delivering cargo to the lunar surface + 9 + COS9021 + UNPRESSURIZED + 0.0 + 1000.0 + 0.0 + + + + + + + 5 + Cargo Lander Active + + ACTIVE + + + + + + 6 + Cargo Lander Decommissioned + + DECOMMISSIONED + + + + + + + + + + 12000.0 + 0.0 + UNPRESSURIZED + 0 + + + + + + 7249728977853430784 + Habit | Create Elements + + 2 + + + + + 5 + Habit | Crew Habitat + Lunar crew habitat + 10 + COS801 + UNPRESSURIZED + 0.0 + 7500.0 + 0.0 + + + + 1 + + + + -1.0 + -1.0 + 0.0 + 5.0 + 1.0 + + + + + + 8 + Habitat Active + + ACTIVE + + + + 1 + Habitat Sparing by Mass + + + 0.01 + 0.04 + false + + + + + 7 + Habitat Dormant + + DORMANT + + + + + + + + + + 1500.0 + 0.0 + UNPRESSURIZED + 4 + + + 6 + Habit | Power Supply Unit + An element to provide the habitat with power + 11 + COS803 + UNPRESSURIZED + 0.0 + 2500.0 + 0.0 + + + + 2 + + + + -1.0 + 2.0 + 0.0 + 3.0 + 1.0 + + + + + + 10 + Power Supply Active + + ACTIVE + + + + 2 + Power Supply Sparing by Mass + + + 0.05 + 0.0 + false + + + + + 9 + Power Supply Dormant + + DORMANT + + + + + + + + + + + + 5230321644480589824 + Habit | Flight Transport + + 3 + + + + + + + + + + + + + + + + 14-Day Surface Exploration + 2020-07-01 00:00:00.0 EDT + + + + 7073146904298001408 + 14-Da | Create Elements + + 1 + + + + + 1 + 14-Da | Crewed Lander + Abstracted lander for delivering crew to the lunar surface + 12 + COS9021 + UNPRESSURIZED + 0.0 + 12000.0 + 0.0 + + + + + + + 1 + Crew Lander Active + + ACTIVE + + + + + + 2 + Crew Lander Decommissioned + + DECOMMISSIONED + + + + + + + + + + 400.0 + 0.0 + UNPRESSURIZED + 4 + + + 2 + 14-Da | Crewed Return Capsule + Abstracted return capsule for returning crew to Earth + 13 + COS9022 + UNPRESSURIZED + 0.0 + 3000.0 + 0.0 + + + + + + + 4 + Crew Return Active + + ACTIVE + + + + + + 3 + Crew Return Dormant + + DORMANT + + + + + + + + + + 100.0 + 0.0 + UNPRESSURIZED + 4 + + + + + + 6502830794281175040 + 14-Da | Create Elements + + 2 + + + + + 4 + 14-Da | Crew Member A + Crew member + 14 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 4 + 14-Da | Crew Member B + Crew member + 15 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 4 + 14-Da | Crew Member C + Crew member + 16 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + 4 + 14-Da | Crew Member D + Crew member + 17 + COS0 + UNPRESSURIZED + 0.0 + 100.0 + 0.0 + + + + + + + 0.66 + + + + + + 3859943637025301504 + 14-Da | Flight Transport + + 3 + + + + + + + + + + 6698191568590083072 + 14-Da | Move Elements + + 1 + + + + + + + + + + + + 5968234702635714560 + 14-Da | Reconfigure Group + + 1 + + + + + + + ACTIVE + + + 4538799828562655232 + 14-Da | Crewed Exploration + + 2 + + + 14.0 + 5.0 + 8.0 + + + + + + + + + + + + + + + + + + + 3423743952627637248 + 14-Da | Move Elements + + 1 + + + + + + + + + + + + 8274917844497198080 + 14-Da | Reconfigure Group + + 1 + + + + + + + DORMANT + + + 1604912141084941312 + 14-Da | Flight Transport + + 2 + + + + + + + + + 3430527131823099904 + 14-Da | Remove Elements + + 1 + + + + + + + + + + + -2017483987 + Crew Consumables Demand Model + + + 0.0 + 0.42 + 4.0 + true + 3.6 + 0.6875 + 0.05556 + 0.76389 + 1.61667 + 3.85714 + 0.07875 + 2.21429 + 0.27778 + 1.8 + 2.3 + 10.0 + 5.0 + 107.0 + 0.3625 + 20.0 + 0.1 + 25.0 + 20.0 + 5.0 + 0.05 + 0.05 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.05 + 0.01 + 0.01 + 1.0E-6 + false + true + NONE + 0.0 + false + + true + true + \ No newline at end of file diff --git a/docs/quick_start_1.xls b/docs/quick_start_1.xls new file mode 100644 index 0000000..c04d556 Binary files /dev/null and b/docs/quick_start_1.xls differ diff --git a/docs/quick_start_2.xls b/docs/quick_start_2.xls new file mode 100644 index 0000000..16676bf Binary files /dev/null and b/docs/quick_start_2.xls differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6b6e5d0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + + edu.mit + spacenet + 2.5.1458 + jar + + spacenet + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 3.8.1 + test + + + net.sf.squirrel-sql.thirdparty-non-maven + ilf-gpl + 1.6.1 + + + com.toedter + jcalendar + 1.4 + + + org.jfree + jfreechart + 1.0.19 + + + org.apache.poi + poi + 3.13 + + + com.thoughtworks.xstream + xstream + 1.4.8 + + + mysql + mysql-connector-java + 5.1.38 + + + diff --git a/src/main/java/edu/mit/spacenet/SpaceNet.java b/src/main/java/edu/mit/spacenet/SpaceNet.java new file mode 100644 index 0000000..843b60e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/SpaceNet.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Insets; +import java.awt.Rectangle; + +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; +import javax.swing.UIManager; + +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.SplashScreen; +import net.infonode.gui.laf.InfoNodeLookAndFeel; + +/** + * This class is used to launch the SpaceNet application. + * + * @author Paul Grogan + */ +public class SpaceNet { + + /** + * Launches the SpaceNet application. + * + * @param args the args + */ + public static void main(String[] args) { + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + UIManager.setLookAndFeel(new InfoNodeLookAndFeel()); + UIManager.put("TextArea.margin", new Insets(3,3,3,3)); + UIManager.put("Button.margin", new Insets(3,3,3,3)); + UIManager.put("ComboBox.background", Color.WHITE); + UIManager.put("ProgressBar.background", Color.WHITE); + } catch(Exception e) { + e.printStackTrace(); + } + // a customized swing worker is used to trigger the splash + // screen in a separate thread so the progress bar can spin + // while the components are loaded in the main frame + SwingWorker worker = new SwingWorker() { + private SplashScreen splash; + @Override + protected Void doInBackground() { + // create and display splash screen while application is + // loading + splash = new SplashScreen(); + splash.setSize(500, 225); + splash.setLocationRelativeTo(null); + splash.setVisible(true); + try { + //TODO check if off screen (e.g. last used with different monitor settings + Rectangle virtualBounds = new Rectangle(); + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] gs = ge.getScreenDevices(); + for(int j=0; j. + */ +package edu.mit.spacenet.data; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.domain.resource.Resource; + +/** + * An abstract implementation of the data source interface. + * + * @author Paul Grogan + */ +public abstract class AbstractDataSource implements I_DataSource { + protected List nodeLibrary; + protected List edgeLibrary; + protected List burnLibrary; + protected List resourceTypeLibrary; + protected List elementPreviewLibrary; + protected List demandModelLibrary; + private Date lastLoadDate; + + /** + * Instantiates a new abstract data source. + */ + public AbstractDataSource() { + nodeLibrary = new ArrayList(); + edgeLibrary = new ArrayList(); + resourceTypeLibrary = new ArrayList(); + elementPreviewLibrary = new ArrayList(); + demandModelLibrary = new ArrayList(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getNodeLibrary() + */ + public final List getNodeLibrary() { + return nodeLibrary; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getEdgeLibrary() + */ + public final List getEdgeLibrary() { + return edgeLibrary; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getEdgeLibrary() + */ + public final List getBurnLibrary() { + return burnLibrary; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getResourceLibrary() + */ + public final List getResourceLibrary() { + return resourceTypeLibrary; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getContinuousResourceLibrary() + */ + public final List getContinuousResourceLibrary() { + ArrayList list = new ArrayList(); + for(I_Resource r : resourceTypeLibrary) { + if(r.getClass().equals(Resource.class)) { + list.add((Resource)r); + } + } + return list; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getItemLibrary() + */ + public final List getItemLibrary() { + ArrayList list = new ArrayList(); + for(I_Resource r : resourceTypeLibrary) { + if(r instanceof I_Item) { + list.add((I_Item)r); + } + } + return list; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getElementPreviewLibrary() + */ + public final List getElementPreviewLibrary() { + return elementPreviewLibrary; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getDemandModelLibrary() + */ + public final List getDemandModelLibrary() { + return demandModelLibrary; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#print() + */ + public void print() { + System.out.println("Node Library:"); + for(Node n : nodeLibrary) { + System.out.println("\t" + n.getTid() + ": " + n.getName() + " (" + n.getClass().getSimpleName() + ") "); + } + System.out.println("Edge Library:"); + for(Edge e : edgeLibrary) { + System.out.println("\t" + e.getTid() + ": " + e.getName() + " (" + e.getClass().getSimpleName() + ") "); + } + System.out.println("Resource Library:"); + for(I_Resource r : resourceTypeLibrary) { + System.out.println("\t" + r.getTid() + ": " + r.getName() + " (COS " + r.getClassOfSupply().getId() + ") "); + } + System.out.println("Element Library:"); + for(ElementPreview o : elementPreviewLibrary) { + System.out.println("\t" + o.ID + ": " + o.NAME + " (" + o.TYPE + ") "); + } + System.out.println("Demand Model Library:"); + for(I_DemandModel o : demandModelLibrary) { + System.out.println("\t" + o.getTid() + ": " + o.getName() + " (" + o.getDemandModelType() + ") "); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#loadLibraries(boolean) + */ + public final void loadLibraries(boolean updateNodes, + boolean updateEdges, + boolean updateResources) throws Exception { + lastLoadDate = new Date(); + if(updateNodes) loadNodeLibrary(); + if(updateEdges) loadEdgeLibrary(); + if(updateResources) loadResourceLibrary(); + loadElementLibrary(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#loadLibraries() + */ + public final void loadLibraries() throws Exception { + lastLoadDate = new Date(); + loadNodeLibrary(); + loadEdgeLibrary(); + loadResourceLibrary(); + loadElementLibrary(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#loadResource(int) + */ + public final I_Resource loadResource(int tid) { + if(tid < 0) { + return new GenericResource(ClassOfSupply.getInstance(-tid)); + } + for(I_Resource resource : resourceTypeLibrary) { + if(resource.getTid() == tid) return resource; + } + return null; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadEdge(int) + */ + public final Edge loadEdge(int tid) { + for(Edge edge : edgeLibrary) { + if(edge.getTid()==tid) return edge; + } + return null; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadNode(int) + */ + public final Node loadNode(int tid) { + for(Node node : nodeLibrary) { + if(node.getTid()==tid) return node; + } + return null; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadElementPreview(int) + */ + public final ElementPreview loadElementPreview(int tid) { + for(ElementPreview preview : elementPreviewLibrary) { + if(preview.ID==tid) return preview; + } + return null; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.scenario.data.I_DataSource#getLastLoadDate() + */ + public final Date getLastLoadDate() { + return lastLoadDate; + } +} diff --git a/src/main/java/edu/mit/spacenet/data/DataSourceType.java b/src/main/java/edu/mit/spacenet/data/DataSourceType.java new file mode 100644 index 0000000..04ac2bd --- /dev/null +++ b/src/main/java/edu/mit/spacenet/data/DataSourceType.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.data; + +import javax.swing.ImageIcon; + +/** + * An enumeration which lists the different types of data sources. + * + * @author Paul Grogan + */ +public enum DataSourceType { + /** No data source. */ + NONE("None", "icons/database.png"), + + /** A SQL-based database. */ + SQL_DB("SpaceNet 2.5 (SQL Database)", "icons/database_yellow.png"), + + /** An excel-based spreadsheet database */ + EXCEL_2_5("SpaceNet 2.5 (Excel)", "icons/page_white_excel.png"); + //EXCEL_1_3("SpaceNet 1.3 (Excel)", Spreadsheet_1_3.class, "icons/page_white_excel.png"); + //, ONLINE("SpaceNet Online", SpaceNetOnline.class, "icons/database.png"); + + private String name; + private ImageIcon icon; + + private DataSourceType(String name, String iconUrl) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } + + /** + * Gets the name of the data source type. + * + * @return the data source type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon of the data source type. + * + * @return the data source type icon + */ + public ImageIcon getIcon() { + return icon; + } +} diff --git a/src/main/java/edu/mit/spacenet/data/Database.java b/src/main/java/edu/mit/spacenet/data/Database.java new file mode 100644 index 0000000..b7a27db --- /dev/null +++ b/src/main/java/edu/mit/spacenet/data/Database.java @@ -0,0 +1,2231 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.data; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.element.Carrier; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.Element; +import edu.mit.spacenet.domain.element.ElementType; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.element.ResourceContainer; +import edu.mit.spacenet.domain.element.State; +import edu.mit.spacenet.domain.element.StateType; +import edu.mit.spacenet.domain.element.SurfaceVehicle; +import edu.mit.spacenet.domain.model.DemandModelType; +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.domain.model.RatedDemandModel; +import edu.mit.spacenet.domain.model.SparingByMassDemandModel; +import edu.mit.spacenet.domain.model.TimedImpulseDemandModel; +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.domain.network.edge.BurnType; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.EdgeType; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.LagrangeNode; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.NodeType; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.domain.resource.Resource; +import edu.mit.spacenet.domain.resource.ResourceType; + +/** + * A spreadsheet format compatible with the features introduced in SpaceNet 2.5 + * + * @author Paul Grogan + */ +public class Database extends AbstractDataSource { + private String host, user, password, database; + private Integer port; + private Connection connection; + + /** + * Instantiates a new database. + * + * @param host the host + * @param port the port + * @param database the database + * @param user the user + * @param password the password + */ + public Database(String host, Integer port, String database, + String user, String password) { + this.host = host; + this.port = port; + this.database = database; + this.user = user; + this.password = password; + } + + /** + * Instantiates a new database and sets the port field to null. + * + * @param host the host + * @param database the database + * @param user the user + * @param password the password + */ + public Database(String host, String database, String user, String password) { + this.host = host; + this.database = database; + this.user = user; + this.password = password; + } + + /** + * Instantiates a new database and sets all fields to default values. + */ + public Database() { + host = ""; + database = ""; + user = ""; + password = ""; + port = 3306; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#deleteEdge(int) + */ + public boolean deleteEdge(int tid) throws SQLException { + createConnection(); + PreparedStatement stmt = null; + try { + if(edgeLibrary.remove(loadEdge(tid))) { + stmt = connection.prepareStatement("DELETE FROM edges " + + "WHERE id=? LIMIT 1"); + stmt.setInt(1, tid); + int i = stmt.executeUpdate(); + if(i > 0) { + stmt = connection.prepareStatement("DELETE FROM burns " + + "WHERE edge_id=?"); + stmt.setInt(1, tid); + stmt.executeUpdate(); + System.out.println("Edge #" + tid + " deleted"); + return true; + } else { + System.out.println("Edge #" + tid + " not found in database"); + return false; // edge not found + } + } else { + System.out.println("Edge #" + tid + " not found in library"); + return false; // edge does not exist + } + } finally { + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#deleteElement(int) + */ + public boolean deleteElement(int tid) throws SQLException { + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + if(elementPreviewLibrary.remove(loadElementPreview(tid))) { + stmt = connection.prepareStatement("DELETE FROM elements " + + "WHERE id=? LIMIT 1"); + stmt.setInt(1, tid); + int i = stmt.executeUpdate(); + if(i==1) { + stmt = connection.prepareStatement("DELETE FROM demands " + + "WHERE container_id=?"); + stmt.setInt(1, tid); + stmt.executeUpdate(); + stmt = connection.prepareStatement("DELETE FROM parts " + + "WHERE element_id=?"); + stmt.setInt(1, tid); + stmt.executeUpdate(); + stmt = connection.prepareStatement("SELECT id FROM states " + + "WHERE element_id=?"); + stmt.setInt(1, tid); + rs = stmt.executeQuery(); + while(rs.next()) { + deleteState(rs.getInt("id")); + } + System.out.println("Element #" + tid + " deleted"); + return true; + } else { + System.out.println("Element #" + tid + " not found in database"); + return false; // element not found + } + } else { + System.out.println("Element #" + tid + " not found in library"); + return false; // element does not exist + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Deletes a state triggers the deletion of any associated demand models. + * + * @param tid the primary key (type ID) + * + * @throws SQLException the SQL exception + */ + private void deleteState(int tid) throws SQLException { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("DELETE FROM states " + + "WHERE id=? LIMIT 1"); + stmt.setInt(1, tid); + int i = stmt.executeUpdate(); + if(i==1) { + stmt = connection.prepareStatement("SELECT id FROM models " + + "WHERE state_id=?"); + stmt.setInt(1, tid); + rs = stmt.executeQuery(); + while(rs.next()) { + deleteModel(rs.getInt("id")); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Deletes a demand model and triggers the deletion of any associated + * demands. + * + * @param tid the primary key (type ID) + * + * @throws SQLException the SQL exception + */ + private void deleteModel(int tid) throws SQLException { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("DELETE FROM models " + + "WHERE id=? LIMIT 1"); + stmt.setInt(1, tid); + stmt.executeUpdate(); + stmt = connection.prepareStatement("DELETE FROM demands " + + "WHERE model_id=?"); + stmt.setInt(1, tid); + stmt.executeUpdate(); + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#deleteNode(int) + */ + public boolean deleteNode(int tid) throws SQLException { + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT COUNT(*) AS conflicts " + + "FROM edges " + + "WHERE origin_id=? OR destination_id=?"); + stmt.setInt(1, tid); + stmt.setInt(2, tid); + rs = stmt.executeQuery(); + if(rs.next()) { + if(rs.getInt("conflicts")>0) + return false; // node is used in edges + } + if(nodeLibrary.remove(loadNode(tid))) { + stmt = connection.prepareStatement("DELETE FROM nodes " + + "WHERE id=? LIMIT 1"); + stmt.setInt(1, tid); + int i = stmt.executeUpdate(); + if(i > 0) { + System.out.println("Node #" + tid + " deleted"); + return true; + } else { + System.out.println("Node #" + tid + " not found in database"); + return false; // node not found + } + } else { + System.out.println("Node #" + tid + " not found in library"); + return false; // node does not exist + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#deleteResource(int) + */ + public boolean deleteResource(int tid) throws SQLException { + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT COUNT(*) AS conflicts " + + "FROM elements " + + "WHERE oms_id=? OR rcs_id=? OR fuel_id=?"); + stmt.setInt(1, tid); + stmt.setInt(2, tid); + stmt.setInt(3, tid); + rs = stmt.executeQuery(); + if(rs.next()) { + if(rs.getInt("conflicts")>0) + return false; // resource is used in elements + } + stmt = connection.prepareStatement("SELECT COUNT(*) AS conflicts " + + "FROM parts " + + "WHERE resource_id=?"); + stmt.setInt(1, tid); + rs = stmt.executeQuery(); + if(rs.next()) { + if(rs.getInt("conflicts")>0) + return false; // resource is used in parts + } + /* TODO: add back in when supporting ISRU or BOILOFF models + stmt = connection.prepareStatement("SELECT COUNT(*) AS conflicts " + + "FROM models " + + "WHERE resource_id=?"); + stmt.setInt(1, tid); + rs = stmt.executeQuery(); + if(rs.next()) { + if(rs.getInt("conflicts")>0) + return false; // resource is used in demand models + } + */ + stmt = connection.prepareStatement("SELECT COUNT(*) AS conflicts " + + "FROM demands " + + "WHERE resource_id=?"); + stmt.setInt(1, tid); + rs = stmt.executeQuery(); + if(rs.next()) { + if(rs.getInt("conflicts")>0) + return false; // resource is used in demands + } + if(resourceTypeLibrary.remove(loadResource(tid))) { + stmt = connection.prepareStatement("DELETE FROM resources " + + "WHERE id=? LIMIT 1"); + stmt.setInt(1, tid); + int i = stmt.executeUpdate(); + if(i > 0) { + System.out.println("Resource #" + tid + " deleted"); + return true; + } else { + System.out.println("Resource #" + tid + " not found in database"); + return false; // resource not found + } + } else { + System.out.println("Resource #" + tid + " not found in library"); + return false; // resource does not exist + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#getDataSourceType() + */ + public DataSourceType getDataSourceType() { + return DataSourceType.SQL_DB; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#getName() + */ + public String getName() { + if(host==null || host.length()==0) return "SpaceNet 2.5 (MySQL)"; + return database + " (" + host + ")"; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadEdgeLibrary() + */ + public void loadEdgeLibrary() throws SQLException { + Map libraryContents = new HashMap(); + for(Edge edge : getEdgeLibrary()) { + // mark all edges as unfound + libraryContents.put(edge.getTid(), false); + } + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT * FROM edges"); + rs = stmt.executeQuery(); + while(rs.next()) { + try { + Edge e = loadEdge(rs.getInt("id")); + String edgeType = rs.getString("type").toLowerCase(); + if(e==null || !e.getEdgeType().getName().toLowerCase().contains(edgeType)) { + edgeLibrary.remove(e); + if(e != null) libraryContents.remove(e.getTid()); + // create new edge and add to library + if(EdgeType.SURFACE.getName().toLowerCase().contains(edgeType)) { + e = new SurfaceEdge(); + } else if(EdgeType.SPACE.getName().toLowerCase().contains(edgeType)) { + e = new SpaceEdge(); + } else if(EdgeType.FLIGHT.getName().toLowerCase().contains(edgeType)) { + e = new FlightEdge(); + } else { + throw new Exception("Unknown Edge Type"); + } + edgeLibrary.add(e); + } else { + // mark edge as found + libraryContents.put(e.getTid(), true); + } + e.setTid(rs.getInt("id")); + e.setName(rs.getString("name")); + e.setOrigin(loadNode(rs.getInt("origin_id"))); + e.setDestination(loadNode(rs.getInt("destination_id"))); + e.setDescription(rs.getString("description")); + if(EdgeType.SURFACE.getName().toLowerCase().contains(edgeType)) { + e = new SurfaceEdge(); + ((SurfaceEdge)e).setDistance(rs.getDouble("distance")); + } else if(EdgeType.SPACE.getName().toLowerCase().contains(edgeType)) { + e = new SpaceEdge(); + ((SpaceEdge)e).setDuration(rs.getDouble("duration")); + loadBurns((SpaceEdge)e); + } else if(EdgeType.FLIGHT.getName().toLowerCase().contains(edgeType)) { + e = new FlightEdge(); + ((FlightEdge)e).setDuration(rs.getDouble("duration")); + ((FlightEdge)e).setMaxCrewSize(rs.getInt("max_crew")); + ((FlightEdge)e).setMaxCargoMass(rs.getDouble("max_cargo")); + } else { + throw new Exception("Unknown Edge Type"); + } + } catch(Exception ex) { + // error reading edge + ex.printStackTrace(); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + for(Integer i : libraryContents.keySet()) { + if(!libraryContents.get(i)) { + // remove all unfound edges + getEdgeLibrary().remove(loadEdge(i)); + } + } + } + + /** + * Loads burns for a specific space edge. + * + * @param edge the edge + * + * @throws SQLException the SQL exception + */ + private void loadBurns(SpaceEdge edge) throws SQLException { + edge.getBurns().clear(); + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT * FROM burns " + + "WHERE burns.edge_id=?"); + stmt.setInt(1, edge.getTid()); + rs = stmt.executeQuery(); + while(rs.next()) { + try { + Burn b = new Burn(); + b.setTid(rs.getInt("id")); + b.setTime(rs.getDouble("time")); + b.setBurnType(BurnType.getInstance(rs.getString("type"))); + b.setDeltaV(rs.getDouble("delta_v")); + edge.getBurns().add(rs.getInt("order"), b); + } catch(Exception ex) { + // error loading burn + ex.printStackTrace(); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadElement(int) + */ + public I_Element loadElement(int tid) throws SQLException { + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT * FROM elements " + + "WHERE id=?"); + stmt.setInt(1, tid); + rs = stmt.executeQuery(); + if(rs.next()) { + try { + I_Element e = null; + String elementType = rs.getString("type").toLowerCase(); + if(ElementType.ELEMENT.getName().toLowerCase().contains(elementType)) { + e = new Element(); + } else if(ElementType.RESOURCE_CONTAINER.getName().toLowerCase().contains(elementType)) { + e = new ResourceContainer(); + ((ResourceContainer)e).setMaxCargoMass(rs.getDouble("cargo_mass")); + ((ResourceContainer)e).setMaxCargoVolume(rs.getDouble("cargo_volume")); + ((ResourceContainer)e).setCargoEnvironment(Environment.getInstance(rs.getString("cargo_environment"))); + } else if(ElementType.CREW_MEMBER.getName().toLowerCase().contains(elementType)) { + e = new CrewMember(); + ((CrewMember)e).setAvailableTimeFraction(rs.getDouble("active_fraction")); + } else if(ElementType.CARRIER.getName().toLowerCase().contains(elementType)) { + e = new Carrier(); + ((Carrier)e).setMaxCrewSize(rs.getInt("max_crew")); + ((Carrier)e).setMaxCargoMass(rs.getDouble("cargo_mass")); + ((Carrier)e).setMaxCargoVolume(rs.getDouble("cargo_volume")); + ((Carrier)e).setCargoEnvironment(Environment.getInstance(rs.getString("cargo_environment"))); + } else if(ElementType.SURFACE_VEHICLE.getName().toLowerCase().contains(elementType)) { + e = new SurfaceVehicle(); + ((SurfaceVehicle)e).setMaxCrewSize(rs.getInt("max_crew")); + ((SurfaceVehicle)e).setMaxCargoMass(rs.getDouble("cargo_mass")); + ((SurfaceVehicle)e).setMaxCargoVolume(rs.getDouble("cargo_volume")); + ((SurfaceVehicle)e).setCargoEnvironment(Environment.getInstance(rs.getString("cargo_environment"))); + ((SurfaceVehicle)e).setMaxSpeed(rs.getDouble("max_speed")); + ((SurfaceVehicle)e).getFuelTank().setMaxAmount(rs.getDouble("max_fuel")); + ((SurfaceVehicle)e).getFuelTank().setAmount(rs.getDouble("max_fuel")); + ((SurfaceVehicle)e).getFuelTank().setResource(loadResource(rs.getInt("fuel_id"))); + } else if(ElementType.PROPULSIVE_VEHICLE.getName().toLowerCase().contains(elementType)) { + e = new PropulsiveVehicle(); + ((PropulsiveVehicle)e).setMaxCrewSize(rs.getInt("max_crew")); + ((PropulsiveVehicle)e).setMaxCargoMass(rs.getDouble("cargo_mass")); + ((PropulsiveVehicle)e).setMaxCargoVolume(rs.getDouble("cargo_volume")); + ((PropulsiveVehicle)e).setCargoEnvironment(Environment.getInstance(rs.getString("cargo_environment"))); + ((PropulsiveVehicle)e).setOmsIsp(rs.getDouble("oms_isp")); + ((PropulsiveVehicle)e).setRcsIsp(rs.getDouble("rcs_isp")); + if(((PropulsiveVehicle)e).getOmsIsp() > 0) { + ((PropulsiveVehicle)e).getOmsFuelTank().setMaxAmount(rs.getDouble("max_oms")); + ((PropulsiveVehicle)e).getOmsFuelTank().setAmount(rs.getDouble("max_oms")); + ((PropulsiveVehicle)e).getOmsFuelTank().setResource(loadResource(rs.getInt("oms_id"))); + } else { + ((PropulsiveVehicle)e).setOmsFuelTank(null); + } + if(((PropulsiveVehicle)e).getRcsIsp() > 0 && rs.getDouble("max_rcs") > 0) { + ((PropulsiveVehicle)e).getRcsFuelTank().setMaxAmount(rs.getDouble("max_rcs")); + ((PropulsiveVehicle)e).getRcsFuelTank().setAmount(rs.getDouble("max_rcs")); + ((PropulsiveVehicle)e).getRcsFuelTank().setResource(loadResource(rs.getInt("rcs_id"))); + } else if(((PropulsiveVehicle)e).getRcsIsp() > 0) { + ((PropulsiveVehicle)e).getContents().remove(((PropulsiveVehicle)e).getRcsFuelTank()); + ((PropulsiveVehicle)e).setRcsFuelTank(((PropulsiveVehicle)e).getOmsFuelTank()); + } else { + ((PropulsiveVehicle)e).setRcsFuelTank(null); + } + } else { + throw new Exception("Unknown Element Type"); + } + e.setTid(rs.getInt("id")); + e.setName(rs.getString("name")); + e.setClassOfSupply(ClassOfSupply.getInstance(rs.getInt("cos"))); + e.setEnvironment(Environment.getInstance(rs.getString("environment"))); + e.setAccommodationMass(rs.getDouble("accommodation_mass")); + e.setMass(rs.getDouble("mass")); + e.setVolume(rs.getDouble("volume")); + e.setDescription(rs.getString("description")); + if(e.getElementType()==ElementType.RESOURCE_CONTAINER) { + ((I_ResourceContainer)e).getContents().clear(); + stmt = connection.prepareStatement("SELECT * FROM demands " + + "WHERE container_id=?"); + stmt.setInt(1, e.getTid()); + rs = stmt.executeQuery(); + while(rs.next()) { + ((ResourceContainer)e).getContents().put( + loadResource(rs.getInt("resource_id")), + rs.getDouble("amount")); + } + } + e.getParts().clear(); + stmt = connection.prepareStatement("SELECT * FROM parts " + + "WHERE element_id=?"); + stmt.setInt(1, e.getTid()); + rs = stmt.executeQuery(); + while(rs.next()) { + PartApplication partApp = new PartApplication(); + partApp.setTid(rs.getInt("id")); + partApp.setPart((Item)loadResource(rs.getInt("resource_id"))); + partApp.setQuantity(rs.getInt("quantity")); + partApp.setDutyCycle(rs.getDouble("duty_cycle")); + partApp.setMeanTimeToFailure(rs.getDouble("mttf")); + partApp.setMeanTimeToRepair(rs.getDouble("mttr")); + partApp.setMassToRepair(rs.getDouble("repair_mass")); + e.getParts().add(partApp); + } + e.getStates().clear(); + stmt = connection.prepareStatement("SELECT * FROM states " + + "WHERE element_id=?"); + stmt.setInt(1, e.getTid()); + rs = stmt.executeQuery(); + while(rs.next()) { + State state = new State(); + state.setTid(rs.getInt("id")); + state.setName(rs.getString("name")); + state.setStateType(StateType.getInstance(rs.getString("type"))); + loadModels(e, state); + e.getStates().add(state); + if(rs.getInt("initial") == 1) + e.setCurrentState(state); + } + return e; + } catch(Exception ex) { + // error reading element + ex.printStackTrace(); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + return null; + } + + /** + * Loads the demand models for a specific state. + * + * @param element the element + * @param state the state + * + * @throws SQLException the SQL exception + */ + private void loadModels(I_Element element, I_State state) throws SQLException { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT * FROM models " + + "WHERE state_id=?"); + stmt.setInt(1, state.getTid()); + rs = stmt.executeQuery(); + while(rs.next()) { + try { + String modelType = rs.getString("type").toLowerCase(); + if(DemandModelType.TIMED_IMPULSE.getName().toLowerCase().contains(modelType)) { + TimedImpulseDemandModel model = new TimedImpulseDemandModel(); + model.setTid(rs.getInt("id")); + model.setName(rs.getString("name")); + PreparedStatement s = connection.prepareStatement("SELECT * FROM demands " + + "WHERE model_id=?"); + s.setInt(1, model.getTid()); + ResultSet r = s.executeQuery(); + while(r.next()) { + Demand demand = new Demand(); + demand.setResource(loadResource(r.getInt("resource_id"))); + demand.setAmount(r.getDouble("amount")); + model.getDemands().add(demand); + } + state.getDemandModels().add(model); + } else if(DemandModelType.RATED.getName().toLowerCase().contains(modelType)) { + RatedDemandModel model = new RatedDemandModel(); + model.setTid(rs.getInt("id")); + model.setName(rs.getString("name")); + PreparedStatement s = connection.prepareStatement("SELECT * FROM demands " + + "WHERE model_id=?"); + s.setInt(1, model.getTid()); + ResultSet r = s.executeQuery(); + while(r.next()) { + Demand demand = new Demand(); + demand.setResource(loadResource(r.getInt("resource_id"))); + demand.setAmount(r.getDouble("amount")); + model.getDemandRates().add(demand); + } + state.getDemandModels().add(model); + } else if(DemandModelType.SPARING_BY_MASS.getName().toLowerCase().contains(modelType)) { + SparingByMassDemandModel model = new SparingByMassDemandModel(element); + model.setTid(rs.getInt("id")); + model.setName(rs.getString("name")); + model.setElement(element); + model.setPartsListEnabled(rs.getInt("parts_list")==1); + model.setUnpressurizedSparesRate(rs.getDouble("unpress_rate")); + model.setPressurizedSparesRate(rs.getDouble("press_rate")); + state.getDemandModels().add(model); + } else { + throw new Exception("Unknown Demand Model Type"); + } + } catch(Exception ex) { + // error reading model + ex.printStackTrace(); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Loads the element library. + * + * @throws SQLException the SQL exception + */ + public void loadElementLibrary() throws SQLException { + getElementPreviewLibrary().clear(); + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT * FROM elements"); + rs = stmt.executeQuery(); + while(rs.next()) { + try { + ElementPreview e = null; + String elementType = rs.getString("type").toLowerCase(); + String name = rs.getString("name"); + int tid = rs.getInt("id"); + // create new element preview and add to library + // TODO: support element icon types + if(ElementType.ELEMENT.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.ELEMENT, null); + } else if(ElementType.RESOURCE_CONTAINER.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.RESOURCE_CONTAINER, null); + } else if(ElementType.CREW_MEMBER.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.CREW_MEMBER, null); + } else if(ElementType.CARRIER.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.CARRIER, null); + } else if(ElementType.SURFACE_VEHICLE.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.SURFACE_VEHICLE, null); + } else if(ElementType.PROPULSIVE_VEHICLE.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.PROPULSIVE_VEHICLE, null); + } else { + throw new Exception("Unknown Element Type"); + } + elementPreviewLibrary.add(e); + } catch(Exception ex) { + // error reading resource + ex.printStackTrace(); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Loads the node library. + * + * @throws SQLException the SQL exception + */ + public void loadNodeLibrary() throws SQLException { + Map libraryContents = new HashMap(); + for(Node node : getNodeLibrary()) { + // mark all nodes as unfound + libraryContents.put(node.getTid(), false); + } + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT * FROM nodes");; + rs = stmt.executeQuery();; + while(rs.next()) { + try { + Node n = loadNode(rs.getInt("id")); + String nodeType = rs.getString("type").toLowerCase(); + if(n==null || !n.getNodeType().getName().toLowerCase().contains(nodeType)) { + nodeLibrary.remove(n); + if(n!=null) libraryContents.remove(n.getTid()); + // create new node and add to library + if(NodeType.SURFACE.getName().toLowerCase().contains(nodeType)) { + n = new SurfaceNode(); + } else if(NodeType.ORBITAL.getName().toLowerCase().contains(nodeType)) { + n = new OrbitalNode(); + } else if(NodeType.LAGRANGE.getName().toLowerCase().contains(nodeType)) { + n = new LagrangeNode(); + } else { + throw new Exception("Unknown Node Type"); + } + nodeLibrary.add(n); + } else { + // mark node as found + libraryContents.put(n.getTid(), true); + } + n.setTid(rs.getInt("id")); + n.setName(rs.getString("name")); + n.setBody(Body.getInstance(rs.getString("body_1"))); + n.setDescription(rs.getString("description")); + if(NodeType.SURFACE.getName().toLowerCase().contains(nodeType)) { + n = new SurfaceNode(); + ((SurfaceNode)n).setLatitude(rs.getDouble("latitude")); + ((SurfaceNode)n).setLongitude(rs.getDouble("longitude")); + } else if(NodeType.ORBITAL.getName().toLowerCase().contains(nodeType)) { + n = new OrbitalNode(); + ((OrbitalNode)n).setApoapsis(rs.getDouble("apoapsis")); + ((OrbitalNode)n).setPeriapsis(rs.getDouble("periapsis")); + ((OrbitalNode)n).setInclination(rs.getDouble("inclination")); + } else if(NodeType.LAGRANGE.getName().toLowerCase().contains(nodeType)) { + n = new LagrangeNode(); + ((LagrangeNode)n).setMinorBody(Body.getInstance(rs.getString("body_2"))); + ((LagrangeNode)n).setNumber(rs.getInt("lp_number")); + } else { + throw new Exception("Unknown Node Type"); + } + } catch(Exception ex) { + // error reading node + ex.printStackTrace(); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + for(Integer i : libraryContents.keySet()) { + if(!libraryContents.get(i)) { + // remove all unfound nodes + getNodeLibrary().remove(loadNode(i)); + } + } + } + + /** + * Loads the resource library. + * + * @throws SQLException the SQL exception + */ + public void loadResourceLibrary() throws SQLException { + Map libraryContents = new HashMap(); + for(I_Resource resource : getResourceLibrary()) { + // mark all resources as not found + libraryContents.put(resource.getTid(), false); + } + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("SELECT * FROM resources"); + rs = stmt.executeQuery(); + while(rs.next()) { + try { + I_Resource r = loadResource(rs.getInt("id")); + String resourceType = rs.getString("type").toLowerCase(); + if(r==null || !r.getResourceType().getName().toLowerCase().contains(resourceType)) { + resourceTypeLibrary.remove(r); + if(r!=null) libraryContents.remove(r.getTid()); + // create new resource and add to library + if(ResourceType.RESOURCE.getName().toLowerCase().contains(resourceType)) { + r = new Resource(); + } else if(ResourceType.ITEM.getName().toLowerCase().contains(resourceType)) { + r = new Item(); + } else { + throw new Exception("Unknown Resource Type"); + } + resourceTypeLibrary.add(r); + } else { + // mark resource as found + libraryContents.put(r.getTid(), true); + } + r.setTid(rs.getInt("id")); + r.setName(rs.getString("name")); + r.setClassOfSupply(ClassOfSupply.getInstance(rs.getInt("cos"))); + r.setUnits(rs.getString("units")); + r.setUnitMass(rs.getDouble("unit_mass")); + r.setUnitVolume(rs.getDouble("unit_volume")); + r.setPackingFactor(rs.getDouble("packing_factor")); + r.setEnvironment(Environment.getInstance(rs.getString("environment"))); + r.setDescription(rs.getString("description")); + } catch(Exception ex) { + // error reading resource + ex.printStackTrace(); + } + } + for(Integer i : libraryContents.keySet()) { + if(!libraryContents.get(i)) { + // remove all unfound resources + getResourceLibrary().remove(loadResource(i)); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#saveEdge(edu.mit.spacenet.domain.network.edge.Edge) + */ + public void saveEdge(Edge edge) throws SQLException { + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("UPDATE edges " + + "SET type=?, name=?, origin_id=?, destination_id=?, " + + "duration=?, distance=?, max_crew=?, max_cargo=?, " + + "description=?" + + "WHERE id=?"); + stmt.setString(1, edge.getEdgeType().getName()); + stmt.setString(2, edge.getName()); + stmt.setInt(3, edge.getOrigin().getTid()); + stmt.setInt(4, edge.getDestination().getTid()); + if(edge.getEdgeType()==EdgeType.SPACE) { + stmt.setDouble(5, ((SpaceEdge)edge).getDuration()); + } else { + if(edge.getEdgeType()!=EdgeType.FLIGHT) + stmt.setNull(5, Types.DOUBLE); // don't overwrite value + } + if(edge.getEdgeType()==EdgeType.SURFACE) { + stmt.setDouble(6, ((SurfaceEdge)edge).getDistance()); + } else { + stmt.setNull(6, Types.DOUBLE); + } + if(edge.getEdgeType()==EdgeType.FLIGHT) { + stmt.setDouble(5, ((FlightEdge)edge).getDuration()); + stmt.setInt(7, ((FlightEdge)edge).getMaxCrewSize()); + stmt.setDouble(8, ((FlightEdge)edge).getMaxCargoMass()); + } else { + if(edge.getEdgeType()!=EdgeType.SPACE) + stmt.setNull(5, Types.DOUBLE); // don't overwrite value + stmt.setNull(7, Types.INTEGER); + stmt.setNull(8, Types.DOUBLE); + } + stmt.setString(9, edge.getDescription()); + stmt.setInt(10, edge.getTid()); + int i = stmt.executeUpdate(); + if(i == 0) { + // insert new edge + stmt = connection.prepareStatement("INSERT INTO edges " + + "(type, name, origin_id, destination_id, duration, " + + "distance, max_crew, max_cargo, description) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, edge.getEdgeType().getName()); + stmt.setString(2, edge.getName()); + stmt.setInt(3, edge.getOrigin().getTid()); + stmt.setInt(4, edge.getDestination().getTid()); + if(edge.getEdgeType()==EdgeType.SPACE) { + stmt.setDouble(5, ((SpaceEdge)edge).getDuration()); + } else { + if(edge.getEdgeType()!=EdgeType.FLIGHT) + stmt.setNull(5, Types.DOUBLE); // don't overwrite value + } + if(edge.getEdgeType()==EdgeType.SURFACE) { + stmt.setDouble(6, ((SurfaceEdge)edge).getDistance()); + } else { + stmt.setNull(6, Types.DOUBLE); + } + if(edge.getEdgeType()==EdgeType.FLIGHT) { + stmt.setDouble(5, ((FlightEdge)edge).getDuration()); + stmt.setInt(7, ((FlightEdge)edge).getMaxCrewSize()); + stmt.setDouble(8, ((FlightEdge)edge).getMaxCargoMass()); + } else { + if(edge.getEdgeType()!=EdgeType.SPACE) + stmt.setNull(5, Types.DOUBLE); // don't overwrite value + stmt.setNull(7, Types.INTEGER); + stmt.setNull(8, Types.DOUBLE); + } + stmt.setString(9, edge.getDescription()); + stmt.executeUpdate(); + stmt = connection.prepareStatement("SELECT LAST_INSERT_ID() AS id"); + rs = stmt.executeQuery(); + if(rs.next()) { + edge.setTid(rs.getInt("id")); + getEdgeLibrary().add(edge); + } + } + if(edge.getEdgeType()==EdgeType.SPACE) saveBurns(((SpaceEdge)edge)); + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Saves the burns associated with an edge. Removed burns will be deleted + * from the data source, changed burns will be updated, and added burns + * will be assigned a new TID and inserted. + * + * @param edge the edge + * + * @throws SQLException the SQL exception + */ + private void saveBurns(SpaceEdge edge) throws SQLException { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + // delete unused burns + if(edge.getBurns().size()>0) { + String burnList = ""; + for(Burn burn : edge.getBurns()) burnList += burn.getTid() + ", "; + burnList = burnList.substring(0, burnList.length()-2); + stmt = connection.prepareStatement("DELETE FROM burns " + + "WHERE edge_id = ? " + + "AND id NOT IN (" + burnList + ")"); + stmt.setInt(1, edge.getTid()); + stmt.executeUpdate(); + } + + // update/insert burns + for(Burn burn : edge.getBurns()) { + stmt = connection.prepareStatement("UPDATE burns " + + "SET `time`=?, `order`=?, type=?, delta_v=? " + + "WHERE id=? AND edge_id=?"); + stmt.setDouble(1, burn.getTime()); + stmt.setInt(2, edge.getBurns().indexOf(burn)); + stmt.setString(3, burn.getBurnType().getName()); + stmt.setDouble(4, burn.getDeltaV()); + stmt.setInt(5, burn.getTid()); + stmt.setInt(6, edge.getTid()); + int i = stmt.executeUpdate(); + if(i == 0) { + // insert new resource + stmt = connection.prepareStatement("INSERT INTO burns " + + "(edge_id, `time`, `order`, type, delta_v) " + + "VALUES (?, ?, ?, ?, ?)"); + stmt.setInt(1, edge.getTid()); + stmt.setDouble(2, burn.getTime()); + stmt.setInt(3, edge.getBurns().indexOf(burn)); + stmt.setString(4, burn.getBurnType().getName()); + stmt.setDouble(5, burn.getDeltaV()); + stmt.executeUpdate(); + stmt = connection.prepareStatement("SELECT LAST_INSERT_ID() AS id"); + rs = stmt.executeQuery(); + if(rs.next()) { + burn.setTid(rs.getInt("id")); + } + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#saveElement(edu.mit.spacenet.domain.element.I_Element) + */ + public void saveElement(I_Element element) throws SQLException { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("UPDATE elements " + + "SET type=?, name=?, cos=?, environment=?, " + + "accommodation_mass=?, mass=?, volume=?, max_crew=?, " + + "cargo_mass=?, cargo_volume=?, cargo_environment=?," + + "active_fraction=?, oms_isp=?, max_oms=?, oms_id=?, " + + "rcs_isp=?, max_rcs=?, rcs_id=?, max_speed=?, max_fuel=?," + + "fuel_id=?, description=?" + + "WHERE id=? "); + stmt.setString(1, element.getElementType().getName()); + stmt.setString(2, element.getName()); + stmt.setInt(3, element.getClassOfSupply().getId()); + stmt.setString(4, element.getEnvironment().getName()); + stmt.setDouble(5, element.getAccommodationMass()); + stmt.setDouble(6, element.getMass()); + stmt.setDouble(7, element.getVolume()); + if(element.getElementType()==ElementType.ELEMENT) { + stmt.setNull(8, Types.INTEGER); + stmt.setNull(9, Types.DOUBLE); + stmt.setNull(10, Types.DOUBLE); + stmt.setNull(11, Types.VARCHAR); + stmt.setNull(12, Types.DOUBLE); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + } if(element.getElementType()==ElementType.RESOURCE_CONTAINER) { + stmt.setNull(8, Types.INTEGER); + stmt.setDouble(9, ((ResourceContainer)element).getMaxCargoMass()); + stmt.setDouble(10, ((ResourceContainer)element).getMaxCargoVolume()); + stmt.setString(11, ((ResourceContainer)element).getCargoEnvironment().getName()); + stmt.setNull(12, Types.DOUBLE); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + saveContents((ResourceContainer)element); + } else if(element.getElementType()==ElementType.CREW_MEMBER) { + stmt.setNull(8, Types.INTEGER); + stmt.setNull(9, Types.DOUBLE); + stmt.setNull(10, Types.DOUBLE); + stmt.setNull(11, Types.VARCHAR); + stmt.setDouble(12, ((CrewMember)element).getAvailableTimeFraction()); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + } else if(element.getElementType()==ElementType.CARRIER) { + stmt.setInt(8, ((Carrier)element).getMaxCrewSize()); + stmt.setDouble(9, ((Carrier)element).getMaxCargoMass()); + stmt.setDouble(10, ((Carrier)element).getMaxCargoVolume()); + stmt.setString(11, ((Carrier)element).getCargoEnvironment().getName()); + stmt.setNull(12, Types.DOUBLE); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + } else if(element.getElementType()==ElementType.PROPULSIVE_VEHICLE) { + stmt.setInt(8, ((PropulsiveVehicle)element).getMaxCrewSize()); + stmt.setDouble(9, ((PropulsiveVehicle)element).getMaxCargoMass()); + stmt.setDouble(10, ((PropulsiveVehicle)element).getMaxCargoVolume()); + stmt.setString(11, ((PropulsiveVehicle)element).getCargoEnvironment().getName()); + stmt.setNull(12, Types.DOUBLE); + if(((PropulsiveVehicle)element).getOmsIsp() > 0) { + stmt.setDouble(13, ((PropulsiveVehicle)element).getOmsIsp()); + stmt.setDouble(14, ((PropulsiveVehicle)element).getOmsFuelTank().getMaxAmount()); + stmt.setInt(15, ((PropulsiveVehicle)element).getOmsFuelTank().getResource().getTid()); + } else { + stmt.setDouble(13, 0); + stmt.setDouble(14, 0); + stmt.setNull(15, Types.INTEGER); + } + if(((PropulsiveVehicle)element).getRcsIsp() > 0) { + stmt.setDouble(16, ((PropulsiveVehicle)element).getRcsIsp()); + if(((PropulsiveVehicle)element).getRcsFuelTank()==null || + ((PropulsiveVehicle)element).getRcsFuelTank()==((PropulsiveVehicle)element).getOmsFuelTank()) { + // shared OMS / RCS tanks + stmt.setDouble(17, 0); + stmt.setNull(18, Types.INTEGER); + } else { + stmt.setDouble(17, ((PropulsiveVehicle)element).getRcsFuelTank().getMaxAmount()); + stmt.setInt(18, ((PropulsiveVehicle)element).getRcsFuelTank().getResource().getTid()); + } + } else { + stmt.setDouble(16, 0); + stmt.setDouble(17, 0); + stmt.setNull(18, Types.INTEGER); + } + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + } else if(element.getElementType()==ElementType.SURFACE_VEHICLE) { + stmt.setInt(8, ((SurfaceVehicle)element).getMaxCrewSize()); + stmt.setDouble(9, ((SurfaceVehicle)element).getMaxCargoMass()); + stmt.setDouble(10, ((SurfaceVehicle)element).getMaxCargoVolume()); + stmt.setString(11, ((SurfaceVehicle)element).getCargoEnvironment().getName()); + stmt.setNull(12, Types.DOUBLE); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setDouble(19, ((SurfaceVehicle)element).getMaxSpeed()); + stmt.setDouble(20, ((SurfaceVehicle)element).getFuelTank().getMaxAmount()); + stmt.setInt(21, ((SurfaceVehicle)element).getFuelTank().getResource().getTid()); + } + stmt.setString(22, element.getDescription()); + stmt.setInt(23, element.getTid()); + int i = stmt.executeUpdate(); + if(i==0) { + // create new element + stmt = connection.prepareStatement("INSERT INTO elements " + + "(type, name, cos, environment, accommodation_mass, " + + "mass, volume, max_crew, cargo_mass, cargo_volume, " + + "cargo_environment, active_fraction, oms_isp, max_oms, " + + "oms_id, rcs_isp, max_rcs, rcs_id, max_speed, max_fuel, " + + "fuel_id, description) " + + "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, element.getElementType().getName()); + stmt.setString(2, element.getName()); + stmt.setInt(3, element.getClassOfSupply().getId()); + stmt.setString(4, element.getEnvironment().getName()); + stmt.setDouble(5, element.getAccommodationMass()); + stmt.setDouble(6, element.getMass()); + stmt.setDouble(7, element.getVolume()); + // TODO: support element icon types + if(element.getElementType()==ElementType.ELEMENT) { + stmt.setNull(8, Types.INTEGER); + stmt.setNull(9, Types.DOUBLE); + stmt.setNull(10, Types.DOUBLE); + stmt.setNull(11, Types.VARCHAR); + stmt.setNull(12, Types.DOUBLE); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + } else if(element.getElementType()==ElementType.RESOURCE_CONTAINER) { + stmt.setNull(8, Types.INTEGER); + stmt.setDouble(9, ((ResourceContainer)element).getMaxCargoMass()); + stmt.setDouble(10, ((ResourceContainer)element).getMaxCargoVolume()); + stmt.setString(11, ((ResourceContainer)element).getCargoEnvironment().getName()); + stmt.setNull(12, Types.DOUBLE); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + saveContents((ResourceContainer)element); + } else if(element.getElementType()==ElementType.CREW_MEMBER) { + stmt.setNull(8, Types.INTEGER); + stmt.setNull(9, Types.DOUBLE); + stmt.setNull(10, Types.DOUBLE); + stmt.setNull(11, Types.VARCHAR); + stmt.setDouble(12, ((CrewMember)element).getAvailableTimeFraction()); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + } else if(element.getElementType()==ElementType.CARRIER) { + stmt.setInt(8, ((Carrier)element).getMaxCrewSize()); + stmt.setDouble(9, ((Carrier)element).getMaxCargoMass()); + stmt.setDouble(10, ((Carrier)element).getMaxCargoVolume()); + stmt.setString(11, ((Carrier)element).getCargoEnvironment().getName()); + stmt.setNull(12, Types.DOUBLE); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + } else if(element.getElementType()==ElementType.PROPULSIVE_VEHICLE) { + stmt.setInt(8, ((PropulsiveVehicle)element).getMaxCrewSize()); + stmt.setDouble(9, ((PropulsiveVehicle)element).getMaxCargoMass()); + stmt.setDouble(10, ((PropulsiveVehicle)element).getMaxCargoVolume()); + stmt.setString(11, ((PropulsiveVehicle)element).getCargoEnvironment().getName()); + stmt.setNull(12, Types.DOUBLE); + if(((PropulsiveVehicle)element).getOmsIsp() > 0) { + stmt.setDouble(13, ((PropulsiveVehicle)element).getOmsIsp()); + stmt.setDouble(14, ((PropulsiveVehicle)element).getOmsFuelTank().getMaxAmount()); + stmt.setInt(15, ((PropulsiveVehicle)element).getOmsFuelTank().getResource().getTid()); + } else { + stmt.setDouble(13, 0); + stmt.setDouble(14, 0); + stmt.setNull(15, Types.INTEGER); + } + if(((PropulsiveVehicle)element).getRcsIsp() > 0) { + stmt.setDouble(16, ((PropulsiveVehicle)element).getRcsIsp()); + if(((PropulsiveVehicle)element).getRcsFuelTank()==null || + ((PropulsiveVehicle)element).getRcsFuelTank()==((PropulsiveVehicle)element).getOmsFuelTank()) { + // shared OMS / RCS tanks + stmt.setDouble(17, 0); + stmt.setNull(18, Types.INTEGER); + } else { + stmt.setDouble(17, ((PropulsiveVehicle)element).getRcsFuelTank().getMaxAmount()); + stmt.setInt(18, ((PropulsiveVehicle)element).getRcsFuelTank().getResource().getTid()); + } + } else { + stmt.setDouble(16, 0); + stmt.setDouble(17, 0); + stmt.setNull(18, Types.INTEGER); + } + stmt.setNull(19, Types.DOUBLE); + stmt.setNull(20, Types.DOUBLE); + stmt.setNull(21, Types.INTEGER); + } else if(element.getElementType()==ElementType.SURFACE_VEHICLE) { + stmt.setInt(8, ((SurfaceVehicle)element).getMaxCrewSize()); + stmt.setDouble(9, ((SurfaceVehicle)element).getMaxCargoMass()); + stmt.setDouble(10, ((SurfaceVehicle)element).getMaxCargoVolume()); + stmt.setString(11, ((SurfaceVehicle)element).getCargoEnvironment().getName()); + stmt.setNull(12, Types.DOUBLE); + stmt.setNull(13, Types.DOUBLE); + stmt.setNull(14, Types.DOUBLE); + stmt.setNull(15, Types.INTEGER); + stmt.setNull(16, Types.DOUBLE); + stmt.setNull(17, Types.DOUBLE); + stmt.setNull(18, Types.INTEGER); + stmt.setDouble(19, ((SurfaceVehicle)element).getMaxSpeed()); + stmt.setDouble(20, ((SurfaceVehicle)element).getFuelTank().getMaxAmount()); + stmt.setInt(21, ((SurfaceVehicle)element).getFuelTank().getResource().getTid()); + } + stmt.setString(22, element.getDescription()); + stmt.executeUpdate(); + stmt = connection.prepareStatement("SELECT LAST_INSERT_ID() AS id"); + rs = stmt.executeQuery(); + if(rs.next()) { + element.setTid(rs.getInt("id")); + } + elementPreviewLibrary.add(new ElementPreview( + element.getTid(), + element.getName(), + element.getElementType(), + element.getIconType())); + } else { + elementPreviewLibrary.remove(loadElementPreview(element.getTid())); + elementPreviewLibrary.add(new ElementPreview( + element.getTid(), + element.getName(), + element.getElementType(), + element.getIconType())); + } + saveParts(element); + saveStates(element); + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Saves the contents of a resource container. Removed resources will be + * deleted from the data source, changed resources will be updated, and + * added resources will be inserted. + * + * @param container the container + * + * @throws SQLException the SQL exception + */ + private void saveContents(I_ResourceContainer container) throws SQLException { + PreparedStatement stmt = null; + try { + // delete unused contents + if(container.getContents().keySet().size()>0) { + String resourceList = ""; + for(I_Resource resource : container.getContents().keySet()) + resourceList += resource.getTid() + ", "; + resourceList = resourceList.substring(0, resourceList.length()-2); + stmt = connection.prepareStatement("DELETE FROM demands " + + "WHERE container_id = ? " + + "AND resource_id NOT IN (" + resourceList + ")"); + stmt.setInt(1, container.getTid()); + stmt.executeUpdate(); + } + + // update/insert contents + for(I_Resource resource : container.getContents().keySet()) { + stmt = connection.prepareStatement("UPDATE demands " + + "SET amount=? " + + "WHERE resource_id=? AND container_id=? "); + stmt.setDouble(1, container.getContents().get(resource)); + stmt.setInt(2, resource.getTid()); + stmt.setInt(3, container.getTid()); + int i = stmt.executeUpdate(); + if(i==0) { + // insert new contents + stmt = connection.prepareStatement("INSERT INTO demands " + + "(resource_id, container_id, amount) " + + "VALUES (?, ?, ?) "); + stmt.setInt(1, resource.getTid()); + stmt.setInt(2, container.getTid()); + stmt.setDouble(3, container.getContents().get(resource)); + stmt.executeUpdate(); + } + } + } finally { + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Saves the parts associated with an element. Removed parts will be + * deleted from the data source, changed parts will be updated, and + * added parts will be inserted. + * + * @param element the element + * + * @throws SQLException the SQL exception + */ + private void saveParts(I_Element element) throws SQLException { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + // delete unused parts + if(element.getParts().size()>0) { + String partsList = ""; + for(PartApplication part : element.getParts()) + partsList += part.getPart().getTid() + ", "; + partsList = partsList.substring(0, partsList.length()-2); + stmt = connection.prepareStatement("DELETE FROM parts " + + "WHERE element_id = ? " + + "AND resource_id NOT IN (" + partsList + ")"); + stmt.setInt(1, element.getTid()); + stmt.executeUpdate(); + } + + // update/insert parts + for(PartApplication part : element.getParts()) { + stmt = connection.prepareStatement("UPDATE parts " + + "SET quantity=?, duty_cycle=?, mttf=?, mttr=?, " + + "repair_mass=? " + + "WHERE resource_id=? AND element_id=? "); + stmt.setDouble(1, part.getQuantity()); + stmt.setDouble(2, part.getDutyCycle()); + stmt.setDouble(3, part.getMeanTimeToFailure()); + stmt.setDouble(4, part.getMeanTimeToRepair()); + stmt.setDouble(5, part.getMassToRepair()); + stmt.setInt(6, part.getPart().getTid()); + stmt.setInt(7, element.getTid()); + int i = stmt.executeUpdate(); + if(i==0) { + // insert new part + stmt = connection.prepareStatement("INSERT INTO parts " + + "(resource_id, element_id, quantity, duty_cycle, " + + "mttf, mttr, repair_mass) " + + "VALUES (?, ?, ?, ?, ?, ?, ?) "); + stmt.setInt(1, part.getPart().getTid()); + stmt.setInt(2, element.getTid()); + stmt.setDouble(3, part.getQuantity()); + stmt.setDouble(4, part.getDutyCycle()); + stmt.setDouble(5, part.getMeanTimeToFailure()); + stmt.setDouble(6, part.getMeanTimeToRepair()); + stmt.setDouble(7, part.getMassToRepair()); + stmt.executeUpdate(); + rs = stmt.executeQuery("SELECT LAST_INSERT_ID() as id"); + if(rs.next()) { + part.setTid(rs.getInt("id")); + } + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Saves the states associated with an element. Removed states will be + * deleted from the data source, changed states will be updated, and + * added states will be assigned a new TID and inserted. + * + * @param element the element + * + * @throws SQLException the SQL exception + */ + private void saveStates(I_Element element) throws SQLException { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + // delete unused states + if(element.getStates().size()>0) { + String statesList = ""; + for(I_State state : element.getStates()) + statesList += state.getTid() + ", "; + statesList = statesList.substring(0, statesList.length()-2); + stmt = connection.prepareStatement("DELETE FROM states " + + "WHERE element_id = ? " + + "AND id NOT IN (" + statesList + ")"); + stmt.setInt(1, element.getTid()); + stmt.executeUpdate(); + } + + // update/insert states + for(I_State state : element.getStates()) { + stmt = connection.prepareStatement("UPDATE states " + + "SET name=?, type=?, initial=? " + + "WHERE id=? "); + stmt.setString(1, state.getName()); + stmt.setString(2, state.getStateType().getName()); + stmt.setInt(3, element.getCurrentState()==state?1:0); + stmt.setInt(4, state.getTid()); + int i = stmt.executeUpdate(); + if(i==0) { + // insert new state + stmt = connection.prepareStatement("INSERT INTO states " + + "(element_id, name, type, initial) " + + "VALUES (?, ?, ?, ?) "); + stmt.setInt(1, element.getTid()); + stmt.setString(2, state.getName()); + stmt.setString(3, state.getStateType().getName()); + stmt.setInt(4, element.getCurrentState()==state?1:0); + stmt.executeUpdate(); + rs = stmt.executeQuery("SELECT LAST_INSERT_ID() as id"); + if(rs.next()) { + state.setTid(rs.getInt("id")); + } + } + saveModels(state); + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Saves the associated demand models contained within a state. Removed + * models will be deleted from the data source, changed models will be + * updated, and added models will assigned a new TID and be inserted. + * + * @param state the state + * + * @throws SQLException the SQL exception + */ + private void saveModels(I_State state) throws SQLException { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + // delete unused models + if(state.getDemandModels().size()>0) { + String modelsList = ""; + for(I_DemandModel model : state.getDemandModels()) + modelsList += model.getTid() + ", "; + modelsList = modelsList.substring(0, modelsList.length()-2); + stmt = connection.prepareStatement("DELETE FROM models " + + "WHERE state_id = ? " + + "AND id NOT IN (" + modelsList + ")"); + stmt.setInt(1, state.getTid()); + stmt.executeUpdate(); + } + + // update/insert models + for(I_DemandModel model : state.getDemandModels()) { + stmt = connection.prepareStatement("UPDATE models " + + "SET type=?, name=?, parts_list=?, unpress_rate=?, press_rate=? " + + "WHERE id=? "); + stmt.setString(1, model.getDemandModelType().getName()); + stmt.setString(2, model.getName()); + stmt.setInt(6, model.getTid()); + if(model.getDemandModelType()==DemandModelType.TIMED_IMPULSE + || model.getDemandModelType()==DemandModelType.RATED) { + stmt.setNull(3, Types.INTEGER); + stmt.setNull(4, Types.DOUBLE); + stmt.setNull(5, Types.DOUBLE); + saveDemands(model); + } else if(model.getDemandModelType()==DemandModelType.SPARING_BY_MASS) { + stmt.setInt(3, ((SparingByMassDemandModel)model).isPartsListEnabled()?1:0); + stmt.setDouble(4, ((SparingByMassDemandModel)model).getUnpressurizedSparesRate()); + stmt.setDouble(5, ((SparingByMassDemandModel)model).getPressurizedSparesRate()); + } + int i = stmt.executeUpdate(); + if(i==0) { + // insert new model + stmt = connection.prepareStatement("INSERT INTO models " + + "(state_id, type, name, parts_list, unpress_rate, press_rate) " + + "VALUES (?, ?, ?, ?, ?, ?) "); + stmt.setInt(1, state.getTid()); + stmt.setString(2, model.getDemandModelType().getName()); + stmt.setString(3, model.getName()); + if(model.getDemandModelType()==DemandModelType.TIMED_IMPULSE) { + stmt.setNull(4, Types.INTEGER); + stmt.setNull(5, Types.DOUBLE); + stmt.setNull(6, Types.DOUBLE); + saveDemands(model); + } else if (model.getDemandModelType()==DemandModelType.RATED) { + stmt.setNull(4, Types.INTEGER); + stmt.setNull(5, Types.DOUBLE); + stmt.setNull(6, Types.DOUBLE); + saveDemands(model); + } else if(model.getDemandModelType()==DemandModelType.SPARING_BY_MASS) { + stmt.setInt(4, ((SparingByMassDemandModel)model).isPartsListEnabled()?1:0); + stmt.setDouble(5, ((SparingByMassDemandModel)model).getUnpressurizedSparesRate()); + stmt.setDouble(6, ((SparingByMassDemandModel)model).getPressurizedSparesRate()); + } + stmt.executeUpdate(); + rs = stmt.executeQuery("SELECT LAST_INSERT_ID() as id"); + if(rs.next()) { + model.setTid(rs.getInt("id")); + } + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /** + * Saves any associated demands from a demand model. Demands that have been + * removed will be deleted from the data source, demands that have been + * changed will be updated, and added demands will be inserted. + * + * @param model the model + * + * @throws SQLException the SQL exception + */ + private void saveDemands(I_DemandModel model) throws SQLException { + PreparedStatement stmt = null; + try { + if(model.getDemandModelType()==DemandModelType.TIMED_IMPULSE) { + // delete unused demands + if(((TimedImpulseDemandModel)model).getDemands().size()>0) { + String demandsList = ""; + for(Demand demand : ((TimedImpulseDemandModel)model).getDemands()) + demandsList += demand.getResource().getTid() + ", "; + demandsList = demandsList.substring(0, demandsList.length()-2); + stmt = connection.prepareStatement("DELETE FROM demands " + + "WHERE model_id = ? " + + "AND resource_id NOT IN (" + demandsList + ")"); + stmt.setInt(1, model.getTid()); + stmt.executeUpdate(); + } + + // update/insert demands + for(Demand demand : ((TimedImpulseDemandModel)model).getDemands()) { + stmt = connection.prepareStatement("UPDATE demands " + + "SET amount=? " + + "WHERE resource_id=? AND model_id=? "); + stmt.setDouble(1, demand.getAmount()); + stmt.setInt(2, demand.getResource().getTid()); + stmt.setInt(3, model.getTid()); + int i = stmt.executeUpdate(); + if(i==0) { + // insert new demand + stmt = connection.prepareStatement("INSERT INTO demands " + + "(resource_id, model_id, amount) " + + "VALUES (?, ?, ?) "); + stmt.setInt(1, demand.getResource().getTid()); + stmt.setInt(2, model.getTid()); + stmt.setDouble(3, demand.getAmount()); + stmt.executeUpdate(); + } + } + } else if(model.getDemandModelType()==DemandModelType.RATED) { + // delete unused demands + if(((RatedDemandModel)model).getDemandRates().size()>0) { + String demandsList = ""; + for(Demand demand : ((RatedDemandModel)model).getDemandRates()) + demandsList += demand.getResource().getTid() + ", "; + demandsList = demandsList.substring(0, demandsList.length()-2); + stmt = connection.prepareStatement("DELETE FROM demands " + + "WHERE model_id = ? " + + "AND resource_id NOT IN (" + demandsList + ")"); + stmt.setInt(1, model.getTid()); + stmt.executeUpdate(); + } + + // update/insert demands + for(Demand demand : ((RatedDemandModel)model).getDemandRates()) { + stmt = connection.prepareStatement("UPDATE demands " + + "SET amount=? " + + "WHERE resource_id=? AND model_id=? "); + stmt.setDouble(1, demand.getAmount()); + stmt.setInt(2, demand.getResource().getTid()); + stmt.setInt(3, model.getTid()); + int i = stmt.executeUpdate(); + if(i==0) { + // insert new demand + stmt = connection.prepareStatement("INSERT INTO demands " + + "(resource_id, model_id, amount) " + + "VALUES (?, ?, ?) "); + stmt.setInt(1, demand.getResource().getTid()); + stmt.setInt(2, model.getTid()); + stmt.setDouble(3, demand.getAmount()); + stmt.executeUpdate(); + } + } + } + } finally { + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#saveNode(edu.mit.spacenet.domain.network.node.Node) + */ + public void saveNode(Node node) throws SQLException { + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("UPDATE nodes " + + "SET type=?, name=?, body_1=?, latitude=?, longitude=?, " + + "apoapsis=?, periapsis=?, inclination=?, body_2=?, " + + "lp_number=?, description=?" + + "WHERE id=?"); + stmt.setString(1, node.getNodeType().getName()); + stmt.setString(2, node.getName()); + stmt.setString(3, node.getBody().getName()); + if(node.getNodeType()==NodeType.SURFACE) { + stmt.setDouble(4, ((SurfaceNode)node).getLatitude()); + stmt.setDouble(5, ((SurfaceNode)node).getLongitude()); + } else { + stmt.setNull(4, Types.DOUBLE); + stmt.setNull(5, Types.DOUBLE); + } + if(node.getNodeType()==NodeType.ORBITAL) { + stmt.setDouble(6, ((OrbitalNode)node).getApoapsis()); + stmt.setDouble(7, ((OrbitalNode)node).getPeriapsis()); + stmt.setDouble(8, ((OrbitalNode)node).getInclination()); + } else { + stmt.setNull(6, Types.DOUBLE); + stmt.setNull(7, Types.DOUBLE); + stmt.setNull(8, Types.DOUBLE); + } + if(node.getNodeType()==NodeType.LAGRANGE) { + stmt.setString(9, ((LagrangeNode)node).getMinorBody().getName()); + stmt.setInt(10, ((LagrangeNode)node).getNumber()); + } else { + stmt.setNull(9, Types.VARCHAR); + stmt.setNull(10, Types.INTEGER); + } + stmt.setString(11, node.getDescription()); + stmt.setInt(12, node.getTid()); + int i = stmt.executeUpdate(); + if(i == 0) { + // insert new node + stmt = connection.prepareStatement("INSERT INTO nodes " + + "(type, name, body_1, latitude, longitude, " + + "apoapsis, periapsis, inclination, body_2, " + + "lp_number, description) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, node.getNodeType().getName()); + stmt.setString(2, node.getName()); + stmt.setString(3, node.getBody().getName()); + if(node.getNodeType()==NodeType.SURFACE) { + stmt.setDouble(4, ((SurfaceNode)node).getLatitude()); + stmt.setDouble(5, ((SurfaceNode)node).getLongitude()); + } else { + stmt.setNull(4, Types.DOUBLE); + stmt.setNull(5, Types.DOUBLE); + } + if(node.getNodeType()==NodeType.ORBITAL) { + stmt.setDouble(6, ((OrbitalNode)node).getApoapsis()); + stmt.setDouble(7, ((OrbitalNode)node).getPeriapsis()); + stmt.setDouble(8, ((OrbitalNode)node).getInclination()); + } else { + stmt.setNull(6, Types.DOUBLE); + stmt.setNull(7, Types.DOUBLE); + stmt.setNull(8, Types.DOUBLE); + } + if(node.getNodeType()==NodeType.LAGRANGE) { + stmt.setString(9, ((LagrangeNode)node).getMinorBody().getName()); + stmt.setInt(10, ((LagrangeNode)node).getNumber()); + } else { + stmt.setNull(9, Types.VARCHAR); + stmt.setNull(10, Types.INTEGER); + } + stmt.setString(11, node.getDescription()); + stmt.executeUpdate(); + stmt = connection.prepareStatement("SELECT LAST_INSERT_ID() AS id"); + rs = stmt.executeQuery(); + if(rs.next()) { + node.setTid(rs.getInt("id")); + getNodeLibrary().add(node); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) {} + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#saveResource(edu.mit.spacenet.domain.resource.I_Resource) + */ + public void saveResource(I_Resource resource) throws SQLException { + createConnection(); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = connection.prepareStatement("UPDATE resources " + + "SET type=?, name=?, cos=?, units=?, unit_mass=?, " + + "unit_volume=?, packing_factor=?, environment=?, " + + "description=? " + + "WHERE id=?"); + stmt.setString(1, resource.getResourceType().getName()); + stmt.setString(2, resource.getName()); + stmt.setInt(3, resource.getClassOfSupply().getId()); + stmt.setString(4, resource.getUnits()); + stmt.setDouble(5, resource.getUnitMass()); + stmt.setDouble(6, resource.getUnitVolume()); + stmt.setDouble(7, resource.getPackingFactor()); + stmt.setString(8, resource.getEnvironment().getName()); + stmt.setString(9, resource.getDescription()); + stmt.setInt(10, resource.getTid()); + int i = stmt.executeUpdate(); + if(i == 0) { + // insert new resource + stmt = connection.prepareStatement("INSERT INTO resources " + + "(type, name, cos, units, unit_mass, unit_volume, " + + "packing_factor, environment, description) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, resource.getResourceType().getName()); + stmt.setString(2, resource.getName()); + stmt.setInt(3, resource.getClassOfSupply().getId()); + stmt.setString(4, resource.getUnits()); + stmt.setDouble(5, resource.getUnitMass()); + stmt.setDouble(6, resource.getUnitVolume()); + stmt.setDouble(7, resource.getPackingFactor()); + stmt.setString(8, resource.getEnvironment().getName()); + stmt.setString(9, resource.getDescription()); + stmt.executeUpdate(); + stmt = connection.prepareStatement("SELECT LAST_INSERT_ID() AS id"); + rs = stmt.executeQuery(); + if(rs.next()) { + resource.setTid(rs.getInt("id")); + getResourceLibrary().add(resource); + } + } + } finally { + if(rs!=null) { + try { + rs.close(); + } catch(SQLException ex) { } + } + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#validateData() + */ + public List validateData() { + // this data source enforces valid data via table structure + return new ArrayList(); + } + + /** + * Creates the connection. + * + * @throws SQLException the SQL exception + */ + public void createConnection() throws SQLException { + if(connection==null) { + if(port==null) { + connection = DriverManager.getConnection("jdbc:mysql://"+host+ + "/"+database+"?user="+user+"&password="+password); + } else { + connection = DriverManager.getConnection("jdbc:mysql://"+host+ + ":"+port+"/"+database+"?user="+user+"&password="+password); + } + } + } + + /** + * Gets the host. + * + * @return the host + */ + public String getHost() { + return host; + } + + /** + * Sets the host. + * + * @param host the new host + */ + public void setHost(String host) { + this.host = host; + } + + /** + * Gets the user. + * + * @return the user + */ + public String getUser() { + return user; + } + + /** + * Sets the user. + * + * @param user the new user + */ + public void setUser(String user) { + this.user = user; + } + + /** + * Gets the password. + * + * @return the password + */ + public String getPassword() { + return password; + } + + /** + * Sets the password. + * + * @param password the new password + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Gets the database. + * + * @return the database + */ + public String getDatabase() { + return database; + } + + /** + * Sets the database. + * + * @param database the new database + */ + public void setDatabase(String database) { + this.database = database; + } + + /** + * Gets the port. + * + * @return the port + */ + public Integer getPort() { + return port; + } + + /** + * Sets the port. + * + * @param port the new port + */ + public void setPort(Integer port) { + this.port = port; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#format() + */ + public void format() throws SQLException { + createConnection(); + PreparedStatement stmt = null; + try { + String query = new String(); + query += "CREATE TABLE IF NOT EXISTS `nodes` (" + + "`id` int(11) NOT NULL auto_increment," + + "`type` enum('Surface','Orbital','Lagrange') NOT NULL," + + "`name` varchar(255) NOT NULL," + + "`body_1` enum('Sun','Earth','Moon','Mars','Phobos','Venus','Jupiter') NOT NULL," + + "`latitude` double default NULL," + + "`longitude` double default NULL," + + "`apoapsis` double default NULL," + + "`periapsis` double default NULL," + + "`inclination` double default NULL," + + "`body_2` enum('Sun','Earth','Moon','Mars','Phobos','Venus','Jupiter') default NULL," + + "`lp_number` int(11) default NULL," + + "`description` varchar(4000) NOT NULL," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + query += "CREATE TABLE IF NOT EXISTS `edges` (" + + "`id` int(11) NOT NULL auto_increment," + + "`type` enum('Space','Surface','Flight') NOT NULL," + + "`name` varchar(255) NOT NULL," + + "`origin_id` int(11) NOT NULL," + + "`destination_id` int(11) NOT NULL," + + "`duration` double default NULL," + + "`distance` double default NULL," + + "`max_crew` int(11) default NULL," + + "`max_cargo` double default NULL," + + "`description` varchar(4000) NOT NULL," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + query += "CREATE TABLE IF NOT EXISTS `burns` (" + + "`id` int(11) NOT NULL auto_increment," + + "`edge_id` int(11) NOT NULL," + + "`time` double NOT NULL," + + "`order` int(11) NOT NULL," + + "`type` enum('OMS','RCS') NOT NULL," + + "`delta_v` double NOT NULL," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + query += "CREATE TABLE IF NOT EXISTS `resources` (" + + "`id` int(11) NOT NULL auto_increment," + + "`type` enum('Continuous','Discrete') NOT NULL," + + "`name` varchar(255) NOT NULL," + + "`cos` int(11) NOT NULL," + + "`units` varchar(255) NOT NULL default 'kg'," + + "`unit_mass` double NOT NULL default '1'," + + "`unit_volume` double NOT NULL default '0.01'," + + "`packing_factor` double NOT NULL default '0'," + + "`environment` enum('Pressurized','Unpressurized') NOT NULL default 'Unpressurized'," + + "`description` varchar(4000) NOT NULL," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + query += "CREATE TABLE IF NOT EXISTS `elements` (" + + "`id` int(11) NOT NULL auto_increment," + + "`type` enum('Element','Crew Member','Resource Container','Carrier','Propulsive Vehicle','Surface Vehicle') NOT NULL default 'Element'," + + "`name` varchar(255) NOT NULL," + + "`cos` int(11) NOT NULL," + + "`environment` enum('Pressurized','Unpressurized') NOT NULL default 'Unpressurized'," + + "`accommodation_mass` double NOT NULL default '0'," + + "`mass` double NOT NULL default '0'," + + "`volume` double NOT NULL default '0'," + + "`max_crew` int(11) default NULL," + + "`cargo_mass` double default NULL," + + "`cargo_volume` double default NULL," + + "`cargo_environment` enum('Pressurized','Unpressurized') default NULL," + + "`active_fraction` double default NULL," + + "`oms_isp` double default NULL," + + "`max_oms` double default NULL," + + "`oms_id` int(11) default NULL," + + "`rcs_isp` double default NULL," + + "`max_rcs` double default NULL," + + "`rcs_id` int(11) default NULL," + + "`max_speed` double default NULL," + + "`max_fuel` double default NULL," + + "`fuel_id` int(11) default NULL," + + "`description` varchar(4000) NOT NULL," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + query += "CREATE TABLE IF NOT EXISTS `parts` (" + + "`id` int(11) NOT NULL auto_increment," + + "`resource_id` int(11) NOT NULL," + + "`element_id` int(11) NOT NULL," + + "`quantity` int(11) NOT NULL default '1'," + + "`duty_cycle` double NOT NULL default '1'," + + "`mttf` double NOT NULL default '0'," + + "`mttr` double NOT NULL default '0'," + + "`repair_mass` double NOT NULL default '0'," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + query += "CREATE TABLE IF NOT EXISTS `states` (" + + "`id` int(11) NOT NULL auto_increment," + + "`element_id` int(11) NOT NULL," + + "`name` varchar(255) NOT NULL," + + "`type` enum('Active','Quiescent','Dormant','Decommissioned') NOT NULL," + + "`initial` tinyint(1) NOT NULL default '0'," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + query += "CREATE TABLE IF NOT EXISTS `models` (" + + "`id` int(11) NOT NULL auto_increment," + + "`type` enum('Rated Demand Model','Timed Impulse Demand Model','Sparing By Mass Demand Model') NOT NULL," + + "`state_id` int(11) NOT NULL," + + "`parts_list` tinyint(1) default NULL," + + "`unpress_rate` double default NULL," + + "`press_rate` double default NULL," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + query += "CREATE TABLE IF NOT EXISTS `demands` (" + + "`id` int(11) NOT NULL auto_increment," + + "`model_id` int(11) default NULL," + + "`container_id` int(11) default NULL," + + "`resource_id` int(11) NOT NULL," + + "`amount` double NOT NULL," + + "PRIMARY KEY (`id`)" + + ") ENGINE=MyISAM DEFAULT CHARSET=latin1;"; + stmt = connection.prepareStatement(""); + stmt.executeUpdate(); + } finally { + if(stmt!=null) { + try { + stmt.close(); + } catch(SQLException ex) {} + } + } + } +} diff --git a/src/main/java/edu/mit/spacenet/data/ElementPreview.java b/src/main/java/edu/mit/spacenet/data/ElementPreview.java new file mode 100644 index 0000000..bc2a102 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/data/ElementPreview.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.data; + +import edu.mit.spacenet.domain.element.ElementIcon; +import edu.mit.spacenet.domain.element.ElementType; + +/** + * A class that displays element properties (name, and type) before the entire + * element is loaded from the data source. + * + * @author Paul Grogan + */ +public class ElementPreview implements Comparable { + + /** The element's type identifier (TID). */ + public final int ID; + + /** The element's name. */ + public final String NAME; + + /** The element's type. */ + public final ElementType TYPE; + + private ElementIcon icon; + + /** The element's class. */ + @Deprecated public final Class CLAZZ; + + /** + * The default constructor sets the preview parameters. + * + * @param id the element id + * @param name the element name + * @param type the element type + */ + public ElementPreview(int id, String name, ElementType type, ElementIcon icon) { + this.ID = id; + this.NAME = name; + this.TYPE = type; + this.icon = icon; + this.CLAZZ = null; + } + + /** + * Gets the icon type. + * + * @return the icon + */ + public ElementIcon getIconType() { + if(icon==null) this.icon = TYPE.getIconType(); + return this.icon; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return NAME + " (" + TYPE.getName() + ")"; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(ElementPreview o) { + return new Integer(ID).compareTo(new Integer(o.ID)); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object object) { + if(object instanceof ElementPreview) { + return ID == ((ElementPreview)object).ID; + } + else return false; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/data/I_DataSource.java b/src/main/java/edu/mit/spacenet/data/I_DataSource.java new file mode 100644 index 0000000..c51b4c1 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/data/I_DataSource.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.data; + +import java.util.Date; +import java.util.List; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.domain.resource.Resource; + +/** + * The data source interface allows for the abstracted loading of libraries and + * elements from a general data source. Nodes, edges, and resources are handled + * by loading and maintaining in memory a library of objects for usage + * in the scenario. Elements are handled differently, where only previews are + * loaded and maintained in memory to save on space -- when an element is used + * in a scenario (during a Create Elements event), the data source is queried to + * build a new element object. + * + * @author Paul Grogan + */ +public interface I_DataSource { + + /** + * Deletes an edge from the data source. Also deletes any associated objects + * (e.g. burns for space edges). + * + * @param tid the primary key (type ID) of the edge to delete + * + * @return true, if successful + * + * @throws Exception the exception + */ + public boolean deleteEdge(int tid) throws Exception; + + /** + * Deletes an element from the data source. Also deletes all associated + * part applications and states. + * + * @param tid the primary key (type ID) of the element to delete + * + * @return true, if successful + * + * @throws Exception the exception + */ + public boolean deleteElement(int tid) throws Exception; + + /** + * Deletes a node from the data source. If node is used in any edges in the + * edge library, this method will fail (return false). + * + * @param tid the primary key (type ID) of the node to delete + * + * @return true, if successful + * + * @throws Exception the exception + */ + public boolean deleteNode(int tid) throws Exception; + + /** + * Deletes a resource from the data source. If resource is used in any + * elements, demand models, or demands, this method will fail (return + * false). + * + * @param tid the primary key (type ID) of the resource to delete + * + * @return true, if successful + * + * @throws Exception the exception + */ + public boolean deleteResource(int tid) throws Exception; + + /** + * Gets the list of resources from the resource library, filtered to only + * include the continuous resources. + * + * @return the list of continuous resources + */ + public List getContinuousResourceLibrary(); + + /** + * Gets the data source type. + * + * @return the data source type + */ + public DataSourceType getDataSourceType(); + + /** + * Gets a list of edges loaded from the data source. + * + * @return the list of edges + */ + public List getEdgeLibrary(); + + /** + * Gets a list of element previews loaded from the data source. + * + * @return the list of element previews + */ + public List getElementPreviewLibrary(); + + /** + * Gets the list of resources from the resource library, filtered to only + * include the discrete resources. + * + * @return the list of discrete resources + */ + public List getItemLibrary(); + + /** + * Gets the date that the data source was last loaded. + * + * @return the last load date + */ + public Date getLastLoadDate(); + + /** + * Gets the name of the data source. + * + * @return the data source name + */ + public String getName(); + + /** + * Gets a list of nodes loaded from the data source. + * + * @return the list of nodes + */ + public List getNodeLibrary(); + + /** + * Gets a list of resources loaded from the data source. + * + * @return the list of resources + */ + public List getResourceLibrary(); + + /** + * Load edge from the edge library by its primary key (type ID). + * + * @param tid the primary key (type ID) + * + * @return the edge + */ + public Edge loadEdge(int tid); + + /** + * Loads (reloads) the edge library. + */ + public void loadEdgeLibrary() throws Exception; + + /** + * Loads an element from the data source by its primary key (type ID). + * + * @param tid the primary key (type ID) + * + * @return the element + */ + public I_Element loadElement(int tid) throws Exception; + + /** + * Loads (reloads) the element library. + */ + public void loadElementLibrary() throws Exception; + + /** + * Loads an element preview by its primary key (type ID). + * + * @param tid the primary key (type ID) + * + * @return the element preview + */ + public ElementPreview loadElementPreview(int tid); + + /** + * Loads (reloads) the libraries (nodes, edges, resources, elements). + */ + public void loadLibraries() throws Exception; + + /** + * Loads (reloads) the libraries with an option to only load certain tables. + * + * @param loadNodes update the nodes table + * @param loadEdges update the edges table + * @param loadResources update the resources table + */ + public void loadLibraries(boolean updateNodes, boolean updateEdges, + boolean updateResources) throws Exception; + + /** + * Loads a node from the node library by its primary key (type ID). + * + * @param tid the primary key (type ID) + * + * @return the node + */ + public Node loadNode(int tid); + + /** + * Loads (reloads) the node library. + */ + public void loadNodeLibrary() throws Exception; + + /** + * Loads a resource from the resource library by its primary key (type ID) + * + * @param tid the primary key (type ID) + * + * @return the resource + */ + public I_Resource loadResource(int tid); + + /** + * Load resource library. + */ + public void loadResourceLibrary() throws Exception; + + /** + * Prints the data source to console. + */ + public void print(); + + /** + * Save an edge to the data source and updates the edge library accordingly. + * Updates existing entry if modified or inserts a new entry (assigning + * a new primary key) if created. Also saves any associated objects (e.g. + * burns for a space edge). + * + * @param edge the edge + */ + public void saveEdge(Edge edge) throws Exception; + + /** + * Saves an element to the data source and updates the element preview + * library accordingly. Updates existing entry if modified or inserts a new + * entry (assigning a new primary key) if created. Also saves all associated + * part applications and states. + * + * @param element the element + */ + public void saveElement(I_Element element) throws Exception; + + /** + * Saves a node to the data source and updates the node library accordingly. + * Updates existing entry if modified or inserts a new entry (assigning + * a new primary key) if created. + * + * @param node the node + */ + public void saveNode(Node node) throws Exception; + + /** + * Saves a resource to the data source and updates the resource library + * accordingly. Updates existing entry if modified or inserts a new entry + * (assigning a new primary key) if created. + * + * @param resource the resource + * + * @throws Exception the exception + */ + public void saveResource(I_Resource resource) throws Exception; + + /** + * Runs a validation script on the data source, checking for any parse + * errors. + * + * @return a list of error messages + */ + public List validateData() throws Exception; + + /** + * Formats the data source to accept data. + * + * @throws Exception the exception + */ + public void format() throws Exception; +} diff --git a/src/main/java/edu/mit/spacenet/data/I_SavedDataSource.java b/src/main/java/edu/mit/spacenet/data/I_SavedDataSource.java new file mode 100644 index 0000000..9cbdf21 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/data/I_SavedDataSource.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.data; + + +/** + * Interface for saving data source information for later use. + */ +public interface I_SavedDataSource { + + /** + * Gets the data source type. + * + * @return the data source type + */ + public abstract DataSourceType getDataSourceType(); +} diff --git a/src/main/java/edu/mit/spacenet/data/SavedOnlineDataSource.java b/src/main/java/edu/mit/spacenet/data/SavedOnlineDataSource.java new file mode 100644 index 0000000..f0192a2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/data/SavedOnlineDataSource.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.data; + + +/** + * Saves a database connection for later use. + */ +public class SavedOnlineDataSource implements I_SavedDataSource { + private String host, user, password, database; + private Integer port; + private boolean passwordSaved; + + /** + * Instantiates a new saved database connection. + */ + public SavedOnlineDataSource() { } + + /** + * Instantiates a new saved database connection. + * + * @param host the host + * @param port the port + * @param database the database + * @param user the user + * @param password the password + */ + public SavedOnlineDataSource(String host, Integer port, String database, + String user, String password) { + this.host = host; + this.port = port; + this.database = database; + this.user = user; + if(passwordSaved) this.password = password; + } + + /** + * Instantiates a new saved database connection. + * + * @param host the host + * @param database the database + * @param user the user + * @param password the password + */ + public SavedOnlineDataSource(String host, String database, String user, + String password) { + this(host, null, database, user, password); + } + + /** + * Gets the host. + * + * @return the host + */ + public String getHost() { + return host; + } + + /** + * Sets the host. + * + * @param host the new host + */ + public void setHost(String host) { + this.host = host; + } + + /** + * Gets the user. + * + * @return the user + */ + public String getUser() { + return user; + } + + /** + * Sets the user. + * + * @param user the new user + */ + public void setUser(String user) { + this.user = user; + } + + /** + * Gets the password. + * + * @return the password + */ + public String getPassword() { + return password; + } + + /** + * Sets the password. + * + * @param password the new password + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Gets the database. + * + * @return the database + */ + public String getDatabase() { + return database; + } + + /** + * Sets the database. + * + * @param database the new database + */ + public void setDatabase(String database) { + this.database = database; + } + + /** + * Gets the port. + * + * @return the port + */ + public Integer getPort() { + return port; + } + + /** + * Sets the port. + * + * @param port the new port + */ + public void setPort(Integer port) { + this.port = port; + } + + /** + * Checks if is password saved. + * + * @return true, if is password saved + */ + public boolean isPasswordSaved() { + return passwordSaved; + } + + /** + * Sets the password saved. If password is changed from saved to not saved, + * any existing password is removed. + * + * @param passwordSaved the new password saved + */ + public void setPasswordSaved(boolean passwordSaved) { + this.passwordSaved = passwordSaved; + if(!passwordSaved) setPassword(null); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.I_SavedDataSource#getDataSourceType() + */ + public DataSourceType getDataSourceType() { + return DataSourceType.SQL_DB; + } +} diff --git a/src/main/java/edu/mit/spacenet/data/SavedSpreadsheetDataSource.java b/src/main/java/edu/mit/spacenet/data/SavedSpreadsheetDataSource.java new file mode 100644 index 0000000..33a8fcf --- /dev/null +++ b/src/main/java/edu/mit/spacenet/data/SavedSpreadsheetDataSource.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.data; + + +/** + * Saves a spreadsheet location for future use. + */ +public class SavedSpreadsheetDataSource implements I_SavedDataSource { + private String filePath; + + /** + * Instantiates a new saved spreadsheet data source. + */ + public SavedSpreadsheetDataSource() { } + + /** + * Instantiates a new saved spreadsheet data source. + * + * @param filePath the file path + */ + public SavedSpreadsheetDataSource(String filePath) { + this.filePath = filePath; + } + + /** + * Gets the file path. + * + * @return the file path + */ + public String getFilePath() { + return filePath; + } + + /** + * Sets the file path. + * + * @param filePath the new file path + */ + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.I_SavedDataSource#getDataSourceType() + */ + public DataSourceType getDataSourceType() { + return DataSourceType.EXCEL_2_5; + } +} diff --git a/src/main/java/edu/mit/spacenet/data/Spreadsheet_2_5.java b/src/main/java/edu/mit/spacenet/data/Spreadsheet_2_5.java new file mode 100644 index 0000000..d8ff50f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/data/Spreadsheet_2_5.java @@ -0,0 +1,2365 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.data; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.element.Carrier; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.Element; +import edu.mit.spacenet.domain.element.ElementIcon; +import edu.mit.spacenet.domain.element.ElementType; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.element.ResourceContainer; +import edu.mit.spacenet.domain.element.State; +import edu.mit.spacenet.domain.element.StateType; +import edu.mit.spacenet.domain.element.SurfaceVehicle; +import edu.mit.spacenet.domain.model.DemandModelType; +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.domain.model.RatedDemandModel; +import edu.mit.spacenet.domain.model.SparingByMassDemandModel; +import edu.mit.spacenet.domain.model.TimedImpulseDemandModel; +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.domain.network.edge.BurnType; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.EdgeType; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.LagrangeNode; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.NodeType; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.domain.resource.Resource; +import edu.mit.spacenet.domain.resource.ResourceType; + +/** + * A spreadsheet format compatible with the features introduced in SpaceNet 2.5. + * + * Assumes the filepath points to a spreadsheet in Excel (.xls) format with the + * following sheets: Nodes, Edges, Burns, Resources, Elements, Parts, States, + * Models, Demands. + * + * @author Paul Grogan + */ +public class Spreadsheet_2_5 extends AbstractDataSource { + private static final int BURN_ID = 0, BURN_EDGE_ID = 1, BURN_TIME = 2, + BURN_ORDER = 3, BURN_TYPE = 4, BURN_DELTA_V = 5; + private static final int DEMAND_ID = 0, DEMAND_MODEL_ID = 1, + DEMAND_RESOURCE_ID = 2, DEMAND_AMOUNT = 3, DEMAND_CONTAINER_ID = 4; + private static final int EDGE_ID = 0, EDGE_TYPE = 1, EDGE_NAME = 2, + EDGE_ORIGIN_ID = 3, EDGE_DESTINATION_ID = 4, EDGE_DURATION = 5, + EDGE_DISTANCE = 6, EDGE_MAX_CREW = 7, EDGE_MAX_CARGO = 8, + EDGE_DESCRIPTION = 9; + private static final int ELEMENT_ID = 0, ELEMENT_TYPE = 1, + ELEMENT_NAME = 2, ELEMENT_COS = 3, ELEMENT_ENVIRONMENT = 4, + ELEMENT_ACCOMMODATION_MASS = 5, ELEMENT_MASS = 6, + ELEMENT_VOLUME = 7, ELEMENT_MAX_CREW = 8, ELEMENT_CARGO_MASS = 9, + ELEMENT_CARGO_VOLUME = 10, ELEMENT_CARGO_ENVIRONMENT = 11, + ELEMENT_ACTIVE_FRACTION = 12, ELEMENT_OMS_ISP = 13, + ELEMENT_MAX_OMS = 14, ELEMENT_OMS_ID = 15, ELEMENT_RCS_ISP = 16, + ELEMENT_MAX_RCS = 17, ELEMENT_RCS_ID = 18, ELEMENT_MAX_SPEED = 19, + ELEMENT_MAX_FUEL = 20, ELEMENT_FUEL_ID = 21, + ELEMENT_DESCRIPTION = 22, ELEMENT_ICON=23; + private static final int MODEL_ID = 0, MODEL_TYPE = 1, MODEL_STATE_ID = 2, + MODEL_NAME = 3, MODEL_PARTS_LIST = 4, MODEL_UNPRESS_RATE = 5, + MODEL_PRESS_RATE = 6; + private static final int NODE_ID = 0, NODE_TYPE = 1, NODE_NAME = 2, + NODE_BODY_1 = 3, NODE_LATITUDE = 4, NODE_LONGITUDE = 5, + NODE_APOAPSIS = 6, NODE_PERIAPSIS = 7, NODE_INCLINATION = 8, + NODE_BODY_2 = 9, NODE_LP_NUMBER = 10, NODE_DESCRIPTION = 11; + private static final int NODE_SHEET = 0, EDGE_SHEET = 1, BURN_SHEET = 2, + RESOURCE_SHEET = 3, ELEMENT_SHEET = 4, PART_SHEET = 5, + STATE_SHEET = 6, MODEL_SHEET = 7, DEMAND_SHEET = 8; + private static final int PART_ID = 0, PART_RESOURCE_ID = 1, + PART_ELEMENT_ID = 2, PART_QUANTITY = 3, PART_DUTY_CYCLE = 4, + PART_MTTF = 5, PART_MTTR = 6, PART_REPAIR_MASS = 7; + private static final int RESOURCE_ID = 0, RESOURCE_TYPE = 1, + RESOURCE_NAME = 2, RESOURCE_COS = 3, RESOURCE_UNITS = 4, + RESOURCE_UNIT_MASS = 5, RESOURCE_UNIT_VOLUME = 6, + RESOURCE_PACKING_FACTOR = 7, RESOURCE_ENVIRONMENT = 8, + RESOURCE_DESCRIPTION = 9; + private static final int STATE_ID = 0, STATE_ELEMENT_ID = 1, + STATE_NAME = 2, STATE_TYPE = 3, STATE_INITIAL = 4; + + private String filePath; + + /** + * Instantiates a new data source with the passed file path. + * + * @param filePath the file path + */ + public Spreadsheet_2_5(String filePath) { + this.filePath = filePath; + } + + /** + * Instantiates a new data source. Does not initialize the file path. + */ + public Spreadsheet_2_5() { } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#deleteEdge(int) + */ + public boolean deleteEdge(int tid) throws IOException { + if (edgeLibrary.remove(loadEdge(tid))) { + Workbook wb = readWorkbook(); + int rowNum = -1; + for (Row row : wb.getSheetAt(EDGE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(EDGE_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + + if (rowNum > 0) { + List burnsToDelete = new ArrayList(); + for (Row row : wb.getSheetAt(BURN_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(BURN_EDGE_ID).getNumericCellValue() == tid) { + burnsToDelete.add((int) row.getCell(BURN_ID) + .getNumericCellValue()); + } + } + for (Integer burnId : burnsToDelete) + deleteBurn(wb, burnId); + deleteRow(wb.getSheetAt(EDGE_SHEET), rowNum); + System.out.println("Edge #" + tid + " deleted"); + writeWorkbook(wb); + return true; + } else { + System.out.println("Edge #" + tid + " not found in database"); + return false; // edge not found + } + } else { + System.out.println("Edge #" + tid + " not found in library"); + return false; // edge does not exist + } + } + + /** + * Deletes a burn from a workbook. + * + * @param wb the workbook + * @param tid the type ID of the part to delete + * + * @return true, if successful + */ + private boolean deleteBurn(Workbook wb, int tid) { + int rowNum = -1; + for (Row row : wb.getSheetAt(BURN_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(BURN_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + if (rowNum > 0) { + deleteRow(wb.getSheetAt(BURN_SHEET), rowNum); + System.out.println("Burn #" + tid + " deleted"); + return true; + } else { + System.out.println("Burn #" + tid + " not found in database"); + return false; // burn not found + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#deleteElement(int) + */ + public boolean deleteElement(int tid) throws IOException { + if (elementPreviewLibrary.remove(loadElementPreview(tid))) { + Workbook wb = readWorkbook(); + int rowNum = -1; + for (Row row : wb.getSheetAt(ELEMENT_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(EDGE_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + if (rowNum > 0) { + List demandsToDelete = new ArrayList(); + for (Row row : wb.getSheetAt(DEMAND_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_CONTAINER_ID).getCellType() == Cell.CELL_TYPE_NUMERIC + && row.getCell(DEMAND_CONTAINER_ID) + .getNumericCellValue() == tid) { + demandsToDelete.add((int) row.getCell(DEMAND_ID).getNumericCellValue()); + } + } + for (Integer demandId : demandsToDelete) + deleteDemand(wb, demandId); + + List partsToDelete = new ArrayList(); + for (Row row : wb.getSheetAt(PART_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(PART_ELEMENT_ID).getNumericCellValue() == tid) { + partsToDelete.add((int) row.getCell(PART_ID).getNumericCellValue()); + } + } + for (Integer partId : partsToDelete) + deletePart(wb, partId); + + List statesToDelete = new ArrayList(); + for (Row row : wb.getSheetAt(STATE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(STATE_ELEMENT_ID).getNumericCellValue() == tid) { + statesToDelete.add((int) row.getCell(STATE_ID).getNumericCellValue()); + } + } + for (Integer stateId : statesToDelete) + deleteState(wb, stateId); + deleteRow(wb.getSheetAt(ELEMENT_SHEET), rowNum); + System.out.println("Element #" + tid + " deleted"); + writeWorkbook(wb); + return true; + } else { + System.out.println("Element #" + tid + " not found in database"); + return false; // element not found + } + } else { + System.out.println("Element #" + tid + " not found in library"); + return false; // element does not exist + } + } + + /** + * Deletes a part from a workbook. Note: part objects do not have a primary + * key so the type ID parameter must be determined internally to the data + * source. + * + * @param wb the workbook + * @param tid the type ID of the part to delete + * + * @return true, if successful + */ + private boolean deletePart(Workbook wb, int tid) { + int rowNum = -1; + for (Row row : wb.getSheetAt(PART_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(PART_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + if (rowNum > 0) { + deleteRow(wb.getSheetAt(PART_SHEET), rowNum); + System.out.println("Part #" + tid + " deleted"); + return true; + } else { + System.out.println("Part #" + tid + " not found in database"); + return false; // part not found + } + } + + /** + * Deletes a state from a workbook. Also deletes any associated demand + * models. + * + * @param wb the workbook + * @param tid the type ID of the state to delete + * + * @return true, if successful + */ + private boolean deleteState(Workbook wb, int tid) { + int rowNum = -1; + for (Row row : wb.getSheetAt(STATE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(STATE_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + if (rowNum > 0) { + List modelsToDelete = new ArrayList(); + for (Row row : wb.getSheetAt(MODEL_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(MODEL_STATE_ID).getNumericCellValue() == tid) { + modelsToDelete.add((int) row.getCell(MODEL_ID) + .getNumericCellValue()); + } + } + for (Integer modelId : modelsToDelete) + deleteModel(wb, modelId); + deleteRow(wb.getSheetAt(STATE_SHEET), rowNum); + System.out.println("State #" + tid + " deleted"); + return true; + } else { + System.out.println("State #" + tid + " not found in database"); + return false; // state not found + } + } + + /** + * Deletes a demand model from a workbook. Also deletes any associated + * demands. Note: demand objects do not have a primary key so the type ID + * parameter must be determined internally to the data source. + * + * @param wb the workbook + * @param tid the type ID of the demand model to delete + * + * @return true, if successful + */ + private boolean deleteModel(Workbook wb, int tid) { + int rowNum = -1; + for (Row row : wb.getSheetAt(MODEL_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(MODEL_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + if (rowNum > 0) { + List demandsToDelete = new ArrayList(); + for (Row row : wb.getSheetAt(DEMAND_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_MODEL_ID).getCellType() == Cell.CELL_TYPE_NUMERIC + && row.getCell(DEMAND_MODEL_ID).getNumericCellValue() == tid) { + demandsToDelete.add((int) row.getCell(DEMAND_ID) + .getNumericCellValue()); + } + } + for (Integer demandId : demandsToDelete) + deleteDemand(wb, demandId); + deleteRow(wb.getSheetAt(MODEL_SHEET), rowNum); + System.out.println("Model #" + tid + " deleted"); + return true; + } else { + System.out.println("Model #" + tid + " not found in database"); + return false; // model not found + } + } + + /** + * Deletes a demand. + * + * @param wb the workbook + * @param tid the type ID of the demand to delete + * + * @return true, if successful + */ + private boolean deleteDemand(Workbook wb, int tid) { + int rowNum = -1; + for (Row row : wb.getSheetAt(DEMAND_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + if (rowNum > 0) { + deleteRow(wb.getSheetAt(DEMAND_SHEET), rowNum); + System.out.println("Demand #" + tid + " deleted"); + return true; + } else { + System.out.println("Demand #" + tid + " not found in database"); + return false; // demand not found + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#deleteNode(int) + */ + public boolean deleteNode(int tid) throws IOException { + Workbook wb = readWorkbook(); + for (Row row : wb.getSheetAt(EDGE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(EDGE_ORIGIN_ID).getNumericCellValue() == tid + || row.getCell(EDGE_DESTINATION_ID).getNumericCellValue() == tid) { + System.out.println("Node #" + tid + " is used in edges"); + return false; // node is used as edge origin or destination + } + } + if (nodeLibrary.remove(loadNode(tid))) { + int rowNum = -1; + for (Row row : wb.getSheetAt(NODE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(NODE_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + if (rowNum > 0) { + deleteRow(wb.getSheetAt(NODE_SHEET), rowNum); + System.out.println("Node #" + tid + " deleted"); + writeWorkbook(wb); + return true; + } else { + System.out.println("Node #" + tid + " not found in database"); + return false; // node not found + } + } else { + System.out.println("Node #" + tid + " not found in library"); + return false; // node does not exist + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#deleteResource(int) + */ + public boolean deleteResource(int tid) throws IOException { + Workbook wb = readWorkbook(); + for (Row row : wb.getSheetAt(ELEMENT_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if ((row.getCell(ELEMENT_OMS_ID).getCellType() == Cell.CELL_TYPE_NUMERIC && row + .getCell(ELEMENT_OMS_ID).getNumericCellValue() == tid) + || (row.getCell(ELEMENT_RCS_ID).getCellType() == Cell.CELL_TYPE_NUMERIC && row + .getCell(ELEMENT_RCS_ID).getNumericCellValue() == tid) + || (row.getCell(ELEMENT_FUEL_ID).getCellType() != Cell.CELL_TYPE_NUMERIC && row + .getCell(ELEMENT_FUEL_ID).getNumericCellValue() == tid)) { + System.out.println("Resource #" + tid + " is used in elements"); + return false; // resource is used in elements + } + } + for (Row row : wb.getSheetAt(PART_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(PART_RESOURCE_ID).getCellType() == Cell.CELL_TYPE_NUMERIC + && row.getCell(PART_RESOURCE_ID).getNumericCellValue() == tid) { + System.out.println("Resource #" + tid + + " is used in applications"); + return false; // resource is used in part applications + } + } + for (Row row : wb.getSheetAt(DEMAND_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_RESOURCE_ID).getCellType() == Cell.CELL_TYPE_NUMERIC + && row.getCell(DEMAND_RESOURCE_ID).getNumericCellValue() == tid) { + System.out.println("Resource #" + tid + " is used in demands"); + return false; // resource is used in demands + } + } + if (resourceTypeLibrary.remove(loadResource(tid))) { + int rowNum = -1; + for (Row row : wb.getSheetAt(RESOURCE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(RESOURCE_ID).getNumericCellValue() == tid) { + rowNum = row.getRowNum(); + break; + } + } + if (rowNum > 0) { + deleteRow(wb.getSheetAt(RESOURCE_SHEET), rowNum); + System.out.println("Resource #" + tid + " deleted"); + writeWorkbook(wb); + return true; + } else { + System.out.println("Resource #" + tid + + " not found in database"); + return false; // resource not found + } + } else { + System.out.println("Resource #" + tid + " not found in library"); + return false; // resource does not exist + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#getDataSourceType() + */ + public DataSourceType getDataSourceType() { + return DataSourceType.EXCEL_2_5; + } + + /** + * Gets the file path. + * + * @return the file path + */ + public String getFilePath() { + return filePath; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#getName() + */ + public String getName() { + if (filePath == null || filePath.length() == 0) + return getDataSourceType().getName(); + int lastIndex = Math.max(filePath.lastIndexOf("/"), filePath + .lastIndexOf("\\")); + return filePath.substring(lastIndex + 1, filePath.length()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadEdgeLibrary() + */ + public void loadEdgeLibrary() throws IOException { + loadEdgeLibrary(readWorkbook()); + } + + /** + * Load edge library from a workbook + * + * @param wb the workbook + */ + private void loadEdgeLibrary(Workbook wb) { + Map libraryContents = new HashMap(); + for(Edge edge : getEdgeLibrary()) { + // mark all edges as unfound + libraryContents.put(edge.getTid(), false); + } + for (Row row : wb.getSheetAt(EDGE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + try { + Edge e = loadEdge((int) row.getCell(EDGE_ID).getNumericCellValue()); + String edgeType = row.getCell(EDGE_TYPE).getStringCellValue().toLowerCase(); + if (e == null|| !e.getEdgeType().getName().toLowerCase().contains(edgeType)) { + edgeLibrary.remove(e); + if(e != null) libraryContents.remove(e.getTid()); + // create new edge and add to library + if (EdgeType.SURFACE.getName().toLowerCase().contains(edgeType)) { + e = new SurfaceEdge(); + } else if (EdgeType.SPACE.getName().toLowerCase().contains(edgeType)) { + e = new SpaceEdge(); + } else if (EdgeType.FLIGHT.getName().toLowerCase().contains(edgeType)) { + e = new FlightEdge(); + } else { + throw new Exception("Unknown Edge Type"); + } + edgeLibrary.add(e); + } else { + // mark edge as found + libraryContents.put(e.getTid(), true); + } + e.setTid((int) row.getCell(EDGE_ID).getNumericCellValue()); + e.setName(row.getCell(EDGE_NAME).getStringCellValue()); + e.setOrigin(loadNode((int) row.getCell(EDGE_ORIGIN_ID).getNumericCellValue())); + e.setDestination(loadNode((int) row.getCell(EDGE_DESTINATION_ID).getNumericCellValue())); + e.setDescription(row.getCell(EDGE_DESCRIPTION).toString()); + if (EdgeType.SURFACE.getName().toLowerCase().contains(edgeType)) { + ((SurfaceEdge) e).setDistance(row.getCell(EDGE_DISTANCE).getNumericCellValue()); + } else if (EdgeType.SPACE.getName().toLowerCase().contains(edgeType)) { + ((SpaceEdge) e).setDuration(row.getCell(EDGE_DURATION).getNumericCellValue()); + loadBurns(wb, (SpaceEdge) e); + } else if (EdgeType.FLIGHT.getName().toLowerCase().contains(edgeType)) { + ((FlightEdge) e).setDuration(row.getCell(EDGE_DURATION).getNumericCellValue()); + ((FlightEdge) e).setMaxCrewSize((int) row.getCell(EDGE_MAX_CREW).getNumericCellValue()); + ((FlightEdge) e).setMaxCargoMass(row.getCell(EDGE_MAX_CARGO).getNumericCellValue()); + } else { + throw new Exception("Unknown Edge Type"); + } + } catch (Exception ex) { + // error loading edge + ex.printStackTrace(); + } + } + for(Integer i : libraryContents.keySet()) { + if(!libraryContents.get(i)) { + // remove all unfound edges + getEdgeLibrary().remove(loadEdge(i)); + } + } + } + + /** + * Load burns for a specific space edge. + * + * @param wb the workbook + * @param edge the space edge + */ + private void loadBurns(Workbook wb, SpaceEdge edge) { + edge.getBurns().clear(); + for (Row row : wb.getSheetAt(BURN_SHEET)) { + try { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(BURN_EDGE_ID).getNumericCellValue() == edge.getTid()) { + Burn b = new Burn(); + b.setTid((int) row.getCell(BURN_ID).getNumericCellValue()); + b.setTime(row.getCell(BURN_TIME).getNumericCellValue()); + b.setBurnType(BurnType.getInstance(row.getCell(BURN_TYPE).getStringCellValue())); + b.setDeltaV(row.getCell(BURN_DELTA_V).getNumericCellValue()); + //TODO problems if burns are "out of order" in database... make sure this gets + // fixed for the online database + while(edge.getBurns().size()<=(int)row.getCell(BURN_ORDER).getNumericCellValue()) + edge.getBurns().add(new Burn()); + edge.getBurns().set((int)row.getCell(BURN_ORDER).getNumericCellValue(), b); + } + } catch (Exception ex) { + // error loading burn + ex.printStackTrace(); + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadElement(int) + */ + public I_Element loadElement(int tid) throws IOException { + Workbook wb = readWorkbook(); + for (Row row : wb.getSheetAt(ELEMENT_SHEET)) { + try { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(ELEMENT_ID).getNumericCellValue() == tid) { + I_Element e = null; + String elementType = row.getCell(ELEMENT_TYPE).getStringCellValue().toLowerCase(); + if (ElementType.ELEMENT.getName().toLowerCase().contains(elementType)) { + e = new Element(); + } else if (ElementType.RESOURCE_CONTAINER.getName().toLowerCase().contains(elementType)) { + e = new ResourceContainer(); + ((ResourceContainer) e).setMaxCargoMass(row.getCell(ELEMENT_CARGO_MASS).getNumericCellValue()); + ((ResourceContainer) e).setMaxCargoVolume(row.getCell(ELEMENT_CARGO_VOLUME).getNumericCellValue()); + ((ResourceContainer) e).setCargoEnvironment(Environment.getInstance(row.getCell(ELEMENT_CARGO_ENVIRONMENT).getStringCellValue())); + } else if (ElementType.CREW_MEMBER.getName().toLowerCase().contains(elementType)) { + e = new CrewMember(); + ((CrewMember) e).setAvailableTimeFraction(row.getCell(ELEMENT_ACTIVE_FRACTION).getNumericCellValue()); + } else if (ElementType.CARRIER.getName().toLowerCase().contains(elementType)) { + e = new Carrier(); + ((Carrier) e).setMaxCrewSize((int) row.getCell(ELEMENT_MAX_CREW).getNumericCellValue()); + ((Carrier) e).setMaxCargoMass(row.getCell(ELEMENT_CARGO_MASS).getNumericCellValue()); + ((Carrier) e).setMaxCargoVolume(row.getCell(ELEMENT_CARGO_VOLUME).getNumericCellValue()); + ((Carrier) e).setCargoEnvironment(Environment.getInstance(row.getCell(ELEMENT_CARGO_ENVIRONMENT).getStringCellValue())); + } else if (ElementType.SURFACE_VEHICLE.getName().toLowerCase().contains(elementType)) { + e = new SurfaceVehicle(); + ((SurfaceVehicle) e).setMaxCrewSize((int) row.getCell(ELEMENT_MAX_CREW).getNumericCellValue()); + ((SurfaceVehicle) e).setMaxCargoMass(row.getCell(ELEMENT_CARGO_MASS).getNumericCellValue()); + ((SurfaceVehicle) e).setMaxCargoVolume(row.getCell(ELEMENT_CARGO_VOLUME).getNumericCellValue()); + ((SurfaceVehicle) e).setCargoEnvironment(Environment.getInstance(row.getCell(ELEMENT_CARGO_ENVIRONMENT).getStringCellValue())); + ((SurfaceVehicle) e).setMaxSpeed(row.getCell(ELEMENT_MAX_SPEED).getNumericCellValue()); + ((SurfaceVehicle) e).getFuelTank().setMaxAmount(row.getCell(ELEMENT_MAX_FUEL).getNumericCellValue()); + ((SurfaceVehicle) e).getFuelTank().setAmount(row.getCell(ELEMENT_MAX_FUEL).getNumericCellValue()); + ((SurfaceVehicle) e).getFuelTank().setResource(loadResource((int) row.getCell(ELEMENT_FUEL_ID).getNumericCellValue())); + } else if (ElementType.PROPULSIVE_VEHICLE.getName().toLowerCase().contains(elementType)) { + e = new PropulsiveVehicle(); + ((PropulsiveVehicle) e).setMaxCrewSize((int) row.getCell(ELEMENT_MAX_CREW).getNumericCellValue()); + ((PropulsiveVehicle) e).setMaxCargoMass(row.getCell(ELEMENT_CARGO_MASS).getNumericCellValue()); + ((PropulsiveVehicle) e).setMaxCargoVolume(row.getCell(ELEMENT_CARGO_VOLUME).getNumericCellValue()); + ((PropulsiveVehicle) e).setCargoEnvironment(Environment.getInstance(row.getCell(ELEMENT_CARGO_ENVIRONMENT).getStringCellValue())); + ((PropulsiveVehicle) e).setOmsIsp(row.getCell(ELEMENT_OMS_ISP).getNumericCellValue()); + ((PropulsiveVehicle) e).setRcsIsp(row.getCell(ELEMENT_RCS_ISP).getNumericCellValue()); + if (((PropulsiveVehicle) e).getOmsIsp() > 0) { + ((PropulsiveVehicle) e).getOmsFuelTank().setMaxAmount(row.getCell(ELEMENT_MAX_OMS).getNumericCellValue()); + ((PropulsiveVehicle) e).getOmsFuelTank().setAmount(row.getCell(ELEMENT_MAX_OMS).getNumericCellValue()); + ((PropulsiveVehicle) e).getOmsFuelTank().setResource(loadResource((int) row.getCell(ELEMENT_OMS_ID).getNumericCellValue())); + } else { + ((PropulsiveVehicle) e).setOmsFuelTank(null); + } + if (((PropulsiveVehicle) e).getRcsIsp() > 0 + && row.getCell(ELEMENT_MAX_RCS).getNumericCellValue() > 0) { + ((PropulsiveVehicle) e).getRcsFuelTank().setMaxAmount(row.getCell(ELEMENT_MAX_RCS).getNumericCellValue()); + ((PropulsiveVehicle) e).getRcsFuelTank().setAmount(row.getCell(ELEMENT_MAX_RCS).getNumericCellValue()); + ((PropulsiveVehicle) e).getRcsFuelTank().setResource(loadResource((int) row.getCell(ELEMENT_RCS_ID).getNumericCellValue())); + } else if (((PropulsiveVehicle) e).getRcsIsp() > 0) { + ((PropulsiveVehicle) e).getContents().remove(((PropulsiveVehicle) e).getRcsFuelTank()); + ((PropulsiveVehicle) e).setRcsFuelTank(((PropulsiveVehicle) e).getOmsFuelTank()); + } else { + ((PropulsiveVehicle) e).setRcsFuelTank(null); + } + } else { + throw new Exception("Unknown Element Type"); + } + e.setTid((int) row.getCell(ELEMENT_ID).getNumericCellValue()); + e.setName(row.getCell(ELEMENT_NAME).getStringCellValue()); + e.setClassOfSupply(ClassOfSupply.getInstance((int) row.getCell(ELEMENT_COS).getNumericCellValue())); + e.setEnvironment(Environment.getInstance(row.getCell(ELEMENT_ENVIRONMENT).getStringCellValue())); + e.setAccommodationMass(row.getCell(ELEMENT_ACCOMMODATION_MASS).getNumericCellValue()); + e.setMass(row.getCell(ELEMENT_MASS).getNumericCellValue()); + e.setVolume(row.getCell(ELEMENT_VOLUME).getNumericCellValue()); + e.setDescription(row.getCell(ELEMENT_DESCRIPTION).toString()); + if(ElementIcon.getInstance(row.getCell(ELEMENT_ICON).toString())!=null) { + e.setIconType(ElementIcon.getInstance(row.getCell(ELEMENT_ICON).toString())); + } + if (e.getElementType() == ElementType.RESOURCE_CONTAINER) { + ((I_ResourceContainer)e).getContents().clear(); + for (Row r : wb.getSheetAt(DEMAND_SHEET)) { + if (r.getRowNum() == 0 || isRowEmpty(r)) + continue; + if (r.getCell(DEMAND_CONTAINER_ID).getNumericCellValue() == e.getTid()) { + ((ResourceContainer) e).getContents().put(loadResource((int) r.getCell(DEMAND_RESOURCE_ID).getNumericCellValue()), + r.getCell(DEMAND_AMOUNT).getNumericCellValue()); + } + } + } + loadParts(wb, e); + loadStates(wb, e); + return e; + } + } catch (Exception ex) { + // error reading element + ex.printStackTrace(); + } + } + return null; + } + + /** + * Load the parts for a specific element. + * + * @param wb the workbook + * @param element the element + */ + private void loadParts(Workbook wb, I_Element element) { + element.getParts().clear(); + for (Row row : wb.getSheetAt(PART_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + try { + if (row.getCell(PART_ELEMENT_ID).getNumericCellValue() == element.getTid()) { + PartApplication partApp = new PartApplication(); + partApp.setTid((int)row.getCell(PART_ID).getNumericCellValue()); + partApp.setPart((Item)loadResource((int) row.getCell(PART_RESOURCE_ID).getNumericCellValue())); + partApp.setQuantity((int) row.getCell(PART_QUANTITY).getNumericCellValue()); + partApp.setDutyCycle(row.getCell(PART_DUTY_CYCLE).getNumericCellValue()); + partApp.setMeanTimeToFailure(row.getCell(PART_MTTF).getNumericCellValue()); + partApp.setMeanTimeToRepair(row.getCell(PART_MTTR).getNumericCellValue()); + partApp.setMassToRepair(row.getCell(PART_REPAIR_MASS).getNumericCellValue()); + element.getParts().add(partApp); + } + } catch (Exception ex) { + // error reading part + ex.printStackTrace(); + } + } + } + + private void loadStates(Workbook wb, I_Element element) { + element.getStates().clear(); + for (Row row : wb.getSheetAt(STATE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + try { + if (row.getCell(STATE_ELEMENT_ID).getNumericCellValue() == element.getTid()) { + State state = new State(); + state.setTid((int) row.getCell(STATE_ID).getNumericCellValue()); + state.setName(row.getCell(STATE_NAME).getStringCellValue()); + state.setStateType(StateType.getInstance(row.getCell(STATE_TYPE).getStringCellValue())); + loadModels(wb, element, state); + element.getStates().add(state); + if (row.getCell(STATE_INITIAL).getBooleanCellValue()) + element.setCurrentState(state); + } + } catch (Exception ex) { + // error reading state + ex.printStackTrace(); + } + } + } + + /** + * Loads the demand models for a given element and state. + * + * @param wb the workbook + * @param element the element + * @param state the state + */ + private void loadModels(Workbook wb, I_Element element, I_State state) { + for (Row row : wb.getSheetAt(MODEL_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + try { + String modelType = row.getCell(MODEL_TYPE).getStringCellValue().toLowerCase(); + if (row.getCell(MODEL_STATE_ID).getNumericCellValue() == state.getTid()) { + if (DemandModelType.TIMED_IMPULSE.getName().toLowerCase().contains(modelType)) { + TimedImpulseDemandModel model = new TimedImpulseDemandModel(); + model.setTid((int) row.getCell(MODEL_ID).getNumericCellValue()); + model.setName(row.getCell(MODEL_NAME).getStringCellValue()); + for (Row r : wb.getSheetAt(DEMAND_SHEET)) { + if (r.getRowNum() == 0 || isRowEmpty(r)) + continue; + if (r.getCell(DEMAND_MODEL_ID).getNumericCellValue() == model.getTid()) { + Demand demand = new Demand(); + demand.setResource(loadResource((int) r.getCell(DEMAND_RESOURCE_ID).getNumericCellValue())); + demand.setAmount(r.getCell(DEMAND_AMOUNT).getNumericCellValue()); + model.getDemands().add(demand); + } + } + state.getDemandModels().add(model); + } else if (DemandModelType.RATED.getName().toLowerCase() + .contains(modelType)) { + RatedDemandModel model = new RatedDemandModel(); + model.setTid((int) row.getCell(MODEL_ID).getNumericCellValue()); + model.setName(row.getCell(MODEL_NAME).getStringCellValue()); + for (Row r : wb.getSheetAt(DEMAND_SHEET)) { + if (r.getRowNum() == 0 || isRowEmpty(r)) + continue; + if (r.getCell(DEMAND_MODEL_ID).getNumericCellValue() == model.getTid()) { + Demand demand = new Demand(); + demand.setResource(loadResource((int) r.getCell(DEMAND_RESOURCE_ID).getNumericCellValue())); + demand.setAmount(r.getCell(DEMAND_AMOUNT).getNumericCellValue()); + model.getDemandRates().add(demand); + } + } + state.getDemandModels().add(model); + } else if (DemandModelType.SPARING_BY_MASS.getName() + .toLowerCase().contains(modelType)) { + SparingByMassDemandModel model = new SparingByMassDemandModel(element); + model.setTid((int) row.getCell(MODEL_ID).getNumericCellValue()); + model.setName(row.getCell(MODEL_NAME).getStringCellValue()); + model.setElement(element); + model.setPartsListEnabled(row.getCell(MODEL_PARTS_LIST).getBooleanCellValue()); + model.setUnpressurizedSparesRate(row.getCell(MODEL_UNPRESS_RATE).getNumericCellValue()); + model.setPressurizedSparesRate(row.getCell(MODEL_PRESS_RATE).getNumericCellValue()); + state.getDemandModels().add(model); + } else { + throw new Exception("Unknown Demand Model Type"); + } + } + } catch (Exception ex) { + // error reading element + ex.printStackTrace(); + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadElementLibrary() + */ + public void loadElementLibrary() throws IOException { + loadElementLibrary(readWorkbook()); + } + + /** + * Loads the element library from a workbook. + * + * @param wb the workbook + */ + private void loadElementLibrary(Workbook wb) { + getElementPreviewLibrary().clear(); + for (Row row : wb.getSheetAt(ELEMENT_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + try { + ElementPreview e = null; + String elementType = row.getCell(ELEMENT_TYPE).getStringCellValue().toLowerCase(); + String name = row.getCell(ELEMENT_NAME).getStringCellValue(); + ElementIcon icon = ElementIcon.getInstance(row.getCell(ELEMENT_ICON).getStringCellValue()); + int tid = (int) row.getCell(ELEMENT_ID).getNumericCellValue(); + // create new element preview and add to library + if (ElementType.ELEMENT.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.ELEMENT, icon); + } else if (ElementType.RESOURCE_CONTAINER.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.RESOURCE_CONTAINER, icon); + } else if (ElementType.CREW_MEMBER.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.CREW_MEMBER, icon); + } else if (ElementType.CARRIER.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.CARRIER, icon); + } else if (ElementType.SURFACE_VEHICLE.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.SURFACE_VEHICLE, icon); + } else if (ElementType.PROPULSIVE_VEHICLE.getName().toLowerCase().contains(elementType)) { + e = new ElementPreview(tid, name, ElementType.PROPULSIVE_VEHICLE, icon); + } else { + throw new Exception("Unknown Element Type"); + } + elementPreviewLibrary.add(e); + } catch (Exception ex) { + // error loading edge + ex.printStackTrace(); + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadNodeLibrary() + */ + public void loadNodeLibrary() throws IOException { + loadNodeLibrary(readWorkbook()); + } + + /** + * Load the node library from a workbook. + * + * @param wb the workbook + */ + private void loadNodeLibrary(Workbook wb) { + Map libraryContents = new HashMap(); + for(Node node : getNodeLibrary()) { + // mark all nodes as unfound + libraryContents.put(node.getTid(), false); + } + for (Row row : wb.getSheetAt(NODE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + try { + Node n = loadNode((int) row.getCell(NODE_ID).getNumericCellValue()); + String nodeType = row.getCell(NODE_TYPE).getStringCellValue().toLowerCase(); + if (n == null + || !n.getNodeType().getName().toLowerCase().contains(nodeType)) { + nodeLibrary.remove(n); + if(n!=null) libraryContents.remove(n.getTid()); + // create new node and add to library + if (NodeType.SURFACE.getName().toLowerCase().contains(nodeType)) { + n = new SurfaceNode(); + } else if (NodeType.ORBITAL.getName().toLowerCase().contains(nodeType)) { + n = new OrbitalNode(); + } else if (NodeType.LAGRANGE.getName().toLowerCase().contains(nodeType)) { + n = new LagrangeNode(); + } else { + throw new Exception("Unknown Node Type"); + } + nodeLibrary.add(n); + } else { + // mark node as found + libraryContents.put(n.getTid(), true); + } + n.setTid((int) row.getCell(NODE_ID).getNumericCellValue()); + n.setName(row.getCell(NODE_NAME).getStringCellValue()); + n.setBody(Body.getInstance(row.getCell(NODE_BODY_1).getStringCellValue())); + n.setDescription(row.getCell(NODE_DESCRIPTION).toString()); + if (NodeType.SURFACE.getName().toLowerCase().contains(nodeType)) { + ((SurfaceNode) n).setLatitude(row.getCell(NODE_LATITUDE).getNumericCellValue()); + ((SurfaceNode) n).setLongitude(row.getCell(NODE_LONGITUDE).getNumericCellValue()); + } else if (NodeType.ORBITAL.getName().toLowerCase().contains( + nodeType)) { + ((OrbitalNode) n).setApoapsis(row.getCell(NODE_APOAPSIS).getNumericCellValue()); + ((OrbitalNode) n).setPeriapsis(row.getCell(NODE_PERIAPSIS).getNumericCellValue()); + ((OrbitalNode) n).setInclination(row.getCell(NODE_INCLINATION).getNumericCellValue()); + } else if (NodeType.LAGRANGE.getName().toLowerCase().contains(nodeType)) { + ((LagrangeNode) n).setMinorBody(Body.getInstance(row.getCell(NODE_BODY_2).getStringCellValue())); + ((LagrangeNode) n).setNumber((int) row.getCell(NODE_LP_NUMBER).getNumericCellValue()); + } else { + throw new Exception("Unknown Node Type"); + } + } catch (Exception ex) { + // error loading node + ex.printStackTrace(); + } + } + for(Integer i : libraryContents.keySet()) { + if(!libraryContents.get(i)) { + // remove all unfound nodes + getNodeLibrary().remove(loadNode(i)); + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#loadResourceLibrary() + */ + public void loadResourceLibrary() throws IOException { + loadResourceLibrary(readWorkbook()); + } + + /** + * Loads the resource library from a workbook. + * + * @param wb the workbook + */ + private void loadResourceLibrary(Workbook wb) { + Map libraryContents = new HashMap(); + for(I_Resource resource : getResourceLibrary()) { + // mark all resources as not found + libraryContents.put(resource.getTid(), false); + } + for (Row row : wb.getSheetAt(RESOURCE_SHEET)) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + try { + I_Resource r = loadResource((int) row.getCell(RESOURCE_ID).getNumericCellValue()); + String resourceType = row.getCell(RESOURCE_TYPE).getStringCellValue().toLowerCase(); + if (r == null + || !r.getResourceType().getName().toLowerCase().contains(resourceType)) { + resourceTypeLibrary.remove(r); + if(r!=null) libraryContents.remove(r.getTid()); + // create new resource and add to library + if (ResourceType.RESOURCE.getName().toLowerCase().contains(resourceType)) { + r = new Resource(); + } else if (ResourceType.ITEM.getName().toLowerCase().contains(resourceType)) { + r = new Item(); + } else { + throw new Exception("Unknown Resource Type"); + } + resourceTypeLibrary.add(r); + } else { + // mark resource as found + libraryContents.put(r.getTid(), true); + } + r.setTid((int) row.getCell(RESOURCE_ID).getNumericCellValue()); + r.setName(row.getCell(RESOURCE_NAME).getStringCellValue()); + r.setClassOfSupply(ClassOfSupply.getInstance((int) row.getCell(RESOURCE_COS).getNumericCellValue())); + r.setUnits(row.getCell(RESOURCE_UNITS).getStringCellValue()); + r.setUnitMass(row.getCell(RESOURCE_UNIT_MASS).getNumericCellValue()); + r.setUnitVolume(row.getCell(RESOURCE_UNIT_VOLUME).getNumericCellValue()); + r.setPackingFactor(row.getCell(RESOURCE_PACKING_FACTOR).getNumericCellValue()); + r.setEnvironment(Environment.getInstance(row.getCell(RESOURCE_ENVIRONMENT).getStringCellValue())); + r.setDescription(row.getCell(RESOURCE_DESCRIPTION).toString()); + } catch (Exception ex) { + // error loading resource + ex.printStackTrace(); + } + } + for(Integer i : libraryContents.keySet()) { + if(!libraryContents.get(i)) { + // remove all unfound resources + getResourceLibrary().remove(loadResource(i)); + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#saveEdge(edu.mit.spacenet.domain.network.edge.Edge) + */ + public void saveEdge(Edge edge) throws IOException { + Workbook wb = readWorkbook(); + Sheet sheet = wb.getSheetAt(EDGE_SHEET); + int rowNum = -1, maxTid = 0; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(EDGE_ID).getNumericCellValue() == edge.getTid()) { + rowNum = row.getRowNum(); + } + maxTid = (int) Math.max(maxTid, row.getCell(EDGE_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // edge not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + edge.setTid(maxTid + 1); + edgeLibrary.add(edge); + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(EDGE_ID).setCellValue(edge.getTid()); + row.getCell(EDGE_TYPE).setCellValue(edge.getEdgeType().getName()); + row.getCell(EDGE_NAME).setCellValue(edge.getName()); + row.getCell(EDGE_ORIGIN_ID).setCellValue(edge.getOrigin().getTid()); + row.getCell(EDGE_DESTINATION_ID).setCellValue(edge.getDestination().getTid()); + row.getCell(EDGE_DESCRIPTION).setCellValue(edge.getDescription()); + if (edge.getEdgeType() == EdgeType.SPACE) { + row.getCell(EDGE_DURATION).setCellValue(((SpaceEdge) edge).getDuration()); + saveBurns(wb, (SpaceEdge) edge); + } else if (edge.getEdgeType() == EdgeType.SURFACE) { + row.getCell(EDGE_DISTANCE).setCellValue(((SurfaceEdge) edge).getDistance()); + } else if (edge.getEdgeType() == EdgeType.FLIGHT) { + row.getCell(EDGE_DURATION).setCellValue(((FlightEdge) edge).getDuration()); + row.getCell(EDGE_MAX_CREW).setCellValue(((FlightEdge) edge).getMaxCrewSize()); + row.getCell(EDGE_MAX_CARGO).setCellValue(((FlightEdge) edge).getMaxCargoMass()); + } + writeWorkbook(wb); + } + + /** + * Saves the burns associated with an edge. Removed burns will be deleted + * from the data source, changed burns will be updated, and added burns + * will be assigned a new TID and inserted. + * + * @param wb the workbook + * @param edge the edge + */ + private void saveBurns(Workbook wb, SpaceEdge edge) { + Sheet sheet = wb.getSheetAt(BURN_SHEET); + List burnsToDelete = new ArrayList(); + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(BURN_EDGE_ID).getNumericCellValue() == edge.getTid()) { + boolean isBurnFound = false; + for (Burn burn : edge.getBurns()) { + if (burn.getTid() == row.getCell(BURN_ID).getNumericCellValue()) { + isBurnFound = true; + break; + } + } + if (!isBurnFound) + burnsToDelete.add((int) row.getCell(BURN_ID).getNumericCellValue()); + } + } + for (Integer i : burnsToDelete) { + deleteBurn(wb, i); + } + for (Burn burn : edge.getBurns()) { + int rowNum = -1, maxTid = 0; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(BURN_ID).getNumericCellValue() == burn.getTid()) { + rowNum = row.getRowNum(); + } + maxTid = (int) Math.max(maxTid, row.getCell(BURN_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // burn not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + burn.setTid(maxTid + 1); + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(BURN_ID).setCellValue(burn.getTid()); + row.getCell(BURN_EDGE_ID).setCellValue(edge.getTid()); + row.getCell(BURN_TIME).setCellValue(burn.getTime()); + row.getCell(BURN_ORDER).setCellValue(edge.getBurns().indexOf(burn)); + row.getCell(BURN_TYPE).setCellValue(burn.getBurnType().getName()); + row.getCell(BURN_DELTA_V).setCellValue(burn.getDeltaV()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#saveElement(edu.mit.spacenet.domain.element.I_Element) + */ + public void saveElement(I_Element element) throws IOException { + Workbook wb = readWorkbook(); + Sheet sheet = wb.getSheetAt(ELEMENT_SHEET); + int rowNum = -1, maxTid = 0; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(ELEMENT_ID).getNumericCellValue() == element.getTid()) { + rowNum = row.getRowNum(); + } + maxTid = (int) Math.max(maxTid, row.getCell(ELEMENT_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // element not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + element.setTid(maxTid + 1); + elementPreviewLibrary.add(new ElementPreview(element.getTid(), + element.getName(), element.getElementType(), element.getIconType())); + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + elementPreviewLibrary.remove(loadElementPreview(element.getTid())); + elementPreviewLibrary.add(new ElementPreview(element.getTid(), + element.getName(), element.getElementType(), element.getIconType())); + } + row.getCell(ELEMENT_ID).setCellValue(element.getTid()); + row.getCell(ELEMENT_TYPE).setCellValue(element.getElementType().getName()); + row.getCell(ELEMENT_NAME).setCellValue(element.getName()); + row.getCell(ELEMENT_COS).setCellValue(element.getClassOfSupply().getId()); + row.getCell(ELEMENT_ENVIRONMENT).setCellValue(element.getEnvironment().getName()); + row.getCell(ELEMENT_ACCOMMODATION_MASS).setCellValue(element.getAccommodationMass()); + row.getCell(ELEMENT_MASS).setCellValue(element.getMass()); + row.getCell(ELEMENT_VOLUME).setCellValue(element.getVolume()); + row.getCell(ELEMENT_DESCRIPTION).setCellValue(element.getDescription()); + row.getCell(ELEMENT_ICON).setCellValue(element.getIconType().getName()); + if (element.getElementType() == ElementType.RESOURCE_CONTAINER) { + row.getCell(ELEMENT_CARGO_MASS).setCellValue(((ResourceContainer) element).getMaxCargoMass()); + row.getCell(ELEMENT_CARGO_VOLUME).setCellValue(((ResourceContainer) element).getMaxCargoVolume()); + row.getCell(ELEMENT_CARGO_ENVIRONMENT).setCellValue(((ResourceContainer) element).getCargoEnvironment().getName()); + saveContents(wb, (ResourceContainer) element); + } else if (element.getElementType() == ElementType.CREW_MEMBER) { + row.getCell(ELEMENT_ACTIVE_FRACTION).setCellValue(((CrewMember) element).getAvailableTimeFraction()); + } else if (element.getElementType() == ElementType.CARRIER) { + row.getCell(ELEMENT_MAX_CREW).setCellValue(((Carrier) element).getMaxCrewSize()); + row.getCell(ELEMENT_CARGO_MASS).setCellValue(((Carrier) element).getMaxCargoMass()); + row.getCell(ELEMENT_CARGO_VOLUME).setCellValue(((Carrier) element).getMaxCargoVolume()); + row.getCell(ELEMENT_CARGO_ENVIRONMENT).setCellValue(((Carrier) element).getCargoEnvironment().getName()); + } else if (element.getElementType() == ElementType.PROPULSIVE_VEHICLE) { + row.getCell(ELEMENT_MAX_CREW).setCellValue(((PropulsiveVehicle) element).getMaxCrewSize()); + row.getCell(ELEMENT_CARGO_MASS).setCellValue(((PropulsiveVehicle) element).getMaxCargoMass()); + row.getCell(ELEMENT_CARGO_VOLUME).setCellValue(((PropulsiveVehicle) element).getMaxCargoVolume()); + row.getCell(ELEMENT_CARGO_ENVIRONMENT).setCellValue(((PropulsiveVehicle) element).getCargoEnvironment().getName()); + if (((PropulsiveVehicle) element).getOmsIsp() > 0) { + row.getCell(ELEMENT_OMS_ISP).setCellValue(((PropulsiveVehicle) element).getOmsIsp()); + row.getCell(ELEMENT_MAX_OMS).setCellValue(((PropulsiveVehicle) element).getOmsFuelTank().getMaxAmount()); + row.getCell(ELEMENT_OMS_ID).setCellValue(((PropulsiveVehicle) element).getOmsFuelTank().getResource().getTid()); + } else { + row.getCell(ELEMENT_OMS_ISP).setCellValue(0); + row.getCell(ELEMENT_MAX_OMS).setCellValue(0); + row.getCell(ELEMENT_OMS_ID).setCellValue(""); + } + if (((PropulsiveVehicle) element).getRcsIsp() > 0) { + row.getCell(ELEMENT_RCS_ISP).setCellValue(((PropulsiveVehicle) element).getRcsIsp()); + if (((PropulsiveVehicle) element).getRcsFuelTank() == null + || ((PropulsiveVehicle) element).getRcsFuelTank() == ((PropulsiveVehicle) element) + .getOmsFuelTank()) { + // shared OMS / RCS tanks + row.getCell(ELEMENT_MAX_RCS).setCellValue(0); + row.getCell(ELEMENT_RCS_ID).setCellValue(""); + } else { + row.getCell(ELEMENT_MAX_RCS).setCellValue(((PropulsiveVehicle) element).getRcsFuelTank().getMaxAmount()); + row.getCell(ELEMENT_RCS_ID).setCellValue(((PropulsiveVehicle) element).getRcsFuelTank().getResource().getTid()); + } + } else { + row.getCell(ELEMENT_RCS_ISP).setCellValue(0); + row.getCell(ELEMENT_MAX_RCS).setCellValue(0); + row.getCell(ELEMENT_RCS_ID).setCellValue(""); + } + } else if (element.getElementType() == ElementType.SURFACE_VEHICLE) { + row.getCell(ELEMENT_MAX_CREW).setCellValue(((SurfaceVehicle) element).getMaxCrewSize()); + row.getCell(ELEMENT_CARGO_MASS).setCellValue(((SurfaceVehicle) element).getMaxCargoMass()); + row.getCell(ELEMENT_CARGO_VOLUME).setCellValue(((SurfaceVehicle) element).getMaxCargoVolume()); + row.getCell(ELEMENT_CARGO_ENVIRONMENT).setCellValue(((SurfaceVehicle) element).getCargoEnvironment().getName()); + row.getCell(ELEMENT_MAX_SPEED).setCellValue(((SurfaceVehicle) element).getMaxSpeed()); + row.getCell(ELEMENT_MAX_FUEL).setCellValue(((SurfaceVehicle) element).getFuelTank().getMaxAmount()); + row.getCell(ELEMENT_FUEL_ID).setCellValue(((SurfaceVehicle) element).getFuelTank().getResource().getTid()); + } + saveParts(wb, element); + saveStates(wb, element); + writeWorkbook(wb); + } + + /** + * Saves the contents of a resource container. Removed resources will be + * deleted from the data source, changed resources will be updated, and + * added resources will be inserted. + * + * @param wb the workbook + * @param container the container + */ + private void saveContents(Workbook wb, I_ResourceContainer container) { + Sheet sheet = wb.getSheetAt(DEMAND_SHEET); + List demandsToDelete = new ArrayList(); + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_CONTAINER_ID).getCellType() != Cell.CELL_TYPE_NUMERIC + && row.getCell(DEMAND_CONTAINER_ID).getNumericCellValue() == container.getTid()) { + boolean isDemandFound = false; + for (I_Resource resource : container.getContents().keySet()) { + if (resource.getTid() == row.getCell(DEMAND_RESOURCE_ID).getNumericCellValue()) { + isDemandFound = true; + break; + } + } + if (!isDemandFound) + demandsToDelete.add((int) row.getCell(DEMAND_ID).getNumericCellValue()); + } + } + for (Integer i : demandsToDelete) { + deleteDemand(wb, i); + } + for (I_Resource resource : container.getContents().keySet()) { + int rowNum = -1, maxTid = 0, tid = -1; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_CONTAINER_ID).getCellType() != Cell.CELL_TYPE_NUMERIC + && row.getCell(DEMAND_CONTAINER_ID).getNumericCellValue() == container.getTid() + && row.getCell(DEMAND_RESOURCE_ID).getNumericCellValue() == resource.getTid()) { + rowNum = row.getRowNum(); + tid = (int)row.getCell(DEMAND_ID).getNumericCellValue(); + } + maxTid = (int)Math.max(maxTid, row.getCell(DEMAND_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // demand not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + tid = maxTid + 1; + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(DEMAND_ID).setCellValue(tid); + row.getCell(DEMAND_RESOURCE_ID).setCellValue(resource.getTid()); + row.getCell(DEMAND_AMOUNT).setCellValue(container.getContents().get(resource)); + row.getCell(DEMAND_CONTAINER_ID).setCellValue(container.getTid()); + } + } + + /** + * Saves the parts associated with an element. Removed parts will be + * deleted from the data source, changed parts will be updated, and + * added parts will be inserted. + * + * @param wb the workbook + * @param element the element + */ + private void saveParts(Workbook wb, I_Element element) { + Sheet sheet = wb.getSheetAt(PART_SHEET); + List partsToDelete = new ArrayList(); + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(PART_ELEMENT_ID).getNumericCellValue() == element + .getTid()) { + boolean isPartFound = false; + for (PartApplication part : element.getParts()) { + if (part.getPart().getTid() == row + .getCell(PART_RESOURCE_ID).getNumericCellValue()) { + isPartFound = true; + break; + } + } + if (!isPartFound) + partsToDelete.add((int) row.getCell(PART_ID) + .getNumericCellValue()); + } + } + for (Integer i : partsToDelete) { + deletePart(wb, i); + } + for (PartApplication part : element.getParts()) { + int rowNum = -1, maxTid = 0; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(PART_ELEMENT_ID).getNumericCellValue() == element.getTid() + && row.getCell(PART_RESOURCE_ID).getNumericCellValue() == part.getPart().getTid()) { + rowNum = row.getRowNum(); + } + maxTid = (int) Math.max(maxTid, row.getCell(PART_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // part not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + part.setTid(maxTid + 1); + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(PART_ID).setCellValue(part.getTid()); + row.getCell(PART_RESOURCE_ID).setCellValue(part.getPart().getTid()); + row.getCell(PART_ELEMENT_ID).setCellValue(element.getTid()); + row.getCell(PART_QUANTITY).setCellValue(part.getQuantity()); + row.getCell(PART_DUTY_CYCLE).setCellValue(part.getDutyCycle()); + row.getCell(PART_MTTF).setCellValue(part.getMeanTimeToFailure()); + row.getCell(PART_MTTR).setCellValue(part.getMeanTimeToRepair()); + row.getCell(PART_REPAIR_MASS).setCellValue(part.getMassToRepair()); + } + } + + /** + * Saves the states associated with an element. Removed states will be + * deleted from the data source, changed states will be updated, and + * added states will be assigned a new TID and inserted. + * + * @param wb the workbook + * @param element the element + */ + private void saveStates(Workbook wb, I_Element element) { + Sheet sheet = wb.getSheetAt(STATE_SHEET); + List statesToDelete = new ArrayList(); + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(STATE_ELEMENT_ID).getNumericCellValue() == element.getTid()) { + boolean isStateFound = false; + for (I_State state : element.getStates()) { + if (state.getTid() == row.getCell(STATE_ID).getNumericCellValue()) { + isStateFound = true; + break; + } + } + if (!isStateFound) + statesToDelete.add((int)row.getCell(STATE_ID).getNumericCellValue()); + } + } + for (Integer i : statesToDelete) { + deleteState(wb, i); + } + for (I_State state : element.getStates()) { + int rowNum = -1, maxTid = 0; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(STATE_ID).getNumericCellValue() == state.getTid()) { + rowNum = row.getRowNum(); + } + maxTid = (int) Math.max(maxTid, row.getCell(STATE_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // state not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + state.setTid(maxTid + 1); + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(STATE_ID).setCellValue(state.getTid()); + row.getCell(STATE_ELEMENT_ID).setCellValue(element.getTid()); + row.getCell(STATE_NAME).setCellValue(state.getName()); + row.getCell(STATE_TYPE).setCellValue(state.getStateType().getName()); + row.getCell(STATE_INITIAL).setCellValue(element.getCurrentState() == state); + + saveModels(wb, state); + } + } + + /** + * Saves the associated demand models contained within a state. Removed + * models will be deleted from the data source, changed models will be + * updated, and added models will assigned a new TID and be inserted. + * + * @param wb the workbook + * @param state the state + */ + private void saveModels(Workbook wb, I_State state) { + Sheet sheet = wb.getSheetAt(MODEL_SHEET); + List modelsToDelete = new ArrayList(); + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(MODEL_STATE_ID).getNumericCellValue() == state.getTid()) { + boolean isModelFound = false; + for (I_DemandModel model : state.getDemandModels()) { + if (model.getTid() == row.getCell(MODEL_ID).getNumericCellValue()) { + isModelFound = true; + break; + } + } + if (!isModelFound) + modelsToDelete.add((int) row.getCell(MODEL_ID).getNumericCellValue()); + } + } + for (Integer i : modelsToDelete) { + deleteModel(wb, i); + } + for (I_DemandModel model : state.getDemandModels()) { + int rowNum = -1, maxTid = 0; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(MODEL_ID).getNumericCellValue() == model.getTid()) { + rowNum = row.getRowNum(); + } + maxTid = (int) Math.max(maxTid, row.getCell(MODEL_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // model not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + model.setTid(maxTid + 1); + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(MODEL_ID).setCellValue(model.getTid()); + row.getCell(MODEL_TYPE).setCellValue(model.getDemandModelType().getName()); + row.getCell(MODEL_STATE_ID).setCellValue(state.getTid()); + row.getCell(MODEL_NAME).setCellValue(model.getName()); + + if (model.getDemandModelType() == DemandModelType.TIMED_IMPULSE + || model.getDemandModelType() == DemandModelType.RATED) { + saveDemands(wb, model); + } else if (model.getDemandModelType() == DemandModelType.SPARING_BY_MASS) { + row.getCell(MODEL_PARTS_LIST).setCellValue(((SparingByMassDemandModel) model).isPartsListEnabled()); + row.getCell(MODEL_UNPRESS_RATE).setCellValue(((SparingByMassDemandModel) model).getUnpressurizedSparesRate()); + row.getCell(MODEL_PRESS_RATE).setCellValue(((SparingByMassDemandModel) model).getPressurizedSparesRate()); + } + } + } + + /** + * Saves any associated demands from a demand model. Demands that have been + * removed will be deleted from the data source, demands that have been + * changed will be updated, and added demands will be inserted. + * + * @param wb the workbook + * @param model the demand model + */ + private void saveDemands(Workbook wb, I_DemandModel model) { + SortedSet demands; + if (model.getDemandModelType() == DemandModelType.TIMED_IMPULSE) { + demands = ((TimedImpulseDemandModel) model).getDemands(); + } else if (model.getDemandModelType() == DemandModelType.RATED) { + demands = ((RatedDemandModel) model).getDemandRates(); + } else { + return; + } + Sheet sheet = wb.getSheetAt(DEMAND_SHEET); + List demandsToDelete = new ArrayList(); + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_MODEL_ID).getCellType() != Cell.CELL_TYPE_NUMERIC + && row.getCell(DEMAND_MODEL_ID).getNumericCellValue() == model.getTid()) { + boolean isDemandFound = false; + for (Demand demand : demands) { + if (demand.getResource().getTid() == row.getCell(DEMAND_RESOURCE_ID).getNumericCellValue()) { + isDemandFound = true; + break; + } + } + if (!isDemandFound) + demandsToDelete.add((int) row.getCell(DEMAND_ID).getNumericCellValue()); + } + } + for (Integer i : demandsToDelete) { + deleteDemand(wb, i); + } + for (Demand demand : demands) { + int rowNum = -1, maxTid = 0, tid = -1; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_MODEL_ID).getCellType() != Cell.CELL_TYPE_NUMERIC + && row.getCell(DEMAND_MODEL_ID).getNumericCellValue() == model.getTid() + && row.getCell(DEMAND_RESOURCE_ID).getNumericCellValue() == demand.getResource().getTid()) { + rowNum = row.getRowNum(); + tid = (int) row.getCell(DEMAND_ID).getNumericCellValue(); + } + maxTid = (int) Math.max(maxTid, row.getCell(DEMAND_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // demand not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + tid = maxTid + 1; + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(DEMAND_ID).setCellValue(tid); + row.getCell(DEMAND_MODEL_ID).setCellValue(model.getTid()); + row.getCell(DEMAND_RESOURCE_ID).setCellValue(demand.getResource().getTid()); + row.getCell(DEMAND_AMOUNT).setCellValue(demand.getAmount()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#saveNode(edu.mit.spacenet.domain.network.node.Node) + */ + public void saveNode(Node node) throws IOException { + Workbook wb = readWorkbook(); + Sheet sheet = wb.getSheetAt(NODE_SHEET); + int rowNum = -1, maxTid = 0; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(NODE_ID).getNumericCellValue() == node.getTid()) { + rowNum = row.getRowNum(); + } + maxTid = (int) Math.max(maxTid, row.getCell(NODE_ID).getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // node not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + node.setTid(maxTid + 1); + nodeLibrary.add(node); + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(NODE_ID).setCellValue(node.getTid()); + row.getCell(NODE_TYPE).setCellValue(node.getNodeType().getName()); + row.getCell(NODE_NAME).setCellValue(node.getName()); + row.getCell(NODE_BODY_1).setCellValue(node.getBody().getName()); + row.getCell(NODE_DESCRIPTION).setCellValue(node.getDescription()); + if (node.getNodeType() == NodeType.SURFACE) { + row.getCell(NODE_LATITUDE).setCellValue(((SurfaceNode) node).getLatitude()); + row.getCell(NODE_LONGITUDE).setCellValue(((SurfaceNode) node).getLongitude()); + } else if (node.getNodeType() == NodeType.ORBITAL) { + row.getCell(NODE_APOAPSIS).setCellValue(((OrbitalNode) node).getApoapsis()); + row.getCell(NODE_PERIAPSIS).setCellValue(((OrbitalNode) node).getPeriapsis()); + row.getCell(NODE_INCLINATION).setCellValue(((OrbitalNode) node).getInclination()); + } else if (node.getNodeType() == NodeType.LAGRANGE) { + row.getCell(NODE_BODY_2).setCellValue(((LagrangeNode) node).getMinorBody().getName()); + row.getCell(NODE_LP_NUMBER).setCellValue(((LagrangeNode) node).getNumber()); + } + writeWorkbook(wb); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#saveResource(edu.mit.spacenet.domain.resource.I_Resource) + */ + public void saveResource(I_Resource resource) throws IOException { + if (resource.getResourceType() == ResourceType.GENERIC) + return; + Workbook wb = readWorkbook(); + Sheet sheet = wb.getSheetAt(RESOURCE_SHEET); + int rowNum = -1, maxTid = 0; + for (Row row : sheet) { + if (row.getRowNum() == 0 || isRowEmpty(row)) + continue; + if (row.getCell(RESOURCE_ID).getNumericCellValue() == resource + .getTid()) { + rowNum = row.getRowNum(); + } + maxTid = (int) Math.max(maxTid, row.getCell(RESOURCE_ID) + .getNumericCellValue()); + } + Row row = null; + if (rowNum < 0) { + // resource not found in database -- create new entry + rowNum = getLastNonEmptyRow(sheet) + 1; + resource.setTid(maxTid + 1); + resourceTypeLibrary.add(resource); + row = sheet.getRow(rowNum); + if (row == null) { + row = sheet.createRow(rowNum); + } + } else { + row = sheet.getRow(rowNum); + } + row.getCell(RESOURCE_ID).setCellValue(resource.getTid()); + row.getCell(RESOURCE_TYPE).setCellValue(resource.getResourceType().getName()); + row.getCell(RESOURCE_NAME).setCellValue(resource.getName()); + row.getCell(RESOURCE_COS).setCellValue(resource.getClassOfSupply().getId()); + row.getCell(RESOURCE_UNITS).setCellValue(resource.getUnits()); + row.getCell(RESOURCE_UNIT_MASS).setCellValue(resource.getUnitMass()); + row.getCell(RESOURCE_UNIT_VOLUME).setCellValue(resource.getUnitVolume()); + row.getCell(RESOURCE_PACKING_FACTOR).setCellValue(resource.getPackingFactor()); + row.getCell(RESOURCE_ENVIRONMENT).setCellValue(resource.getEnvironment().getName()); + row.getCell(RESOURCE_DESCRIPTION).setCellValue(resource.getDescription()); + writeWorkbook(wb); + } + + /** + * Sets the file path. + * + * @param filePath the new file path + */ + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#validateData() + */ + public List validateData() throws IOException { + Workbook wb = readWorkbook(); + ArrayList errors = new ArrayList(); + errors.addAll(checkNodes(wb.getSheetAt(NODE_SHEET))); + errors.addAll(checkEdges(wb.getSheetAt(EDGE_SHEET))); + errors.addAll(checkBurns(wb.getSheetAt(BURN_SHEET))); + errors.addAll(checkResources(wb.getSheetAt(RESOURCE_SHEET))); + errors.addAll(checkElements(wb.getSheetAt(ELEMENT_SHEET))); + errors.addAll(checkPartApplications(wb.getSheetAt(PART_SHEET))); + errors.addAll(checkStates(wb.getSheetAt(STATE_SHEET))); + errors.addAll(checkModels(wb.getSheetAt(MODEL_SHEET))); + errors.addAll(checkDemands(wb.getSheetAt(DEMAND_SHEET))); + return errors; + } + + /** + * Checks the nodes sheet to find any parse errors. + * + * @param sheet the nodes sheet + * + * @return the list of error messages + */ + private List checkNodes(Sheet sheet) { + ArrayList errors = new ArrayList(); + + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + String type = ""; + if (row.getCell(NODE_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Node in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(NODE_TYPE).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Node in row " + (i + 1) + " has missing or invalid type."); + } else { + type = row.getCell(NODE_TYPE).getStringCellValue().toLowerCase(); + } + if (row.getCell(NODE_NAME).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Node in row " + (i + 1) + " has missing or invalid name."); + } + if (row.getCell(NODE_BODY_1).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Node in row " + (i + 1) + " has missing or invalid body."); + } + if (NodeType.SURFACE.getName().toLowerCase().contains(type)) { + if (row.getCell(NODE_LATITUDE).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Node in row " + (i + 1) + " has missing or invalid latitude."); + } + if (row.getCell(NODE_LONGITUDE).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Node in row " + (i + 1) + " has missing or invalid longitude."); + } + } else if (NodeType.ORBITAL.getName().toLowerCase().contains(type)) { + if (row.getCell(NODE_APOAPSIS).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Node in row " + (i + 1) + " has missing or invalid apoapsis."); + } + if (row.getCell(NODE_PERIAPSIS).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Node in row " + (i + 1) + " has missing or invalid periapsis."); + } + if (row.getCell(NODE_INCLINATION).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Node in row " + (i + 1) + " has missing or invalid inclination."); + } + } else if (NodeType.LAGRANGE.getName().toLowerCase().contains(type)) { + if (row.getCell(NODE_BODY_2).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Node in row " + (i + 1) + " has missing or invalid minor body."); + } + if (row.getCell(NODE_LP_NUMBER).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Node in row " + (i + 1) + " has missing or invalid lagrange number."); + } + } else if (!type.equals("")) { + errors.add("Node in row " + (i + 1) + " has missing or invalid type."); + } + } + return errors; + } + + /** + * Checks the edges sheet to find any parse errors. + * + * @param sheet the edges sheet + * + * @return the list of error messages + */ + private List checkEdges(Sheet sheet) { + ArrayList errors = new ArrayList(); + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + String type = ""; + if (row.getCell(EDGE_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(EDGE_TYPE).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid type."); + } else { + type = row.getCell(EDGE_TYPE).getStringCellValue().toLowerCase(); + } + if (row.getCell(EDGE_NAME).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid name."); + } + if (row.getCell(EDGE_ORIGIN_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid origin node."); + } + if (row.getCell(EDGE_DESTINATION_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid destination node."); + } + if (EdgeType.SPACE.getName().toLowerCase().contains(type)) { + if (row.getCell(EDGE_DURATION).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid duration."); + } + } else if (EdgeType.SURFACE.getName().toLowerCase().contains(type)) { + if (row.getCell(EDGE_DISTANCE).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid distance."); + } + } else if (EdgeType.FLIGHT.getName().toLowerCase().contains(type)) { + if (row.getCell(EDGE_DURATION).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid duration."); + } + if (row.getCell(EDGE_MAX_CREW).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid max crew size."); + } + if (row.getCell(EDGE_MAX_CARGO).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid max cargo mass."); + } + } else if (!type.equals("")) { + errors.add("Edge in row " + (i + 1) + " has missing or invalid type."); + } + } + return errors; + } + + /** + * Checks the burns sheet to find any parse errors. + * + * @param sheet the burns sheet + * + * @return the list of error messages + */ + private List checkBurns(Sheet sheet) { + ArrayList errors = new ArrayList(); + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + if (row.getCell(BURN_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Burn in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(BURN_TIME).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Burn in row " + (i + 1) + " has missing or invalid time."); + } + if (row.getCell(BURN_ORDER).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Burn in row " + (i + 1) + " has missing or invalid order."); + } + if (row.getCell(BURN_TYPE).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Burn in row " + (i + 1) + " has missing or invalid type."); + } + if (row.getCell(BURN_DELTA_V).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Burn in row " + (i + 1) + " has missing or invalid delta-v."); + } + } + return errors; + } + + /** + * Checks the resources sheet to find any parse errors. + * + * @param sheet the resources sheet + * + * @return the list of error messages + */ + private List checkResources(Sheet sheet) { + ArrayList errors = new ArrayList(); + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + String type = ""; + if (row.getCell(RESOURCE_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(RESOURCE_TYPE).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid type."); + } else { + type = row.getCell(RESOURCE_TYPE).getStringCellValue().toLowerCase(); + } + if (row.getCell(RESOURCE_NAME).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid name."); + } + if (row.getCell(RESOURCE_COS).getCellType() != Cell.CELL_TYPE_NUMERIC + || ClassOfSupply.getInstance((int) row.getCell(3).getNumericCellValue()) == null) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid class of supply."); + } + if (row.getCell(RESOURCE_UNITS).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid units."); + } + if (row.getCell(RESOURCE_UNIT_MASS).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid unit mass."); + } + if (row.getCell(RESOURCE_UNIT_VOLUME).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid unit volume."); + } + if (row.getCell(RESOURCE_PACKING_FACTOR).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid packing factor."); + } + if (row.getCell(RESOURCE_ENVIRONMENT).getCellType() != Cell.CELL_TYPE_STRING + || (!Environment.PRESSURIZED.getName().toLowerCase().equals(row.getCell(RESOURCE_ENVIRONMENT).getStringCellValue().toLowerCase()) + && !Environment.UNPRESSURIZED.getName().toLowerCase().equals(row.getCell(RESOURCE_ENVIRONMENT).getStringCellValue().toLowerCase()))) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid environment."); + } + if (ResourceType.RESOURCE.getName().toLowerCase().contains(type)) { + } else if (ResourceType.ITEM.getName().toLowerCase().contains(type)) { + } else if (!type.equals("")) { + errors.add("Resource in row " + (i + 1) + " has missing or invalid type."); + } + } + return errors; + } + + /** + * Checks the elements sheet to find any parse errors. + * + * @param sheet the elements sheet + * + * @return the list of error messages + */ + private List checkElements(Sheet sheet) { + ArrayList errors = new ArrayList(); + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + String type = ""; + if (row.getCell(ELEMENT_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Element in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(ELEMENT_TYPE).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Element in row " + (i + 1) + " has missing or invalid type."); + } else { + type = row.getCell(ELEMENT_TYPE).getStringCellValue().toLowerCase(); + } + if (row.getCell(ELEMENT_NAME).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Element in row " + (i + 1) + " has missing or invalid name."); + } + if (row.getCell(ELEMENT_COS).getCellType() != Cell.CELL_TYPE_NUMERIC + || ClassOfSupply.getInstance((int) row.getCell(3) + .getNumericCellValue()) == null) { + errors.add("Element in row " + (i + 1) + " has missing or invalid class of supply."); + } + if (row.getCell(ELEMENT_ENVIRONMENT).getCellType() != Cell.CELL_TYPE_STRING + || (!Environment.PRESSURIZED.getName().toLowerCase().equals(row.getCell(ELEMENT_ENVIRONMENT).getStringCellValue().toLowerCase()) + && !Environment.UNPRESSURIZED.getName().toLowerCase().equals(row.getCell(ELEMENT_ENVIRONMENT).getStringCellValue().toLowerCase()))) { + errors.add("Element in row " + (i + 1) + " has missing or invalid environment."); + } + if (row.getCell(ELEMENT_ACCOMMODATION_MASS).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Element in row " + (i + 1) + " has missing or invalid accommodation mass."); + } + if (row.getCell(ELEMENT_MASS).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Element in row " + (i + 1) + " has missing or invalid mass."); + } + if (row.getCell(ELEMENT_VOLUME).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Element in row " + (i + 1) + " has missing or invalid volume."); + } + if (ElementType.ELEMENT.getName().toLowerCase().contains(type)) { + } else if (ElementType.RESOURCE_CONTAINER.getName().toLowerCase().contains(type)) { + if (row.getCell(ELEMENT_CARGO_MASS).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Container in row " + (i + 1) + " has missing or invalid max cargo mass."); + } + if (row.getCell(ELEMENT_CARGO_VOLUME).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Container in row " + (i + 1) + " has missing or invalid max cargo volume."); + } + if (row.getCell(ELEMENT_CARGO_ENVIRONMENT).getCellType() != Cell.CELL_TYPE_STRING + || (!Environment.PRESSURIZED.getName().toLowerCase().equals(row.getCell(ELEMENT_CARGO_ENVIRONMENT).getStringCellValue().toLowerCase()) + && !Environment.UNPRESSURIZED.getName().toLowerCase().equals(row.getCell(ELEMENT_CARGO_ENVIRONMENT).getStringCellValue().toLowerCase()))) { + errors.add("Container in row " + (i + 1) + " has missing or invalid cargo environment."); + } + } else if (ElementType.CREW_MEMBER.getName().toLowerCase().contains(type)) { + if (row.getCell(ELEMENT_ACTIVE_FRACTION).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Crew Member in row " + (i + 1) + " has missing or invalid active time fraction."); + } + } else if (ElementType.CARRIER.getName().toLowerCase().contains(type) + || ElementType.SURFACE_VEHICLE.getName().toLowerCase().contains(type) + || ElementType.PROPULSIVE_VEHICLE.getName().toLowerCase().contains(type)) { + if (row.getCell(ELEMENT_MAX_CREW).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Carrier in row " + (i + 1) + " has missing or invalid max crew."); + } + if (row.getCell(ELEMENT_CARGO_MASS).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Carrier in row " + (i + 1) + " has missing or invalid max cargo mass."); + } + if (row.getCell(ELEMENT_CARGO_VOLUME).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Container in row " + (i + 1) + " has missing or invalid max cargo volume."); + } + if (row.getCell(ELEMENT_CARGO_ENVIRONMENT).getCellType() != Cell.CELL_TYPE_STRING + || (!Environment.PRESSURIZED.getName().toLowerCase().equals(row.getCell(ELEMENT_CARGO_ENVIRONMENT).getStringCellValue().toLowerCase()) + && !Environment.UNPRESSURIZED.getName().toLowerCase().equals(row.getCell(ELEMENT_CARGO_ENVIRONMENT).getStringCellValue().toLowerCase()))) { + errors.add("Container in row " + (i + 1) + " has missing or invalid cargo environment."); + } + } else if (ElementType.PROPULSIVE_VEHICLE.getName().toLowerCase().contains(type)) { + if (row.getCell(ELEMENT_OMS_ISP).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Propulsive Vehicle in row " + (i + 1) + " has missing or invalid OMS Isp."); + } + if (row.getCell(ELEMENT_OMS_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Propulsive Vehicle in row " + (i + 1) + " has missing or invalid max OMS fuel."); + } + if (row.getCell(ELEMENT_RCS_ISP).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Propulsive Vehicle in row " + (i + 1) + " has missing or invalid RCS Isp."); + } + if (row.getCell(ELEMENT_RCS_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Propulsive Vehicle in row " + (i + 1) + " has missing or invalid max RCS fuel."); + } + } else if (ElementType.SURFACE_VEHICLE.getName().toLowerCase().contains(type)) { + if (row.getCell(ELEMENT_MAX_SPEED).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Surface Vehicle in row " + (i + 1) + " has missing or invalid max speed."); + } + if (row.getCell(ELEMENT_MAX_FUEL).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Surface Vehicle in row " + (i + 1) + " has missing or invalid max fuel."); + } + if (row.getCell(ELEMENT_FUEL_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Surface Vehicle in row " + (i + 1) + " has missing or invalid fuel id."); + } + } else if (!type.equals("")) { + errors.add("Element in row " + (i + 1) + + " has missing or invalid type."); + } + } + return errors; + } + + /** + * Checks the part applications sheet to find any parse errors. + * + * @param sheet the parts sheet + * + * @return the list of error messages + */ + private List checkPartApplications(Sheet sheet) { + ArrayList errors = new ArrayList(); + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + if (row.getCell(PART_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Part Application in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(PART_RESOURCE_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Part Application in row " + (i + 1) + " has missing or invalid resource id."); + } + if (row.getCell(PART_QUANTITY).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Part Application in row " + (i + 1) + " has missing or invalid quantity."); + } + if (row.getCell(PART_DUTY_CYCLE).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Part Application in row " + (i + 1) + " has missing or invalid duty cycle."); + } + if (row.getCell(PART_MTTF).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Part Application in row " + (i + 1) + " has missing or invalid mean time to failure."); + } + if (row.getCell(PART_MTTR).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Part Application in row " + (i + 1) + " has missing or invalid mean time to repair."); + } + if (row.getCell(PART_REPAIR_MASS).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Part Application in row " + (i + 1) + " has missing or invalid mass to repair."); + } + } + return errors; + } + + /** + * Checks the states sheet to find any parsing errors. + * + * @param sheet the states sheet + * + * @return the list of error messages + */ + private List checkStates(Sheet sheet) { + ArrayList errors = new ArrayList(); + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + if (row.getCell(STATE_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("State in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(STATE_NAME).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("State in row " + (i + 1) + " has missing or invalid name."); + } + if (row.getCell(STATE_TYPE).getCellType() != Cell.CELL_TYPE_STRING + || !(StateType.ACTIVE.getName().toLowerCase().contains(row.getCell(STATE_TYPE).getStringCellValue().toLowerCase()) + || StateType.SPECIAL.getName().toLowerCase().contains(row.getCell(STATE_TYPE).getStringCellValue().toLowerCase()) + || StateType.QUIESCENT.getName().toLowerCase().contains(row.getCell(STATE_TYPE).getStringCellValue().toLowerCase()) + || StateType.DORMANT.getName().toLowerCase().contains(row.getCell(STATE_TYPE).getStringCellValue().toLowerCase()) + || StateType.DECOMMISSIONED.getName().toLowerCase().contains(row.getCell(STATE_TYPE).getStringCellValue().toLowerCase()))) { + errors.add("State in row " + (i + 1) + " has missing or invalid type."); + } + if (row.getCell(STATE_INITIAL).getCellType() != Cell.CELL_TYPE_BOOLEAN) { + errors.add("State in row " + (i + 1) + " has missing or invalid initial state boolean."); + } + } + return errors; + } + + /** + * Checks the models sheet to find any parsing errors. + * + * @param sheet the models sheet + * + * @return the list of errors + */ + private List checkModels(Sheet sheet) { + ArrayList errors = new ArrayList(); + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + String type = ""; + if (row.getCell(MODEL_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Model in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(MODEL_TYPE).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Model in row " + (i + 1) + " has missing or invalid type."); + } else { + type = row.getCell(MODEL_TYPE).getStringCellValue().toLowerCase(); + } + if (row.getCell(MODEL_NAME).getCellType() != Cell.CELL_TYPE_STRING) { + errors.add("Model in row " + (i + 1) + " has missing or invalid name."); + } + if (DemandModelType.TIMED_IMPULSE.getName().toLowerCase().contains(type)) { + } else if (DemandModelType.RATED.getName().toLowerCase().contains(type)) { + } else if (DemandModelType.SPARING_BY_MASS.getName().toLowerCase().contains(type)) { + if (row.getCell(MODEL_PARTS_LIST).getCellType() != Cell.CELL_TYPE_BOOLEAN) { + errors.add("Sparing by Mass Model in row " + (i + 1)+ " has missing or invalid parts list boolean."); + } + if (row.getCell(MODEL_UNPRESS_RATE).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Sparing by Mass Model in row " + (i + 1)+ " has missing or invalid unpressurized spares rate."); + } + if (row.getCell(MODEL_PRESS_RATE).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Sparing by Mass Model in row " + (i + 1) + " has missing or invalid pressurized spares rate."); + } + } else if (!type.equals("")) { + errors.add("Model in row " + (i + 1) + " has missing or invalid type."); + } + } + return errors; + } + + /** + * Checks the demands sheet to find any parsing errors. + * + * @param sheet the demands sheet + * + * @return the list of error messages + */ + private List checkDemands(Sheet sheet) { + ArrayList errors = new ArrayList(); + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (isRowEmpty(row)) + continue; + if (row.getCell(DEMAND_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Demand in row " + (i + 1) + " has missing or invalid id."); + } + if (row.getCell(DEMAND_RESOURCE_ID).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Demand in row " + (i + 1) + " has missing or invalid resource id."); + } + if (row.getCell(DEMAND_AMOUNT).getCellType() != Cell.CELL_TYPE_NUMERIC) { + errors.add("Demand in row " + (i + 1) + " has missing or invalid amount."); + } + } + return errors; + } + + /** + * Reads a workbook from file. + * + * @return the workbook + * + * @throws IOException Signals that an I/O exception has occurred. + */ + private Workbook readWorkbook() throws IOException { + FileInputStream fis = new FileInputStream(filePath); + Workbook wb = new HSSFWorkbook(fis); + wb.setMissingCellPolicy(Row.CREATE_NULL_AS_BLANK); + fis.close(); + return wb; + } + + /** + * Writes a workbook to file, saving and changes that had been made. + * + * @param wb the workbook + * + * @throws IOException Signals that an I/O exception has occurred. + */ + private void writeWorkbook(Workbook wb) throws IOException { + FileOutputStream fos = new FileOutputStream(filePath); + wb.write(fos); + fos.close(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.data.I_DataSource#format() + */ + public void format() throws IOException { + FileOutputStream fos = new FileOutputStream(filePath); + Workbook wb = new HSSFWorkbook(); + wb.setMissingCellPolicy(Row.CREATE_NULL_AS_BLANK); + if(wb.getNumberOfSheets() <= NODE_SHEET) { + wb.createSheet("nodes"); + Row row = wb.getSheetAt(NODE_SHEET).createRow(0); + row.getCell(NODE_ID).setCellValue("id"); + row.getCell(NODE_TYPE).setCellValue("type"); + row.getCell(NODE_NAME).setCellValue("name"); + row.getCell(NODE_BODY_1).setCellValue("body_1"); + row.getCell(NODE_LATITUDE).setCellValue("latitude"); + row.getCell(NODE_LONGITUDE).setCellValue("longitude"); + row.getCell(NODE_APOAPSIS).setCellValue("apoapsis"); + row.getCell(NODE_PERIAPSIS).setCellValue("periapsis"); + row.getCell(NODE_INCLINATION).setCellValue("inclination"); + row.getCell(NODE_BODY_2).setCellValue("body_2"); + row.getCell(NODE_LP_NUMBER).setCellValue("lp_number"); + row.getCell(NODE_DESCRIPTION).setCellValue("description"); + } + if(wb.getNumberOfSheets() <= EDGE_SHEET) { + wb.createSheet("edges"); + Row row = wb.getSheetAt(EDGE_SHEET).createRow(0); + row.getCell(EDGE_ID).setCellValue("id"); + row.getCell(EDGE_TYPE).setCellValue("type"); + row.getCell(EDGE_NAME).setCellValue("name"); + row.getCell(EDGE_ORIGIN_ID).setCellValue("origin_id"); + row.getCell(EDGE_DESTINATION_ID).setCellValue("destination_id"); + row.getCell(EDGE_DURATION).setCellValue("duration"); + row.getCell(EDGE_DISTANCE).setCellValue("distance"); + row.getCell(EDGE_MAX_CREW).setCellValue("max_crew"); + row.getCell(EDGE_MAX_CARGO).setCellValue("max_cargo"); + row.getCell(EDGE_DESCRIPTION).setCellValue("description"); + } + if(wb.getNumberOfSheets() <= BURN_SHEET) { + wb.createSheet("burns"); + Row row = wb.getSheetAt(BURN_SHEET).createRow(0); + row.getCell(BURN_ID).setCellValue("id"); + row.getCell(BURN_EDGE_ID).setCellValue("edge_id"); + row.getCell(BURN_TIME).setCellValue("time"); + row.getCell(BURN_ORDER).setCellValue("order"); + row.getCell(BURN_TYPE).setCellValue("type"); + row.getCell(BURN_DELTA_V).setCellValue("delta_v"); + } + if(wb.getNumberOfSheets() <= RESOURCE_SHEET) { + wb.createSheet("resources"); + Row row = wb.getSheetAt(RESOURCE_SHEET).createRow(0); + row.getCell(RESOURCE_ID).setCellValue("id"); + row.getCell(RESOURCE_TYPE).setCellValue("type"); + row.getCell(RESOURCE_NAME).setCellValue("name"); + row.getCell(RESOURCE_COS).setCellValue("cos"); + row.getCell(RESOURCE_UNITS).setCellValue("units"); + row.getCell(RESOURCE_UNIT_MASS).setCellValue("unit_mass"); + row.getCell(RESOURCE_UNIT_VOLUME).setCellValue("unit_volume"); + row.getCell(RESOURCE_PACKING_FACTOR).setCellValue("packing_factor"); + row.getCell(RESOURCE_ENVIRONMENT).setCellValue("environment"); + row.getCell(RESOURCE_DESCRIPTION).setCellValue("description"); + } + if(wb.getNumberOfSheets() <= ELEMENT_SHEET) { + wb.createSheet("elements"); + Row row = wb.getSheetAt(ELEMENT_SHEET).createRow(0); + row.getCell(ELEMENT_ID).setCellValue("id"); + row.getCell(ELEMENT_TYPE).setCellValue("type"); + row.getCell(ELEMENT_NAME).setCellValue("name"); + row.getCell(ELEMENT_COS).setCellValue("cos"); + row.getCell(ELEMENT_ENVIRONMENT).setCellValue("environment"); + row.getCell(ELEMENT_ACCOMMODATION_MASS).setCellValue( + "accommodation_mass"); + row.getCell(ELEMENT_MASS).setCellValue("mass"); + row.getCell(ELEMENT_VOLUME).setCellValue("volume"); + row.getCell(ELEMENT_MAX_CREW).setCellValue("max_crew"); + row.getCell(ELEMENT_CARGO_MASS).setCellValue("cargo_mass"); + row.getCell(ELEMENT_CARGO_VOLUME).setCellValue("cargo_volume"); + row.getCell(ELEMENT_CARGO_ENVIRONMENT).setCellValue("cargo_environment"); + row.getCell(ELEMENT_ACTIVE_FRACTION).setCellValue("active_fraction"); + row.getCell(ELEMENT_OMS_ISP).setCellValue("oms_isp"); + row.getCell(ELEMENT_MAX_OMS).setCellValue("max_oms"); + row.getCell(ELEMENT_OMS_ID).setCellValue("oms_id"); + row.getCell(ELEMENT_RCS_ISP).setCellValue("rcs_isp"); + row.getCell(ELEMENT_MAX_RCS).setCellValue("max_rcs"); + row.getCell(ELEMENT_RCS_ID).setCellValue("rcs_id"); + row.getCell(ELEMENT_MAX_SPEED).setCellValue("max_speed"); + row.getCell(ELEMENT_MAX_FUEL).setCellValue("max_fuel"); + row.getCell(ELEMENT_FUEL_ID).setCellValue("fuel_id"); + row.getCell(ELEMENT_DESCRIPTION).setCellValue("description"); + } + if(wb.getNumberOfSheets() <= PART_SHEET) { + wb.createSheet("parts"); + Row row = wb.getSheetAt(PART_SHEET).createRow(0); + row.getCell(PART_ID).setCellValue("id"); + row.getCell(PART_RESOURCE_ID).setCellValue("resource_id"); + row.getCell(PART_ELEMENT_ID).setCellValue("element_id"); + row.getCell(PART_QUANTITY).setCellValue("quantity"); + row.getCell(PART_DUTY_CYCLE).setCellValue("duty_cycle"); + row.getCell(PART_MTTF).setCellValue("mttf"); + row.getCell(PART_MTTR).setCellValue("mttr"); + row.getCell(PART_REPAIR_MASS).setCellValue("repair_mass"); + } + if(wb.getNumberOfSheets() <= STATE_SHEET) { + wb.createSheet("states"); + Row row = wb.getSheetAt(STATE_SHEET).createRow(0); + row.getCell(STATE_ID).setCellValue("id"); + row.getCell(STATE_ELEMENT_ID).setCellValue("element_id"); + row.getCell(STATE_NAME).setCellValue("name"); + row.getCell(STATE_TYPE).setCellValue("type"); + row.getCell(STATE_INITIAL).setCellValue("initial_state"); + } + if(wb.getNumberOfSheets() <= MODEL_SHEET) { + wb.createSheet("models"); + Row row = wb.getSheetAt(MODEL_SHEET).createRow(0); + row.getCell(MODEL_ID).setCellValue("id"); + row.getCell(MODEL_TYPE).setCellValue("type"); + row.getCell(MODEL_STATE_ID).setCellValue("state_id"); + row.getCell(MODEL_NAME).setCellValue("name"); + row.getCell(MODEL_PARTS_LIST).setCellValue("parts_list"); + row.getCell(MODEL_UNPRESS_RATE).setCellValue("unpress_rate"); + row.getCell(MODEL_PRESS_RATE).setCellValue("press_rate"); + } + if(wb.getNumberOfSheets() <= DEMAND_SHEET) { + wb.createSheet("demands"); + Row row = wb.getSheetAt(DEMAND_SHEET).createRow(0); + row.getCell(DEMAND_ID).setCellValue("id"); + row.getCell(DEMAND_MODEL_ID).setCellValue("model_id"); + row.getCell(DEMAND_RESOURCE_ID).setCellValue("resource_id"); + row.getCell(DEMAND_AMOUNT).setCellValue("amount"); + row.getCell(DEMAND_CONTAINER_ID).setCellValue("container_id"); + } + wb.write(fos); + fos.close(); + } + + /** + * Deletes a row from a sheet and shifts all subsequent rows up one row to + * fill the blank spot. + * + * @param sheet the sheet + * @param row the row + */ + private static void deleteRow(Sheet sheet, int row) { + sheet.removeRow(sheet.getRow(row)); + if (row + 1 <= sheet.getLastRowNum()) + sheet.shiftRows(row + 1, sheet.getLastRowNum(), -1); + } + + /** + * Gets the last non empty row. The last non-empty row is the last row + * before the first empty row (missing or invalid primary key) is + * encountered + * + * @param sheet the sheet on which to find the non-empty row + * + * @return the last non empty row index + */ + private static int getLastNonEmptyRow(Sheet sheet) { + for (Row row : sheet) { + if (row.getRowNum() > 0 && isRowEmpty(row)) + return row.getRowNum() - 1; + } + return sheet.getLastRowNum(); + } + + /** + * Checks if a row is empty by checking the primary key column (assumed to + * always be column 0) to see if it is not null, numeric, and greater than 0 + * + * @param row the row to check + * + * @return true, if is row empty + */ + private static boolean isRowEmpty(Row row) { + if (row == null + || row.getCell(0) == null + || row.getCell(0).getCellType() != Cell.CELL_TYPE_NUMERIC + || row.getCell(0).getNumericCellValue() <= 0) + return true; + else + return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/ClassOfSupply.java b/src/main/java/edu/mit/spacenet/domain/ClassOfSupply.java new file mode 100644 index 0000000..0912b9d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/ClassOfSupply.java @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain; + +import java.awt.Color; + +/** + * This enumeration lists the ten main classes of supply, and the sub-classes + * of supply. + * + * @author Paul Grogan + */ +public enum ClassOfSupply { + + /** The COS 0. */ + COS0(0, "None", new Color(0,0,0)), + + /** The COS 1. */ + COS1(1, "Propellants and Fuels", new Color(0xff,0x99,0xff)), + + /** The COS 2. */ + COS2(2, "Crew Provisions", new Color(0,0xcc,0)), + + /** The COS 3. */ + COS3(3, "Crew Operations", new Color(0,0,0xcc)), + + /** The COS 4. */ + COS4(4, "Maintenance and Upkeep", new Color(0xff, 0xcc, 0)), + + /** The COS 5. */ + COS5(5, "Stowage and Restraint ", new Color(0xcc,0,0)), + + /** The COS 6. */ + COS6(6, "Exploration and Research", new Color(0xff,0x99,0)), + + /** The COS 7. */ + COS7(7, "Waste and Disposal", new Color(0x99,0x66,0)), + + /** The COS 8. */ + COS8(8, "Habitation and Infrastructure", new Color(0x66,0,0x99)), + + /** The COS 9. */ + COS9(9, "Transportation and Carriers", new Color(0,0x66,0x99)), + + /** The COS 10. */ + COS10(10, "Miscellaneous", new Color(0x99,0x99,0x99)), + + /** The COS 101. */ + COS101(101, "Cryogens", null), + + /** The COS 102. */ + COS102(102, "Hypergols", null), + + /** The COS 103. */ + COS103(103, "Nuclear Fuel", null), + + /** The COS 104. */ + COS104(104, "Petroleum Fuels", null), + + /** The COS 105. */ + COS105(105, "Other Fuels", null), + + /** The COS 106. */ + COS106(106, "Green Propellant", null), + + /** The COS 201. */ + COS201(201, "Water and Support Equipment", null), + + /** The COS 202. */ + COS202(202, "Food and Support Equipment", null), + + /** The COS 203. */ + COS203(203, "Gases", null), + + /** The COS 204. */ + COS204(204, "Hygiene Items", null), + + /** The COS 205. */ + COS205(205, "Clothing", null), + + /** The COS 206. */ + COS206(206, "Personal Items", null), + + /** The COS 301. */ + COS301(301, "Office Equipment and Supplies", null), + + /** The COS 302. */ + COS302(302, "EVA Equipment and Consumables", null), + + /** The COS 303. */ + COS303(303, "Health Equipment and Consumables", null), + + /** The COS 304. */ + COS304(304, "Safety Equipment", null), + + /** The COS 305. */ + COS305(305, "Communications Equipment", null), + + /** The COS 306. */ + COS306(306, "Computers and Support Equipment", null), + + /** The COS 401. */ + COS401(401, "Spares and Repair Parts", null), + + /** The COS 402. */ + COS402(402, "Maintenance Tools", null), + + /** The COS 403. */ + COS403(403, "Lubricants and Bulk Chemicals", null), + + /** The COS 404. */ + COS404(404, "Batteries", null), + + /** The COS 405. */ + COS405(405, "Cleaning Equipment and Consumables", null), + + /** The COS 501. */ + COS501(501, "Cargo Containers and Restraints", null), + + /** The COS 502. */ + COS502(502, "Inventory Management Equipment", null), + + /** The COS 601. */ + COS601(601, "Science Payloads and Instruments", null), + + /** The COS 602. */ + COS602(602, "Field Equipment", null), + + /** The COS 603. */ + COS603(603, "Samples", null), + + /** The COS 701. */ + COS701(701, "Waste", null), + + /** The COS 702. */ + COS702(702, "Waste Management Equipment", null), + + /** The COS 703. */ + COS703(703, "Failed Parts", null), + + /** The COS 801. */ + COS801(801, "Habitation Facilities", null), + + /** The COS 802. */ + COS802(802, "Surface Mobility Systems", null), + + /** The COS 803. */ + COS803(803, "Power Systems", null), + + /** The COS 804. */ + COS804(804, "Robotic Systems", null), + + /** The COS 805. */ + COS805(805, "Resource Utilization Systems", null), + + /** The COS 806. */ + COS806(806, "Orbiting Service Systems", null), + + /** The COS 901. */ + COS901(901, "Carriers, Non-propulsive Elements", null), + + /** The COS 902. */ + COS902(902, "Propulsive Elements", null), + + /** The COS 4011. */ + COS4011(4011, "Spares", null), + + /** The COS 4012. */ + COS4012(4012, "Repair Parts", null), + + /** The COS 8041. */ + COS8041(8041, "Science Robotics", null), + + /** The COS 8042. */ + COS8042(8042, "Construction/Maintenance Robotics", null), + + /** The COS 9021. */ + COS9021(9021, "Launch Vehicles", null), + + /** The COS 9022. */ + COS9022(9022, "Upper Stages/In-Space Propulsion Systems", null), + + /** The COS 9023. */ + COS9023(9023, "Descent Stages", null), + + /** The COS 9024. */ + COS9024(9024, "Ascent Stages", null); + + private int id; + private String name; + private Color color; + + /** + * The default constructor. + * @param id the class of supply number + * @param name the name to display + * @param color the default color to display in charts) + */ + private ClassOfSupply(int id, String name, Color color) { + this.id = id; + this.name = name; + this.color = color; + } + + /** + * Gets a particular instance of a class of supply based on its number. + * + * @param id the class of supply number + * + * @return the class of supply + */ + public static ClassOfSupply getInstance(int id) { + for(ClassOfSupply cos : ClassOfSupply.values()) { + if(cos.getId()==id) return cos; + } + return null; + } + + /** + * Gets the class of supply number. + * + * @return the class of supply number + */ + public int getId() { + return id; + } + + /** + * Gets the class of supply name. + * + * @return the class of supply name + */ + public String getName() { + return name; + } + + public String toString() { + return "COS " + getId() + ": " + getName(); + } + + /** + * Gets the color to be used in charts. + * + * @return the color + */ + public Color getColor() { + if(color==null) return getBaseClass().getColor(); + else return color; + } + + /** + * Gets the base class of supply (i.e. 0 through 10) + * + * @return the base class of supply + */ + public ClassOfSupply getBaseClass() { + for(int i = 0; i <= 10; i++) { + if(this.isInstanceOf(ClassOfSupply.getInstance(i))) + return ClassOfSupply.getInstance(i); + } + return null; + } + + /** + * Determines whether this class of supply is an instance (equal to or a + * subclass of) the given class of supply. + * + * @param cos the class of supply to compare against + * + * @return true if this is an instance of cos, false otherwise + */ + public boolean isInstanceOf(ClassOfSupply cos) { + if(this.equals(cos) || this.isSubclassOf(cos)) return true; + else return false; + } + + /** + * Determines whether this class of supply is a subclass (i.e. child, more + * specific) of the given class of supply. + * + * @param cos the class of supply to compare against + * + * @return true if this is a subclass of cos, false otherwise + */ + public boolean isSubclassOf(ClassOfSupply cos) { + String superclassId = new Integer(cos.getId()).toString(); + String subclassId = new Integer(id).toString(); + if(superclassId.length() >= subclassId.length()) return false; + if(id == 10 || cos.getId() == 10) return false; + // above is a HACK to account for poor naming convention + for(int i = 0; i < superclassId.length(); i++) { + if(superclassId.charAt(i) != subclassId.charAt(i)) return false; + } + return true; + } + + /** + * Determines whether this class of supply is a superclass (i.e. parent, + * less specific) of the given class of supply. + * + * @param cos the class of supply to compare against + * + * @return true if this is a superclass of cos, false otherwise + */ + public boolean isSuperclassOf(ClassOfSupply cos) { + String superclassId = new Integer(id).toString(); + String subclassId = new Integer(cos.getId()).toString(); + if(superclassId.length() >= subclassId.length()) return false; + if(id == 10 || cos.getId() == 10) return false; + // above is a HACK to account for poor naming convention + for(int i = 0; i < superclassId.length(); i++) { + if(superclassId.charAt(i) != subclassId.charAt(i)) return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/DomainObject.java b/src/main/java/edu/mit/spacenet/domain/DomainObject.java new file mode 100644 index 0000000..c2573b7 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/DomainObject.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain; + +import edu.mit.spacenet.util.IdGenerator; + +/** + * The base class for any classes utilizing a database-storage format that also + * require a specialized method for comparisons of objects that may reside at + * different memory locations, but correspond to one logical object. + * + * @author Paul Grogan + */ +public abstract class DomainObject extends DomainType implements I_DomainObject { + private int uid; + + /** + * The default constructor automatically assigns the unique identifier and + * defaults the type identifier to -1. + */ + public DomainObject() { + super(); + uid = IdGenerator.getUid(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainObject#getUid() + */ + public int getUid() { + return uid; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainObject#resetUid() + */ + public void resetUid() { + uid = IdGenerator.getUid(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#equals(java.lang.Object) + */ + public boolean equals(Object object) { + /* Due to the serialization process used in SpaceNet, domain objects + * (i.e. elements) must use unique identification numbers instead of + * memory addresses to determine equality. + */ + if(object instanceof DomainObject + && getClass().equals(object.getClass())) + return getUid() == ((DomainObject)object).getUid(); + else return false; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/DomainType.java b/src/main/java/edu/mit/spacenet/domain/DomainType.java new file mode 100644 index 0000000..3f2e34e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/DomainType.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain; + +/** + * The domain type class is used to assign identification numbers to objects + * pulled from the data source. A domain type is used to differentiate static + * objects like locations, and also object-types like element types. + * + * @author Paul Grogan + */ +public abstract class DomainType implements I_DomainType { + private int tid; + private String name; + private String description; + + /** + * The default constructor automatically assigns the type identifier to + * negative random number and assigns a default name of "". + */ + public DomainType() { + tid = (int)(-1*Integer.MAX_VALUE*Math.random()); + setName(""); + setDescription(""); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainType#getTid() + */ + public int getTid() { + return tid; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainType#setTid(int) + */ + public void setTid(int tid) { + this.tid = tid; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainType#getName() + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainType#setName(java.lang.String) + */ + public void setName(String name) { + this.name = name; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainType#getDescription() + */ + public String getDescription() { + return description; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainType#setDescription(java.lang.String) + */ + public void setDescription(String description) { + this.description = description; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return getName(); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object object) { + /* Due to the serialization process used in SpaceNet, domain types + * (i.e. locations, states, etc.) must use type identification numbers + * instead of memory addresses to determine equality. + */ + if(object instanceof DomainType + && getClass().equals(object.getClass())) + return getTid() == ((DomainType)object).getTid(); + else return false; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainType#print() + */ + public void print() { + print(0); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_DomainType#print(int) + */ + public void print(int tabOrder) { + String s = ""; + for(int i=0; i. + */ +package edu.mit.spacenet.domain; + +/** + * The environment enumeration is used to differentiate between pressurized and + * unpressurized cargo. + * + * @author Paul Grogan + */ +public enum Environment { + + /** Pressurized environments. */ + PRESSURIZED("Pressurized"), + + /** Unpressurized environments. */ + UNPRESSURIZED("Unpressurized"); + + private String name; + + private Environment(String name) { + this.name = name; + } + + /** + * Gets the name. + * + * @return the name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the single instance of Environment. + * + * @param name the name + * + * @return single instance of Environment + */ + public static Environment getInstance(String name) { + for(Environment environment : values()) { + if(environment.getName().toLowerCase().equals(name.toLowerCase())) + return environment; + } + return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/I_Container.java b/src/main/java/edu/mit/spacenet/domain/I_Container.java new file mode 100644 index 0000000..bfd862a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/I_Container.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain; + +import java.util.SortedSet; + +import edu.mit.spacenet.domain.element.I_Element; + +/** + * The interface for any object that can contain items. + * + * @author Paul Grogan + */ +public interface I_Container extends I_DomainType { + + /** + * Returns the contents of this container. + * + * @return the set of items + */ + public SortedSet getContents(); + + /** + * Gets the complete contents of a location, including any nested elements + * at any level. + * + * @return the set of elements + */ + public SortedSet getCompleteContents(); + + /** + * Gets whether an element can be added. + * + * @param element the element + * + * @return true, if successful + */ + public boolean canAdd(I_Element element); + + /** + * Gets whether mass can be added to a nested element. + * + * @param addedMass the added mass + * + * @return true, if successful + */ + public boolean canAdd(double addedMass); + + /** + * Adds the item to the container. + * + * @param element the element to add + * + * @return true, if successful + */ + public boolean add(I_Element element); + + /** + * Removes the element from the container. + * + * @param element the element to add + * + * @return true, if successful + */ + public boolean remove(I_Element element); + + /** + * Gets the current cargo mass. + * + * @return the cargo mass (kilograms) + */ + public double getCargoMass(); + + /** + * Gets the total cargo mass including any nested elements and resources. + * + * @return the total cargo mass (kilograms) + */ + public double getTotalMass(); + + /** + * Gets the current number of crew members. + * + * @return the number of crew members + */ + public int getCrewSize(); + + /** + * Gets the total crew size including any nested elements. + * + * @return the total number of crew members + */ + public int getTotalCrewSize(); + + /** + * Gets the total volume of cargo elements. + * + * @return the cargo volume (cubic meters) + */ + public double getCargoVolume(); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/I_DomainObject.java b/src/main/java/edu/mit/spacenet/domain/I_DomainObject.java new file mode 100644 index 0000000..4e53fd9 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/I_DomainObject.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain; + +/** + * The base interface for any domain-level objects. + * + * @author Paul Grogan + */ +public interface I_DomainObject extends I_DomainType { + + /** + * Gets the Unique IDentifier. + * + * @return the unique identifier + */ + public int getUid(); + + /** + * Resets the Unique IDentifier after instantiation. Used during copy + * processes where already-instantiated domain objects must be reassigned + * a new identifier. + */ + public void resetUid(); + + /** + * Gets the Type IDentifier. + * + * @return the type identifier + */ + public int getTid(); + + /** + * Sets the Type IDentifier. + * + * @param tid the type identifier + */ + public void setTid(int tid); + + /** + * Prints to console without any indentation. + */ + public void print(); + + /** + * Prints to console at a specific tab indentation level. + * + * @param tabOrder the indentation level + */ + public void print(int tabOrder); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/I_DomainType.java b/src/main/java/edu/mit/spacenet/domain/I_DomainType.java new file mode 100644 index 0000000..42dfcc0 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/I_DomainType.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain; + +/** + * The base interface for any domain-level objects. + * + * @author Paul Grogan + */ +public interface I_DomainType { + + /** + * Gets the Type IDentifier. + * + * @return the type identifier + */ + public int getTid(); + + /** + * Sets the Type IDentifier. + * + * @param tid the type identifier + */ + public void setTid(int tid); + + /** + * Gets the name. + * + * @return the name + */ + public String getName(); + + /** + * Sets the name. + * + * @param name the name + */ + public void setName(String name); + + /** + * Gets the description. + * + * @return the description + */ + public String getDescription(); + + /** + * Sets the description. + * + * @param description the description + */ + public void setDescription(String description); + + /** + * Prints to console without any indentation. + */ + public void print(); + + /** + * Prints to console at a specific tab indentation level. + * + * @param tabOrder the indentation level + */ + public void print(int tabOrder); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/element/Carrier.java b/src/main/java/edu/mit/spacenet/domain/element/Carrier.java new file mode 100644 index 0000000..37d7d28 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/Carrier.java @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * An element with the capability to contain crew and cargo up to capacity + * constraints. + * + * @author Paul Grogan + */ +public class Carrier extends Element implements I_Carrier { + private SortedSet contents; + private double maxCargoMass; + private double maxCargoVolume; + private Environment cargoEnvironment; + private int maxCrewSize; + + /** + * The default constructor that initializes the contents, crew, and cargo + * structures. + */ + public Carrier() { + super(); + setCargoEnvironment(Environment.UNPRESSURIZED); + contents = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Carrier#getCargoEnvironment() + */ + public Environment getCargoEnvironment() { + return cargoEnvironment; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Carrier#setCargoEnvironment(edu.mit.spacenet.domain.Environment) + */ + public void setCargoEnvironment(Environment cargoEnvironment) { + this.cargoEnvironment = cargoEnvironment; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Carrier#getMaxCargoMass() + */ + public double getMaxCargoMass() { + return GlobalParameters.getRoundedMass(maxCargoMass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Carrier#setMaxCargoMass(double) + */ + public void setMaxCargoMass(double maxCargoMass) { + this.maxCargoMass = maxCargoMass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getCargoMass() + */ + public double getCargoMass() { + double mass = 0; + for(I_Element i : contents) { + if(!(i instanceof CrewMember)) { + mass += i.getTotalMass(); + } + } + return mass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Carrier#getMaxCargoVolume() + */ + public double getMaxCargoVolume() { + return GlobalParameters.getRoundedVolume(maxCargoVolume); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Carrier#setMaxCargoVolume(double) + */ + public void setMaxCargoVolume(double maxCargoVolume) { + this.maxCargoVolume = maxCargoVolume; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getCargoVolume() + */ + public double getCargoVolume() { + double volume = 0; + for(I_Element e : contents) { + if(!(e instanceof CrewMember)) { + volume += e.getVolume(); + } + } + return GlobalParameters.getRoundedVolume(volume); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getCrewSize() + */ + public int getCrewSize() { + int crew = 0; + for(I_Element e : contents) { + if(e instanceof CrewMember) { + crew++; + } + } + return crew; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getTotalCrewSize() + */ + public int getTotalCrewSize() { + int crew = 0; + for(I_Element e : contents) { + if(e instanceof CrewMember) { + crew++; + } else if(e instanceof I_Carrier) { + crew+=((I_Carrier)e).getTotalCrewSize(); + } + } + return crew; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Carrier#getMaxCrewSize() + */ + public int getMaxCrewSize() { + return maxCrewSize; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Carrier#setMaxCrewSize(int) + */ + public void setMaxCrewSize(int maxCrewSize) { + this.maxCrewSize = maxCrewSize; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#canAdd(edu.mit.spacenet.domain.element.I_Element) + */ + public boolean canAdd(I_Element element) { + if(element instanceof CrewMember) { + if(contents.contains(element)) return true; + else if(getCrewSize() < maxCrewSize) return true; + else return false; + } else { + if(contents.contains(element)) { + return true; + } else if(getCargoMass() + element.getTotalMass() - getMaxCargoMass() > GlobalParameters.getMassPrecision()/2d ) { + return false; // mass constrained + } else if(GlobalParameters.isVolumeConstrained() + && getCargoVolume() + element.getVolume() - getMaxCargoVolume() > GlobalParameters.getVolumePrecision()/2d) { + return false; // volume constrained + } else if(GlobalParameters.isEnvironmentConstrained() + && (element.getEnvironment().equals(Environment.PRESSURIZED) + && getCargoEnvironment().equals(Environment.UNPRESSURIZED))) { + return false; // environment constrained + } else return getContainer()==null?true:getContainer().canAdd(element.getTotalMass()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#canAdd(double) + */ + public boolean canAdd(double addedMass) { + if(getCargoMass() + addedMass - getMaxCargoMass() > GlobalParameters.getMassPrecision()/2d ) + return false; + else return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#add(edu.mit.spacenet.domain.element.I_Element) + */ + public boolean add(I_Element element) { + if(contents.contains(element)) return true; + else if(canAdd(element)) { + if(element.getContainer()!=null) element.getContainer().remove(element); + element.setContainer(this); + contents.add(element); + return true; + } else return false; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#remove(edu.mit.spacenet.domain.element.I_Element) + */ + public boolean remove(I_Element element) { + if(contents.contains(element)) { + element.setContainer(null); + contents.remove(element); + return true; + } else return false; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getContents() + */ + public SortedSet getContents() { + return contents; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getCompleteContents() + */ + public SortedSet getCompleteContents() { + SortedSet elements = new TreeSet(); + for(I_Element element : contents) recursiveAdd(elements, element); + return elements; + } + private void recursiveAdd(SortedSet elements, I_Element element) { + elements.add(element); + if(element instanceof I_Container) { + for(I_Element child : ((I_Container)element).getContents()) { + recursiveAdd(elements, child); + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getTotalMass() + */ + @Override + public double getTotalMass() { + double mass = 0; + for(I_Element e : contents) { + mass += e.getTotalMass(); + } + return GlobalParameters.getRoundedMass(super.getTotalMass() + mass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getTotalMass(edu.mit.spacenet.domain.ClassOfSupply) + */ + @Override + public double getTotalMass(ClassOfSupply cos) { + double amount = super.getTotalMass(cos); + for(I_Element e : getContents()) { + amount+=e.getTotalMass(cos); + } + return GlobalParameters.getRoundedMass(amount); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + for(I_Element e : contents) { + e.print(tabOrder+1); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#satisfyDemands(edu.mit.spacenet.domain.resource.DemandSet, edu.mit.spacenet.simulator.I_Simulator) + */ + @Override + public void satisfyDemands(DemandSet demands, I_Simulator simulator) { + super.satisfyDemands(demands, simulator); + for(I_Element i : contents) i.satisfyDemands(demands, simulator); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getElementType() + */ + @Override + public ElementType getElementType() { + return ElementType.CARRIER; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/element/CrewMember.java b/src/main/java/edu/mit/spacenet/domain/element/CrewMember.java new file mode 100644 index 0000000..7d54613 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/CrewMember.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import edu.mit.spacenet.domain.ClassOfSupply; + +/** + * An element used to represent crew members. + * + * @author Paul Grogan + */ +public class CrewMember extends Element implements I_Agent { + private double availableTimeFraction; + + /** + * The default constructor that sets the class of supply to COS0. + */ + public CrewMember() { + super(); + setClassOfSupply(ClassOfSupply.COS0); + availableTimeFraction = 0.667; + } + + /** + * Gets the available time fraction (percent of time available for + * exploration, maintenance, etc.) + * + * @return the available time fraction + */ + public double getAvailableTimeFraction() { + return availableTimeFraction; + } + + /** + * Sets the available time fraction (percent of time available for + * exploration, maintenance, etc.) + * + * @param availableTimeFraction the available time fraction + */ + public void setAvailableTimeFraction(double availableTimeFraction) { + this.availableTimeFraction = availableTimeFraction; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getElementType() + */ + @Override + public ElementType getElementType() { + return ElementType.CREW_MEMBER; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/element/Element.java b/src/main/java/edu/mit/spacenet/domain/element/Element.java new file mode 100644 index 0000000..eb48363 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/Element.java @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.swing.ImageIcon; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.DomainObject; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimScavenge; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Represents the main objects in simulation, each may have a set of parts + * (through the intermediate part application class), and a set of states, with + * one current state. + * + * @author Paul Grogan + */ +public class Element extends DomainObject implements I_Element { + private ClassOfSupply classOfSupply; + private Environment environment; + private double accommodationMass; + private double mass; + private double volume; + private SortedSet parts; + private SortedSet states; + private I_State currentState; + private I_Container container; + private transient ImageIcon icon; + private ElementIcon iconType; + + /** + * The default constructor sets the default class of supply to COS0, sets + * the environment to unpressurized, and initializes the set of part + * applications and the set of states. Also creates a default state, adds it + * to the set of states, and sets it as the current state. + */ + public Element() { + super(); + setClassOfSupply(ClassOfSupply.COS0); + setEnvironment(Environment.UNPRESSURIZED); + parts = new TreeSet(); + states = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getClassOfSupply() + */ + public ClassOfSupply getClassOfSupply() { + return classOfSupply; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setClassOfSupply(edu.mit.spacenet.domain.ClassOfSupply) + */ + public void setClassOfSupply(ClassOfSupply classOfSupply) { + this.classOfSupply = classOfSupply; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getEnvironment() + */ + public Environment getEnvironment() { + return GlobalParameters.isEnvironmentConstrained()? + environment:Environment.UNPRESSURIZED; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setEnvironment(edu.mit.spacenet.domain.Environment) + */ + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getAccommodationMass() + */ + public double getAccommodationMass() { + return GlobalParameters.getRoundedMass(accommodationMass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setAccommodationMass(double) + */ + public void setAccommodationMass(double mass) { + this.accommodationMass = mass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getMass() + */ + public double getMass() { + return GlobalParameters.getRoundedMass(mass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setMass(double) + */ + public void setMass(double mass) { + this.mass = mass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getTotalMass() + */ + public double getTotalMass() { + return GlobalParameters.getRoundedMass(getMass()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getVolume() + */ + public double getVolume() { + return GlobalParameters.getRoundedVolume(volume); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setVolume(double) + */ + public void setVolume(double volume) { + this.volume = volume; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getTotalVolume() + */ + public double getTotalVolume() { + return GlobalParameters.getRoundedVolume(getVolume()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#generateDemands(double, edu.mit.spacenet.simulator.I_Simulator) + */ + public DemandSet generateDemands(double duration, I_Simulator simulator) { + if(getCurrentState() == null) { + return new DemandSet(); + } else { + return getCurrentState().generateDemands(duration, simulator); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#satisfyDemands(edu.mit.spacenet.domain.resource.DemandSet, edu.mit.spacenet.simulator.I_Simulator) + */ + public void satisfyDemands(DemandSet demands, I_Simulator simulator) { + if(simulator.getScenario().isScavengeSpares() + && getCurrentState() != null + && getCurrentState().getStateType().equals(StateType.DECOMMISSIONED)) { + for(PartApplication application : getParts()) { + for(Demand demand : demands) { + if(application.getPart().equals(demand.getResource())) { + if(demand.getAmount() > 0) { + if(demand.getAmount() > application.getQuantity()) { + simulator.getScavengedParts().add(new SimScavenge(simulator.getTime(), + application.getPart(), application.getQuantity(), + getLocation(), this)); + demand.setAmount(demand.getAmount() - application.getQuantity()); + application.setQuantity(0); + } else { + simulator.getScavengedParts().add(new SimScavenge(simulator.getTime(), + application.getPart(), demand.getAmount(), + getLocation(), this)); + application.setQuantity(application.getQuantity() - demand.getAmount()); + demands.remove(demand); + break; + } + } + } + } + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getTotalMass(edu.mit.spacenet.domain.ClassOfSupply) + */ + public double getTotalMass(ClassOfSupply cos) { + double mass = 0; + if(GlobalParameters.isScavengeSpares() + && getCurrentState() != null + && getCurrentState().getStateType().equals(StateType.DECOMMISSIONED)) { + double partsMass = 0; + for(PartApplication p : getParts()) { + partsMass += p.getQuantity()*p.getPart().getUnitMass(); + if(p.getPart().getClassOfSupply().isInstanceOf(cos)) { + mass += p.getQuantity()*p.getPart().getUnitMass(); + } + } + if(getClassOfSupply().isInstanceOf(cos)) { + mass += Math.max(0,getMass()-partsMass); + } + } else { + if(getClassOfSupply().isInstanceOf(cos)) { + mass += getMass(); + } + } + return GlobalParameters.getRoundedMass(mass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getParts() + */ + public SortedSet getParts() { + return this.parts; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setParts(java.util.SortedSet) + */ + public void setParts(SortedSet parts) { + this.parts = parts; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getStates() + */ + public SortedSet getStates() { + return states; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setStates(java.util.SortedSet) + */ + public void setStates(SortedSet states) { + this.states = states; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getCurrentState() + */ + public I_State getCurrentState() { + return currentState; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setCurrentState(edu.mit.spacenet.domain.element.I_State) + */ + public boolean setCurrentState(I_State newState) { + if(states.size()==0 && newState==null) { + this.currentState = null; + return true; + } else if(states.contains(newState)) { + this.currentState = newState; + return true; + } else return false; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getContainer() + */ + public I_Container getContainer() { + return container; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setContainer(edu.mit.spacenet.domain.I_Container) + */ + public void setContainer(I_Container container) { + this.container = container; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getLocation() + */ + public Location getLocation() { + if(getContainer()==null) return null; + else if(getContainer() instanceof Location) return (Location)getContainer(); + else if(getContainer() instanceof I_Carrier) return ((I_Carrier)getContainer()).getLocation(); + else throw new RuntimeException("Illegal container: " + getContainer()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#isInside(edu.mit.spacenet.domain.I_Container) + */ + public boolean isInside(I_Container container) { + if(getContainer().equals(container)) + return true; + else if(getContainer() instanceof I_Carrier) + return ((I_Carrier)getContainer()).isInside(container); + else + return false; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(I_Element element) { + if(getName().equals(element.getName())) { + if(getTid() == element.getTid()) { + return new Integer(getUid()).compareTo( + new Integer(element.getUid())); + } else { + return new Integer(getTid()).compareTo( + new Integer(element.getTid())); + } + } else { + return getName().compareTo(element.getName()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getElementType() + */ + public ElementType getElementType() { + return ElementType.ELEMENT; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getIcon() + */ + public ImageIcon getIcon() { + if(iconType==null) return getElementType().getIconType().getIcon(); + else if(icon==null) icon = iconType.getIcon(); + return icon; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#getIconType() + */ + public ElementIcon getIconType() { + if(iconType==null && icon!=null) { + for(ElementIcon t : ElementIcon.values()) { + if(t.getIcon().equals(icon)) { + this.iconType = t; + break; + } + } + } else if(iconType==null && icon==null) { + this.iconType = getElementType().getIconType(); + } + return iconType; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_Element#setIconType(java.lang.String) + */ + public void setIconType(ElementIcon iconType) { + this.iconType = iconType; + this.icon = null; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/element/ElementFactory.java b/src/main/java/edu/mit/spacenet/domain/element/ElementFactory.java new file mode 100644 index 0000000..66a3a1f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/ElementFactory.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +/** + * A factory for creating elements. + * + * @author Paul Grogan + */ +public abstract class ElementFactory { + + /** + * Factory method that creates a new element based on the passed element + * type. Throws a runtime exception if an unsupported element type is used. + * + * @param type the element type to create + * + * @return the newly-created element + */ + public static I_Element createElement(ElementType type) { + switch(type) { + case ELEMENT: return new Element(); + case CREW_MEMBER: return new CrewMember(); + case RESOURCE_CONTAINER: return new ResourceContainer(); + case RESOURCE_TANK: return new ResourceTank(); + case CARRIER: return new Carrier(); + case SURFACE_VEHICLE: return new SurfaceVehicle(); + case PROPULSIVE_VEHICLE: return new PropulsiveVehicle(); + default: throw new RuntimeException("Unsupported Element"); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/ElementIcon.java b/src/main/java/edu/mit/spacenet/domain/element/ElementIcon.java new file mode 100644 index 0000000..399d65f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/ElementIcon.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import javax.swing.ImageIcon; + +/** + * The element icon enumeration serves as a library of built-in icons for + * elements. + * + * @author Paul Grogan + */ +public enum ElementIcon { + + /** The brick. */ + BRICK("Brick", "icons/brick.png"), + + /** The blue person. */ + USER("Blue Person", "icons/user.png"), + + /** The pink person. */ + USER_FEMALE("Pink Person", "icons/user_female.png"), + + /** The the green person. */ + USER_GREEN("Green Person", "icons/user_green.png"), + + /** The orange person. */ + USER_ORANGE("Orange Person", "icons/user_orange.png"), + + /** The red person. */ + USER_RED("Red Person", "icons/user_red.png"), + + /** The package. */ + PACKAGE("Package", "icons/package.png"), + + /** The delivery truck. */ + LORRY("Delivery Truck", "icons/lorry.png"), + + /** The car. */ + CAR("Car", "icons/car.png"), + + /** The crew module. */ + CREW_MODULE("Crew Module", "icons/crew_module.png"), + + /** The service module. */ + SERVICE_MODULE("Service Module", "icons/service_module.png"), + + /** The ascent stage. */ + ASCENT_STAGE("Ascent Stage", "icons/ascent_stage.png"), + + /** The descent stage. */ + DESCENT_STAGE("Descent Stage", "icons/descent_stage.png"), + + /** The lunar lander. */ + LUNAR_LANDER("Lunar Lander", "icons/lunar_lander.png"), + + /** The crew capsule. */ + CREW_CAPSULE("Crew Capsule", "icons/crew_capsule.png"), + + /** The launch abort system. */ + LAUNCH_ABORT("Launch Abort", "icons/launch_abort.png"), + + /** The Ares I first stage. */ + ARES_I_FS("Ares I First Stage", "icons/ares_i_fs.png"), + + /** The Ares I upper stage. */ + ARES_I_US("Ares I Upper Stage", "icons/ares_i_us.png"), + + /** The Ares V SRBs. */ + ARES_V_SRBS("Ares V SRBs", "icons/ares_v_srbs.png"), + + /** The Ares V Core. */ + ARES_V_CORE("Ares V Core", "icons/ares_v_core.png"), + + /** The Ares V EDS. */ + ARES_V_EDS("Ares V EDS", "icons/ares_v_eds.png"), + + /** The Ares V Interstage. */ + ARES_V_IS("Ares V Interstage", "icons/ares_v_is.png"), + + /** The Ares V Payload Fairing. */ + ARES_V_PLF("Ares V PLF", "icons/ares_v_plf.png"), + + /** The EVA Astronaut. */ + ASTRONAUT_WHITE("EVA Suit Astronaut", "icons/astronaut_white.png"), + + /** The Flight Suit Astronaut. */ + ASTRONAUT_ORANGE("Flight Suit Astronaut", "icons/astronaut_orange.png"), + + /** The Shuttle. */ + SHUTTLE("Shuttle", "icons/shuttle.png"), + + /** The Orbiter. */ + ORBITER("Orbiter", "icons/orbiter.png"), + + /** The Habitat. */ + HABITAT("Habitat", "icons/habitat.png"), + + /** The Power Supply. */ + POWER_SUPPLY("Power Supply", "icons/power_supply.png"), + + /** The SOYUZ. */ + SOYUZ("Soyuz", "icons/soyuz.png"), + + /** The PROGRESS. */ + PROGRESS("Progress", "icons/progress.png"), + + /** The ATV. */ + ATV("ATV", "icons/atv.png"), + + /** The HTV. */ + HTV("HTV", "icons/htv.png"), + + /** The CYGNUS. */ + CYGNUS("Cygnus", "icons/cygnus.png"), + + /** The DRAGON. */ + DRAGON("Dragon", "icons/dragon.png"), + + /** The ISS. */ + ISS("ISS", "icons/iss.png"), + + AMS("AMS", "icons/ams.png"), + + PMM("PMM", "icons/pmm.png"), + + ELC("ELC", "icons/elc.png"), + + MLM("MLM", "icons/mlm.png"), + + MARS_TRANSFER_HABITAT("Mars Transfer Habitat", "icons/mth.png"), + + LH2_DROP_TANK("LH2 Drop Tank", "icons/lh2_drop_tank.png"), + + AEROSHELL("Aeroshell", "icons/aeroshell.png"), + + INLINE_LH2_TANK("Inline LH2 Tank", "icons/lh2_tank.png"), + + NUCLEAR_THERMAL_ROCKET("Nuclear Thermal Rocket", "icons/ntr.png"), + + HABITAT_LANDER("Habitat Lander", "icons/hab_lander.png") + ; + + private String name; + private ImageIcon icon; + + private ElementIcon(String name, String iconUrl) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } + + /** + * Gets the name of the icon. + * + * @return the icon name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon. + * + * @return the icon + */ + public ImageIcon getIcon() { + return icon; + } + + /** + * Gets the element icon instance based on a given icon. + * + * @param icon the icon to match + * + * @return the matching element icon, null if no match was found + */ + public static ElementIcon getInstance(ImageIcon icon) { + for(ElementIcon elementIcon : values()) { + if(elementIcon.getIcon().equals(icon)) return elementIcon; + } + return null; + } + + /** + * Gets the single instance of ElementIcon. + * + * @param string the string + * + * @return single instance of ElementIcon + */ + public static ElementIcon getInstance(String string) { + for(ElementIcon icon : values()) { + if(icon.getName().toLowerCase().equals(string.toLowerCase())) return icon; + } + return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/ElementType.java b/src/main/java/edu/mit/spacenet/domain/element/ElementType.java new file mode 100644 index 0000000..755064f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/ElementType.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + + +/** + * The element type enumeration lists the different types of elements, typically + * one per element subclass. The element type provides a default name and a + * default icon. + * + * @author Paul Grogan + */ +public enum ElementType { + + /** Used for elements of the Element class. */ + ELEMENT("Element", ElementIcon.BRICK), + + /** Used for elements of the CrewMember class. */ + CREW_MEMBER("Crew Member", ElementIcon.USER), + + /** Used for elements of the ResourceContainer class. */ + RESOURCE_CONTAINER("Resource Container", ElementIcon.PACKAGE), + + /** Used for elements of the ResourceTank class. */ + RESOURCE_TANK("Resource Tank", ElementIcon.PACKAGE), + + /** Used for elements of the Carrier class. */ + CARRIER("Carrier", ElementIcon.LORRY), + + /** Used for elements of the PropulsiveVehicle class. */ + PROPULSIVE_VEHICLE("Propulsive Vehicle", ElementIcon.BRICK), + + /** Used for elements of the SurfaceVehicle class. */ + SURFACE_VEHICLE("Surface Vehicle", ElementIcon.CAR); + + private String name; + private ElementIcon icon; + + private ElementType(String name, ElementIcon icon) { + this.name = name; + this.icon = icon; + } + + /** + * Gets the text representation of the element type. + * + * @return the element type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon used as the default for elements of this type. + * + * @return the default icon + */ + public ElementIcon getIconType() { + return icon; + } + + /** + * Gets an element type instance based on a give name. + * + * @param name the element type name to match + * + * @return the element type, null if no match was found. + */ + public static ElementType getInstance(String name) { + for(ElementType t : ElementType.values()) { + if(t.getName().toLowerCase().equals(name.toLowerCase())) { + return t; + } + } + return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/GenericResourceContainer.java b/src/main/java/edu/mit/spacenet/domain/element/GenericResourceContainer.java new file mode 100644 index 0000000..4c1f592 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/GenericResourceContainer.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A generic type of resource container where the element's mass and volume are + * functions of the contents' mass and volume via mass and volume packing + * factors. Instead of specifying maximum cargo masses and volumes, you instead + * specify maximum masses and volumes for the entire container. + * + * @author Paul Grogan + */ +public class GenericResourceContainer extends ResourceContainer { + private double massPackingFactor, volumePackingFactor; + private double maxMass, maxVolume; + + /** + * Instantiates a new generic resource container. + */ + public GenericResourceContainer() { + super(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getVolume() + */ + @Override + public double getVolume() { + return GlobalParameters.getRoundedVolume(super.getVolume() + volumePackingFactor*getCargoVolume()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getMass() + */ + @Override + public double getMass() { + return GlobalParameters.getRoundedMass(super.getMass() + massPackingFactor*getCargoMass()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.ResourceContainer#getMaxCargoMass() + */ + @Override + public double getMaxCargoMass() { + return GlobalParameters.getRoundedMass((maxMass-getMass())/(massPackingFactor+1)); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.ResourceContainer#setMaxCargoMass(double) + */ + @Override + public void setMaxCargoMass(double maxCargoMass) { + maxMass = maxCargoMass*(massPackingFactor+1)+getMass(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.ResourceContainer#getMaxCargoVolume() + */ + @Override + public double getMaxCargoVolume() { + return GlobalParameters.getRoundedVolume((maxVolume-getVolume())/(volumePackingFactor+1)); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.ResourceContainer#setMaxCargoVolume(double) + */ + @Override + public void setMaxCargoVolume(double maxCargoVolume) { + maxVolume = maxCargoVolume*(volumePackingFactor+1)+getVolume(); + } + + /** + * Gets the mass packing factor. + * + * @return the mass packing factor + */ + public double getMassPackingFactor() { + return massPackingFactor; + } + + /** + * Sets the mass packing factor. + * + * @param massPackingFactor the mass packing factor + */ + public void setMassPackingFactor(double massPackingFactor) { + this.massPackingFactor = massPackingFactor; + } + + /** + * Gets the volume packing factor. + * + * @return the volume packing factor + */ + public double getVolumePackingFactor() { + return volumePackingFactor; + } + + /** + * Sets the volume packing factor. + * + * @param volumePackingFactor the volume packing factor + */ + public void setVolumePackingFactor(double volumePackingFactor) { + this.volumePackingFactor = volumePackingFactor; + } + + /** + * Gets the maximum container mass. + * + * @return the maximum mass (kilograms) + */ + public double getMaxMass() { + return GlobalParameters.getRoundedMass(maxMass); + } + + /** + * Sets the maximum container mass. + * + * @param maxMass the maximum mass (kilograms) + */ + public void setMaxMass(double maxMass) { + this.maxMass = maxMass; + } + + /** + * Gets the maximum container volume. + * + * @return the maximum container volume (cubic meters) + */ + public double getMaxVolume() { + return GlobalParameters.getRoundedVolume(maxVolume); + } + + /** + * Sets the maximum container volume. + * + * @param maxVolume the maximum container volume (cubic meters) + */ + public void setMaxVolume(double maxVolume) { + this.maxVolume = maxVolume; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/element/I_Agent.java b/src/main/java/edu/mit/spacenet/domain/element/I_Agent.java new file mode 100644 index 0000000..f230bbc --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/I_Agent.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +/** + * The I_Agent interface is reserved for future development to represent + * elements that can perform tasks (i.e. human agents and robotic agents). + * + * @author Paul Grogan + */ +public interface I_Agent extends I_Element { + +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/I_Carrier.java b/src/main/java/edu/mit/spacenet/domain/element/I_Carrier.java new file mode 100644 index 0000000..10a9953 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/I_Carrier.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.I_Container; + +/** + * The I_Carrier interface represents objects that implement both the I_Element + * and the I_Container interfaces (that is, elements that can contain other + * elements). + * + * @author Paul Grogan + */ +public interface I_Carrier extends I_Element, I_Container { + + /** + * Gets the cargo environment. + * + * @return the cargo environment + */ + public Environment getCargoEnvironment(); + + /** + * Sets the cargo environment. + * + * @param cargoEnvironment the cargo environment + */ + public void setCargoEnvironment(Environment cargoEnvironment); + + /** + * Gets the maximum cargo mass. + * + * @return the maximum cargo mass (kilograms) + */ + public double getMaxCargoMass(); + + /** + * Sets the maximum cargo mass. + * + * @param maxCargoMass the maximum cargo mass (kilograms) + */ + public void setMaxCargoMass(double maxCargoMass); + + /** + * Gets the maximum cargo volume. + * + * @return the maximum volume (cubic meters) + */ + public double getMaxCargoVolume(); + + /** + * Sets the maximum cargo volume. + * + * @param maxCargoVolume the maximum volume (cubic meters) + */ + public void setMaxCargoVolume(double maxCargoVolume); + + /** + * Gets the maximum crew size. + * + * @return the maximum crew size + */ + public int getMaxCrewSize(); + + /** + * Sets the maximum crew size. + * + * @param maxCrewSize the maximum crew size + */ + public void setMaxCrewSize(int maxCrewSize); +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/I_Element.java b/src/main/java/edu/mit/spacenet/domain/element/I_Element.java new file mode 100644 index 0000000..e35551f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/I_Element.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import java.util.SortedSet; + +import javax.swing.ImageIcon; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.I_DomainObject; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * The I_Element interface represents the elements of the simulation. + * + * @author Paul Grogan + */ +public interface I_Element extends I_DomainObject, Comparable { + + /** + * Gets the class of supply. + * + * @return the class of supply + */ + public ClassOfSupply getClassOfSupply(); + + /** + * Sets the class of supply. + * + * @param classOfSupply the class of supply + */ + public void setClassOfSupply(ClassOfSupply classOfSupply); + + /** + * Gets the element environment. + * + * @return the environment + */ + public Environment getEnvironment(); + + /** + * Sets the element environment. + * + * @param environment the environment + */ + public void setEnvironment(Environment environment); + + /** + * Gets the mass of the element. + * + * @return the mass (kilograms) + */ + public double getMass(); + + /** + * Sets the mass of the element. + * + * @param mass the mass (kilograms) + */ + public void setMass(double mass); + + /** + * Gets the mass of the element and any nested resources. + * + * @return the total mass of the element and any nested elements + * (kilograms) + */ + public double getTotalMass(); + + /** + * Get the total mass of all contained resources of the specified class of + * supply. + * + * @param cos the class of supply + * + * @return the total mass of all resources + */ + public double getTotalMass(ClassOfSupply cos); + + /** + * Gets the volume of the element. + * + * @return the volume (cubic meters) + */ + public double getVolume(); + + /** + * Sets the volume of the element. + * + * @param volume the volume (cubic meters) + */ + public void setVolume(double volume); + + /** + * Gets the total volume of the element. + * + * @return the total volume (cubic meters) + */ + public double getTotalVolume(); + + /** + * Gets the container that this element resides in. + * + * @return the element's container + */ + public I_Container getContainer(); + + /** + * Sets the container that this element resides in. + * + * @param container the element's container + */ + public void setContainer(I_Container container); + + /** + * Gets the location (node or edge) for this element. + * + * @return the location + */ + public Location getLocation(); + + /** + * Gets whether this element is nested at some level inside a given + * container. + * + * @param container the container to look inside + * + * @return if this element is nested inside + */ + public boolean isInside(I_Container container); + + /** + * Generates the set of aggregate demands from the element's active state + * for the specified duration (in days). + * + * @param duration the duration (in days) to generate for + * @param simulator the simulator requesting the demands + * + * @return the aggregated set of demands + */ + public DemandSet generateDemands(double duration, I_Simulator simulator); + + /** + * Request the element to satisfy the given demands (may be passed to nested + * elements). + * + * @param demands the demands to be satisfied + * @param simulator the simulator requesting the demand satisfaction + */ + void satisfyDemands(DemandSet demands, I_Simulator simulator); + + /** + * Gets the set of part applications. + * + * @return the set of part applications + */ + public SortedSet getParts(); + + /** + * Sets the set of part applications. + * + * @param parts the set of part applications + */ + public void setParts(SortedSet parts); + + /** + * Gets the set of states. + * + * @return the set of states + */ + public SortedSet getStates(); + + /** + * Sets the set of states. + * + * @param states the set of states + */ + public void setStates(SortedSet states); + + /** + * Gets the current state. + * + * @return the current state + */ + public I_State getCurrentState(); + + /** + * Sets the current state. + * + * @param newState the current state. + * + * @return true if successful, false otherwise + */ + public boolean setCurrentState(I_State newState); + + /** + * Gets the amount of additional COS5 required to secure this element when + * being placed inside a carrier. + * + * @return the accommodation mass + */ + public double getAccommodationMass(); + + /** + * Sets the amount of additional COS5 required to secure this element when + * being placed inside a carrier. + * + * @param mass the accommodation mass + */ + public void setAccommodationMass(double mass); + + /** + * Gets the element type. + * + * @return the element type + */ + public ElementType getElementType(); + + /** + * Gets the icon representation of the element. Returns a default icon + * based on element type if no icon is previously set. + * + * @return the element icon + */ + public ImageIcon getIcon(); + + /** + * Gets the icon type. + * + * @return the icon type + */ + public ElementIcon getIconType(); + + /** + * Sets the icon type. + * + * @param iconType the new icon type + */ + public void setIconType(ElementIcon iconType); +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/I_ResourceContainer.java b/src/main/java/edu/mit/spacenet/domain/element/I_ResourceContainer.java new file mode 100644 index 0000000..6555f19 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/I_ResourceContainer.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import java.util.SortedMap; + +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.resource.I_Resource; + +/** + * The I_ResourceContainer represents elements that can contain resources. + * + * @author Paul Grogan + */ +public interface I_ResourceContainer extends I_Element { + + /** + * Determines if the resource can be added. + * + * @param resource the resource to add + * @param amount the amount to add + * + * @return true if it can be added, false otherwise + */ + public boolean canAdd(I_Resource resource, double amount); + + /** + * Attempts to add an amount of a resource to the container. + * + * @param resource the resource to add + * @param amount the amount to add + * + * @return true if successful, false otherwise + */ + public boolean add(I_Resource resource, double amount); + + /** + * Attempts to remove an amount of a resource from the container. + * + * @param resource the resource to remove + * @param amount the amount to remove + * + * @return true if successful, false otherwise + */ + public boolean remove(I_Resource resource, double amount); + + /** + * Gets the cargo environment. + * + * @return the cargo environment + */ + public Environment getCargoEnvironment(); + + /** + * Sets the cargo environment. + * + * @param cargoEnvironment the cargo environment + */ + public void setCargoEnvironment(Environment cargoEnvironment); + + /** + * Gets the maximum cargo mass. + * + * @return the maximum cargo mass (kilograms) + */ + public double getMaxCargoMass(); + + /** + * Sets the maximum cargo mass. + * + * @param maxCargoMass the maximum cargo mass (kilograms) + */ + public void setMaxCargoMass(double maxCargoMass); + + /** + * Gets the maximum cargo volume. + * + * @return the maximum volume (cubic meters) + */ + public double getMaxCargoVolume(); + + /** + * Sets the maximum cargo volume. + * + * @param maxCargoVolume the maximum volume (cubic meters) + */ + public void setMaxCargoVolume(double maxCargoVolume); + + /** + * Gets the total volume of cargo items. + * + * @return the cargo volume (cubic meters) + */ + public double getCargoVolume() ; + + /** + * Gets the total mass of cargo items. + * + * @return the cargo mass (kilograms) + */ + public double getCargoMass(); + + /** + * Gets the contents of the container. + * + * @return the contents + */ + public SortedMap getContents(); +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/I_State.java b/src/main/java/edu/mit/spacenet/domain/element/I_State.java new file mode 100644 index 0000000..ba09d04 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/I_State.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import java.util.SortedSet; + +import edu.mit.spacenet.domain.I_DomainType; +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * The I_State interface represents an element's operational state, which + * contains a set of demand models (to drive demands) and a duty cycle. + * + * @author Paul Grogan + */ +public interface I_State extends I_DomainType, Comparable { + + /** + * Gets the state type. + * + * @return the state type + */ + public StateType getStateType(); + + /** + * Sets the state type. + * + * @param stateType the state type + */ + public void setStateType(StateType stateType); + + /** + * Gets the set of demand models. + * + * @return the set of demand models + */ + public SortedSet getDemandModels(); + + /** + * Sets the set of demand models. + * + * @param demandModels the set of demand models + */ + public void setDemandModels(SortedSet demandModels); + + /** + * Generates the set of aggregate demands from the demand models for a + * specified duration (in days). + * + * @param duration the duration (in days) to generate for + * @param simulator the simulator requesting the demands + * + * @return the aggregated set of demands + */ + public DemandSet generateDemands(double duration, I_Simulator simulator); +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/PartApplication.java b/src/main/java/edu/mit/spacenet/domain/element/PartApplication.java new file mode 100644 index 0000000..8458db4 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/PartApplication.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import edu.mit.spacenet.domain.DomainType; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Defines a relationship between an element and a a part object that includes + * several modifying quantities. + * + * @author Paul Grogan + */ +public class PartApplication extends DomainType implements Comparable { + private Item partType; + private double meanTimeToFailure; + private double meanTimeToRepair; + private double massToRepair; + private double quantity; + private double dutyCycle; + + /** + * Default constructor sets the mean time to failure to 0, the mean time to + * repair to 0, the quantity to 1, and the duty cycle to 1. + */ + public PartApplication() { + super(); + partType = new Item(); + setMeanTimeToFailure(0); + setMeanTimeToRepair(0); + setQuantity(1); + setDutyCycle(1); + } + + /** + * Gets the part. + * + * @return the part + */ + public I_Item getPart() { + return partType; + } + + /** + * Sets the part. + * + * @param partType the part type + */ + public void setPart(Item partType) { + this.partType = partType; + } + + /** + * Gets the unit mean time to repair. + * + * @return the unit mean time to repair (hours per kilogram) + */ + public double getUnitMeanTimeToRepair() { + return getMeanTimeToRepair()/partType.getUnitMass(); + } + + /** + * Gets the mean time to failure. + * + * @return the mean time to failure (hours), does not fail if = 0 + */ + public double getMeanTimeToFailure() { + return meanTimeToFailure; + } + + /** + * Sets the mean time to failure. + * + * @param meanTimeToFailure the mean time to failure (hours), does not fail + * if < 0 + */ + public void setMeanTimeToFailure(double meanTimeToFailure) { + this.meanTimeToFailure = meanTimeToFailure; + } + + /** + * Gets the mean time to repair the part. + * + * @return the mean time to repair (hours), not repairable if = 0 + */ + public double getMeanTimeToRepair() { + return meanTimeToRepair; + } + + /** + * Sets the mean time required to repair the part. + * + * @param meanTimeToRepair the mean time to repair(hours), not repairable + * if < 0 + */ + public void setMeanTimeToRepair(double meanTimeToRepair) { + this.meanTimeToRepair = meanTimeToRepair; + } + + /** + * Gets the mass of generic COS 4 required to perform a repair. + * + * @return the mass required to repair (kilograms) + */ + public double getMassToRepair() { + return massToRepair; + } + + /** + * Sets the mass of generic COS 4 required to perform a repair. + * + * @param massToRepair the mass required to repair (kilograms) + */ + public void setMassToRepair(double massToRepair) { + this.massToRepair = massToRepair; + } + + /** + * Gets the duty cycle. + * + * @return the duty cycle (percent) + */ + public double getDutyCycle() { + return dutyCycle; + } + + /** + * Sets the duty cycle. + * + * @param dutyCycle the duty cycle (percent) + */ + public void setDutyCycle(double dutyCycle) { + this.dutyCycle = dutyCycle; + } + + /** + * Gets the quantity. + * + * @return the quantity of parts + */ + public double getQuantity() { + return quantity; + } + + /** + * Sets the quantity. + * + * @param quantity the quantity of parts + */ + public void setQuantity(double quantity) { + this.quantity = GlobalParameters.getRoundedDemand(quantity); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(PartApplication partApplication) { + if(getPart() == null) { + if(partApplication.getPart() == null) return 0; + else return -1; + } else { + return getPart().compareTo(partApplication.getPart()); + } + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return partType + " (" + ((int)getQuantity()) + ")"; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/PropulsiveVehicle.java b/src/main/java/edu/mit/spacenet/domain/element/PropulsiveVehicle.java new file mode 100644 index 0000000..3449552 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/PropulsiveVehicle.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A vehicle that is characterized by having one, either, or both OMS impulsive + * burns and RCS impulsive burns capabilities. + * + * @author Paul Grogan + */ +public class PropulsiveVehicle extends Carrier { + private double omsIsp, rcsIsp; + private ResourceTank omsFuelTank, rcsFuelTank; + + /** + * The default constructor that initializes the OMS and RCS resource + * containers. + */ + public PropulsiveVehicle() { + super(); + omsFuelTank = new ResourceTank(); + omsFuelTank.setName(getName() + " OMS Fuel Tank"); + omsFuelTank.setContainer(this); + rcsFuelTank = new ResourceTank(); + rcsFuelTank.setName(getName() + " RCS Fuel Tank"); + rcsFuelTank.setContainer(this); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#setName(java.lang.String) + */ + @Override + public void setName(String name) { + super.setName(name); + if(omsFuelTank!=null) + omsFuelTank.setName(getName() + " OMS Fuel Tank"); + if(rcsFuelTank!=null && rcsFuelTank!=omsFuelTank) + rcsFuelTank.setName(getName() + " RCS Fuel Tank"); + } + + /** + * Gets the Isp (specific impulse) of the OMS engine. + * + * @return the OMS Isp (seconds) + */ + public double getOmsIsp() { + return omsIsp; + } + + /** + * Sets the Isp (specific impulse) of the OMS engine. + * + * @param omsIsp the OMS Isp (seconds) + */ + public void setOmsIsp(double omsIsp) { + this.omsIsp = omsIsp; + } + + /** + * Gets the resource container representing the OMS fuel tank. + * + * @return the OMS fuel tank resource container + */ + public ResourceTank getOmsFuelTank() { + return omsFuelTank; + } + + /** + * Sets the resource container representing the OMS fuel tank. + * + * @param omsFuelTank the OMS fuel tank resource container + */ + public void setOmsFuelTank(ResourceTank omsFuelTank) { + this.omsFuelTank = omsFuelTank; + if(omsFuelTank!=null) { + omsFuelTank.setName(getName() + " OMS Fuel Tank"); + omsFuelTank.setContainer(this); + } + } + + /** + * Gets the Isp (specific impulse) of the RCS engine. + * + * @return the RCS Isp (seconds) + */ + public double getRcsIsp() { + return rcsIsp; + } + + /** + * Sets the Isp (specific impulse) of the RCS engine. + * + * @param rcsIsp the RCS Isp (seconds) + */ + public void setRcsIsp(double rcsIsp) { + this.rcsIsp = rcsIsp; + } + + /** + * Gets the resource container representing the RCS fuel tank. + * + * @return the RCS fuel tank resource container + */ + public ResourceTank getRcsFuelTank() { + return rcsFuelTank; + } + + /** + * Sets the resource container representing the RCS fuel tank. + * + * @param rcsFuelTank the RCS fuel tank resource container + */ + public void setRcsFuelTank(ResourceTank rcsFuelTank) { + this.rcsFuelTank = rcsFuelTank; + if(rcsFuelTank!=null && rcsFuelTank!=omsFuelTank) { + rcsFuelTank.setName(getName() + " RCS Fuel Tank"); + rcsFuelTank.setContainer(this); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#getTotalMass() + */ + @Override + public double getTotalMass() { + double mass = super.getTotalMass(); + if(omsFuelTank != null) + mass += omsFuelTank.getTotalMass(); + if(rcsFuelTank != null && rcsFuelTank != omsFuelTank) + mass += rcsFuelTank.getTotalMass(); + return GlobalParameters.getRoundedMass(mass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#getTotalMass(edu.mit.spacenet.domain.ClassOfSupply) + */ + @Override + public double getTotalMass(ClassOfSupply cos) { + double amount = super.getTotalMass(cos); + if(getOmsFuelTank()!=null) + amount += getOmsFuelTank().getTotalMass(cos); + if(getRcsFuelTank() != null && getRcsFuelTank()!=getOmsFuelTank()) + amount += getRcsFuelTank().getTotalMass(cos); + return GlobalParameters.getRoundedMass(amount); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + if(omsFuelTank != null) + omsFuelTank.print(tabOrder+1); + if(rcsFuelTank != null && rcsFuelTank != omsFuelTank) + rcsFuelTank.print(tabOrder+1); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#satisfyDemands(edu.mit.spacenet.domain.resource.DemandSet, edu.mit.spacenet.simulator.I_Simulator) + */ + @Override + public void satisfyDemands(DemandSet demands, I_Simulator simulator) { + if(omsFuelTank != null) + omsFuelTank.satisfyDemands(demands, simulator); + if(rcsFuelTank != null && rcsFuelTank != omsFuelTank) + rcsFuelTank.satisfyDemands(demands, simulator); + super.satisfyDemands(demands, simulator); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#getElementType() + */ + @Override + public ElementType getElementType() { + return ElementType.PROPULSIVE_VEHICLE; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/ResourceContainer.java b/src/main/java/edu/mit/spacenet/domain/element/ResourceContainer.java new file mode 100644 index 0000000..47240b5 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/ResourceContainer.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import java.util.SortedMap; +import java.util.TreeMap; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * An element that can hold many types of continuous resources up to set + * mass, volume, and environment constraints (volume and environment can be + * disabled via global parameters). + * + * @author Paul Grogan + */ +public class ResourceContainer extends Element implements I_ResourceContainer { + private double maxCargoMass, maxCargoVolume; + private Environment cargoEnvironment; + protected SortedMap contents; + + /** + * Instantiates a new resource container. + */ + public ResourceContainer() { + super(); + setCargoEnvironment(Environment.UNPRESSURIZED); + setClassOfSupply(ClassOfSupply.COS501); + contents = new TreeMap(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#canAdd(edu.mit.spacenet.domain.resource.I_Resource, double) + */ + public boolean canAdd(I_Resource resource, double amount) { + if(getCargoMass() + resource.getUnitMass()*amount - maxCargoMass > GlobalParameters.getMassPrecision()/2d) { + return false; // mass constrained + } else if(GlobalParameters.isVolumeConstrained() + && getCargoVolume() + resource.getUnitVolume()*amount - maxCargoVolume > GlobalParameters.getVolumePrecision()/2d) { + return false; // volume constrained + } else if(GlobalParameters.isEnvironmentConstrained() + && resource.getEnvironment().equals(Environment.PRESSURIZED) + && getCargoEnvironment().equals(Environment.UNPRESSURIZED)) { + return false; // environment constrained + } else return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#add(edu.mit.spacenet.domain.resource.I_Resource, double) + */ + public boolean add(I_Resource resource, double amount) { + if(canAdd(resource, amount)) { + if(contents.keySet().contains(resource)) { + double q = contents.get(resource); + contents.put(resource, q+amount); + } else { + contents.put(resource, amount); + } + return true; + } else return false; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#remove(edu.mit.spacenet.domain.resource.I_Resource, double) + */ + public boolean remove(I_Resource resource, double amount) { + if(contents.keySet().contains(resource) + && contents.get(resource) > amount) { + double q = contents.get(resource); + contents.put(resource, q-amount); + return true; + } else if(contents.keySet().contains(resource) + && contents.get(resource) == amount) { + contents.remove(resource); + return true; + } else return false; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getCargoEnvironment() + */ + public Environment getCargoEnvironment() { + return cargoEnvironment; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#setCargoEnvironment(edu.mit.spacenet.domain.Environment) + */ + public void setCargoEnvironment(Environment cargoEnvironment) { + this.cargoEnvironment = cargoEnvironment; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getMaxCargoMass() + */ + public double getMaxCargoMass() { + return GlobalParameters.getRoundedMass(maxCargoMass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#setMaxCargoMass(double) + */ + public void setMaxCargoMass(double maxCargoMass) { + this.maxCargoMass = maxCargoMass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getMaxCargoVolume() + */ + public double getMaxCargoVolume() { + return GlobalParameters.getRoundedVolume(maxCargoVolume); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#setMaxCargoVolume(double) + */ + public void setMaxCargoVolume(double maxCargoVolume) { + this.maxCargoVolume = maxCargoVolume; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getCargoVolume() + */ + public double getCargoVolume() { + double volume = 0; + for(I_Resource r : contents.keySet()) { + volume += r.getUnitVolume()*contents.get(r); + } + return GlobalParameters.getRoundedVolume(volume); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getCargoMass() + */ + public double getCargoMass() { + double mass = 0; + for(I_Resource r : contents.keySet()) { + mass += r.getUnitMass()*contents.get(r); + } + return GlobalParameters.getRoundedMass(mass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getContents() + */ + public SortedMap getContents() { + return contents; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getTotalMass() + */ + @Override + public double getTotalMass() { + return GlobalParameters.getRoundedMass(super.getTotalMass() + getCargoMass()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getTotalMass(edu.mit.spacenet.domain.ClassOfSupply) + */ + @Override + public double getTotalMass(ClassOfSupply cos) { + double amount = super.getTotalMass(cos); + + for(I_Resource resource : getContents().keySet()) { + if(resource.getClassOfSupply().isInstanceOf(cos)) { + amount += getContents().get(resource)*resource.getUnitMass(); + } + } + + return GlobalParameters.getRoundedMass(amount); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + for(I_Resource r : contents.keySet()) { + r.print(tabOrder + 1); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#satisfyDemands(edu.mit.spacenet.domain.resource.DemandSet, edu.mit.spacenet.simulator.I_Simulator) + */ + @Override + public void satisfyDemands(DemandSet demands, I_Simulator simulator) { + super.satisfyDemands(demands, simulator); + for(Demand demand : demands) { + if(demand.getAmount() > 0) { // consumption + for(I_Resource resource : contents.keySet()) { + if(resource.isSubstitutableFor(demand.getResource())) { + if(demand.getAmount() >= contents.get(resource)) { + // don't consume science demands! + demand.setAmount(demand.getAmount() - contents.get(resource)); + if(!demand.getResource().getClassOfSupply().isInstanceOf(ClassOfSupply.COS6)) + contents.put(resource,0d); + } else { + // don't consume science demands! + if(!demand.getResource().getClassOfSupply().isInstanceOf(ClassOfSupply.COS6)) + contents.put(resource, contents.get(resource)-demand.getAmount()); + demand.setAmount(0); + break; + } + } + } + } else { // production + //TODO need to check for resource compatibility (e.g. water in water tanks) + boolean containsResource = false; + for(I_Resource resource : contents.keySet()) if(resource.equals(demand.getResource())) containsResource = true; + if(!containsResource) contents.put(demand.getResource(), 0d); + for(I_Resource resource : contents.keySet()) { + if(resource.equals(demand.getResource())) { + containsResource = true; + if(-demand.getAmount() > getMaxCargoMass() - getCargoMass()) { + demand.setAmount(demand.getAmount() + (getMaxCargoMass() - getCargoMass())); + contents.put(resource, contents.get(resource) + getMaxCargoMass() - getCargoMass()); + } else { + contents.put(resource, contents.get(resource) + -demand.getAmount()); + demand.setAmount(0); + } + } + } + } + } + demands.clean(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getElementType() + */ + @Override + public ElementType getElementType() { + return ElementType.RESOURCE_CONTAINER; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/element/ResourceContainerFactory.java b/src/main/java/edu/mit/spacenet/domain/element/ResourceContainerFactory.java new file mode 100644 index 0000000..014ec9f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/ResourceContainerFactory.java @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import edu.mit.spacenet.domain.Environment; + +/** + * Class which is used to build the "default" resource containers used in + * auto-packing and auto-manifesting. + * + * @author Paul Grogan + */ +public abstract class ResourceContainerFactory { + + /** The Constant DCTB_TID. */ + public static final int DCTB_TID = -22; + + /** The Constant DCTB_MAX_MASS. */ + public static final double DCTB_MAX_MASS = 90.72; + + /** The Constant DCTB_MAX_VOLUME. */ + public static final double DCTB_MAX_VOLUME = 0.1058; + + /** + * Creates a new double cargo transfer bag (DCTB). + * + * @return the cargo transfer bag + */ + public static ResourceContainer createDCTB() { + // double cargo transfer bag + ResourceContainer ctb = new ResourceContainer(); + ctb.setTid(DCTB_TID); + ctb.setMass(3.62); + ctb.setMaxCargoMass(DCTB_MAX_MASS); + ctb.setVolume(0.1058); + ctb.setMaxCargoVolume(DCTB_MAX_VOLUME); + + ctb.setName("DCTB " + ctb.getUid()); + return ctb; + } + + + /** The Constant CTB_TID. */ + public static final int CTB_TID = -10; + + /** The Constant CTB_MAX_MASS. */ + public static final double CTB_MAX_MASS = 45.36; + + /** The Constant CTB_MAX_VOLUME. */ + public static final double CTB_MAX_VOLUME = 0.0529; + + /** + * Creates a cargo transfer bag (CTB). + * + * @return the cargo transfer bag + */ + public static ResourceContainer createCTB() { + // cargo transfer bag + ResourceContainer ctb = new ResourceContainer(); + ctb.setTid(CTB_TID); + ctb.setMass(1.81); + ctb.setMaxCargoMass(CTB_MAX_MASS); + ctb.setVolume(0.0529); + ctb.setMaxCargoVolume(CTB_MAX_VOLUME); + + ctb.setName("CTB " + ctb.getUid()); + return ctb; + } + + /** The Constant HCTB_TID. */ + public static final int HCTB_TID = -11; + + /** The Constant HCTB_MAX_MASS. */ + public static final double HCTB_MAX_MASS = 27.22; + + /** The Constant HCTB_MAX_VOLUME. */ + public static final double HCTB_MAX_VOLUME = 0.0248; + + /** + * Creates a half-size cargo transfer bag (CTB). + * + * @return the half cargo transfer bag + */ + public static ResourceContainer createHCTB() { + // half cargo transfer bag + ResourceContainer ctb = new ResourceContainer(); + ctb.setTid(HCTB_TID); + ctb.setMass(1); + ctb.setMaxCargoMass(HCTB_MAX_MASS); + ctb.setVolume(0.0248); + ctb.setMaxCargoVolume(HCTB_MAX_VOLUME); + + ctb.setName("Half CTB " + ctb.getUid()); + return ctb; + } + + /** The Constant CWC_TID. */ + public static final int CWC_TID = -12; + + /** + * Creates a contingency water container (CWC). + * + * @return the contingency water container + */ + public static ResourceContainer createCWC() { + // contingency water container + ResourceContainer cwc = new ResourceContainer(); + cwc.setTid(CWC_TID); + cwc.setMass(1.361); + cwc.setMaxCargoMass(32.8); + cwc.setVolume(0.0328); + cwc.setMaxCargoVolume(0.0328); + + cwc.setName("Contingency Water Container " + cwc.getUid()); + return cwc; + } + + /** The Constant LT_TID. */ + public static final int LT_TID = -13; + + /** The Constant LT_MAX_MASS. */ + public static final double LT_MAX_MASS = 74.8; + + /** The Constant LT_MAX_VOLUME. */ + public static final double LT_MAX_VOLUME = 0.0748; + + /** + * Creates a liquid tank (LT). + * + * @return the liquid tank + */ + public static ResourceContainer createLT() { + // liquid tank + ResourceContainer lt = new ResourceContainer(); + lt.setTid(LT_TID); + lt.setMass(34.37); + lt.setMaxCargoMass(LT_MAX_MASS); + lt.setVolume(0.0748); + lt.setMaxCargoVolume(LT_MAX_VOLUME); + + lt.setName("Liquid Tank " + lt.getUid()); + return lt; + } + + /** The Constant LTD_TID. */ + public static final int LTD_TID = -14; + + /** The Constant LTD_MAX_MASS. */ + public static final double LTD_MAX_MASS = 24.9333; + + /** The Constant LTD_MAX_VOLUME. */ + public static final double LTD_MAX_VOLUME = 0.0249; + + /** + * Creates a derivative liquid tank (LT). + * + * @return the liquid tank + */ + public static ResourceContainer createLTD() { + // liquid tank derivative + ResourceContainer ltd = new ResourceContainer(); + ltd.setTid(LTD_TID); + ltd.setMass(11.4567); + ltd.setMaxCargoMass(LTD_MAX_MASS); + ltd.setVolume(0.0249); + ltd.setMaxCargoVolume(LTD_MAX_VOLUME); + + ltd.setName("Liquid Tank Derivative " + ltd.getUid()); + return ltd; + } + + /** The Constant SHOSS_TID. */ + public static final int SHOSS_TID = -15; + + /** The Constant SHOSS_MAX_MASS. */ + public static final double SHOSS_MAX_MASS = 200; + + /** The Constant SHOSS_MAX_VOLUME. */ + public static final double SHOSS_MAX_VOLUME = 0.4444; + + /** + * Creates a SHOSS box. + * + * @return the SHOSS box + */ + public static ResourceContainer createShoss() { + // shoss box + ResourceContainer shoss = new ResourceContainer(); + shoss.setTid(SHOSS_TID); + shoss.setMass(120); + shoss.setMaxCargoMass(SHOSS_MAX_MASS); + shoss.setVolume(0.4444); + shoss.setMaxCargoVolume(SHOSS_MAX_VOLUME); + + shoss.setName("Shoss " + shoss.getUid()); + return shoss; + } + + /** The Constant PSHOSS_TID. */ + public static final int PSHOSS_TID = -16; + + /** The Constant PSHOSS_MAX_MASS. */ + public static final double PSHOSS_MAX_MASS = 200; + + /** The Constant PSHOSS_MAX_VOLUME. */ + public static final double PSHOSS_MAX_VOLUME = 0.8; + + /** + * Creates a pressurized SHOSS box. + * + * @return the pressurized SHOSS box + */ + public static ResourceContainer createPressShoss() { + // pressurized shoss box + ResourceContainer pshoss = new ResourceContainer(); + pshoss.setTid(PSHOSS_TID); + pshoss.setMass(0); + pshoss.setMaxCargoMass(PSHOSS_MAX_MASS); + pshoss.setVolume(0.8); + pshoss.setMaxCargoVolume(PSHOSS_MAX_VOLUME); + + pshoss.setName("Press. Shoss " + pshoss.getUid()); + pshoss.setCargoEnvironment(Environment.PRESSURIZED); + return pshoss; + } + + /** The Constant GT_TID. */ + public static final int GT_TID = -17; + + /** The Constant GT_MAX_MASS. */ + public static final double GT_MAX_MASS = 100; + + /** The Constant GT_MAX_VOLUME. */ + public static final double GT_MAX_VOLUME = 2.75; + + /** + * Creates a gas tank (GT). + * + * @return the gas tank + */ + public static ResourceContainer createGT() { + // gas tank + ResourceContainer gt = new ResourceContainer(); + gt.setTid(GT_TID); + gt.setMass(108); + gt.setMaxCargoMass(GT_MAX_MASS); + gt.setVolume(2.75); + gt.setMaxCargoVolume(GT_MAX_VOLUME); + + gt.setName("Gas Tank " + gt.getUid()); + return gt; + } + + /** The Constant GTD_TID. */ + public static final int GTD_TID = -17; + + /** The Constant GTD_MAX_MASS. */ + public static final double GTD_MAX_MASS = 10; + + /** The Constant GTD_MAX_VOLUME. */ + public static final double GTD_MAX_VOLUME = 0.275; + + /** + * Creates a derivative gas tank (GT). + * + * @return the derivative gas tank + */ + public static ResourceContainer createGTD() { + // gas tank derivative + ResourceContainer gtd = new ResourceContainer(); + gtd.setTid(GTD_TID); + gtd.setMass(10.8); + gtd.setMaxCargoMass(GTD_MAX_MASS); + gtd.setVolume(0.275); + gtd.setMaxCargoVolume(GTD_MAX_VOLUME); + + gtd.setName("Gas Tank Derivative " + gtd.getUid()); + return gtd; + } + + /** The Constant O2T_TID. */ + public static final int O2T_TID = -18; + + /** + * Creates an oxygen tank (O2T). + * + * @return the oxygen tank + */ + public static ResourceContainer createO2T() { + // oxygen tank + ResourceContainer o2t = new ResourceContainer(); + o2t.setTid(O2T_TID); + o2t.setMass(108); + o2t.setMaxCargoMass(108.9); + o2t.setVolume(2.75); + o2t.setMaxCargoVolume(2.275); + + o2t.setName("O2 Tank " + o2t.getUid()); + return o2t; + } + + /** The Constant O2TD_TID. */ + public static final int O2TD_TID = -19; + + /** + * Creates a derivative oxygen tank (O2T). + * + * @return the derivative oxygen tank + */ + public static ResourceContainer createO2TD() { + // oxygen tank derivative + ResourceContainer o2td = new ResourceContainer(); + o2td.setTid(O2TD_TID); + o2td.setMass(10.8); + o2td.setMaxCargoMass(10.89); + o2td.setVolume(0.275); + o2td.setMaxCargoVolume(0.275); + + o2td.setName("O2 Tank Derivative " + o2td.getUid()); + return o2td; + } + + /** The Constant N2T_TID. */ + public static final int N2T_TID = -20; + + /** + * Creats a nitrogen tank (N2T). + * + * @return the nitrogen tank + */ + public static ResourceContainer createN2T() { + // nitrogen tank + ResourceContainer n2t = new ResourceContainer(); + n2t.setTid(N2T_TID); + n2t.setMass(108); + n2t.setMaxCargoMass(94.8); + n2t.setVolume(2.732); + n2t.setMaxCargoVolume(2.732); + + n2t.setName("N2 Tank " + n2t.getUid()); + return n2t; + } + + /** The Constant N2TD_TID. */ + public static final int N2TD_TID = -21; + + /** + * Creates a derivative nitrogen tank (N2T). + * + * @return the derivative nitrogen tank + */ + public static ResourceContainer createN2TD() { + // nitrogen tank derivative + ResourceContainer n2td = new ResourceContainer(); + n2td.setTid(N2TD_TID); + n2td.setMass(10.8); + n2td.setMaxCargoMass(9.48); + n2td.setVolume(0.2732); + n2td.setMaxCargoVolume(0.2732); + + n2td.setName("N2 Tank Derivative " + n2td.getUid()); + return n2td; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/ResourceTank.java b/src/main/java/edu/mit/spacenet/domain/element/ResourceTank.java new file mode 100644 index 0000000..0b8ebd8 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/ResourceTank.java @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + + +import java.text.DecimalFormat; +import java.util.SortedMap; +import java.util.TreeMap; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * An element that can hold at most one type of continuous resource up to a + * capacity constraint.

A resource tank is assigned a resource (which + * itself has a unit mass which could be non-zero depending on the units for + * which consumption is measured by), a current amount, and a maximum amount. + * + * @author Paul Grogan + */ +public class ResourceTank extends Element implements I_ResourceContainer { + private I_Resource resource; + private double amount; + private double maxAmount; + + /** + * The default constructor. + */ + public ResourceTank() { + super(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#canAdd(edu.mit.spacenet.domain.resource.I_Resource, double) + */ + public boolean canAdd(I_Resource resource, double amount) { + if(this.resource!=null && !this.resource.equals(resource)) return false; + else if(this.amount + amount - maxAmount > GlobalParameters.getDemandPrecision()/2d) return false; + else return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#add(edu.mit.spacenet.domain.resource.I_Resource, double) + */ + public boolean add(I_Resource resource, double amount) { + if(canAdd(resource, amount)) { + if(this.resource==null) { + this.resource = resource; + } + this.amount += amount; + return true; + } else return false; + } + + /** + * Adds an amount of resource to the tank. + * + * @param amount the amount + * + * @return true, if successful + */ + public boolean add(double amount) { + return add(resource, amount); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#remove(edu.mit.spacenet.domain.resource.I_Resource, double) + */ + public boolean remove(I_Resource resource, double amount) { + if(this.resource==null + || !this.resource.equals(resource)) { + return false; + } else if(this.amount - amount >= 0) { + this.amount = this.amount - amount; + return true; + } else return false; + } + + /** + * Removes an amount of a resource from the tank. + * + * @param amount the amount + * + * @return true, if successful + */ + public boolean remove(double amount) { + return remove(resource, amount); + } + + /** + * Gets the contained resource. + * + * @return the contained resource + */ + public I_Resource getResource() { + return resource; + } + + /** + * Sets the contained resource. + * + * @param resource the contained resource + */ + public void setResource(I_Resource resource) { + this.resource = resource; + } + + /** + * Gets the amount of the contained resource. + * + * @return the amount of resource (units of resource consumption) + */ + public double getAmount() { + return GlobalParameters.getRoundedDemand(amount); + } + + /** + * Sets the amount of the contained resource. + * + * @param amount the amount of resource (units of resource consumption) + */ + public void setAmount(double amount) { + this.amount = amount; + } + + /** + * Gets the maximum amount of the contained resource. + * + * @return the maximum amount of resource (units of resource consumption) + */ + public double getMaxAmount() { + return GlobalParameters.getRoundedDemand(maxAmount); + } + + /** + * Sets the maximum amount of the contained resource. + * + * @param maxAmount the maximum amount of resource (units of resource + * consumption) + */ + public void setMaxAmount(double maxAmount) { + this.maxAmount = maxAmount; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getTotalMass() + */ + @Override + public double getTotalMass() { + return GlobalParameters.getRoundedMass(super.getTotalMass() + getCargoMass()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getTotalMass(edu.mit.spacenet.domain.ClassOfSupply) + */ + public double getTotalMass(ClassOfSupply cos) { + double mass = super.getTotalMass(cos); + if(resource!=null && getResource().getClassOfSupply().isInstanceOf(cos)) { + mass += getResource().getUnitMass()*getAmount(); + } + return GlobalParameters.getRoundedMass(mass); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#toString() + */ + public String toString() { + DecimalFormat format = new DecimalFormat("0.0"); + if(resource==null) + return super.toString() + " (" + format.format(getAmount()) + " / " + + format.format(getMaxAmount()) + ")"; + else + return super.toString() + " (" + format.format(getAmount()) + " / " + + format.format(getMaxAmount()) + " " + resource.getUnits() + + " " + resource + ")"; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + resource.print(tabOrder+1); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#satisfyDemands(edu.mit.spacenet.domain.resource.DemandSet, edu.mit.spacenet.simulator.I_Simulator) + */ + @Override + public void satisfyDemands(DemandSet demands, I_Simulator simulator) { + super.satisfyDemands(demands, simulator); + for(Demand demand : demands) { + if(demand.getResource().isSubstitutableFor(resource)) { + if(demand.getAmount() > 0) { // consumption + if(demand.getAmount() > amount) { + demand.setAmount(demand.getAmount() - amount); + amount = 0; + } else { + amount -= demand.getAmount(); + demand.setAmount(0); + } + } else { // production + if(-demand.getAmount() > maxAmount - amount) { + demand.setAmount(demand.getAmount() + (maxAmount - amount)); + amount = maxAmount; + } else { + amount += -demand.getAmount(); + demand.setAmount(0); + } + } + } + } + demands.clean(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getCargoEnvironment() + */ + public Environment getCargoEnvironment() { + return Environment.UNPRESSURIZED; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getCargoMass() + */ + public double getCargoMass() { + return resource==null?0:GlobalParameters.getRoundedMass(amount*resource.getUnitMass()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getCargoVolume() + */ + public double getCargoVolume() { + return resource==null?0:GlobalParameters.getRoundedVolume(amount*resource.getUnitVolume()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getMaxCargoMass() + */ + public double getMaxCargoMass() { + return resource==null?0:GlobalParameters.getRoundedMass(maxAmount*resource.getUnitMass()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getMaxCargoVolume() + */ + public double getMaxCargoVolume() { + return resource==null?0:GlobalParameters.getRoundedVolume(maxAmount*resource.getUnitVolume()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#setCargoEnvironment(edu.mit.spacenet.domain.Environment) + */ + public void setCargoEnvironment(Environment cargoEnvironment) { } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#setMaxCargoMass(double) + */ + public void setMaxCargoMass(double maxCargoMass) { + if(resource!=null) { + maxAmount=maxCargoMass/resource.getUnitMass(); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#setMaxCargoVolume(double) + */ + public void setMaxCargoVolume(double maxCargoVolume) { + if(resource!=null) { + maxAmount=maxCargoVolume/resource.getUnitVolume(); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_ResourceContainer#getContents() + */ + public SortedMap getContents() { + TreeMap contents = new TreeMap(); + contents.put(resource, amount); + return contents; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Element#getElementType() + */ + @Override + public ElementType getElementType() { + return ElementType.RESOURCE_TANK; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/element/State.java b/src/main/java/edu/mit/spacenet/domain/element/State.java new file mode 100644 index 0000000..d000c55 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/State.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.DomainType; +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * Class that defines an operational state of an element. An operational state + * is composed of a state type, one or more demand models, and an overall duty + * cycle. + * + * @author Paul Grogan + */ +public class State extends DomainType implements I_State { + private StateType stateType; + private SortedSet demandModels; + + /** + * The default constructor sets the default values for name to Default, + * state type to ACTIVE, and duty cycle to 1. It also initializes the set of + * demand models, but does not add any. + */ + public State() { + super(); + setName("Default"); + setStateType(StateType.ACTIVE); + this.demandModels = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_State#getStateType() + */ + public StateType getStateType() { + return stateType; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_State#setStateType(edu.mit.spacenet.domain.element.StateType) + */ + public void setStateType(StateType stateType) { + this.stateType = stateType; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_State#getDemandModels() + */ + public SortedSet getDemandModels() { + return demandModels; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_State#setDemandModels(java.util.SortedSet) + */ + public void setDemandModels(SortedSet demandModels) { + this.demandModels = demandModels; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.I_State#generateDemands(double, edu.mit.spacenet.simulator.I_Simulator) + */ + public DemandSet generateDemands(double duration, I_Simulator simulator) { + DemandSet demands = new DemandSet(); + for(I_DemandModel model : demandModels) { + for(Demand demand : model.generateDemands(duration, simulator)) { + demands.add(demand); + } + } + return demands; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(I_State state) { + if(getStateType().equals(state.getStateType())){ + if(getName().equals(state.getName())) { + return new Integer(getTid()).compareTo(new Integer(state.getTid())); + } else { + return getName().compareTo(state.getName()); + } + } else { + return getStateType().compareTo(state.getStateType()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#toString() + */ + @Override + public String toString() { + return getName(); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/element/StateType.java b/src/main/java/edu/mit/spacenet/domain/element/StateType.java new file mode 100644 index 0000000..603bf71 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/StateType.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + +import javax.swing.ImageIcon; + +/** + * Enumeration that defines the four operational states for elements. + * + * @author Paul Grogan + */ +public enum StateType { + + /** The active state type is used for states where the element is in a typical or nominal active condition. */ + ACTIVE("Active", "icons/clock_play.png"), + + /** The special state type is used for states where the element is in a special active condition. */ + SPECIAL("Special", "icons/clock_add.png"), + + /** The quiescent state type is used for states where the element is only operational part of the time (duty cycle < 1). */ + QUIESCENT("Quiescent", "icons/clock_pause.png"), + + /** The dormant state type is used for states where the element is operational for a small percentage of the time (duty cycle << 1). */ + DORMANT("Dormant", "icons/clock_stop.png"), + + /** The decommissioned state type is used for states where the element is not operational and will not become operational in the future. This state type is reserved for cannibalization of spare parts. */ + DECOMMISSIONED("Decommissioned", "icons/clock_red.png"); + + private String name; + private ImageIcon icon; + + private StateType(String name, String iconUrl) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } + + /** + * Gets the textual representation of the state type. + * + * @return the state type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + @Override + public String toString() { + return name; + } + + /** + * Gets the icon representation of the state type. + * + * @return the state type icon + */ + public ImageIcon getIcon() { + return icon; + } + + /** + * Method to get a particular instance of a state type based on a + * case-insensitive string. + * + * @param name case-insensitive string of name + * + * @return the state type, returns null if unmatched + */ + public static StateType getInstance(String name) { + for(StateType t : values()) { + if(t.getName().toLowerCase().equals(name.toLowerCase())) + return t; + } + return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/element/SurfaceVehicle.java b/src/main/java/edu/mit/spacenet/domain/element/SurfaceVehicle.java new file mode 100644 index 0000000..042644b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/element/SurfaceVehicle.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.element; + + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A vehicle with an assigned maximum speed and a resource container to + * represent a fuel tank. Note that unlike a propulsive vehicle, consumption of + * fuel should be handled by a demand model rather than through impulsive burns. + * + * @author Paul Grogan + */ +public class SurfaceVehicle extends Carrier { + private double maxSpeed; + private ResourceTank fuelTank; + + /** + * The default constructor that initializes the fuel tank. + */ + public SurfaceVehicle() { + super(); + fuelTank = new ResourceTank(); + fuelTank.setName(getName() + " Fuel Tank"); + fuelTank.setContainer(this); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#setName(java.lang.String) + */ + @Override + public void setName(String name) { + super.setName(name); + if(fuelTank!=null) + fuelTank.setName(getName() + " Fuel Tank"); + } + + /** + * Gets the maximum speed. + * + * @return the maximum speed (kilometers per hour) + */ + public double getMaxSpeed() { + return maxSpeed; + } + + /** + * Sets the maximum speed. + * + * @param maxSpeed the maximum speed (kilometers per hour) + */ + public void setMaxSpeed(double maxSpeed) { + this.maxSpeed = maxSpeed; + } + + /** + * Gets the fuel tank resource container. + * + * @return the fuel tank resource container + */ + public ResourceTank getFuelTank() { + return fuelTank; + } + + /** + * Sets the fuel tank resource container. + * + * @param fuelTank the fuel tank resource container + */ + public void setFuelTank(ResourceTank fuelTank) { + this.fuelTank = fuelTank; + if(fuelTank!=null) { + fuelTank.setName(getName() + " Fuel Tank"); + fuelTank.setContainer(this); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#getTotalMass() + */ + @Override + public double getTotalMass() { + return GlobalParameters.getRoundedMass(super.getTotalMass() + fuelTank.getTotalMass()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#getTotalMass(edu.mit.spacenet.domain.ClassOfSupply) + */ + @Override + public double getTotalMass(ClassOfSupply cos) { + double amount = super.getTotalMass(cos); + if(getFuelTank()!=null) amount += getFuelTank().getTotalMass(cos); + return GlobalParameters.getRoundedMass(amount); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + fuelTank.print(tabOrder+1); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#satisfyDemands(edu.mit.spacenet.domain.resource.DemandSet, edu.mit.spacenet.simulator.I_Simulator) + */ + @Override + public void satisfyDemands(DemandSet demands, I_Simulator simulator) { + fuelTank.satisfyDemands(demands, simulator); + super.satisfyDemands(demands, simulator); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.element.Carrier#getElementType() + */ + @Override + public ElementType getElementType() { + return ElementType.SURFACE_VEHICLE; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/model/AbstractDemandModel.java b/src/main/java/edu/mit/spacenet/domain/model/AbstractDemandModel.java new file mode 100644 index 0000000..922972a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/model/AbstractDemandModel.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.model; + +import edu.mit.spacenet.domain.DomainType; + +/** + * Base class for all demand models. + * + * @author Paul Grogan + */ +public abstract class AbstractDemandModel extends DomainType implements I_DemandModel { + + /** + * The default constructor that sets a default name. + */ + public AbstractDemandModel() { + setName(getDemandModelType().getName()); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(I_DemandModel demandModel) { + if(getName().equals(demandModel.getName())) { + return new Integer(getTid()).compareTo(new Integer(demandModel.getTid())); + } else { + return getName().compareTo(demandModel.getName()); + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/model/CrewConsumablesDemandModel.java b/src/main/java/edu/mit/spacenet/domain/model/CrewConsumablesDemandModel.java new file mode 100644 index 0000000..67730ff --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/model/CrewConsumablesDemandModel.java @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.model; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * A mission-level demand model that estimates the resources needed to sustain + * a crew during a mission. + */ +public class CrewConsumablesDemandModel extends AbstractDemandModel { + private Mission mission; + + private double reservesDuration, waterRecoveryRate, clothingLifetime; + private boolean transitDemandsOmitted; + private double waterRate, evaWaterRate, foodSupportRate, ambientFoodRate, + rfFoodRate, oxygenRate, evaOxygenRate, nitrogenRate, hygieneRate, + hygieneKit, clothingRate, personalItems; + private double officeEquipment, evaSuit, evaLithiumHydroxide, + healthEquipment, healthConsumables, safetyEquipment, commEquipment, + computerEquipment; + private double trashBagRate, wasteContainmentRate; + + /** + * Instantiates a new crew consumables demand model. + * + * @param mission the mission for which to generate demands + */ + public CrewConsumablesDemandModel(Mission mission) { + super(); + this.mission = mission; + setReservesDuration(0); + setWaterRecoveryRate(0.42); + setClothingLifetime(4); + resetDefaultRates(); + } + + public CrewConsumablesDemandModel() { + // TODO Auto-generated constructor stub + } + + /** + * Reset all rates to default values (based on SpaceNet 1.3). + */ + public void resetDefaultRates() { + setWaterRate(3.6); + setEvaWaterRate(0.6875); + setFoodSupportRate(0.05556); + setAmbientFoodRate(0.76389); + setRfFoodRate(1.61667); + setOxygenRate(3.85714); + setEvaOxygenRate(0.07875); + setNitrogenRate(2.21429); + setHygieneRate(0.27778); + setHygieneKit(1.8); + setClothingRate(2.3); + setPersonalItems(10); + + setOfficeEquipment(5); + setEvaSuit(107); + setEvaLithiumHydroxide(0.3625); + setHealthEquipment(20); + setHealthConsumables(0.1); + setSafetyEquipment(25); + setCommEquipment(20); + setComputerEquipment(5); + + setTrashBagRate(0.05); + setWasteContainmentRate(0.05); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.model.I_DemandModel#generateDemands(double, edu.mit.spacenet.simulator.I_Simulator) + */ + public DemandSet generateDemands(double duration, I_Simulator simulator) { + DemandSet demands = new DemandSet(); + + demands.add(new Demand(new GenericResource(ClassOfSupply.COS201), + (getMissionExplorationDuration()+getMissionTransitDuration()+getReservesDuration())*getWaterRate()*getMissionCrewSize()*(1-getWaterRecoveryRate()))); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS201), + getMissionEvaCrewTime()*getEvaWaterRate())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS202), + (getMissionExplorationDuration()+getMissionTransitDuration()+getReservesDuration())*getFoodSupportRate()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS202), + (getMissionExplorationDuration()+getMissionTransitDuration()+getReservesDuration())*getAmbientFoodRate()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS202), + (getMissionExplorationDuration()+getMissionTransitDuration()+getReservesDuration())*getRfFoodRate()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS203), + (getMissionExplorationDuration()+getMissionTransitDuration()+getReservesDuration())*getOxygenRate()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS203), + getMissionEvaCrewTime()*getEvaOxygenRate())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS203), + (getMissionExplorationDuration()+getMissionTransitDuration()+getReservesDuration())*getNitrogenRate()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS204), + (getMissionExplorationDuration()+getMissionTransitDuration()+getReservesDuration())*getHygieneRate()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS204), + getHygieneKit()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS205), + (getMissionExplorationDuration()+getMissionTransitDuration())*getClothingRate()*getMissionCrewSize()/getClothingLifetime())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS206), + getPersonalItems()*getMissionCrewSize())); + + demands.add(new Demand(new GenericResource(ClassOfSupply.COS301), + getOfficeEquipment()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS302), + getEvaSuit()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS302), + getEvaLithiumHydroxide()*getMissionEvaCrewTime())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS303), + getHealthEquipment())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS303), + getHealthConsumables()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS304), + getSafetyEquipment())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS305), + getCommEquipment())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS306), + getComputerEquipment()*getMissionCrewSize())); + + demands.add(new Demand(new GenericResource(ClassOfSupply.COS701), + (getMissionExplorationDuration()+getMissionTransitDuration())*getTrashBagRate()*getMissionCrewSize())); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS702), + (getMissionExplorationDuration()+getMissionTransitDuration()+getReservesDuration())*getWasteContainmentRate()*getMissionCrewSize())); + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.model.I_DemandModel#getDemandModelType() + */ + public DemandModelType getDemandModelType() { + return DemandModelType.CREW_CONSUMABLES; + } + + /** + * Gets the mission crew size. + * + * @return the crew size + */ + public int getMissionCrewSize() { + return mission.getCrewSize(); + } + + /** + * Gets the mission EVA crew time. + * + * @return the mission EVA crew time (crew-hour) + */ + public double getMissionEvaCrewTime() { + return mission.getEvaCrewTime(); + } + + /** + * Gets the mission exploration duration. + * + * @return the exploration duration (days) + */ + public double getMissionExplorationDuration() { + return mission.getDestinationDuration(); + } + + /** + * Gets the mission transit duration. + * + * @return the mission transit duration (days) + */ + public double getMissionTransitDuration() { + if(isTransitDemandsOmitted()) { + return 0; + } else { + return mission.getTransitDuration() + mission.getReturnTransitDuration(); + } + } + + /** + * Gets the reserves duration. + * + * @return the reserves duration (days) + */ + public double getReservesDuration() { + return reservesDuration; + } + + /** + * Sets the reserves duration. + * + * @param reservesDuration the new reserves duration (days) + */ + public void setReservesDuration(double reservesDuration) { + this.reservesDuration = reservesDuration; + } + + /** + * Gets the water recovery rate. + * + * @return the water recovery rate ([0:1]) + */ + public double getWaterRecoveryRate() { + return waterRecoveryRate; + } + + /** + * Sets the water recovery rate. + * + * @param waterRecoveryRate the new water recovery rate ([0:1]) + */ + public void setWaterRecoveryRate(double waterRecoveryRate) { + this.waterRecoveryRate = Math.max(0,Math.min(waterRecoveryRate,1)); + } + + /** + * Gets the EVA water rate. + * + * @return the EVA water rate (kilograms/crew/hour) + */ + public double getEvaWaterRate() { + return evaWaterRate; + } + + /** + * Sets the EVA water rate. + * + * @param evaWaterRate the new EVA water rate (kilograms/crew/hour) + */ + public void setEvaWaterRate(double evaWaterRate) { + this.evaWaterRate = evaWaterRate; + } + + /** + * Gets the clothing lifetime. + * + * @return the clothing lifetime (days) + */ + public double getClothingLifetime() { + return clothingLifetime; + } + + /** + * Sets the clothing lifetime (minimum 1 day). + * + * @param clothingLifetime the new clothing lifetime (days) + */ + public void setClothingLifetime(double clothingLifetime) { + this.clothingLifetime = Math.max(1, clothingLifetime); + } + + /** + * Gets the water rate. + * + * @return the water rate (kilograms/crew/day) + */ + public double getWaterRate() { + return waterRate; + } + + /** + * Sets the water rate. + * + * @param waterRate the new water rate (kilograms/crew/day) + */ + public void setWaterRate(double waterRate) { + this.waterRate = waterRate; + } + + /** + * Gets the food support rate. + * + * @return the food support rate (kilograms/crew/day) + */ + public double getFoodSupportRate() { + return foodSupportRate; + } + + /** + * Sets the food support rate. + * + * @param foodSupportRate the new food support rate (kilograms/crew/day) + */ + public void setFoodSupportRate(double foodSupportRate) { + this.foodSupportRate = foodSupportRate; + } + + /** + * Gets the ambient food rate. + * + * @return the ambient food rate (kilograms/crew/day) + */ + public double getAmbientFoodRate() { + return ambientFoodRate; + } + + /** + * Sets the ambient food rate. + * + * @param ambientFoodRate the new ambient food rate (kilograms/crew/day) + */ + public void setAmbientFoodRate(double ambientFoodRate) { + this.ambientFoodRate = ambientFoodRate; + } + + /** + * Gets the R/F food rate. + * + * @return the R/F food rate (kilograms/crew/day) + */ + public double getRfFoodRate() { + return rfFoodRate; + } + + /** + * Sets the R/F food rate. + * + * @param rfFoodRate the new R/F food rate (kilograms/crew/day) + */ + public void setRfFoodRate(double rfFoodRate) { + this.rfFoodRate = rfFoodRate; + } + + /** + * Gets the oxygen rate. + * + * @return the oxygen rate (kilograms/crew/day) + */ + public double getOxygenRate() { + return oxygenRate; + } + + /** + * Sets the oxygen rate. + * + * @param oxygenRate the new oxygen rate (kilograms/crew/day) + */ + public void setOxygenRate(double oxygenRate) { + this.oxygenRate = oxygenRate; + } + + /** + * Gets the EVA oxygen rate. + * + * @return the EVA oxygen rate (kilograms/crew/hour) + */ + public double getEvaOxygenRate() { + return evaOxygenRate; + } + + /** + * Sets the EVA oxygen rate. + * + * @param evaOxygenRate the new EVA oxygen rate (kilograms/crew/hour) + */ + public void setEvaOxygenRate(double evaOxygenRate) { + this.evaOxygenRate = evaOxygenRate; + } + + /** + * Gets the nitrogen rate. + * + * @return the nitrogen rate (kilograms/crew/day) + */ + public double getNitrogenRate() { + return nitrogenRate; + } + + /** + * Sets the nitrogen rate. + * + * @param nitrogenRate the new nitrogen rate (kilograms/crew/day) + */ + public void setNitrogenRate(double nitrogenRate) { + this.nitrogenRate = nitrogenRate; + } + + /** + * Gets the hygiene rate. + * + * @return the hygiene rate (kilograms/crew/day) + */ + public double getHygieneRate() { + return hygieneRate; + } + + /** + * Sets the hygiene rate. + * + * @param hygieneRate the new hygiene rate (kilograms/crew/day) + */ + public void setHygieneRate(double hygieneRate) { + this.hygieneRate = hygieneRate; + } + + /** + * Gets the hygiene kit. + * + * @return the hygiene kit (kilograms/crew) + */ + public double getHygieneKit() { + return hygieneKit; + } + + /** + * Sets the hygiene kit. + * + * @param hygieneKit the new hygiene kit (kilograms/crew) + */ + public void setHygieneKit(double hygieneKit) { + this.hygieneKit = hygieneKit; + } + + /** + * Gets the clothing rate. + * + * @return the clothing rate (kilograms/crew/change) + */ + public double getClothingRate() { + return clothingRate; + } + + /** + * Sets the clothing rate. + * + * @param clothingRate the new clothing rate (kilograms/crew/change) + */ + public void setClothingRate(double clothingRate) { + this.clothingRate = clothingRate; + } + + /** + * Gets the personal items. + * + * @return the personal items (kilograms/crew) + */ + public double getPersonalItems() { + return personalItems; + } + + /** + * Sets the personal items. + * + * @param personalItems the new personal items (kilograms/crew) + */ + public void setPersonalItems(double personalItems) { + this.personalItems = personalItems; + } + + /** + * Gets the office equipment. + * + * @return the office equipment (kilograms/crew) + */ + public double getOfficeEquipment() { + return officeEquipment; + } + + /** + * Sets the office equipment. + * + * @param officeEquipment the new office equipment (kilograms/crew) + */ + public void setOfficeEquipment(double officeEquipment) { + this.officeEquipment = officeEquipment; + } + + /** + * Gets the eva suit. + * + * @return the eva suit (kilograms/crew) + */ + public double getEvaSuit() { + return evaSuit; + } + + /** + * Sets the eva suit. + * + * @param evaSuit the new eva suit (kilograms/crew) + */ + public void setEvaSuit(double evaSuit) { + this.evaSuit = evaSuit; + } + + /** + * Gets the EVA lithium hydroxide. + * + * @return the EVA lithium hydroxide (kilograms/crew/hour) + */ + public double getEvaLithiumHydroxide() { + return evaLithiumHydroxide; + } + + /** + * Sets the EVA lithium hydroxide. + * + * @param evaLithiumHydroxide the new EVA lithium hydroxide (kilograms/crew/hour) + */ + public void setEvaLithiumHydroxide(double evaLithiumHydroxide) { + this.evaLithiumHydroxide = evaLithiumHydroxide; + } + + /** + * Gets the health equipment. + * + * @return the health equipment (kilograms) + */ + public double getHealthEquipment() { + return healthEquipment; + } + + /** + * Sets the health equipment. + * + * @param healthEquipment the new health equipment (kilograms) + */ + public void setHealthEquipment(double healthEquipment) { + this.healthEquipment = healthEquipment; + } + + /** + * Gets the health consumables. + * + * @return the health consumables (kilograms/crew/day) + */ + public double getHealthConsumables() { + return healthConsumables; + } + + /** + * Sets the health consumables. + * + * @param healthConsumables the new health consumables (kilograms/crew/day) + */ + public void setHealthConsumables(double healthConsumables) { + this.healthConsumables = healthConsumables; + } + + /** + * Gets the safety equipment. + * + * @return the safety equipment (kilograms) + */ + public double getSafetyEquipment() { + return safetyEquipment; + } + + /** + * Sets the safety equipment. + * + * @param safetyEquipment the new safety equipment (kilograms) + */ + public void setSafetyEquipment(double safetyEquipment) { + this.safetyEquipment = safetyEquipment; + } + + /** + * Gets the communications equipment. + * + * @return the communications equipment (kilograms) + */ + public double getCommEquipment() { + return commEquipment; + } + + /** + * Sets the communications equipment. + * + * @param commEquipment the new communications equipment (kilograms) + */ + public void setCommEquipment(double commEquipment) { + this.commEquipment = commEquipment; + } + + /** + * Gets the computer equipment. + * + * @return the computer equipment (kilograms) + */ + public double getComputerEquipment() { + return computerEquipment; + } + + /** + * Sets the computer equipment. + * + * @param computerEquipment the new computer equipment (kilograms) + */ + public void setComputerEquipment(double computerEquipment) { + this.computerEquipment = computerEquipment; + } + + /** + * Gets the trashBag rate. + * + * @return the trashBag rate (kilograms/crew/day) + */ + public double getTrashBagRate() { + return trashBagRate; + } + + /** + * Sets the trash bag rate. + * + * @param trashBagRate the new trash bag rate (kilograms/crew/day) + */ + public void setTrashBagRate(double trashBagRate) { + this.trashBagRate = trashBagRate; + } + + /** + * Gets the waste containment rate. + * + * @return the waste containment rate (kilograms/crew/day) + */ + public double getWasteContainmentRate() { + return wasteContainmentRate; + } + + /** + * Sets the waste containment rate. + * + * @param wasteContainmentRate the new waste containment rate (kilograms/crew/day) + */ + public void setWasteContainmentRate(double wasteContainmentRate) { + this.wasteContainmentRate = wasteContainmentRate; + } + + /** + * Checks if is transit demands are omitted. + * + * @return true, if is transit demands omitted + */ + public boolean isTransitDemandsOmitted() { + return transitDemandsOmitted; + } + + /** + * Sets if the transit demands are omitted. + * + * @param transitDemandsOmitted whether the transit demands are omitted + */ + public void setTransitDemandsOmitted(boolean transitDemandsOmitted) { + this.transitDemandsOmitted = transitDemandsOmitted; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/model/DemandModelFactory.java b/src/main/java/edu/mit/spacenet/domain/model/DemandModelFactory.java new file mode 100644 index 0000000..24b2c62 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/model/DemandModelFactory.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.model; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.scenario.Mission; + +/** + * A factory for creating demand models. + * + * @author Paul Grogan + */ +public abstract class DemandModelFactory { + + /** + * Creates a new DemandModel object for a mission. + * + * @param mission the mission + * @param type the type of demand model + * + * @return the demand model + */ + public static I_DemandModel createDemandModel(Mission mission, + DemandModelType type) { + switch(type) { + case CREW_CONSUMABLES: return new CrewConsumablesDemandModel(mission); + case RATED: return new RatedDemandModel(); + case TIMED_IMPULSE: return new TimedImpulseDemandModel(); + default: throw new RuntimeException("Unsupported Demand Model"); + } + } + + /** + * Creates a new DemandModel object for an element. + * + * @param element the element + * @param type the type of demand model + * + * @return the demand model + */ + public static I_DemandModel createDemandModel(I_Element element, + DemandModelType type) { + switch(type) { + case RATED: return new RatedDemandModel(); + case SPARING_BY_MASS: return new SparingByMassDemandModel(element); + case TIMED_IMPULSE: return new TimedImpulseDemandModel(); + default: throw new RuntimeException("Unsupported Demand Model"); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/model/DemandModelType.java b/src/main/java/edu/mit/spacenet/domain/model/DemandModelType.java new file mode 100644 index 0000000..21440da --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/model/DemandModelType.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.model; + +import javax.swing.ImageIcon; + +/** + * An enumeration for the demand model types. + * + * @author Paul Grogan + */ +public enum DemandModelType { + + /** The crew consumables model type. */ + CREW_CONSUMABLES("Crew Consumables Demand Model", "icons/comment.png"), + + /** The timed impulse model type. */ + TIMED_IMPULSE("Timed Impulse Demand Model", "icons/comment.png"), + + /** The rated model type. */ + RATED("Rated Demand Model", "icons/comment.png"), + + /** The sparing by mass model type. */ + SPARING_BY_MASS("Sparing by Mass Demand Model", "icons/comment.png"); + + private String name; + private ImageIcon icon; + + private DemandModelType(String name, String iconUrl) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } + + /** + * Gets the name of the demand model type. + * + * @return the demand model type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon for the demand model type. + * + * @return the demand model type icon + */ + public ImageIcon getIcon() { + return icon; + } + + /** + * Gets the enumeration value based on a passed name. + * + * @param name the name to match + * + * @return the matching demand model type (null if no match found) + */ + public static DemandModelType getInstance(String name) { + for(DemandModelType t : DemandModelType.values()) { + if(t.getName().toLowerCase().equals(name.toLowerCase())) { + return t; + } + } + return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/model/I_DemandModel.java b/src/main/java/edu/mit/spacenet/domain/model/I_DemandModel.java new file mode 100644 index 0000000..883e61e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/model/I_DemandModel.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.model; + + + +import edu.mit.spacenet.domain.I_DomainType; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * Interface for broad class of demand models. A demand model generates a set + * of demands based on the duration of time that has elapsed. + * + * @author Paul Grogan + */ +public interface I_DemandModel extends I_DomainType, Comparable { + + /** + * Generates a set of demands based on the duration (in days) of time that + * has elapsed. + * + * @param duration the duration (in days) to generate for + * @param simulator the simulator requesting the demands + * + * @return the set of demands + */ + public DemandSet generateDemands(double duration, I_Simulator simulator); + + /** + * Gets the demand model type. + * + * @return the demand model type + */ + public DemandModelType getDemandModelType(); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/model/RatedDemandModel.java b/src/main/java/edu/mit/spacenet/domain/model/RatedDemandModel.java new file mode 100644 index 0000000..dbc2f30 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/model/RatedDemandModel.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.model; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * Demand model that generates an amount of a set demands proportional to a rate + * constant. For discrete items, it aggregates the fractional items until at + * least a whole unit can be demanded. + * + * @author Paul Grogan + */ +public class RatedDemandModel extends AbstractDemandModel { + private SortedSet demandRates; + + /** + * Default constructor that initializes the demand rates and item + * generation structures. + */ + public RatedDemandModel() { + demandRates = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.model.I_DemandModel#generateDemands(double, edu.mit.spacenet.simulator.I_Simulator) + */ + public DemandSet generateDemands(double duration, I_Simulator simulator) { + DemandSet demands = new DemandSet(); + for(Demand demand : demandRates) { + Demand resource = new Demand(); + resource.setResource(demand.getResource()); + resource.setAmount(demand.getAmount()*duration); + demands.add(resource); + } + return demands; + } + + /** + * Gets the set of demand rates. + * + * @return the set of demands with rate constant in place of amount + */ + public SortedSet getDemandRates() { + return demandRates; + } + + /** + * Sets the set of demand rates. + * + * @param demandRates the set of demands with rate constant in place of + * amount + */ + public void setDemandRates(SortedSet demandRates) { + this.demandRates = demandRates; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.model.I_DemandModel#getDemandModelType() + */ + public DemandModelType getDemandModelType() { + return DemandModelType.RATED; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/model/SparingByMassDemandModel.java b/src/main/java/edu/mit/spacenet/domain/model/SparingByMassDemandModel.java new file mode 100644 index 0000000..cb3838d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/model/SparingByMassDemandModel.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.model; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * Crude sparing demand model that demands generic class of supply 4 resources + * proportional to the element's mass, a annual sparing rate, and the duration. + * An option allows an element's parts list to be utilized to generate specific + * resource demands if desired. + * + * @author Paul Grogan + */ +public class SparingByMassDemandModel extends AbstractDemandModel { + private I_Element element; + private double unpressurizedSparesRate; + private double pressurizedSparesRate; + private boolean partsListEnabled; + + /** + * The default constructor sets the default packaging factors. + * + * @param element the element + */ + public SparingByMassDemandModel(I_Element element) { + this.element = element; + this.partsListEnabled = true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.model.I_DemandModel#generateDemands(double, edu.mit.spacenet.simulator.I_Simulator) + */ + public DemandSet generateDemands(double duration, I_Simulator simulator) { + return generateDemands(duration, pressurizedSparesRate, unpressurizedSparesRate, partsListEnabled); + } + + /** + * Generate demands. + * + * @param duration the duration + * @param pressurizedSparesRate the pressurized spares rate + * @param unpressurizedSparesRate the unpressurized spares rate + * @param partsListEnabled the parts list enabled + * @return the demand set + */ + public DemandSet generateDemands(double duration, double pressurizedSparesRate, + double unpressurizedSparesRate, boolean partsListEnabled) { + DemandSet demands = new DemandSet(); + + double pressPartMass = 0; + double unpressPartMass = 0; + double genericPartMass = 0; + + if(partsListEnabled) { + for(PartApplication p : element.getParts()) { + if(p.getQuantity()>0) { + if(p.getPart().getEnvironment().equals(Environment.PRESSURIZED)) { + pressPartMass += p.getQuantity()*p.getPart().getUnitMass(); + } else if(p.getPart().getEnvironment().equals(Environment.UNPRESSURIZED)) { + unpressPartMass += p.getQuantity()*p.getPart().getUnitMass(); + } + } + } + // TODO: should check for error conditions: + // pressPartMass > element.getMass() + // unpressPartMass > element.getMass() + // pressPartMass + unpressPartMass > element.getMass() + genericPartMass = Math.max(0,element.getMass()-pressPartMass-unpressPartMass); + for(PartApplication p : element.getParts()) { + if(p.getQuantity()>0) { + Demand demand = new Demand(); + demand.setResource(p.getPart()); + if(p.getPart().getEnvironment().equals(Environment.PRESSURIZED)) { + demand.setAmount(duration*pressurizedSparesRate/365*element.getMass()*p.getQuantity()/(genericPartMass + pressPartMass)); + } else if(p.getPart().getEnvironment().equals(Environment.UNPRESSURIZED)) { + demand.setAmount(duration*unpressurizedSparesRate/365*element.getMass()*p.getQuantity()/(genericPartMass + unpressPartMass)); + } + demands.add(demand); + } + } + } else { + genericPartMass = element.getMass(); + } + + Demand unpressSpares = new Demand(); + unpressSpares.setResource(new GenericResource(ClassOfSupply.COS4)); + unpressSpares.getResource().setEnvironment(Environment.UNPRESSURIZED); + unpressSpares.setAmount(duration*unpressurizedSparesRate/365*element.getMass()*genericPartMass/(genericPartMass+unpressPartMass)); + demands.add(unpressSpares); + + Demand pressSpares = new Demand(); + pressSpares.setResource(new GenericResource(ClassOfSupply.COS4)); + pressSpares.getResource().setEnvironment(Environment.PRESSURIZED); + pressSpares.setAmount(duration*pressurizedSparesRate/365*element.getMass()*genericPartMass/(genericPartMass+pressPartMass)); + demands.add(pressSpares); + + return demands; + } + + /** + * Gets the element. + * + * @return the element + */ + public I_Element getElement() { + return element; + } + + /** + * Sets the element. + * + * @param element the element + */ + public void setElement(I_Element element) { + this.element = element; + } + + /** + * Gets the unpressurized sparing rate. + * + * @return the sparing rate (percent element mass per year) + */ + public double getUnpressurizedSparesRate() { + return unpressurizedSparesRate; + } + + /** + * Sets the unpressurized sparing rate. + * + * @param sparesRate the sparing rate (percent element mass per year) + */ + public void setUnpressurizedSparesRate(double sparesRate) { + this.unpressurizedSparesRate = sparesRate; + } + + /** + * Gets the pressurized sparing rate. + * + * @return the sparing rate (percent element mass per year) + */ + public double getPressurizedSparesRate() { + return pressurizedSparesRate; + } + + /** + * Sets the pressurized sparing rate. + * + * @param sparesRate the spares rate + */ + public void setPressurizedSparesRate(double sparesRate) { + this.pressurizedSparesRate = sparesRate; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.model.I_DemandModel#getDemandModelType() + */ + public DemandModelType getDemandModelType() { + return DemandModelType.SPARING_BY_MASS; + } + + /** + * Checks if is parts list enabled, allowing demands for generic and + * specific resources. + * + * @return true, if is parts list enabled + */ + public boolean isPartsListEnabled() { + return partsListEnabled; + } + + /** + * Sets the parts list enabled, allowing demands for generic and specific + * resources. + * + * @param partsListEnabled the new parts list enabled + */ + public void setPartsListEnabled(boolean partsListEnabled) { + this.partsListEnabled = partsListEnabled; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/model/TimedImpulseDemandModel.java b/src/main/java/edu/mit/spacenet/domain/model/TimedImpulseDemandModel.java new file mode 100644 index 0000000..97eda64 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/model/TimedImpulseDemandModel.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.model; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * Demand model that generates an impulse demand on its first call to generate + * demands, and nothing afterwards. + * + * @author Paul Grogan + */ +public class TimedImpulseDemandModel extends AbstractDemandModel { + private SortedSet demands; + private boolean flag = false; + + /** + * The default constructor initializes the set of demands. + */ + public TimedImpulseDemandModel() { + demands = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.model.I_DemandModel#generateDemands(double, edu.mit.spacenet.simulator.I_Simulator) + */ + public DemandSet generateDemands(double duration, I_Simulator simulator) { + if(!flag) { + flag = true; + DemandSet d = new DemandSet(); + for(Demand demand : demands) { + d.add(demand); + } + return d; + } else return new DemandSet(); + } + + /** + * Gets the set of demands to generate. + * + * @return the set of demands + */ + public SortedSet getDemands() { + return demands; + } + + /** + * Sets the set of demands to generate. + * + * @param demands the set of demands + */ + public void setDemands(SortedSet demands) { + this.demands = demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.model.I_DemandModel#getDemandModelType() + */ + public DemandModelType getDemandModelType() { + return DemandModelType.TIMED_IMPULSE; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/Location.java b/src/main/java/edu/mit/spacenet/domain/network/Location.java new file mode 100644 index 0000000..9120dfa --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/Location.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.DomainType; +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.simulator.I_Simulator; + +/** + * Base class for any network component (e.g. node or edge). + * + * @author Paul Grogan + */ +public abstract class Location extends DomainType implements I_Container, Comparable { + private SortedSet contents; + + /** + * The default constructor initializes the contents structure. + */ + public Location() { + contents = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getContents() + */ + public SortedSet getContents() { + return contents; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getCompleteContents() + */ + public SortedSet getCompleteContents() { + SortedSet elements = new TreeSet(); + for(I_Element element : contents) recursiveAdd(elements, element); + return elements; + } + private void recursiveAdd(SortedSet elements, I_Element element) { + elements.add(element); + if(element instanceof I_Container) { + for(I_Element child : ((I_Container)element).getContents()) { + recursiveAdd(elements, child); + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#canAdd(edu.mit.spacenet.domain.element.I_Element) + */ + public boolean canAdd(I_Element element) { + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#canAdd(double) + */ + public boolean canAdd(double addedMass) { + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#add(edu.mit.spacenet.domain.element.I_Element) + */ + public boolean add(I_Element element) { + if(element.getContainer()!=null) element.getContainer().remove(element); + element.setContainer(this); + return contents.add(element); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#remove(edu.mit.spacenet.domain.element.I_Element) + */ + public boolean remove(I_Element element) { + element.setContainer(null); + return contents.remove(element); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getCargoMass() + */ + public double getCargoMass() { + double mass = 0; + for(I_Element i : contents) { + if(!(i instanceof CrewMember)) { + mass += i.getTotalMass(); + } + } + return mass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getCargoVolume() + */ + public double getCargoVolume() { + double volume = 0; + for(I_Element e : contents) { + if(!(e instanceof CrewMember)) { + volume += e.getVolume(); + } + } + return volume; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getCrewSize() + */ + public int getCrewSize() { + int crew = 0; + for(I_Element e : contents) { + if(e instanceof CrewMember) { + crew++; + } + } + return crew; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getTotalCrewSize() + */ + public int getTotalCrewSize() { + int crew = 0; + for(I_Element e : contents) { + if(e instanceof CrewMember) { + crew++; + } else if(e instanceof I_Carrier) { + crew+=((I_Carrier)e).getTotalCrewSize(); + } + } + return crew; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.I_Container#getTotalMass() + */ + public double getTotalMass() { + return getCargoMass(); + } + + /** + * Gets the total volume. + * + * @return the total volume + */ + public double getTotalVolume() { + return getCargoVolume(); + } + + /** + * Gets the total mass. + * + * @param cos the cos + * @param simulator the simulator + * + * @return the total mass + */ + public double getTotalMass(ClassOfSupply cos, I_Simulator simulator) { + double amount = 0; + for(I_Element element : getContents()) { + amount+=element.getTotalMass(cos); + } + return amount; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#toString() + */ + public String toString() { + return getName(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#print(int) + */ + public void print(int tabOrder) { + super.print(tabOrder); + for(I_Element i : ((I_Container)this).getContents()) { + i.print(tabOrder+1); + } + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Location location) { + //return new Integer(getTid()).compareTo(new Integer(location.getTid())); + if(getTid()==location.getTid()) return 0; + else if(getName()!=null && !getName().equals(location.getName())) + return getName().compareTo(location.getName()); + else return new Integer(getTid()).compareTo(new Integer(location.getTid())); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/network/Network.java b/src/main/java/edu/mit/spacenet/domain/network/Network.java new file mode 100644 index 0000000..f3265e9 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/Network.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * Represents the network of nodes and edges for the simulation to act over. + * + * @author Paul Grogan + */ +public class Network { + private SortedSet nodes; + private SortedSet edges; + private SortedMap registrar; + private SortedMap removedRegistrar; + + /** + * Default constructor that initializes the structures for the nodes and + * edges. + */ + public Network() { + nodes = new TreeSet(); + edges = new TreeSet(); + registrar = new TreeMap(); + removedRegistrar = new TreeMap(); + } + + /** + * Gets the set of nodes. + * + * @return the set of nodes + */ + public SortedSet getNodes() { + return nodes; + } + + /** + * Gets a node by its type identifier. + * + * @param tid the node's type identifier (primary key) + * + * @return the node, or null if not found + */ + public Node getNodeByTid(int tid) { + Node node = null; + for(Node n : nodes) { + if(n.getTid() == tid) { + node = n; + break; + } + } + return node; + } + + /** + * Gets the set of edges. + * + * @return the set of edges + */ + public SortedSet getEdges() { + return edges; + } + + /** + * Gets an edge by its type identifier. + * + * @param tid the edge's type identifier (primary key) + * + * @return the edge, or null if not found + */ + public Edge getEdgeByTid(int tid) { + Edge edge = null; + for(Edge e : edges) { + if(e.getTid() == tid) { + edge = e; + break; + } + } + return edge; + } + + /** + * Adds a network component (node or edge) to the network. In the case of an + * edge, the origin and destination node must exist in the network to be + * successful. + * + * @param c the network component + * + * @return true, if successful, false otherwise + */ + public boolean add(Location c) { + if(c instanceof Node) return nodes.add((Node)c); + else { + Edge e = (Edge)c; + if(nodes.contains(e.getOrigin()) && nodes.contains(e.getDestination())) + return edges.add(e); + else return false; + } + } + + /** + * Removes a network component (node or edge) from the network. In the case + * of a node, it will also remove all associated edges from the network. + * + * @param n the network component + * + * @return true, if successful, false otherwise + */ + public boolean remove(Location n) { + if(n instanceof Node) { + Set edgesToRemove = new HashSet(); + for(Edge e : edges) { + if(e.getOrigin().equals(n) || e.getDestination().equals(n)) + edgesToRemove.add(e); + } + for(Edge e : edgesToRemove) { + edges.remove(e); + } + return nodes.remove((Node)n); + } + else return edges.remove((Edge)n); + } + + /** + * Gets the locations. + * + * @return the locations + */ + public List getLocations() { + ArrayList locations = new ArrayList(); + for(Node node : getNodes()) { + locations.add(node); + } + for(Edge edge : getEdges()) { + locations.add(edge); + } + Collections.sort(locations); + return locations; + } + + /** + * Gets the registry of elements. + * + * @return the element registry + */ + public SortedMap getRegistrar() { + return registrar; + } + + /** + * Gets the registry of removed elements. + * + * @return the removed element registry + */ + public SortedMap getRemovedRegistrar() { + if(removedRegistrar==null) removedRegistrar = new TreeMap(); + return removedRegistrar; + } + + /** + * Gets the contents of. + * + * @param container the container + * + * @return the contents of + */ + public SortedSet getContentsOf(I_Container container) { + TreeSet elements = new TreeSet(); + for(I_Element element : getRegistrar().values()) { + if(element.getContainer().equals(container)) elements.add(element); + } + return elements; + } + + /** + * Gets the complete contents of. + * + * @param location the location + * + * @return the complete contents of + */ + public SortedSet getCompleteContentsOf(Location location) { + TreeSet elements = new TreeSet(); + for(I_Element element : getRegistrar().values()) { + if(element.getLocation().equals(location)) elements.add(element); + } + return elements; + } + + /** + * Prints a network representation to console. + */ + public void print() { + System.out.println("Network Nodes"); + for(Node n : nodes) { + n.print(1); + } + System.out.println("Network Edges"); + for(Edge e : edges) { + e.print(1); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/edge/Burn.java b/src/main/java/edu/mit/spacenet/domain/network/edge/Burn.java new file mode 100644 index 0000000..1bc0107 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/edge/Burn.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.edge; + +import edu.mit.spacenet.domain.DomainType; + +/** + * Class that represents an impulsive burn (either OMS or RCS) to achieve a + * specified delta-v (m/s), offset from the propulsive maneuver by a time. + * + * @author Paul Grogan + */ +public class Burn extends DomainType implements Comparable { + private double time; + private BurnType burnType; + private double deltaV; + + /** + * The default constructor sets the burn type to OMS. + */ + public Burn() { + super(); + setBurnType(BurnType.OMS); + } + + /** + * The inline constructor. + * + * @param time the burn time (days) + * @param burnType the burn type + * @param deltaV the delta-v (meters per second) + */ + public Burn(double time, BurnType burnType, double deltaV) { + super(); + setTime(time); + setBurnType(burnType); + setDeltaV(deltaV); + } + + /** + * Gets the time offset from the initial propulsive maneuver. + * + * @return the time offset (days) + */ + public double getTime() { + return time; + } + + /** + * Sets the time offset from the initial propulsive maneuver. + * + * @param time the time offset (days) + */ + public void setTime(double time) { + this.time = time; + } + + /** + * Gets the burn type. + * + * @return the burn type + */ + public BurnType getBurnType() { + return burnType; + } + + /** + * Sets the burn type. + * + * @param burnType the burn type + */ + public void setBurnType(BurnType burnType) { + this.burnType = burnType; + } + + /** + * Gets the delta-v. + * + * @return the delta-v (meters per second) + */ + public double getDeltaV() { + return deltaV; + } + + /** + * Sets the delta-v. + * + * @param deltaV the delta-v (meters per second) + */ + public void setDeltaV(double deltaV) { + this.deltaV = deltaV; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#toString() + */ + @Override + public String toString() { + return burnType + " (" + deltaV + " m/s)"; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Burn o) { + if(o==null) return -1; + return new Double(getTime()).compareTo(o.getTime()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/network/edge/BurnType.java b/src/main/java/edu/mit/spacenet/domain/network/edge/BurnType.java new file mode 100644 index 0000000..865b745 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/edge/BurnType.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.edge; + +import java.io.Serializable; + +/** + * Enumeration of the two types of propulsive burns (OMS for Orbit Maneuvering + * System, RCS for Reaction Control System). + * + * @author Paul Grogan + */ +public enum BurnType implements Serializable { + + /** Abbreviation for Orbit Maneuvering System. */ + OMS("OMS"), + + /** Abbreviation for Reaction Control System. */ + RCS("RCS"); + + private String name; + + /** + * The default constructor. + * @param name the name of the burn type to display + */ + private BurnType(String name) { + this.name = name; + } + + /** + * Gets the name of the burn type. + * + * @return the burn type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Method to get a particular instance of a state type based on a + * case-insensitive string. + * + * @param name case-insensitive string of name + * + * @return the burn type, returns RCS if unknown name + */ + public static BurnType getInstance(String name) { + if(name.toLowerCase().equals(OMS.getName().toLowerCase())) return OMS; + else return RCS; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/network/edge/Edge.java b/src/main/java/edu/mit/spacenet/domain/network/edge/Edge.java new file mode 100644 index 0000000..fe229dd --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/edge/Edge.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.edge; + +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * Base class for network components that connect two nodes (edges). + * + * @author Paul Grogan + */ +public abstract class Edge extends Location { + private Node origin; + private Node destination; + private EdgeType edgetype; + + /** + * The default constructor. + */ + public Edge() { + super(); + } + + /** + * Gets the origin. + * + * @return the origin + */ + public Node getOrigin() { + return origin; + } + + /** + * Sets the origin. + * + * @param origin the origin + */ + public void setOrigin(Node origin) { + this.origin = origin; + } + + /** + * Gets the destination. + * + * @return the destination + */ + public Node getDestination() { + return destination; + } + + /** + * Sets the destination. + * + * @param destination the destination + */ + public void setDestination(Node destination) { + this.destination = destination; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.network.Location#compareTo(edu.mit.spacenet.domain.network.Location) + */ + public int compareTo(Location location) { + if(location instanceof Edge) { + return super.compareTo(location); + /* TODO ordering by node origin breaks compatibility + Edge edge = (Edge)location; + if(getOrigin().equals(edge.getOrigin())) + // if both edges have same origin, order by name/id + return super.compareTo(location); + else + // if edges have different origin, order by origin + return getOrigin().compareTo(edge.getOrigin()); + */ + } else if(location instanceof Node) { + Node node = (Node)location; + if(getOrigin().equals(node)) + // if node is edge's origin, order node first + return 1; + else + // else order by origin node + return getOrigin().compareTo(node); + } else { + return 0; + } + } + + /** + * Gets the edge type. + * + * @return the edge type + */ + public EdgeType getEdgeType(){ + return edgetype; + } + + public void setEdgeType(EdgeType edgetype1) { + this.edgetype=edgetype1; + + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/edge/EdgeType.java b/src/main/java/edu/mit/spacenet/domain/network/edge/EdgeType.java new file mode 100644 index 0000000..1a8b0e2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/edge/EdgeType.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.edge; + +import java.awt.Color; + +import javax.swing.ImageIcon; + +/** + * Enumeration to represent the different subclasses of edges. + * + * @author Paul Grogan + */ +public enum EdgeType { + + /** The flight edge type. */ + FLIGHT("Flight", "icons/edge_yellow.png", Color.YELLOW), + + /** The space edge type. */ + SPACE("Space", "icons/edge_red.png", Color.RED), + + /** The surface edge type. */ + SURFACE("Surface", "icons/edge_green.png", Color.GREEN), + + /** The time dependent edge type. */ + TIME_DEPENDENT("Time-Dependent", "icons/edge_red.png", Color.RED); + + private String name; + private ImageIcon icon; + private Color color; + + private EdgeType(String name, String iconUrl, Color color) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + this.color = color; + } + + /** + * Gets the name of the edge type. + * + * @return the edge type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon of the edge type. + * + * @return the edge type icon + */ + public ImageIcon getIcon() { + return icon; + } + + /** + * Gets the color of the edge type (used in visualizations). + * + * @return the edge type color + */ + public Color getColor() { + return color; + } + + /** + * Gets the edge type based on a given name. + * + * @param name the edge type name + * + * @return the edge type, return null if not found + */ + public static EdgeType getInstance(String name) { + for(EdgeType t : EdgeType.values()) { + if(t.getName().toLowerCase().equals(name.toLowerCase())) { + return t; + } + } + return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/edge/FlightEdge.java b/src/main/java/edu/mit/spacenet/domain/network/edge/FlightEdge.java new file mode 100644 index 0000000..2706dec --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/edge/FlightEdge.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.edge; + +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Edge that represents an abstracted flight with a finite duration and + * capacity constraints on crew and cargo mass. + * + * @author Paul Grogan + */ +public class FlightEdge extends Edge { + private double duration; + private int maxCrewSize; + private double maxCargoMass; + + /** + * The default constructor. + */ + public FlightEdge() { + super(); + } + + /** + * Gets the flight duration. + * + * @return the duration (days) + */ + public double getDuration() { + return GlobalParameters.getRoundedTime(duration); + } + + /** + * Sets the flight duration, rounding to nearest time precision. + * + * @param duration the duration (days) + */ + public void setDuration(double duration) { + this.duration = duration; + } + + /** + * Gets the maximum crew size. + * + * @return the maximum crew size + */ + public int getMaxCrewSize() { + return maxCrewSize; + } + + /** + * Sets the maximum crew size. + * + * @param maxCrewSize the maximum crew size + */ + public void setMaxCrewSize(int maxCrewSize) { + this.maxCrewSize = maxCrewSize; + } + + /** + * Gets the maximum cargo mass. + * + * @return the maximum caro mass (kilograms) + */ + public double getMaxCargoMass() { + return maxCargoMass; + } + + /** + * Sets the maximum cargo mass. + * + * @param maxCargoMass the maximum cargo mass (kilograms) + */ + public void setMaxCargoMass(double maxCargoMass) { + this.maxCargoMass = maxCargoMass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.network.edge.Edge#getEdgeType() + */ + @Override + public EdgeType getEdgeType() { + return EdgeType.FLIGHT; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/network/edge/SpaceEdge.java b/src/main/java/edu/mit/spacenet/domain/network/edge/SpaceEdge.java new file mode 100644 index 0000000..dae7f3d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/edge/SpaceEdge.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.edge; + +import java.util.ArrayList; +import java.util.List; + +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Edge that represents a series of propulsive burns with a finite duration. + * + * @author Paul Grogan + */ +public class SpaceEdge extends Edge { + private double duration; + private List burns; + + /** + * The default constructor that initializes the list of burns. + */ + public SpaceEdge() { + super(); + burns = new ArrayList(); + } + + /** + * Gets the duration. + * + * @return the duration (days) + */ + public double getDuration() { + return GlobalParameters.getRoundedTime(duration); + } + + /** + * Sets the duration, rounding to nearest time precision. + * + * @param duration the duration (days) + */ + public void setDuration(double duration) { + this.duration = duration; + } + + /** + * Gets the list of burns. + * + * @return the list of burns + */ + public List getBurns() { + return burns; + } + + /** + * Sets the list of burns. + * + * @param burns the list of burns + */ + public void setBurns(List burns) { + this.burns = burns; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.network.edge.Edge#getEdgeType() + */ + @Override + public EdgeType getEdgeType() { + return EdgeType.SPACE; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/edge/SurfaceEdge.java b/src/main/java/edu/mit/spacenet/domain/network/edge/SurfaceEdge.java new file mode 100644 index 0000000..7701b15 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/edge/SurfaceEdge.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.edge; + +/** + * Edge that represents a surface transfer with a specified distance. + * + * @author Paul Grogan + */ +public class SurfaceEdge extends Edge { + + /** The distance. */ + double distance; + + /** + * The default constructor. + */ + public SurfaceEdge() { + super(); + } + + /** + * Gets the distance. + * + * @return the distance (kilometers) + */ + public double getDistance() { + return this.distance; + } + + /** + * Sets the distance. + * + * @param distance the distance (kilometers) + */ + public void setDistance(double distance) { + this.distance = distance; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.network.edge.Edge#getEdgeType() + */ + @Override + public EdgeType getEdgeType() { + return EdgeType.SURFACE; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/network/edge/TimeDependentEdge.java b/src/main/java/edu/mit/spacenet/domain/network/edge/TimeDependentEdge.java new file mode 100644 index 0000000..ac78acc --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/edge/TimeDependentEdge.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.edge; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; + +import edu.mit.spacenet.domain.network.node.OrbitalNode; + +public class TimeDependentEdge extends Edge { + private OrbitalNode origin, destination; + + @Override + public OrbitalNode getOrigin() { + return origin; + } + public void setOrigin(OrbitalNode origin) { + this.origin = origin; + } + @Override + public OrbitalNode getDestination() { + return destination; + } + public void setDestination(OrbitalNode destination) { + this.destination = destination; + } + + private String filePath; + + @SuppressWarnings("deprecation") + public List getEdges(Date departureDate, double originPeriapsis, double originApoapsis, double destinationPeriapsis, double destinationApoapsis, double departureC3Limit, double arrivalC3Limit, boolean usesAerocapture) throws IOException { + List edges = new ArrayList(); + + // add code to open file @ filePath + // read data into SpaceEdge structures + // add SpaceEdge structures into List + + // create poi file system + // open poi workbook + // open poi worksheet + + POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(filePath)); + HSSFWorkbook wb = new HSSFWorkbook(fs); + + HSSFSheet infoSheet = wb.getSheetAt(0); + HSSFRow infoRow = infoSheet.getRow(2); + + // date of origin (0,0) in the C3 chart + // Date originDate = infoRow.getCell(0).getDateCellValue(); + int originDateJulian = (int) infoRow.getCell(1).getNumericCellValue(); + // departure date axis + // int xAxisRange = (int) infoRow.getCell(2).getNumericCellValue(); + // int xCellNum = (int) infoRow.getCell(3).getNumericCellValue(); + int xStepSize = (int) infoRow.getCell(4).getNumericCellValue(); + // TOF axis + // int yAxisRange = (int) infoRow.getCell(5).getNumericCellValue(); + int yCellNum = (int) infoRow.getCell(6).getNumericCellValue(); + int yStepSize = (int) infoRow.getCell(7).getNumericCellValue(); + // departure/arrival planet + // String departurePlanet = infoRow.getCell(8).toString(); + double radiusOriginBody = infoRow.getCell(9).getNumericCellValue(); + double muOriginBody = infoRow.getCell(10).getNumericCellValue(); + // String arrivalPlanet = infoRow.getCell(11).toString(); + double radiusDestinationBody = infoRow.getCell(12).getNumericCellValue(); + double muDestinationBody = infoRow.getCell(13).getNumericCellValue(); + + // Julian Day for departure date + int departureDateYear = departureDate.getYear(); + int departureDateMonth = departureDate.getMonth(); + int departureDateDate = departureDate.getDate(); + int departureDateHour = 12; + int departureDateMinute = 0; + int departureDateSecond = 0; + double departureDateHMD = departureDateHour+departureDateMinute/60+departureDateSecond/(60*60); + double departureDateJulian = 367*departureDateYear-Math.floor(7*(departureDateYear+Math.floor((departureDateMonth+9)/12))/4)+Math.floor(275*departureDateMonth/9)+departureDateDate+departureDateHMD/24+1721013.5; + + // radii of origin and destination orbits + double radiusOriginPeriapsis = radiusOriginBody + originPeriapsis; // [km] + double radiusOriginApoapsis = radiusOriginBody + originApoapsis; // [km] + double radiusDestinationPeriapsis = radiusDestinationBody + destinationPeriapsis; // [km] + double radiusDestinationApoapsis = radiusDestinationBody + destinationApoapsis; // [km] + + // departure Julian Date -> row number + int departureDateRowNumber = (int) Math.ceil((departureDateJulian-originDateJulian)/xStepSize); + + // C3d worksheet + // C3d row + HSSFSheet C3dSheet = wb.getSheetAt(1); + HSSFRow C3dRow = C3dSheet.getRow(departureDateRowNumber); + + // C3a worksheet + // C3a row + HSSFSheet C3aSheet = wb.getSheetAt(2); + HSSFRow C3aRow = C3aSheet.getRow(departureDateRowNumber); + + // for each row until end + for(int j = 0; j <= yCellNum - 1; j++) { + // read C3d and C3a + double C3d = C3dRow.getCell(j).getNumericCellValue(); + double C3a = C3aRow.getCell(j).getNumericCellValue(); + + // check against departure limit + // check against arrival limit + // if within bounds: + if(C3d <= departureC3Limit && C3a <= arrivalC3Limit) { + // create new space edge + SpaceEdge edge = new SpaceEdge(); + + // copy same information (id, name, origin, destination, description) + edge.setTid(getTid()); + edge.setName(getName()); + edge.setOrigin(getOrigin()); + edge.setDestination(getDestination()); + edge.setDescription(getDescription()); + + // read and fill duration and burns + // TOF = duration [days] + double TOF = j*yStepSize; + edge.setDuration(TOF); + + // delta-V's = burn [m/s] + // C3 -> delta-V conversion + // assuming both departure and arrival at periapsis + double departureDeltaV = (Math.sqrt(C3d+2*muOriginBody/radiusOriginPeriapsis)-Math.sqrt(muOriginBody/radiusOriginPeriapsis)*Math.sqrt(2*radiusOriginApoapsis/(radiusOriginPeriapsis+radiusOriginApoapsis)))*1000; + double arrivalDeltaV = (Math.sqrt(C3a+2*muDestinationBody/radiusDestinationPeriapsis)-Math.sqrt(muDestinationBody/radiusDestinationPeriapsis)*Math.sqrt(2*radiusDestinationApoapsis/(radiusDestinationPeriapsis+radiusDestinationApoapsis)))*1000; + edge.getBurns().add(new Burn(0, BurnType.OMS, departureDeltaV)); + if(usesAerocapture == false) { + edge.getBurns().add(new Burn(TOF, BurnType.OMS, arrivalDeltaV)); + } + + // add new edge to list + edges.add(edge); + + // end if + } + // end for + } + + return edges; + } + public String getFilePath() { + return filePath; + } + public void setFilePath(String filePath) { + this.filePath = filePath; + } + @Override + public EdgeType getEdgeType() { + return EdgeType.TIME_DEPENDENT; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/node/Body.java b/src/main/java/edu/mit/spacenet/domain/network/node/Body.java new file mode 100644 index 0000000..2a56bae --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/node/Body.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.node; + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.Serializable; + +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +/** + * Enumeration of the celestial bodies. + * + * @author Paul Grogan + */ +public enum Body implements Serializable { + + /** The sun */ + SUN("Sun", Color.YELLOW, "/icons/sun.png", null, 33200., 109., 0, "icons/sun_icon.png"), + + /** Venus */ + VENUS("Venus", Color.WHITE, null, SUN, 0.815, 0.950, 0.723, "icons/venus_icon.png"), + + /** Earth */ + EARTH("Earth", Color.BLUE, "/icons/earth.png", SUN, 1., 1., 1., "icons/earth_icon.png"), + + /** The moon */ + MOON("Moon", Color.LIGHT_GRAY, "/icons/moon.png", EARTH, 0.0123, 0.273, 0.00257, "icons/moon_icon.png"), + + /** Mars */ + MARS("Mars", Color.RED, "/icons/mars.png", SUN, 0.11, 0.532, 1.52, "icons/mars_icon.png"), + + /** Phobos */ + PHOBOS("Phobos", Color.DARK_GRAY, null, MARS, 1.8*Math.pow(10,-9), 11.1/6378., 9377.2/(150*Math.pow(10,6)), "icons/phobos_icon.png"), + + /** Deimos */ + DEIMOS("Deimos", Color.DARK_GRAY, null, MARS, 0.25*Math.pow(10,-9), 6.2/6378., 23460/(150*Math.pow(10,6)), "icons/deimos_icon.png"), + + /** Jupiter */ + JUPITER("Jupiter", Color.RED, null, SUN, 317.8, 11.209, 5.20, "icons/jupiter_icon.png"); + + /** 1 AU (astronomical unit) in kilometers. */ + public static final long AU = Math.round(150*Math.pow(10,6)); + + /** Earth's radius (kilometers). */ + public static final long EARTH_RADIUS = 6378; + + /** Earth's mass (kilograms). */ + public static final long EARTH_MASS = Math.round(5.9736*Math.pow(10,27)); + + /** + * Gets the nicely-formatted name of the body. + * + * @return the body's name + */ + public String getName() { + return name; + } + + /** + * Gets the body's color representation. + * + * @return the body's color + */ + public Color getColor() { + return color; + } + + /** + * Gets the body's Lambert-Azimuthal projection. + * + * @return the body's image + */ + public BufferedImage getImage() { + return image; + } + + /** + * Gets the parent body about which this body is orbiting. + * + * @return the parent + */ + public Body getParent() { + return parent; + } + + /** + * Gets the mass. + * + * @return the body's mass (units of Earth mass) + */ + public double getMass() { + return mass; + } + + /** + * Gets the mean planetary radius. + * + * @return the body's mean radius (units of Earth radius) + */ + public double getPlanetaryRadius() { + return planetaryRadius; + } + + /** + * Gets the mean orbital radius. + * + * @return the body's mean orbital radius (units of AU) + */ + public double getOrbitalRadius() { + return orbitalRadius; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Method to get a particular instance of a body based on a + * case-insensitive string. + * + * @param name case-insensitive string of name + * + * @return the body, returns null if unknown name + */ + public static Body getInstance(String name) { + for(Body body : Body.values()) { + if(body.getName().toLowerCase().equals(name.toLowerCase())) return body; + } + return null; + } + + /** + * Gets the icon of the body type. + * + * @return the body type icon + */ + public ImageIcon getIcon() { + return icon; + } + + // PRIVATE + + private String name; + private Color color; + private BufferedImage image; + private Body parent; + private double mass; + private double planetaryRadius; + private double orbitalRadius; + private ImageIcon icon; + + /** + * The default constructor. + * + * @param name the name to display + * @param color the color + * @param imageUrl the image url + * @param parent the parent + * @param mass the mass (earth mass) + * @param planetaryRadius the planetary radius (earth radii) + * @param orbitalRadius the orbital radius (astronomical units) + * @param iconUrl the icon url + */ + private Body(String name, Color color, String imageUrl, Body parent, double mass, double planetaryRadius, double orbitalRadius, String iconUrl) { + this.name = name; + this.color = color; + if(imageUrl!=null) { + try { + image = ImageIO.read(getClass().getResource(imageUrl)); + } catch (IOException e) { + System.out.println("error opening image"); + } + } + this.parent = parent; + this.mass = mass; + this.planetaryRadius = planetaryRadius; + this.orbitalRadius = orbitalRadius; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/network/node/LagrangeNode.java b/src/main/java/edu/mit/spacenet/domain/network/node/LagrangeNode.java new file mode 100644 index 0000000..cbd1266 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/node/LagrangeNode.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.node; + +/** + * Node that represents Lagrangian points in space. + * + * @author Paul Grogan + */ +public class LagrangeNode extends SpaceNode { + private Body minorBody; + private int number; + + /** + * The default constructor. + */ + public LagrangeNode() { + super(); + } + + /** + * Gets the Lagrangian number. + * + * @return the Lagrangian number + */ + public int getNumber() { + return number; + } + + /** + * Sets the Lagrangian number. + * + * @param number the Lagrangian number + */ + public void setNumber(int number) { + this.number = number; + } + + /** + * Gets the minor body of the Lagrangian. + * + * @return the minor body + */ + public Body getMinorBody() { + return minorBody; + } + + /** + * Sets the major body of the Lagrangian. + * + * @param minorBody the minor body + */ + public void setMinorBody(Body minorBody) { + this.minorBody = minorBody; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.network.node.Node#getNodeType() + */ + @Override + public NodeType getNodeType() { + return NodeType.LAGRANGE; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/node/Node.java b/src/main/java/edu/mit/spacenet/domain/network/node/Node.java new file mode 100644 index 0000000..11e78fe --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/node/Node.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.node; + +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.edge.Edge; + +/** + * Network component that represents a static location on a planetary body, a + * stable orbit, or a Lagrangian point. + * + * @author Paul Grogan + */ +public abstract class Node extends Location { + private Body body; + + /** + * The default constructor. + */ + public Node() { + super(); + } + + /** + * Gets the main body associated with the node. + * + * @return the main body + */ + public Body getBody() { + return body; + } + + /** + * Sets the main body associated with the node. + * + * @param body the main body + */ + public void setBody(Body body) { + this.body = body; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.network.Location#compareTo(edu.mit.spacenet.domain.network.Location) + */ + public int compareTo(Location location) { + if(location instanceof Node) { + Node node = (Node)location; + if(getBody().equals(node.getBody())) { + if(getBody().equals(Body.EARTH)) { + // in the case of the Earth, order nodes surface then space + if(this instanceof SurfaceNode && node instanceof SpaceNode) + return -1; + else if(this instanceof SpaceNode && node instanceof SurfaceNode) + return 1; + else + return super.compareTo(location); + } else { + // for all other bodies, order nodes space then surface + if(this instanceof SurfaceNode && node instanceof SpaceNode) + return 1; + else if(this instanceof SpaceNode && node instanceof SurfaceNode) + return -1; + else + return super.compareTo(location); + } + } else if(node.getBody()==Body.EARTH) { + return 1; + } else if(getBody()==Body.EARTH) { + return -1; + } else { + return getBody().compareTo(node.getBody()); + } + } else if(location instanceof Edge) { + Edge edge = (Edge)location; + if(this.equals(edge.getOrigin())) + // if edge has same origin, order node first + return -1; + else + // else order by origin node + return this.compareTo(edge.getOrigin()); + } else { + return 0; + } + } + + /** + * Gets the node type. + * + * @return the node type + */ + public abstract NodeType getNodeType(); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/network/node/NodeType.java b/src/main/java/edu/mit/spacenet/domain/network/node/NodeType.java new file mode 100644 index 0000000..55e3183 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/node/NodeType.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.node; + +import javax.swing.ImageIcon; + +/** + * An enumeration that represents the different subclasses of nodes. + * + * @author Paul Grogan + */ +public enum NodeType { + /** The lagrange node type. */ + LAGRANGE("Lagrange", "icons/bullet_purple.png"), + + /** The orbital node type. */ + ORBITAL("Orbital", "icons/bullet_red.png"), + + /** The surface node type. */ + SURFACE("Surface", "icons/bullet_yellow.png"), ; + + private String name; + private ImageIcon icon; + + private NodeType(String name, String iconUrl) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } + + /** + * Gets the name of the node type. + * + * @return the node type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon of the node type. + * + * @return the node type icon + */ + public ImageIcon getIcon() { + return icon; + } + + /** + * Gets the node type instance based on a passed name. + * + * @param name the node type name + * + * @return the node type, null if not found + */ + public static NodeType getInstance(String name) { + for(NodeType t : NodeType.values()) { + if(t.getName().toLowerCase().equals(name.toLowerCase())) { + return t; + } + } + return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/node/OrbitalNode.java b/src/main/java/edu/mit/spacenet/domain/network/node/OrbitalNode.java new file mode 100644 index 0000000..3f9a201 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/node/OrbitalNode.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.node; + +/** + * Node that represents stable orbits around planetary bodies. + * + * @author Paul Grogan + */ +public class OrbitalNode extends SpaceNode { + private double inclination; + private double periapsis; + private double apoapsis; + + /** + * The default constructor. + */ + public OrbitalNode() { + super(); + } + + /** + * Gets the inclination of the orbit. + * + * @return the inclination (degrees) + */ + public double getInclination() { + return inclination; + } + + /** + * Sets the inclination of the orbit. + * + * @param inclination the inclination (degrees) + */ + public void setInclination(double inclination) { + this.inclination = inclination; + } + + /** + * Gets the periapsis, or distance from the center of the planetary body to + * the point on the orbit closest to the planetary body. + * + * @return periapsis the orbital periapsis (kilometers) + */ + public double getPeriapsis() { + return periapsis; + } + + /** + * Sets the periapsis, or distance from the center of the planetary body to + * the point on the orbit closest to the planetary body. + * + * @param periapsis the orbital periapsis (kilometers) + */ + public void setPeriapsis(double periapsis) { + this.periapsis = periapsis; + } + + /** + * Gets the apoapsis, or distance from the center of the planetary body to + * the point on the orbit farthest away to the planetary body. + * + * @return the orbital apoapsis (kilometers) + */ + public double getApoapsis() { + return apoapsis; + } + + /** + * Sets the apoapsis, or distance from the center of the planetary body to + * the point on the orbit farthest away to the planetary body. + * + * @param apoapsis the apoapsis (kilometers) + */ + public void setApoapsis(double apoapsis) { + this.apoapsis = apoapsis; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.network.node.Node#getNodeType() + */ + @Override + public NodeType getNodeType() { + return NodeType.ORBITAL; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/network/node/SpaceNode.java b/src/main/java/edu/mit/spacenet/domain/network/node/SpaceNode.java new file mode 100644 index 0000000..ea9d7ab --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/node/SpaceNode.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.node; + +/** + * Abstract node that represents nodes not on the surface of planetary bodies. + * + * @author Paul Grogan + */ +public abstract class SpaceNode extends Node { + +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/network/node/SurfaceNode.java b/src/main/java/edu/mit/spacenet/domain/network/node/SurfaceNode.java new file mode 100644 index 0000000..d36cb43 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/network/node/SurfaceNode.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.network.node; + +/** + * Node that represents a point on a planetary body's surface. + * + * @author Paul Grogan + */ +public class SurfaceNode extends Node { + private double latitude; + private double longitude; + + /** + * The default constructor. + */ + public SurfaceNode() { + super(); + } + + /** + * Gets the latitude of the point. + * + * @return the latitude (degrees) + */ + public double getLatitude() { + return latitude; + } + + /** + * Sets the latitude of the point. + * + * @param latitude the latitude (degrees) + */ + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + /** + * Gets the longitude of the point. + * + * @return the longitude (degrees) + */ + public double getLongitude() { + return longitude; + } + + /** + * Sets the longitude of the point. + * + * @param longitude the longitude (degrees) + */ + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.network.node.Node#getNodeType() + */ + @Override + public NodeType getNodeType() { + return NodeType.SURFACE; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/resource/Demand.java b/src/main/java/edu/mit/spacenet/domain/resource/Demand.java new file mode 100644 index 0000000..e3de3a1 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/resource/Demand.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.resource; + +import java.text.DecimalFormat; + +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Represents a demanded resource and the demanded amount. + * + * @author Paul Grogan + */ +public class Demand implements Comparable { + private I_Resource resource; + private double amount; + + /** + * The default constructor. + */ + public Demand() { + + } + + /** + * Gets the mass of the associated demand. + * + * @return the mass of the associated demand (kilograms) + */ + public double getMass() { + if(resource==null) return 0; + else return GlobalParameters.getRoundedMass(resource.getUnitMass()*amount); + } + + /** + * Gets the volume of the associated demand. + * + * @return the volume of the associated demand (cubic meters) + */ + public double getVolume() { + if(resource==null) return 0; + else return GlobalParameters.getRoundedVolume(resource.getUnitVolume()*amount); + } + + /** + * A constructor that sets the resource and amount. + * + * @param resource the resource + * @param amount the amount + */ + public Demand(I_Resource resource, double amount) { + super(); + setResource(resource); + setAmount(amount); + } + + /** + * Gets the demanded resource. + * + * @return the resource + */ + public I_Resource getResource() { + return resource; + } + + /** + * Sets the demanded resource. + * + * @param resource the resource + */ + public void setResource(I_Resource resource) { + this.resource = resource; + } + + /** + * Gets the demanded amount. + * + * @return the demanded amount (units of resource) + */ + public double getAmount() { + return GlobalParameters.getRoundedDemand(amount); + } + + /** + * Sets the demanded amount. + * + * @param amount the demanded amount (units of resource) + */ + public void setAmount(double amount) { + this.amount = amount; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + DecimalFormat format = new DecimalFormat("0.00"); + if(resource == null) { + return format.format(getAmount()) + " units of unknown"; + } else { + return format.format(getAmount()) + " " + resource.getUnits() + " of " + resource.getName(); + } + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Demand demand) { + if(getResource() == null) { + if(demand.getResource() == null) return 0; + else return -1; + } else { + return getResource().compareTo(demand.getResource()); + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/resource/DemandSet.java b/src/main/java/edu/mit/spacenet/domain/resource/DemandSet.java new file mode 100644 index 0000000..4f25830 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/resource/DemandSet.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.resource; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A wrapper for a set of demands that performs grouping operations. + * + * @author Paul Grogan + */ +public class DemandSet implements Iterable { + private static final long serialVersionUID = 153270744123011256L; + private SortedSet demands; + + /** + * The constructor. + */ + public DemandSet() { + demands = new TreeSet(); + } + + /** + * Adds a demand. + * + * @param demand the demand + * + * @return whether the operation was successful + */ + public boolean add(Demand demand) { + for(Demand d : demands) { + if(d.getResource().equals((demand.getResource()))) { + d.setAmount(d.getAmount() + demand.getAmount()); + return true; + } + } + Demand d = new Demand(); + d.setResource(demand.getResource()); + d.setAmount(demand.getAmount()); + return demands.add(d); + } + + /** + * Adds a set of demands. + * + * @param demands the demands + */ + public void addAll(Iterable demands) { + for(Demand demand : demands) { + add(demand); + } + } + + /** + * Removes a demand. + * + * @param demand the demand + * + * @return whether the operation was successful + */ + public boolean remove(Demand demand) { + for(Demand d : demands) { + if(d.getResource().equals(demand.getResource())) { + if(d.getAmount() >= demand.getAmount()) { + d.setAmount(d.getAmount() - demand.getAmount()); + demand.setAmount(0); + return true; + } else { + demand.setAmount(demand.getAmount() - d.getAmount()); + d.setAmount(0); + return false; + } + } + } + return false; + } + + /** + * Gets the total mass of all demands. + * + * @return the mass (kilograms) + */ + public double getTotalMass() { + double mass = 0; + for(Demand demand : demands) { + mass += demand.getMass(); + } + return GlobalParameters.getRoundedMass(mass); + } + + /** + * Gets the total volume of all demands. + * + * @return the volume (cubic meters) + */ + public double getTotalVolume() { + double volume = 0; + for(Demand demand : demands) { + volume += demand.getVolume(); + } + return GlobalParameters.getRoundedVolume(volume); + } + + /* (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + public Iterator iterator() { + return demands.iterator(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return demands.toString(); + } + + /** + * Gets the number of different demands. + * + * @return the size of the set + */ + public int size() { + return demands.size(); + } + + /** + * Clears all of the demands. + */ + public void clear() { + demands.clear(); + } + + /** + * Removes any demands with zero amount. + */ + public void clean() { + List forRemoval = new ArrayList(); + for(Demand demand : this) { + if(demand==null||demand.getAmount()==0) + forRemoval.add(demand); + } + for(Demand d : forRemoval) { + demands.remove(d); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/resource/GenericResource.java b/src/main/java/edu/mit/spacenet/domain/resource/GenericResource.java new file mode 100644 index 0000000..6422197 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/resource/GenericResource.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.resource; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; + +/** + * A specific type of resource that is forced to have type identifier -cos and + * (unit) mass 1. + * + * @author Paul Grogan + */ +public class GenericResource extends Resource { + + /** + * The constructor that assigns a TID of -COS and a (unit) mass of 1. It + * also sets the class of supply and creates a generic name based on it. + * + * @param classOfSupply the resource class of supply + */ + public GenericResource(ClassOfSupply classOfSupply) { + super(); + setTid(-classOfSupply.getId()); + setName("Generic COS " + classOfSupply.getId() + " (" + classOfSupply.getName() + ")"); + setUnitMass(1); + setUnits("kg"); + setClassOfSupply(classOfSupply); + } + + /** + * Constructor that sets the class of supply and environment. Also assigns + * a TID of -COS and a (unit) mass of 1. + * + * @param classOfSupply the resource class of supply + * @param environment the resource environment + */ + public GenericResource(ClassOfSupply classOfSupply, Environment environment) { + this(classOfSupply); + setEnvironment(environment); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.Resource#getUnitVolume() + */ + @Override + public double getUnitVolume() { + if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS1)) return 1900/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS201)) return 1/1000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS2)) return 7000/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS3)) return 5000/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS4)) return 3000/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS5)) return 7000/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS6)) return 5000/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS7)) return 5000/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS8)) return 3500/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS9)) return 3500/1000000d; + else if(getClassOfSupply().isInstanceOf(ClassOfSupply.COS10)) return 7000/1000000d; + else return super.getUnitVolume(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.Resource#getPackingFactor() + */ + @Override + public double getPackingFactor() { + if(getClassOfSupply().equals(ClassOfSupply.COS203)) return 1.0; + else if(getClassOfSupply().equals(ClassOfSupply.COS201)) return 0.5; + else if(getClassOfSupply().equals(ClassOfSupply.COS6)) return 0; + else if(getEnvironment().equals(Environment.UNPRESSURIZED)) return 0.6; + //else if(getEnvironment().equals(Environment.PRESSURIZED_INTERNAL)) return 0.2; + //else if(getEnvironment().equals(Environment.PRESSURIZED_EXTERNAL)) return 1.2; + else if(getEnvironment().equals(Environment.PRESSURIZED)) return 1.2; + else return super.getPackingFactor(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.Resource#getResourceType() + */ + @Override + public ResourceType getResourceType() { + return ResourceType.GENERIC; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/resource/I_Item.java b/src/main/java/edu/mit/spacenet/domain/resource/I_Item.java new file mode 100644 index 0000000..a77db0f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/resource/I_Item.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.resource; + +/** + * Interface that represents discrete supply items. + * + * @author Paul Grogan + */ +public interface I_Item extends I_Resource { + +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/resource/I_Resource.java b/src/main/java/edu/mit/spacenet/domain/resource/I_Resource.java new file mode 100644 index 0000000..fd6ef17 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/resource/I_Resource.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.resource; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.I_DomainType; + +/** + * Interface that represents any supply item (discrete or continuous). + * + * @author Paul Grogan + */ +public interface I_Resource extends I_DomainType, Comparable { + + /** + * Gets the class of supply. + * + * @return the class of supply + */ + public ClassOfSupply getClassOfSupply(); + + /** + * Sets the class of supply. + * + * @param classOfSupply the class of supply + */ + public void setClassOfSupply(ClassOfSupply classOfSupply); + + /** + * Gets the resource environment. + * + * @return the environment + */ + public Environment getEnvironment(); + + /** + * Sets the resource environment. + * + * @param environment the environment + */ + public void setEnvironment(Environment environment); + + /** + * Gets the packing factor, which is the factor of additional COS 5 demands + * that is added to unpacked demand figures. + * + * @return the packing factor + */ + public double getPackingFactor(); + + /** + * Sets the packing factor, which is the factor of additional COS 5 demands + * that is added to unpacked demand figures. + * + * @param factor the packing factor + */ + public void setPackingFactor(double factor); + + /** + * Gets the units of measure. + * + * @return the units of measure + */ + public String getUnits(); + + /** + * Sets the units of measure. + * + * @param units the units of measure + */ + public void setUnits(String units); + + /** + * Gets the unit mass. + * + * @return the unit mass (kilograms per unit of consumption) + */ + public double getUnitMass(); + + /** + * Sets the unit mass. + * + * @param unitMass the unit mass + */ + public void setUnitMass(double unitMass); + + /** + * Gets the unit volume. + * + * @return the unit volume (cubic meters per unit) + */ + public double getUnitVolume(); + + /** + * Sets the unit volume. + * + * @param unitVolume the unit volume (cubic meters per unit) + */ + public void setUnitVolume(double unitVolume); + + /** + * Checks whether this resource is substitutable (same or higher level of + * fidelity) for a given resource during demand consumption. + * + * @param resource the resource to check for substitutability + * + * @return true if this can be substituted for resource, false otherwise + */ + public boolean isSubstitutableFor(I_Resource resource); + + /** + * Gets the resource type. + * + * @return the resource type + */ + public ResourceType getResourceType(); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/resource/Item.java b/src/main/java/edu/mit/spacenet/domain/resource/Item.java new file mode 100644 index 0000000..30564fe --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/resource/Item.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.resource; + +/** + * A discrete resource. + * + * @author Paul Grogan + */ +public class Item extends Resource implements I_Item { + + /** + * The default constructor. + */ + public Item() { + super(); + setUnits("item"); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.Resource#getResourceType() + */ + @Override + public ResourceType getResourceType() { + return ResourceType.ITEM; + } +} diff --git a/src/main/java/edu/mit/spacenet/domain/resource/Resource.java b/src/main/java/edu/mit/spacenet/domain/resource/Resource.java new file mode 100644 index 0000000..bb66640 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/resource/Resource.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.resource; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.DomainType; +import edu.mit.spacenet.domain.Environment; + +/** + * A continuous resource. + * + * @author Paul Grogan + */ +public class Resource extends DomainType implements I_Resource { + private ClassOfSupply classOfSupply; + private Environment environment; + private String units; + private double unitMass; + private double unitVolume; + private double packingFactor; + + /** + * The default constructor that sets a default name, sets the default class + * of supply to COS 0, sets the environment to unpressurized, and sets + * default units to kilograms. + */ + public Resource() { + super(); + setName("New " + getClass().getSimpleName()); + setClassOfSupply(ClassOfSupply.COS0); + setEnvironment(Environment.UNPRESSURIZED); + setUnitMass(1); + setUnits("kg"); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#getClassOfSupply() + */ + public ClassOfSupply getClassOfSupply() { + return classOfSupply; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#setClassOfSupply(edu.mit.spacenet.domain.ClassOfSupply) + */ + public void setClassOfSupply(ClassOfSupply classOfSupply) { + this.classOfSupply = classOfSupply; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#getEnvironment() + */ + public Environment getEnvironment() { + return environment; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#setEnvironment(edu.mit.spacenet.domain.Environment) + */ + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#getUnits() + */ + public String getUnits() { + return units; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#setUnits(java.lang.String) + */ + public void setUnits(String units) { + this.units = units; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#getUnitMass() + */ + public double getUnitMass() { + return unitMass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#setUnitMass(double) + */ + public void setUnitMass(double unitMass) { + this.unitMass = unitMass; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#getUnitVolume() + */ + public double getUnitVolume() { + return unitVolume; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#setUnitVolume(double) + */ + public void setUnitVolume(double unitVolume) { + this.unitVolume = unitVolume; + } + + /** + * Gets the total mass. + * + * @return the total mass + */ + public double getTotalMass() { + return getUnitMass(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.DomainType#equals(java.lang.Object) + */ + @Override + public boolean equals(Object object) { + if(super.equals(object) && object instanceof I_Resource) { + return getEnvironment().equals(((I_Resource)object).getEnvironment()); + } else return false; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(I_Resource resource) { + if(getClassOfSupply().equals(resource.getClassOfSupply())) { + if(getTid()==resource.getTid()) { + return getEnvironment().compareTo(resource.getEnvironment()); + } else return new Integer(getTid()).compareTo(resource.getTid()); + } else return getClassOfSupply().compareTo(resource.getClassOfSupply()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#isSubstitutableFor(edu.mit.spacenet.domain.resource.I_Resource) + */ + public boolean isSubstitutableFor(I_Resource resource) { + if(getTid() < 0) { + // tid < 0 means this is a generic resource + if(getClassOfSupply().equals(resource.getClassOfSupply()) + || getClassOfSupply().isSubclassOf(resource.getClassOfSupply())) { + // if this class of supply is the same as or more specific + // than target class of supply this resource can be substituted + // for target resource + return true; + } else { + return false; + } + } else if(getTid() > 0) { + // tid > 0 means this is a specific resource loaded from the database + if(getTid() == resource.getTid()) { + // if this type id is the same as the target type id, the two + // resources are mutually substitutable + return true; + } else { + return false; + } + } else { + // tid == 0 means this resource was created during execution + System.out.println("Cannot currently use non-database resources in demands."); + return false; + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#getPackingFactor() + */ + public double getPackingFactor() { + return packingFactor; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#setPackingFactor(double) + */ + public void setPackingFactor(double packingFactor) { + this.packingFactor = packingFactor; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.resource.I_Resource#getResourceType() + */ + public ResourceType getResourceType() { + return ResourceType.RESOURCE; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/domain/resource/ResourceType.java b/src/main/java/edu/mit/spacenet/domain/resource/ResourceType.java new file mode 100644 index 0000000..064c5a1 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/domain/resource/ResourceType.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.domain.resource; + +import javax.swing.ImageIcon; + +/** + * An enumeration for the different subclasses of resources. + * + * @author Paul Grogan + */ +public enum ResourceType { + + /** The generic resource type. */ + GENERIC("Generic", "icons/bullet_pink.png"), + + /** The continuous resource type. */ + RESOURCE("Continuous", "icons/bullet_blue.png"), + + /** The discrete resource type. */ + ITEM("Discrete", "icons/bullet_wrench.png"); + + private String name; + private ImageIcon icon; + + private ResourceType(String name, String iconUrl) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } + + /** + * Gets the name of the resource type. + * + * @return the resource type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon of the resource type. + * + * @return the resource type icon + */ + public ImageIcon getIcon() { + return icon; + } + + /** + * Gets the resource type instance based on a passed name. + * + * @param name the resource type name + * + * @return the resource type, null if not found + */ + public static ResourceType getInstance(String name) { + for(ResourceType t : ResourceType.values()) { + if(t.getName().toLowerCase().equals(name.toLowerCase())) { + return t; + } + } + return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/AboutDialog.java b/src/main/java/edu/mit/spacenet/gui/AboutDialog.java new file mode 100644 index 0000000..9499215 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/AboutDialog.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; + +/** + * Dialog that displays information about SpaceNet, including the version + * number, the authors, and any licensing details. + * + * @author Paul Grogan + */ +public class AboutDialog extends JDialog { + private static final long serialVersionUID = -802497885876127342L; + + /** + * Initializes a new about dialog. + * + * @param spaceNetFrame the parent space net frame + */ + public AboutDialog() { + super(SpaceNetFrame.getInstance(), "About SpaceNet", true); + setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); + buildDialog(); + pack(); + } + + /** + * Builds the dialog. + */ + private void buildDialog() { + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setBackground(new Color(153,51,51)); + contentPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.HORIZONTAL; + JLabel mitLogo = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("icons/mit_footer.png"))); + mitLogo.setOpaque(false); + contentPanel.add(mitLogo, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + JLabel spaceNetLogo = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("icons/spacenet_splash.png"))); + spaceNetLogo.setPreferredSize(new Dimension(138,119)); + contentPanel.add(spaceNetLogo, c); + c.gridy++; + JLabel titleLabel = new JLabel("SpaceNet 2.5r2"); + titleLabel.setForeground(Color.WHITE); + titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD).deriveFont(18f)); + contentPanel.add(titleLabel, c); + c.gridy++; + JLabel websiteLabel = new JLabel("http://spacenet.mit.edu"); + websiteLabel.setForeground(Color.WHITE); + contentPanel.add(websiteLabel, c); + c.gridy++; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + JTextPane textPane = new JTextPane(); + textPane.setText("Copyright (c) 2010 MIT Strategic Engineering Research Group" + + "\n\nSpaceNet 2.5r2 is released under the GNU General Public License (GPL) Version 3." + + "\n\nThis project was paritally supported by the Jet Propulsion Laboratory (JPL) " + + "under the Strategic University Relations Program (SURP) and contract number 1344341." + + "\n\nResearch Advisor:\tOlivier de Weck" + + "\n\nJPL Contacts:\t\tGene Lee\n\t\tLiz Jordan" + + "\n\nLead Developer:\tPaul Grogan" + + "\n\nContributors:\t\tNii Armar\n\t\tIvo Ferreira\n\t\tAbe Grindle\n\t\tTakuto Ishimatsu\n\t\tBasant Sagar\n\t\tRobert Shishko\n\t\tAfreen Siddiqi" + + "\n\nPast Developers:\tJaemyung Ahn\n\t\tErica Gralla\n\t\tDiego Klabjan\n\t\tJason Mellein\n\t\tSarah Shull" + + "\n\nTest Subjects:\t\tTorin Clark\n\t\tBen Corbin\n\t\tJustin Kaderka\n\t\tGreg O'Neill\n\t\tDaniel Selva\n\t\tNarek Shougarian\n\t\tAnthony Wicht\n\t\tHoward Yue" + + "\n\nIcon Set:\t\tMark James, FamFamFam Silk" + + "\n\nLook and Feel:\t\tNNL Technology, InfoNode"); + textPane.setEditable(false); + textPane.setCaretPosition(0); + JScrollPane textScroll = new JScrollPane(textPane); + textScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + textScroll.setPreferredSize(new Dimension(300,200)); + contentPanel.add(textScroll, c); + c.weighty = 0; + c.gridy++; + c.fill = GridBagConstraints.NONE; + JButton okButton = new JButton("OK"); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + contentPanel.add(okButton, c); + getRootPane().setDefaultButton(okButton); + + setContentPane(contentPanel); + } + + /** + * Show dialog. + */ + public void showDialog() { + pack(); + setLocationRelativeTo(getParent()); + setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/OptionsDialog.java b/src/main/java/edu/mit/spacenet/gui/OptionsDialog.java new file mode 100644 index 0000000..50b8aa2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/OptionsDialog.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.Hashtable; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.JSpinner; +import javax.swing.JTabbedPane; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.scenario.ItemDiscretization; + +/** + * Dialog that displays options related to a specific scenario. + * + * @author Paul Grogan + */ +public class OptionsDialog extends JDialog { + private static final long serialVersionUID = -802497885876127342L; + + private ScenarioPanel scenarioPanel; + + private JPanel precisionPanel, constraintsPanel, demandsPanel, simulationPanel; + private SpinnerNumberModel timeModel, demandModel, massModel, volumeModel; + private JSpinner timeSpinner, demandSpinner, massSpinner, volumeSpinner; + private JCheckBox volumeConstrained, environmentConstrained; + + private JComboBox discretizationCombo; + private JSlider aggregationSlider; + private JCheckBox scavengeSparesCheck; + + private JCheckBox explorationCheck, evaCheck; + + /** + * Instantiates a new options dialog. + * + * @param scenarioPanel the scenario panel + */ + public OptionsDialog(ScenarioPanel scenarioPanel) { + super(scenarioPanel.getSpaceNetFrame(), "Scenario Options", true); + this.scenarioPanel = scenarioPanel; + + buildDialog(); + setResizable(false); + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + } + + /** + * Builds the dialog. + */ + private void buildDialog() { + buildPrecisionPanel(); + buildConstraintsPanel(); + buildDemandsPanel(); + buildSimulationPanel(); + + JPanel contentPanel = new JPanel(); + contentPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + JTabbedPane tabbedPane = new JTabbedPane(); + tabbedPane.addTab("Precision", precisionPanel); + tabbedPane.addTab("Constraints", constraintsPanel); + tabbedPane.addTab("Demands", demandsPanel); + tabbedPane.addTab("Simulation", simulationPanel); + contentPanel.add(tabbedPane, c); + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + JButton okButton = new JButton("OK"); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveOptions(); + scenarioPanel.updateView(); + dispose(); + } + }); + buttonPanel.add(okButton, c); + getRootPane().setDefaultButton(okButton); + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPanel.add(cancelButton, c); + contentPanel.add(buttonPanel, c); + + setModal(true); + setContentPane(contentPanel); + setMinimumSize(new Dimension(300,250)); + } + + /** + * Builds the precision panel. + */ + private void buildPrecisionPanel() { + precisionPanel = new JPanel(); + precisionPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + precisionPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + precisionPanel.add(new JLabel("Time Precision: "), c); + c.gridy++; + precisionPanel.add(new JLabel("Demand Precision: "), c); + c.gridy++; + precisionPanel.add(new JLabel("Mass Precision: "), c); + c.gridy++; + precisionPanel.add(new JLabel("Volume Precision: "), c); + c.gridy++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.gridx = 1; + c.gridy = 0; + timeModel = new SpinnerNumberModel(0.001,0.001,1.000,0.001); + timeSpinner = new JSpinner(timeModel); + precisionPanel.add(new UnitsWrapper(timeSpinner, "days"), c); + c.gridy++; + demandModel = new SpinnerNumberModel(0.001,0.001,1.000,0.001); + demandSpinner = new JSpinner(demandModel); + precisionPanel.add(new UnitsWrapper(demandSpinner, "units"), c); + c.gridy++; + massModel = new SpinnerNumberModel(0.001,0.001,1.000,0.001); + massSpinner = new JSpinner(massModel); + precisionPanel.add(new UnitsWrapper(massSpinner, "kg"), c); + c.gridy++; + volumeModel = new SpinnerNumberModel(0.1,0.1,100.,0.1); + volumeSpinner = new JSpinner(volumeModel); + precisionPanel.add(new UnitsWrapper(volumeSpinner, "cm^3"), c); + c.gridy++; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + precisionPanel.add(new JLabel(), c); + } + + /** + * Builds the constraints panel. + */ + private void buildConstraintsPanel() { + constraintsPanel = new JPanel(); + constraintsPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + constraintsPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + volumeConstrained = new JCheckBox("Volume Constraints Enforced"); + volumeConstrained.setOpaque(false); + constraintsPanel.add(volumeConstrained, c); + c.gridy++; + environmentConstrained = new JCheckBox("Environment Constraints Enforced"); + environmentConstrained.setOpaque(false); + constraintsPanel.add(environmentConstrained, c); + c.gridy++; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + constraintsPanel.add(new JLabel(), c); + } + + /** + * Builds the demands panel. + */ + private void buildDemandsPanel() { + demandsPanel = new JPanel(); + demandsPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + demandsPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + demandsPanel.add(new JLabel("Item Discretization: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + demandsPanel.add(new JLabel("Item Aggregation: "), c); + c.weightx = 1; + c.gridx = 1; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + discretizationCombo = new JComboBox(); + discretizationCombo.setToolTipText("Discretize demands for items to integer values at the selected level"); + for(ItemDiscretization t : ItemDiscretization.values()) { + discretizationCombo.addItem(t); + } + discretizationCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + aggregationSlider.setEnabled(discretizationCombo.getSelectedItem()!=ItemDiscretization.NONE); + } + } + }); + demandsPanel.add(discretizationCombo, c); + c.gridy++; + aggregationSlider = new JSlider(JSlider.VERTICAL,0,4,0); + aggregationSlider.setOpaque(false); + aggregationSlider.setFocusable(false); + aggregationSlider.setToolTipText("Aggregate discretized item demands ahead or behind demands."); + Hashtable labelTable = new Hashtable(); + labelTable.put(new Integer(0), new JLabel("First Demand", JLabel.LEFT)); + labelTable.put(new Integer(2), new JLabel("Half Demand", JLabel.LEFT)); + labelTable.put(new Integer(4), new JLabel("Unit Demand", JLabel.RIGHT)); + aggregationSlider.setLabelTable(labelTable); + aggregationSlider.setPaintLabels(true); + aggregationSlider.setMajorTickSpacing(1); + aggregationSlider.setSnapToTicks(true); + aggregationSlider.setPaintTicks(true); + aggregationSlider.setPreferredSize(new Dimension(100,100)); + demandsPanel.add(aggregationSlider, c); + c.gridy++; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridwidth = 2; + c.gridx = 0; + scavengeSparesCheck = new JCheckBox("Scavenge Spares"); + scavengeSparesCheck.setOpaque(false); + demandsPanel.add(scavengeSparesCheck, c); + c.gridy++; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + demandsPanel.add(new JLabel(), c); + } + + /** + * Builds the simulation panel. + */ + private void buildSimulationPanel() { + simulationPanel = new JPanel(); + simulationPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + simulationPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + explorationCheck = new JCheckBox("Detailed Explorations"); + explorationCheck.setOpaque(false); + simulationPanel.add(explorationCheck, c); + c.gridy++; + evaCheck = new JCheckBox("Detailed EVAs"); + evaCheck.setOpaque(false); + simulationPanel.add(evaCheck, c); + c.gridy++; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + simulationPanel.add(new JLabel(), c); + } + + /** + * Saves the options. + */ + private void saveOptions() { + scenarioPanel.updateView(); + scenarioPanel.getScenario().setTimePrecision(timeModel.getNumber().doubleValue()); + scenarioPanel.getScenario().setDemandPrecision(demandModel.getNumber().doubleValue()); + scenarioPanel.getScenario().setMassPrecision(massModel.getNumber().doubleValue()); + scenarioPanel.getScenario().setVolumePrecision(volumeModel.getNumber().doubleValue()/1000000D); + scenarioPanel.getScenario().setVolumeConstrained(volumeConstrained.isSelected()); + scenarioPanel.getScenario().setEnvironmentConstrained(environmentConstrained.isSelected()); + scenarioPanel.getScenario().setItemDiscretization((ItemDiscretization)discretizationCombo.getSelectedItem()); + scenarioPanel.getScenario().setItemAggregation(aggregationSlider.getValue()/4D); + scenarioPanel.getScenario().setScavengeSpares(scavengeSparesCheck.isSelected()); + scenarioPanel.getScenario().setDetailedEva(evaCheck.isSelected()); + scenarioPanel.getScenario().setDetailedExploration(explorationCheck.isSelected()); + } + + /** + * Initializes the dialog with the options data. + */ + private void initialize() { + timeModel.setValue(scenarioPanel.getScenario().getTimePrecision()); + demandModel.setValue(scenarioPanel.getScenario().getDemandPrecision()); + massModel.setValue(scenarioPanel.getScenario().getMassPrecision()); + volumeModel.setValue(scenarioPanel.getScenario().getVolumePrecision()*1000000); + + volumeConstrained.setSelected(scenarioPanel.getScenario().isVolumeConstrained()); + environmentConstrained.setSelected(scenarioPanel.getScenario().isEnvironmentConstrained()); + + discretizationCombo.setSelectedItem(scenarioPanel.getScenario().getItemDiscretization()); + aggregationSlider.setEnabled(discretizationCombo.getSelectedItem()!=ItemDiscretization.NONE); + aggregationSlider.setValue((int)(4*scenarioPanel.getScenario().getItemAggregation())); + scavengeSparesCheck.setSelected(scenarioPanel.getScenario().isScavengeSpares()); + + explorationCheck.setSelected(scenarioPanel.getScenario().isDetailedExploration()); + evaCheck.setSelected(scenarioPanel.getScenario().isDetailedEva()); + } + + /** + * Initializes the view components, re-positions the dialog to the center + * of the frame, and enabled visibility. + */ + public void showDialog() { + initialize(); + pack(); + setLocationRelativeTo(getParent()); + setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/ScenarioPanel.java b/src/main/java/edu/mit/spacenet/gui/ScenarioPanel.java new file mode 100644 index 0000000..b9625ca --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/ScenarioPanel.java @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.text.SimpleDateFormat; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import com.toedter.calendar.JDateChooser; + +import edu.mit.spacenet.data.DataSourceType; +import edu.mit.spacenet.gui.command.LoadDataSourceCommand; +import edu.mit.spacenet.gui.data.DataSourceDialog; +import edu.mit.spacenet.gui.demand.DemandsTab; +import edu.mit.spacenet.gui.manifest.ManifestTab; +import edu.mit.spacenet.gui.mission.MissionsTab; +import edu.mit.spacenet.gui.network.NetworkTab; +import edu.mit.spacenet.gui.simulation.SimulationTab; +import edu.mit.spacenet.scenario.Scenario; + +/** + * The main component for displaying and organizing scenario information. A + * JSplitPane with the top component being the "details panel" (red background), + * and the bottom component being a JTabbedView with the five major modules + * (Network, Missions, Demands, Manifest, Simulation). + * + * @author Paul Grogan + */ +public class ScenarioPanel extends JSplitPane { + private static final long serialVersionUID = 6919650461629452601L; + + private SpaceNetFrame spaceNetFrame; + private Scenario scenario; + + private OptionsDialog optionsDialog; + + private JTextField nameText, ownerText; + private JDateChooser startDate; + private JLabel dataSourceLabel, lastLoadLabel; + private JButton optionsButton, dataSourceButton, reloadButton; + private JTextArea descriptionText; + + private JTabbedPane tabs; + private NetworkTab networkTab; + private MissionsTab missionsTab; + private DemandsTab demandsTab; + private ManifestTab manifestTab; + private SimulationTab simulationTab; + + /** + * Instantiates a new scenario panel. + * + * @param spaceNetFrame the space net frame + */ + public ScenarioPanel(SpaceNetFrame spaceNetFrame) { + super(JSplitPane.VERTICAL_SPLIT); + this.spaceNetFrame = spaceNetFrame; + optionsDialog = new OptionsDialog(this); + + buildPanel(); + + setBackground(Color.LIGHT_GRAY); + setDividerSize(5); + setOneTouchExpandable(true); + setDividerLocation(100); + setResizeWeight(0); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + JPanel detailsPanel = new JPanel(); + detailsPanel.setForeground(Color.WHITE); + detailsPanel.setBackground(new Color(153,51,51)); + detailsPanel.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); + detailsPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.gridheight = 3; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + ImageIcon icon = new ImageIcon(getClass().getClassLoader().getResource("icons/spacenet_splash.png")); + icon.setImage(icon.getImage().getScaledInstance(75, 75, Image.SCALE_SMOOTH)); + detailsPanel.add(new JLabel(icon), c); + + c.gridx++; + c.weightx = .05; + c.gridheight = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + detailsPanel.add(new HeaderLabel("Name: "), c); + c.gridy++; + detailsPanel.add(new HeaderLabel("Start Date: "), c); + c.gridy++; + detailsPanel.add(new HeaderLabel("Created By: "), c); + + c.gridx++; + c.gridy = 0; + c.weightx = .25; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText = new JTextField(20); + nameText.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent e) { + scenario.setName(nameText.getText()); + spaceNetFrame.repaint(); // update frame title + } + }); + detailsPanel.add(nameText, c); + c.gridy++; + startDate = new JDateChooser(); + startDate.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + if(e.getPropertyName().equals("date")) { + scenario.setStartDate(startDate.getDate()); + } + } + }); + detailsPanel.add(startDate, c); + c.gridy++; + ownerText = new JTextField(15); + ownerText.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent e) { + scenario.setCreatedBy(ownerText.getText()); + } + }); + detailsPanel.add(ownerText, c); + + c.gridx++; + c.gridy = 0; + c.weightx = .05; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + detailsPanel.add(new HeaderLabel("Description: "), c); + + c.gridx++; + c.weightx = .4; + c.weighty = 1; + c.gridheight = 4; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + descriptionText.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent e) { + scenario.setDescription(descriptionText.getText()); + } + }); + JScrollPane descriptionScroll = new JScrollPane(descriptionText); + descriptionScroll.setPreferredSize(new Dimension(250,50)); + detailsPanel.add(descriptionScroll, c); + + c.gridx++; + c.gridy = 0; + c.weightx = .05; + c.weighty = 0; + c.gridheight = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + detailsPanel.add(new HeaderLabel("Options: "), c); + c.gridy++; + detailsPanel.add(new HeaderLabel("Data Source: "), c); + + c.gridx++; + c.gridy = 0; + c.weightx = .1; + c.anchor = GridBagConstraints.LINE_START; + optionsButton = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/cog_edit.png"))); + optionsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + optionsDialog.showDialog(); + } + }); + detailsPanel.add(optionsButton, c); + c.gridy++; + c.fill = GridBagConstraints.HORIZONTAL; + JPanel dataPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + dataPanel.setOpaque(false); + dataSourceLabel = new JLabel(""); + dataSourceLabel.setForeground(Color.WHITE); + dataPanel.add(dataSourceLabel); + dataSourceButton = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/database_edit.png"))); + dataSourceButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DataSourceDialog.createAndShowGUI(getThis()); + } + }); + dataPanel.add(dataSourceButton); + reloadButton = new JButton("Reload", new ImageIcon(getClass().getClassLoader().getResource("icons/database_refresh.png"))); + reloadButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + LoadDataSourceCommand command = new LoadDataSourceCommand(getThis()); + command.execute(); + } + }); + dataPanel.add(reloadButton); + detailsPanel.add(dataPanel, c); + c.gridy++; + lastLoadLabel = new JLabel(); + lastLoadLabel.setForeground(Color.WHITE); + detailsPanel.add(lastLoadLabel, c); + + setTopComponent(detailsPanel); + + tabs = new JTabbedPane(); + + networkTab = new NetworkTab(this); + tabs.addTab("Network", new ImageIcon(getClass().getClassLoader().getResource("icons/world.png")), networkTab); + + missionsTab = new MissionsTab(this); + tabs.addTab("Missions", new ImageIcon(getClass().getClassLoader().getResource("icons/flag_red.png")), missionsTab); + + demandsTab = new DemandsTab(this); + tabs.addTab("Demands", new ImageIcon(getClass().getClassLoader().getResource("icons/comment.png")), demandsTab); + + manifestTab = new ManifestTab(this); + tabs.addTab("Manifest", new ImageIcon(getClass().getClassLoader().getResource("icons/book_open.png")), manifestTab); + + simulationTab = new SimulationTab(this); + tabs.addTab("Simulation", new ImageIcon(getClass().getClassLoader().getResource("icons/lightning.png")), simulationTab); + + setBottomComponent(tabs); + + tabs.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + if(!tabs.getSelectedComponent().equals(networkTab) + && scenario.getNetwork().getNodes().size()==0) { + tabs.setSelectedComponent(networkTab); + JOptionPane.showMessageDialog(spaceNetFrame, + "At least one network node is required.", + "SpaceNet Warning", JOptionPane.WARNING_MESSAGE, + null); + } else if(!tabs.getSelectedComponent().equals(networkTab) + && !tabs.getSelectedComponent().equals(missionsTab) + && scenario.getMissionList().size()==0) { + tabs.setSelectedComponent(missionsTab); + JOptionPane.showMessageDialog(spaceNetFrame, + "At least one mission is required.", + "SpaceNet Warning", JOptionPane.WARNING_MESSAGE, + null); + } else if(tabs.getSelectedComponent().equals(networkTab)) { + // network tab is initialized when the scenario is + // loaded and is not dependent on any other components + } else if(tabs.getSelectedComponent().equals(missionsTab)) { + missionsTab.initialize(); + } else if(tabs.getSelectedComponent().equals(demandsTab)) { + demandsTab.initialize(); + } else if(tabs.getSelectedComponent().equals(manifestTab)) { + // do not re-initialize manifest + } else if(tabs.getSelectedComponent().equals(simulationTab)) { + // do not re-initialize scenario + } + spaceNetFrame.repaint(); + } + }); + } + + private void initialize() { + nameText.setEnabled(scenario!=null); + startDate.setEnabled(scenario!=null); + ownerText.setEnabled(scenario!=null); + optionsButton.setEnabled(scenario!=null); + dataSourceButton.setEnabled(scenario!=null); + reloadButton.setEnabled(scenario!=null); + descriptionText.setEnabled(scenario!=null); + if(scenario!=null) { + nameText.setText(scenario.getName()); + startDate.setDate(scenario.getStartDate()); + ownerText.setText(scenario.getCreatedBy()); + descriptionText.setText(scenario.getDescription()); + if(scenario.getDataSource()==null) { + dataSourceLabel.setText(DataSourceType.NONE.getName()); + dataSourceLabel.setIcon(DataSourceType.NONE.getIcon()); + } else { + dataSourceLabel.setText(getScenario().getDataSource().getDataSourceType().getName()); + dataSourceLabel.setIcon(getScenario().getDataSource().getDataSourceType().getIcon()); + } + networkTab.initialize(); + manifestTab.initialize(); + simulationTab.initialize(); + editNetwork(); + } + } + + /** + * Opens the tab to edit the network. + */ + public void editNetwork() { + tabs.setSelectedComponent(networkTab); + } + + /** + * Gets whether the network tab is being edited. + * + * @return whether the network is being edited + */ + public boolean isEditingNetwork() { + return tabs.getSelectedComponent().equals(networkTab); + } + + /** + * Opens the tab to edit the missions. + */ + public void editMissions() { + tabs.setSelectedComponent(missionsTab); + } + + /** + * Gets whether the missions tab is being edited. + * + * @return whether the missions are being edited + */ + public boolean isEditingMissions() { + return tabs.getSelectedComponent().equals(missionsTab); + } + + /** + * Opens the tab to edit the demands. + */ + public void editDemands() { + tabs.setSelectedComponent(demandsTab); + } + + /** + * Gets whether the demands tab is being edited. + * + * @return whether the demands tab is being edited + */ + public boolean isEditingDemands() { + return tabs.getSelectedComponent().equals(demandsTab); + } + + /** + * Opens the tab to edit the manifest. + */ + public void editManifest() { + tabs.setSelectedComponent(manifestTab); + } + + /** + * Gets whether the manifest tab is being edited. + * + * @return whether the manifest tab is being edited + */ + public boolean isEditingManifest() { + return tabs.getSelectedComponent().equals(manifestTab); + } + + /** + * Opens the tab to edit the simulation. + */ + public void editSimulation() { + tabs.setSelectedComponent(simulationTab); + } + + /** + * Gets whether the simulation tab is being edited. + * + * @return whether the simulation tab is being edited + */ + public boolean isEditingSimulation() { + return tabs.getSelectedComponent().equals(simulationTab); + } + + /** + * A custom JLabel class to format the labels in the scenario details panel. + */ + private class HeaderLabel extends JLabel { + private static final long serialVersionUID = -7501636123809460913L; + public HeaderLabel(String text) { + super(text); + setFont(getFont().deriveFont(Font.BOLD)); + setForeground(Color.WHITE); + } + } + + /** + * Gets this. + * + * @return this + */ + private ScenarioPanel getThis() { + return this; + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return scenario; + } + + /** + * Sets the scenario and refreshes all visible components. + * + * @param scenario the new scenario + */ + public void setScenario(Scenario scenario) { + this.scenario = scenario; + initialize(); + } + + /** + * Orders the scenario panel to update itself by reloading information from + * the model. Also orders the current open tab to update itself. + */ + public void updateView() { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Updating..."); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + if(getScenario().getDataSource()==null) { + reloadButton.setEnabled(false); + dataSourceLabel.setText(DataSourceType.NONE.getName()); + dataSourceLabel.setIcon(DataSourceType.NONE.getIcon()); + lastLoadLabel.setText(null); + } else { + reloadButton.setEnabled(true); + dataSourceLabel.setText(getScenario().getDataSource().getName()); + dataSourceLabel.setIcon(getScenario().getDataSource().getDataSourceType().getIcon()); + SimpleDateFormat format = new SimpleDateFormat("MMM, d yyyy h:mm a zzz"); + lastLoadLabel.setText("Last Loaded: " + (getScenario().getDataSource().getLastLoadDate()==null?"Never":format.format(getScenario().getDataSource().getLastLoadDate()))); + } + + if(isEditingNetwork()) { + networkTab.updateView(); + } else if(isEditingMissions()) { + missionsTab.updateView(); + } else if(isEditingDemands()) { + demandsTab.updateView(); + } else if(isEditingManifest()) { + manifestTab.updateView(); + } else if(isEditingSimulation()) { + simulationTab.updateView(); + } + + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + setCursor(Cursor.getDefaultCursor()); + } + + /** + * Gets the parent SpaceNet frame. + * + * @return the parent SpaceNet frame + */ + public SpaceNetFrame getSpaceNetFrame() { + return spaceNetFrame; + } + + /** + * Gets the options dialog. + * + * @return the options dialog + */ + public OptionsDialog getOptionsDialog() { + return optionsDialog; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/SpaceNetFrame.java b/src/main/java/edu/mit/spacenet/gui/SpaceNetFrame.java new file mode 100644 index 0000000..ec58b07 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/SpaceNetFrame.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; + +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.io.XMLFileFilter; +import edu.mit.spacenet.io.XStreamEngine; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.util.IconLibrary; +import edu.mit.spacenet.util.IdGenerator; + +/** + * The frame to contain the SpaceNet application. + * + * @author Paul Grogan + */ +public class SpaceNetFrame extends JFrame { + private static final long serialVersionUID = -6005760557525734285L; + + private static SpaceNetFrame instance; + + /** + * Gets the singleton reference to the SpaceNet frame. + * + * @return the singleton frame + */ + public static SpaceNetFrame getInstance() { + if(instance==null) instance = new SpaceNetFrame(); + return instance; + } + + private JFileChooser scenarioChooser; + private SpaceNetSettingsDialog spaceNetSettingsDialog; + private AboutDialog aboutDialog; + private SpaceNetMenuBar menuBar; + private JPanel contentPanel; + private ScenarioPanel scenarioPanel; + private SpaceNetStatusBar statusBar; + + private SpaceNetFrame() { + scenarioChooser = new JFileChooser(SpaceNetSettings.getInstance().getDefaultDirectory()) { + private static final long serialVersionUID = 5853237903722516861L; + public void approveSelection() { + if(getDialogType()==JFileChooser.SAVE_DIALOG) { + File file = getSelectedFile(); + if (file != null && file.exists()) { + int answer = JOptionPane.showOptionDialog(this, + "Scenario '" + file.getAbsolutePath() + "' already exists. Overwrite?", + "Save Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); + if (answer == JOptionPane.NO_OPTION) { + return; + } + } + } + super.approveSelection(); + } + }; + scenarioChooser.setFileFilter(new XMLFileFilter()); + scenarioPanel = new ScenarioPanel(this); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + setMinimumSize(new Dimension(800,600)); + // try to specify multiple icon sizes (used for windows 7 task bar) + try { + java.lang.reflect.Method method = Class.forName("java.awt.Window").getDeclaredMethod("setIconImages", java.util.List.class); + ArrayList images = new ArrayList(); + images.add(IconLibrary.getIcon("spacenet_icon_16").getImage()); + images.add(IconLibrary.getIcon("spacenet_icon_32").getImage()); + method.invoke(this,images); + } catch( Exception e ) { + // otherwise assign small icon only + setIconImage(IconLibrary.getIcon("spacenet_icon_16").getImage()); + } + buildFrame(); + } + + /** + * Builds the frame. + */ + private void buildFrame() { + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + exitSpaceNet(); + } + }); + + menuBar = new SpaceNetMenuBar(); + setJMenuBar(menuBar); + + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + contentPanel = new JPanel(); + contentPanel.setLayout(new BorderLayout()); + contentPanel.setBackground(Color.LIGHT_GRAY); + add(contentPanel, c); + c.gridy++; + c.weighty = 0; + statusBar = new SpaceNetStatusBar(); + add(statusBar, c); + } + + /* (non-Javadoc) + * @see java.awt.Container#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + super.paint(g); + if(scenarioPanel.getScenario()==null) setTitle("SpaceNet 2.5r2"); + else setTitle("SpaceNet 2.5r2 | " + scenarioPanel.getScenario().getName()); + } + + /** + * Gets the about dialog. + * + * @return the about dialog + */ + public AboutDialog getAboutDialog() { + if(aboutDialog==null) aboutDialog = new AboutDialog(); + return aboutDialog; + } + + /** + * Gets the settings dialog. + * + * @return the settings dialog + */ + public SpaceNetSettingsDialog getSpaceNetSettingsDialog() { + if(spaceNetSettingsDialog==null) spaceNetSettingsDialog = new SpaceNetSettingsDialog(); + return spaceNetSettingsDialog; + } + + /** + * Gets the status bar. + * + * @return the status bar + */ + public SpaceNetStatusBar getStatusBar() { + return statusBar; + } + + /** + * Creates and displays a new scenario. + */ + public void newScenario() { + setScenario(new Scenario()); + } + + /** + * Opens a saved scenario from a passed file path. + * + * @param filePath the file path of the saved scenario + */ + public void openScenario(String filePath) { + try { + Scenario scenario = XStreamEngine.openScenario(filePath); + scenario.setFilePath(filePath); + setScenario(scenario); + } catch(FileNotFoundException e) { + JOptionPane.showMessageDialog(this, + "The scenario file path (" + filePath + ") is invalid.", + "SpaceNet Error", + JOptionPane.ERROR_MESSAGE); + } catch (IOException e) { + JOptionPane.showMessageDialog(this, + "The open process failed due to an I/O exception.", + "SpaceNet Error", + JOptionPane.ERROR_MESSAGE); + } + } + + /** + * Closes the scenario. + */ + public void closeScenario() { + setScenario(null); + } + + /** + * Saves the open scenario. + */ + public void saveScenario() { + try { + XStreamEngine.saveScenario(scenarioPanel.getScenario()); + } catch (FileNotFoundException e) { + JOptionPane.showMessageDialog(this, + "The scenario file path (" + scenarioPanel.getScenario().getFilePath() + ") is invalid.", + "SpaceNet Error", + JOptionPane.ERROR_MESSAGE); + } catch (IOException e) { + JOptionPane.showMessageDialog(this, + "The save process failed due to an I/O exception.", + "SpaceNet Error", + JOptionPane.ERROR_MESSAGE); + } + } + + /** + * Sets the scenario (and updates the id generator last value) and updates + * the scenario panel, or closes the scenario if null. + * + * @param scenario the new scenario + */ + private void setScenario(Scenario scenario) { + if(scenario==null) { + scenarioPanel.setScenario(null); + contentPanel.removeAll(); + } else { + int lastUid = 0; + for(I_Element element : scenario.getElements()) { + if(element.getUid()>lastUid) lastUid = element.getUid(); + } + for(I_Element container : scenario.getManifest().getContainers()) { + if(container.getUid()>lastUid) lastUid = container.getUid(); + } + IdGenerator.setLastUid(lastUid); + scenarioPanel.setScenario(scenario); + contentPanel.removeAll(); + contentPanel.add(scenarioPanel, BorderLayout.CENTER); + } + validate(); + repaint(); + } + + /** + * Gets the scenario panel component. + * + * @return the scenario panel. + */ + public ScenarioPanel getScenarioPanel() { + return scenarioPanel; + } + + /** + * Gets the scenario file chooser. + * + * @return the scenario file chooser + */ + public JFileChooser getScenarioChooser() { + return scenarioChooser; + } + + /** + * Exit space net. + */ + public void exitSpaceNet() { + if(getScenarioPanel().getScenario() != null) { + int answer = JOptionPane.showOptionDialog(this, + "Save '" + scenarioPanel.getScenario().getName() + "' before exiting?", + "Close Warning", JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.WARNING_MESSAGE, null, null, null); + if (answer == JOptionPane.YES_OPTION) { + saveScenario(); + } + if (answer != JOptionPane.CANCEL_OPTION) { + SpaceNetSettings.saveSettings(); + System.exit(0); + } + } else { + SpaceNetSettings.saveSettings(); + System.exit(0); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/SpaceNetMenuBar.java b/src/main/java/edu/mit/spacenet/gui/SpaceNetMenuBar.java new file mode 100644 index 0000000..d2ce1c5 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/SpaceNetMenuBar.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; + +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JSeparator; +import javax.swing.KeyStroke; + +import edu.mit.spacenet.gui.command.CloseScenarioCommand; +import edu.mit.spacenet.gui.command.NewScenarioCommand; +import edu.mit.spacenet.gui.command.OpenScenarioCommand; +import edu.mit.spacenet.gui.command.SaveScenarioAsCommand; +import edu.mit.spacenet.gui.command.SaveScenarioCommand; +import edu.mit.spacenet.gui.data.DataSourceDialog; + +/** + * The menu bar that contains all of the items in the pull-down menus. Most menu + * items use commands which abstract the actual triggering of the various + * features so they can be used elsewhere (e.g. exit on window close OR on + * selecting the exit command). + * + * @author Paul Grogan + */ +public class SpaceNetMenuBar extends JMenuBar { + private static final long serialVersionUID = -5251667632821734398L; + + private JMenu fileMenu, editMenu, toolsMenu, helpMenu; + private JMenuItem newScenarioMenuItem, openScenarioMenuItem, + closeScenarioMenuItem, saveScenarioMenuItem, saveScenarioAsMenuItem, + exitMenuItem, optionsMenuItem, dataSourceMenuItem, preferencesMenuItem, + helpMenuItem, aboutMenuItem; + private JRadioButtonMenuItem networkMenuItem, missionsMenuItem, + demandsMenuItem, manifestMenuItem, simulationMenuItem; + private JCheckBoxMenuItem autoRefreshMenuItem; + + /** + * The constructor. + * + * @param spaceNet the parent SpaceNet frame + */ + public SpaceNetMenuBar() { + buildFileMenu(); + add(fileMenu); + + buildEditMenu(); + add(editMenu); + + buildToolsMenu(); + add(toolsMenu); + + buildHelpMenu(); + add(helpMenu); + } + + /* (non-Javadoc) + * @see javax.swing.JComponent#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + super.paint(g); + boolean fileOpen = SpaceNetFrame.getInstance().getScenarioPanel().getScenario()!=null; + newScenarioMenuItem.setEnabled(!fileOpen); + openScenarioMenuItem.setEnabled(!fileOpen); + closeScenarioMenuItem.setEnabled(fileOpen); + saveScenarioMenuItem.setEnabled(fileOpen); + saveScenarioAsMenuItem.setEnabled(fileOpen); + editMenu.setEnabled(fileOpen); + if(fileOpen) { + networkMenuItem.setSelected(SpaceNetFrame.getInstance().getScenarioPanel().isEditingNetwork()); + missionsMenuItem.setSelected(SpaceNetFrame.getInstance().getScenarioPanel().isEditingMissions()); + demandsMenuItem.setSelected(SpaceNetFrame.getInstance().getScenarioPanel().isEditingDemands()); + manifestMenuItem.setSelected(SpaceNetFrame.getInstance().getScenarioPanel().isEditingManifest()); + simulationMenuItem.setSelected(SpaceNetFrame.getInstance().getScenarioPanel().isEditingSimulation()); + } + } + + /** + * Builds the file menu. + */ + private void buildFileMenu() { + fileMenu = new JMenu("File"); + fileMenu.setMnemonic(KeyEvent.VK_F); + + newScenarioMenuItem = new JMenuItem("New Scenario", KeyEvent.VK_N); + newScenarioMenuItem.setAccelerator(KeyStroke.getKeyStroke( + KeyEvent.VK_N, ActionEvent.CTRL_MASK)); + newScenarioMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + NewScenarioCommand command = new NewScenarioCommand(SpaceNetFrame.getInstance()); + command.execute(); + } + }); + fileMenu.add(newScenarioMenuItem); + + openScenarioMenuItem = new JMenuItem("Open Scenario", KeyEvent.VK_O); + openScenarioMenuItem.setAccelerator(KeyStroke.getKeyStroke( + KeyEvent.VK_O, ActionEvent.CTRL_MASK)); + openScenarioMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + OpenScenarioCommand command = new OpenScenarioCommand(SpaceNetFrame.getInstance()); + command.execute(); + } + }); + fileMenu.add(openScenarioMenuItem); + + closeScenarioMenuItem = new JMenuItem("Close Scenario", KeyEvent.VK_C); + closeScenarioMenuItem.setAccelerator(KeyStroke.getKeyStroke( + KeyEvent.VK_W, ActionEvent.CTRL_MASK)); + closeScenarioMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + CloseScenarioCommand command = new CloseScenarioCommand(SpaceNetFrame.getInstance()); + command.execute(); + } + }); + fileMenu.add(closeScenarioMenuItem); + + fileMenu.addSeparator(); + + saveScenarioMenuItem = new JMenuItem("Save Scenario", KeyEvent.VK_S); + saveScenarioMenuItem.setAccelerator(KeyStroke.getKeyStroke( + KeyEvent.VK_S, ActionEvent.CTRL_MASK)); + saveScenarioMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SaveScenarioCommand command = new SaveScenarioCommand(SpaceNetFrame.getInstance()); + command.execute(); + } + }); + fileMenu.add(saveScenarioMenuItem); + + saveScenarioAsMenuItem = new JMenuItem("Save Scenario As...", KeyEvent.VK_A); + saveScenarioAsMenuItem.setAccelerator(KeyStroke.getKeyStroke( + KeyEvent.VK_S, ActionEvent.CTRL_MASK + ActionEvent.SHIFT_MASK)); + saveScenarioAsMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SaveScenarioAsCommand command = new SaveScenarioAsCommand(SpaceNetFrame.getInstance()); + command.execute(); + } + }); + fileMenu.add(saveScenarioAsMenuItem); + + fileMenu.addSeparator(); + + exitMenuItem = new JMenuItem("Exit"); + exitMenuItem.setAccelerator(KeyStroke.getKeyStroke( + KeyEvent.VK_Q, ActionEvent.CTRL_MASK)); + exitMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().exitSpaceNet(); + } + }); + fileMenu.add(exitMenuItem); + } + + /** + * Builds the edit menu. + */ + private void buildEditMenu() { + editMenu = new JMenu("Edit"); + editMenu.setMnemonic(KeyEvent.VK_E); + + optionsMenuItem = new JMenuItem("Options"); + optionsMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().getScenarioPanel().getOptionsDialog().showDialog(); + } + }); + editMenu.add(optionsMenuItem); + + dataSourceMenuItem = new JMenuItem("Data Source"); + dataSourceMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DataSourceDialog.createAndShowGUI(SpaceNetFrame.getInstance().getScenarioPanel()); + } + }); + editMenu.add(dataSourceMenuItem); + + editMenu.add(new JSeparator()); + + networkMenuItem = new JRadioButtonMenuItem("Network"); + networkMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().getScenarioPanel().editNetwork(); + } + }); + editMenu.add(networkMenuItem); + + missionsMenuItem = new JRadioButtonMenuItem("Missions"); + missionsMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().getScenarioPanel().editMissions(); + } + }); + editMenu.add(missionsMenuItem); + + demandsMenuItem = new JRadioButtonMenuItem("Demands"); + demandsMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().getScenarioPanel().editDemands(); + } + }); + editMenu.add(demandsMenuItem); + + manifestMenuItem = new JRadioButtonMenuItem("Manifest"); + manifestMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().getScenarioPanel().editManifest(); + } + }); + editMenu.add(manifestMenuItem); + + simulationMenuItem = new JRadioButtonMenuItem("Simulation"); + simulationMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().getScenarioPanel().editSimulation(); + } + }); + editMenu.add(simulationMenuItem); + } + + /** + * Builds the tools menu. + */ + private void buildToolsMenu() { + toolsMenu = new JMenu("Tools"); + toolsMenu.setMnemonic(KeyEvent.VK_T); + + autoRefreshMenuItem = new JCheckBoxMenuItem("Auto-Refresh Charts"); + autoRefreshMenuItem.setSelected(SpaceNetSettings.getInstance().isAutoRefresh()); + autoRefreshMenuItem.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + SpaceNetSettings.getInstance().setAutoRefresh(e.getStateChange()==ItemEvent.SELECTED); + SpaceNetSettings.saveSettings(); + SpaceNetFrame.getInstance().getScenarioPanel().updateView(); + } + }); + toolsMenu.add(autoRefreshMenuItem); + + toolsMenu.addSeparator(); + + preferencesMenuItem = new JMenuItem("Preferences", KeyEvent.VK_P); + preferencesMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().getSpaceNetSettingsDialog().showDialog(); + } + }); + toolsMenu.add(preferencesMenuItem); + + } + + /** + * Builds the help menu. + */ + private void buildHelpMenu() { + helpMenu = new JMenu("Help"); + helpMenu.setMnemonic(KeyEvent.VK_H); + + helpMenuItem = new JMenuItem("Help", KeyEvent.VK_H); + helpMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JOptionPane.showMessageDialog(SpaceNetFrame.getInstance(), + "For help with SpaceNet, please see:\n\n" + + "SpaceNet User's Manual (docs/manual)\n" + + "Quick Start Tutorial (docs/tutorial)\n" + + "SpaceNet Website (http://spacenet.mit.edu)", + "SpaceNet Help", JOptionPane.PLAIN_MESSAGE); + } + }); + helpMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); + helpMenu.add(helpMenuItem); + + helpMenu.addSeparator(); + + aboutMenuItem = new JMenuItem("About SpaceNet", KeyEvent.VK_A); + aboutMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SpaceNetFrame.getInstance().getAboutDialog().showDialog(); + } + }); + helpMenu.add(aboutMenuItem); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/SpaceNetSettings.java b/src/main/java/edu/mit/spacenet/gui/SpaceNetSettings.java new file mode 100644 index 0000000..85cddd1 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/SpaceNetSettings.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; + +import java.awt.Rectangle; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * The Class SpaceNetSettings. + */ +public class SpaceNetSettings implements Serializable { + private static final long serialVersionUID = 6683421611404213906L; + private static final String filePath = "config"; + private String defaultDirectory; + private boolean autoRefresh; + private Rectangle lastBounds; + + /** + * Instantiates a new space net settings. + */ + private SpaceNetSettings() { + lastBounds = new Rectangle(); + autoRefresh = true; + } + + private static SpaceNetSettings instance; + + /** + * Gets the single instance of SpaceNetSettings. + * + * @return single instance of SpaceNetSettings + */ + public static SpaceNetSettings getInstance() { + if(instance==null) loadSettings(); + return instance; + } + + /** + * Gets the default directory. + * + * @return the default directory + */ + public String getDefaultDirectory() { + if(defaultDirectory==null) return System.getProperty("user.dir"); + else return defaultDirectory; + } + + /** + * Sets the default directory. + * + * @param defaultDirectory the new default directory + */ + public void setDefaultDirectory(String defaultDirectory) { + this.defaultDirectory = defaultDirectory; + } + + /** + * Gets the last bounds. + * + * @return the last bounds + */ + public Rectangle getLastBounds() { + return lastBounds; + } + + /** + * Sets the last bounds. + * + * @param bounds the new last bounds + */ + public void setLastBounds(Rectangle bounds) { + this.lastBounds = bounds; + } + + /** + * Load settings. + */ + public static void loadSettings() { + FileInputStream fis; + try { + fis = new FileInputStream(filePath); + ObjectInputStream inStream = new ObjectInputStream(fis); + instance = (SpaceNetSettings)inStream.readObject(); + inStream.close(); + fis.close(); + } catch (Exception e) { + // there was a problem loading the settings, reverting to defaults + instance = new SpaceNetSettings(); + } + } + + /** + * Save settings. + */ + public static void saveSettings() { + SpaceNetSettings.getInstance().setLastBounds(SpaceNetFrame.getInstance().getBounds()); + FileOutputStream fos; + try { + fos = new FileOutputStream(filePath); + ObjectOutputStream outStream = new ObjectOutputStream(fos); + outStream.writeObject(SpaceNetSettings.getInstance()); + outStream.flush(); + outStream.close(); + fos.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Checks if is auto refresh. + * + * @return true, if is auto refresh + */ + public boolean isAutoRefresh() { + return autoRefresh; + } + + /** + * Sets the auto refresh. + * + * @param autoRefresh the new auto refresh + */ + public void setAutoRefresh(boolean autoRefresh) { + this.autoRefresh = autoRefresh; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/SpaceNetSettingsDialog.java b/src/main/java/edu/mit/spacenet/gui/SpaceNetSettingsDialog.java new file mode 100644 index 0000000..688fddb --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/SpaceNetSettingsDialog.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import edu.mit.spacenet.util.IconLibrary; + +/** + * A dialog to edit the global SpaceNet preferences. + * + * @author Paul Grogan + */ +public class SpaceNetSettingsDialog extends JDialog { + private static final long serialVersionUID = -802497885876127342L; + + private JFileChooser directoryChooser; + private JCheckBox autoRefreshCheck; + private JTextField defaultDirectoryText; + + /** + * The constructor. + * + * @param spaceNetFrame the parent SpaceNet frame + */ + public SpaceNetSettingsDialog() { + super(SpaceNetFrame.getInstance(), "SpaceNet Settings", true); + directoryChooser = new JFileChooser(); + directoryChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + buildDialog(); + pack(); + setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); + } + + /** + * Builds the dialog components. + */ + private void buildDialog() { + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + contentPanel.add(new JLabel("Default directory: "), c); + c.gridx++; + c.weightx = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; + defaultDirectoryText = new JTextField(); + defaultDirectoryText.setEnabled(false); + defaultDirectoryText.setPreferredSize(new Dimension(300,20)); + contentPanel.add(defaultDirectoryText, c); + c.gridx++; + c.weightx = 0; + JButton browseButton = new JButton("Browse...", IconLibrary.getIcon("folder_explore")); + browseButton.setMargin(new Insets(3,3,3,3)); + browseButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + directoryChooser.setCurrentDirectory(new File(SpaceNetSettings.getInstance().getDefaultDirectory())); + int returnVal = directoryChooser.showOpenDialog(SpaceNetFrame.getInstance()); + if(returnVal == JFileChooser.APPROVE_OPTION) { + defaultDirectoryText.setText(directoryChooser.getSelectedFile().getAbsolutePath()); + } + } + }); + contentPanel.add(browseButton, c); + c.gridy++; + c.gridx = 0; + c.gridwidth = 3; + autoRefreshCheck = new JCheckBox("Auto-refresh charts (lags with large scenarios)"); + contentPanel.add(autoRefreshCheck, c); + + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + JButton okButton = new JButton("OK"); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + savePreferences(); + setVisible(false); + } + }); + buttonPanel.add(okButton); + getRootPane().setDefaultButton(okButton); + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + setVisible(false); + } + }); + buttonPanel.add(cancelButton); + contentPanel.add(buttonPanel, c); + setContentPane(contentPanel); + } + + /** + * Initializes the dialog. + */ + private void initialize() { + defaultDirectoryText.setText(SpaceNetSettings.getInstance().getDefaultDirectory()); + autoRefreshCheck.setSelected(SpaceNetSettings.getInstance().isAutoRefresh()); + } + + /** + * Save preferences. + */ + private void savePreferences() { + SpaceNetSettings.getInstance().setAutoRefresh(autoRefreshCheck.isSelected()); + SpaceNetSettings.getInstance().setDefaultDirectory(defaultDirectoryText.getText().equals("")||defaultDirectoryText.getText().equals(System.getProperty("user.dir"))?null:defaultDirectoryText.getText()); + } + + /** + * Show dialog. + */ + public void showDialog() { + initialize(); + pack(); + setLocationRelativeTo(getParent()); + setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/SpaceNetStatusBar.java b/src/main/java/edu/mit/spacenet/gui/SpaceNetStatusBar.java new file mode 100644 index 0000000..9ae341e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/SpaceNetStatusBar.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; + +/** + * The status bar sits at the bottom of the main SpaceNet application and + * provides feedback on long-duration processes (e.g. simulation, loading, etc) + * with a status label and progress bar, similar to many web browsers. + * + * @author Paul Grogan + */ +public class SpaceNetStatusBar extends JPanel { + private static final long serialVersionUID = 8714221468753419089L; + + private JLabel statusLabel; + private JProgressBar progressBar; + + /** + * The constructor. + */ + public SpaceNetStatusBar() { + buildStatusBar(); + } + private void buildStatusBar() { + setLayout(new GridBagLayout()); + setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY)); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weighty = 1; + c.weightx = .9; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + statusLabel = new JLabel(); + add(statusLabel, c); + c.gridx++; + c.weightx = .1; + progressBar = new JProgressBar(); + add(progressBar, c); + } + + /** + * Sets the status message in the lower-left hand corner and triggers the + * indeterminate progress bar. + * + * @param message the status message to display + */ + public void setStatusMessage(String message) { + setStatusMessage(message, true); + } + + /** + * Sets the status message in the lower-left hand corner with the option to + * trigger the progress bar. + * + * @param message the message to display + * @param triggerProcess whether to trigger the progress bar + */ + public void setStatusMessage(String message, boolean triggerProcess) { + statusLabel.setText(message); + if(triggerProcess) progressBar.setIndeterminate(true); + } + + /** + * Clears the status message and resets the progress bar. + */ + public void clearStatusMessage() { + statusLabel.setText(""); + progressBar.setIndeterminate(false); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/SplashScreen.java b/src/main/java/edu/mit/spacenet/gui/SplashScreen.java new file mode 100644 index 0000000..37e9c25 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/SplashScreen.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JWindow; + +/** + * The splash screen is a window that is displayed while the rest of the + * application is loading. + * + * @author Paul Grogan, ptgrogan@mit.edu + */ +public class SplashScreen extends JWindow { + private static final long serialVersionUID = -1859950222357089575L; + + /** + * Instantiates a new splash screen. + */ + public SplashScreen() { + JPanel content = new JPanel(new GridBagLayout()); + content.setBackground(new Color(153,51,51)); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + + c.gridheight = 2; + JLabel logo = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("icons/spacenet_splash.png"))); + logo.setPreferredSize(new Dimension(138,119)); + content.add(logo, c); + + c.gridx++; + c.gridheight = 1; + c.insets = new Insets(20, 20, 2, 20); + c.anchor = GridBagConstraints.LAST_LINE_START; + JLabel title = new JLabel ("SpaceNet 2.5"); + title.setForeground(Color.WHITE); + title.setFont(new Font("Arial", Font.BOLD, 36)); + content.add(title, c); + + c.gridy++; + c.insets = new Insets(2, 20, 10, 20); + c.anchor = GridBagConstraints.FIRST_LINE_START; + JLabel subtitle = new JLabel("Simulation and modeling software for space logistics"); + subtitle.setForeground(Color.WHITE); + subtitle.setFont(new Font("Arial", Font.BOLD, 12)); + content.add(subtitle, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.insets = new Insets(10, 20, 5, 20); + c.anchor = GridBagConstraints.CENTER; + JLabel loading = new JLabel("Loading..."); + loading.setFont(new Font ("Arial", Font.BOLD, 12)); + loading.setForeground(Color.WHITE); + content.add(loading, c); + + c.gridy++; + c.insets = new Insets(5, 20, 20, 20); + JProgressBar progressBar = new JProgressBar(); + progressBar.setIndeterminate(true); + progressBar.setForeground(new Color(153, 51, 51)); + progressBar.setBackground(Color.WHITE); + progressBar.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + content.add(progressBar, c); + + add(content); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/AddMissionCommand.java b/src/main/java/edu/mit/spacenet/gui/command/AddMissionCommand.java new file mode 100644 index 0000000..7a9b915 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/AddMissionCommand.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import edu.mit.spacenet.gui.mission.MissionsTab; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.util.DateFunctions; + +/** + * The command to add a mission to a scenario, pre-filling data as available and + * triggering a secondary command to edit the newly-created mission. + * + * @author Paul Grogan + */ +public class AddMissionCommand implements I_Command { + private MissionsTab missionsTab; + private Mission mission; + + /** + * The constructor. + * + * @param missionsTab the missions tab component + * @param mission the mission to add + */ + public AddMissionCommand(MissionsTab missionsTab, Mission mission) { + this.missionsTab = missionsTab; + this.mission = mission; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + if(missionsTab.getScenarioPanel().getScenario().getMissionList().size() > 0) { + Mission prevMission = missionsTab.getScenarioPanel().getScenario().getMissionList().get(missionsTab.getScenarioPanel().getScenario().getMissionList().size()-1); + mission.setStartDate(DateFunctions.getDate(prevMission.getStartDate(), prevMission.getDuration())); + mission.setOrigin(prevMission.getOrigin()); + mission.setDestination(prevMission.getDestination()); + mission.setReturnOrigin(prevMission.getReturnOrigin()); + mission.setReturnDestination(prevMission.getReturnDestination()); + } else { + mission.setStartDate(missionsTab.getScenarioPanel().getScenario().getStartDate()); + if(missionsTab.getScenarioPanel().getScenario().getNetwork().getNodes().size() > 0) { + mission.setOrigin(missionsTab.getScenarioPanel().getScenario().getNetwork().getNodes().first()); + mission.setDestination(missionsTab.getScenarioPanel().getScenario().getNetwork().getNodes().first()); + } + } + missionsTab.getScenarioPanel().getScenario().getMissionList().add(mission); + missionsTab.editMission(mission); + } + +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/CloseScenarioCommand.java b/src/main/java/edu/mit/spacenet/gui/command/CloseScenarioCommand.java new file mode 100644 index 0000000..925bb92 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/CloseScenarioCommand.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import javax.swing.JOptionPane; + +import edu.mit.spacenet.gui.SpaceNetFrame; + +/** + * The command to close a scenario. + * + * @author Paul Grogan + */ +public class CloseScenarioCommand { + private SpaceNetFrame spaceNetFrame; + + /** + * The constructor. + * + * @param spaceNetFrame the SpaceNet frame component. + */ + public CloseScenarioCommand(SpaceNetFrame spaceNetFrame) { + this.spaceNetFrame=spaceNetFrame; + } + + /** + * Execute. + */ + public void execute() { + int answer = JOptionPane.showOptionDialog(spaceNetFrame, + "Save " + spaceNetFrame.getScenarioPanel().getScenario().getName() + " before closing?", + "Close Warning", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); + if(answer == JOptionPane.YES_OPTION) { + SaveScenarioCommand command = new SaveScenarioCommand(spaceNetFrame); + command.execute(); + } + if(answer != JOptionPane.CANCEL_OPTION) spaceNetFrame.closeScenario(); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/CopyMissionCommand.java b/src/main/java/edu/mit/spacenet/gui/command/CopyMissionCommand.java new file mode 100644 index 0000000..fe6eb7d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/CopyMissionCommand.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.mission.MissionsTab; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.event.AddEvent; +import edu.mit.spacenet.simulator.event.BurnEvent; +import edu.mit.spacenet.simulator.event.BurnStageItem; +import edu.mit.spacenet.simulator.event.CreateEvent; +import edu.mit.spacenet.simulator.event.DemandEvent; +import edu.mit.spacenet.simulator.event.EvaEvent; +import edu.mit.spacenet.simulator.event.ExplorationProcess; +import edu.mit.spacenet.simulator.event.FlightTransport; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.MoveEvent; +import edu.mit.spacenet.simulator.event.ReconfigureEvent; +import edu.mit.spacenet.simulator.event.ReconfigureGroupEvent; +import edu.mit.spacenet.simulator.event.SpaceTransport; +import edu.mit.spacenet.simulator.event.SurfaceTransport; +import edu.mit.spacenet.simulator.event.TransferEvent; +import edu.mit.spacenet.util.SerializeUtil; + +/** + * The command to copy a mission, performing all housekeeping operations to + * reset unique identifiers and redirect pointers after serialization. + * + * @author Paul Grogan + */ +public class CopyMissionCommand implements I_Command { + private MissionsTab missionsTab; + private Mission mission; + + /** + * The constructor. + * + * @param missionsTab the missionsTab component + * @param mission the mission to copy + */ + public CopyMissionCommand(MissionsTab missionsTab, Mission mission) { + this.missionsTab = missionsTab; + this.mission = mission; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + Mission mission = (Mission)SerializeUtil.deepClone(this.mission); + missionsTab.getScenarioPanel().getScenario().getMissionList().add(mission); + mission.setName(mission.getName() + " (Copy)"); + GregorianCalendar g = new GregorianCalendar(); + g.setTime(mission.getStartDate()); + g.add(Calendar.MONTH, 1); + mission.setStartDate(g.getTime()); + // note: must reset all links to data objects that were destroyed in serialization + mission.setScenario(missionsTab.getScenarioPanel().getScenario()); + if(mission.getOrigin()!=null) { + mission.setOrigin(getNode(mission.getOrigin().getTid())); + } + if(mission.getDestination()!=null) { + mission.setDestination(getNode(mission.getDestination().getTid())); + } + if(mission.getReturnOrigin()!=null) { + mission.setReturnOrigin(getNode(mission.getReturnOrigin().getTid())); + } + if(mission.getReturnDestination()!=null) { + mission.setReturnDestination(getNode(mission.getReturnDestination().getTid())); + } + for(I_Event event : mission.getEventList()) { + event.resetUid(); + if(event.getLocation() instanceof Edge) { + event.setLocation(getEdge(event.getLocation().getTid())); + } else if(event.getLocation() instanceof Node) { + event.setLocation(getNode(event.getLocation().getTid())); + } + if(event instanceof CreateEvent) { + for(I_Element o : ((CreateEvent)event).getElements()) { + o.resetUid(); + } + if(((CreateEvent)event).getContainer() instanceof Node) { + ((CreateEvent)event).setContainer(event.getLocation()); + } else if(((CreateEvent) event).getContainer() instanceof I_Carrier) { + ((CreateEvent)event).setContainer((I_Carrier)getElement(((I_Carrier)((CreateEvent)event).getContainer()).getUid())); + } + } else if(event instanceof MoveEvent) { + if(((MoveEvent)event).getContainer() instanceof Node) { + ((MoveEvent)event).setContainer(event.getLocation()); + } else if(((MoveEvent) event).getContainer() instanceof I_Carrier) { + ((MoveEvent)event).setContainer((I_Carrier)getElement(((I_Carrier)((MoveEvent)event).getContainer()).getUid())); + } + List elements = new ArrayList(); + for(I_Element element : ((MoveEvent)event).getElements()) { + elements.add(getElement(element.getUid())); + } + ((MoveEvent)event).getElements().clear(); + ((MoveEvent)event).getElements().addAll(elements); + } else if(event instanceof TransferEvent) { + ((TransferEvent)event).setOriginContainer( + (I_ResourceContainer)getElement( + ((I_ResourceContainer)((TransferEvent)event).getOriginContainer()).getUid())); + ((TransferEvent)event).setDestinationContainer( + (I_ResourceContainer)getElement( + ((I_ResourceContainer)((TransferEvent)event).getDestinationContainer()).getUid())); + } else if(event instanceof AddEvent) { + ((AddEvent)event).setContainer( + (I_ResourceContainer)getElement( + ((I_ResourceContainer)((AddEvent)event).getContainer()).getUid())); + } else if(event instanceof DemandEvent) { + ((DemandEvent)event).setElement( + (I_ResourceContainer)getElement( + ((I_ResourceContainer)((DemandEvent)event).getElement()).getUid())); + } else if(event instanceof ReconfigureEvent) { + ((ReconfigureEvent)event).setElement( + (I_ResourceContainer)getElement( + ((I_ResourceContainer)((ReconfigureEvent)event).getElement()).getUid())); + for(I_State state : ((ReconfigureEvent)event).getElement().getStates()) { + if(state.equals(((ReconfigureEvent)event).getState())) { + ((ReconfigureEvent)event).setState(state); + break; + } + } + } else if(event instanceof ReconfigureGroupEvent) { + List elements = new ArrayList(); + for(I_Element element : ((ReconfigureGroupEvent)event).getElements()) { + elements.add(getElement(element.getUid())); + } + ((ReconfigureGroupEvent)event).getElements().clear(); + ((ReconfigureGroupEvent)event).getElements().addAll(elements); + } else if(event instanceof BurnEvent) { + for(BurnStageItem item : ((BurnEvent)event).getBurnStageSequence()) { + item.setElement(getElement(item.getElement().getUid())); + } + List elements = new ArrayList(); + for(I_Element element : ((BurnEvent)event).getElements()) { + elements.add(getElement(element.getUid())); + } + ((BurnEvent)event).getElements().clear(); + ((BurnEvent)event).getElements().addAll(elements); + } else if(event instanceof EvaEvent) { + Map map = new HashMap(); + for(CrewMember crew : ((EvaEvent)event).getStateMap().keySet()) { + I_State s = ((EvaEvent)event).getStateMap().get(crew); + if(s==null) { + map.put((CrewMember)getElement(crew.getUid()), null); + } else { + for(I_State state : getElement(crew.getUid()).getStates()) { + if(state.equals(s)) { + map.put((CrewMember)getElement(crew.getUid()), state); + break; + } + } + } + } + ((EvaEvent)event).getStateMap().clear(); + for(CrewMember crew : map.keySet()) { + ((EvaEvent)event).getStateMap().put(crew, map.get(crew)); + } + ((EvaEvent)event).setVehicle((I_Carrier)getElement(((EvaEvent)event).getVehicle().getUid())); + } else if(event instanceof ExplorationProcess) { + Map map = new HashMap(); + for(CrewMember crew : ((ExplorationProcess)event).getStateMap().keySet()) { + I_State s = ((ExplorationProcess)event).getStateMap().get(crew); + if(s==null) { + map.put((CrewMember)getElement(crew.getUid()), null); + } else { + for(I_State state : getElement(crew.getUid()).getStates()) { + if(state.equals(s)) { + map.put((CrewMember)getElement(crew.getUid()), state); + break; + } + } + } + } + ((ExplorationProcess)event).getStateMap().clear(); + for(CrewMember crew : map.keySet()) { + ((ExplorationProcess)event).getStateMap().put(crew, map.get(crew)); + } + ((ExplorationProcess)event).setVehicle((I_Carrier)getElement(((ExplorationProcess)event).getVehicle().getUid())); + } else if(event instanceof SpaceTransport) { + List> sequenceList = new ArrayList>(); + for(List list : ((SpaceTransport)event).getBurnStageSequence()) { + List sequence = new ArrayList(); + for(BurnStageItem item : list) { + item.setElement(getElement(item.getElement().getUid())); + sequence.add(item); + } + sequenceList.add(sequence); + } + ((SpaceTransport)event).setEdge((SpaceEdge)getEdge(((SpaceTransport)event).getEdge().getTid())); + ((SpaceTransport)event).getBurnStageSequence().clear(); + for(List list : sequenceList) { + ((SpaceTransport)event).getBurnStageSequence().add(list); + } + List elements = new ArrayList(); + for(I_Element element : ((SpaceTransport)event).getElements()) { + elements.add(getElement(element.getUid())); + } + ((SpaceTransport)event).getElements().clear(); + ((SpaceTransport)event).getElements().addAll(elements); + } else if(event instanceof SurfaceTransport) { + ((SurfaceTransport)event).setEdge((SurfaceEdge)getEdge(((SurfaceTransport)event).getEdge().getTid())); + List elements = new ArrayList(); + for(I_Element element : ((SurfaceTransport)event).getElements()) { + elements.add(getElement(element.getUid())); + } + ((SurfaceTransport)event).getElements().clear(); + ((SurfaceTransport)event).getElements().addAll(elements); + } else if(event instanceof FlightTransport) { + ((FlightTransport)event).setEdge((FlightEdge)getEdge(((FlightTransport)event).getEdge().getTid())); + List elements = new ArrayList(); + for(I_Element element : ((FlightTransport)event).getElements()) { + elements.add(getElement(element.getUid())); + } + ((FlightTransport)event).getElements().clear(); + ((FlightTransport)event).getElements().addAll(elements); + } + } + missionsTab.editMission(mission); + } + private Node getNode(int tid) { + return getScenario().getNetwork().getNodeByTid(tid); + } + private Edge getEdge(int tid) { + return getScenario().getNetwork().getEdgeByTid(tid); + } + private I_Element getElement(int uid) { + return getScenario().getElementByUid(uid); + } + private Scenario getScenario() { + return missionsTab.getScenarioPanel().getScenario(); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/EditMissionCommand.java b/src/main/java/edu/mit/spacenet/gui/command/EditMissionCommand.java new file mode 100644 index 0000000..9d1fd3b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/EditMissionCommand.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import edu.mit.spacenet.gui.mission.MissionsTab; +import edu.mit.spacenet.scenario.Mission; + +/** + * The command to edit a mission. + * + * @author Paul Grogan + */ +public class EditMissionCommand implements I_Command { + private MissionsTab missionsTab; + private Mission mission; + + /** + * The constructor. + * + * @param missionsTab the missions tab component. + * @param mission the mission to edit + */ + public EditMissionCommand(MissionsTab missionsTab, Mission mission) { + this.missionsTab = missionsTab; + this.mission = mission; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + missionsTab.editMission(mission); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/FilterNetworkCommand.java b/src/main/java/edu/mit/spacenet/gui/command/FilterNetworkCommand.java new file mode 100644 index 0000000..d51c96d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/FilterNetworkCommand.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import java.util.ArrayList; +import java.util.List; + +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.scenario.Scenario; + +/** + * The command to filter the scenario network based on its scenario type. Any + * nodes or edges that are in use will not be removed by this operation. + * + * @author Paul Grogan + */ +public class FilterNetworkCommand implements I_Command { + private Scenario scenario; + + /** + * The constructor. + * + * @param scenarioPanel the scenario panel component + */ + public FilterNetworkCommand(Scenario scenario) { + this.scenario = scenario; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + List forAddition = new ArrayList(); + List forRemoval = new ArrayList(); + for(Node node : scenario.getDataSource().getNodeLibrary()) { + if(!scenario.getNetwork().getNodes().contains(node) + && scenario.getScenarioType().isNodeVisible(node)) { + forAddition.add(node); + } else if(scenario.getNetwork().getNodes().contains(node) + && !scenario.isNodeUsed(node) + && !scenario.getScenarioType().isNodeVisible(node)) { + forRemoval.add(node); + } + } + for(Edge edge : scenario.getDataSource().getEdgeLibrary()) { + if(!scenario.getNetwork().getEdges().contains(edge) + && scenario.getScenarioType().isEdgeVisible(edge)) { + forAddition.add(edge); + } else if(scenario.getNetwork().getEdges().contains(edge) + && !scenario.isEdgeUsed(edge) + && !scenario.getScenarioType().isEdgeVisible(edge)) { + forRemoval.add(edge); + } + } + for(Location location : forAddition) { + scenario.getNetwork().add(location); + } + for(Location location : forRemoval) { + scenario.getNetwork().remove(location); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/I_Command.java b/src/main/java/edu/mit/spacenet/gui/command/I_Command.java new file mode 100644 index 0000000..4e1a4af --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/I_Command.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +/** + * Interface for all SpaceNet commands. + * + * @author Paul Grogan + */ +public interface I_Command { + + /** + * Executes the command. + */ + public void execute(); +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/LoadDataSourceCommand.java b/src/main/java/edu/mit/spacenet/gui/command/LoadDataSourceCommand.java new file mode 100644 index 0000000..b9fbfd8 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/LoadDataSourceCommand.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import java.awt.Component; +import java.awt.Cursor; +import java.util.List; + +import javax.swing.BoxLayout; +import javax.swing.DefaultListModel; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingWorker; + +import edu.mit.spacenet.domain.element.Carrier; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.ElementType; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.element.ResourceContainer; +import edu.mit.spacenet.domain.element.SurfaceVehicle; +import edu.mit.spacenet.gui.ScenarioPanel; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.data.DataSourceDialog; + +/** + * Command to load the libraries from the scenario data source. + * + * @author Paul Grogan + */ +public class LoadDataSourceCommand implements I_Command { + private DataSourceDialog dataSourceDialog; + private ScenarioPanel scenarioPanel; + + /** + * The constructor if called from the data source dialog. + * + * @param dataSourceDialog the data source dialog component + */ + public LoadDataSourceCommand(DataSourceDialog dataSourceDialog) { + this.dataSourceDialog = dataSourceDialog; + scenarioPanel = dataSourceDialog.getScenarioPanel(); + } + + /** + * The constructor if called from the scenario panel. + * + * @param scenarioPanel the scenario panel + */ + public LoadDataSourceCommand(ScenarioPanel scenarioPanel) { + this.scenarioPanel = scenarioPanel; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + SwingWorker worker = new SwingWorker() { + public Void doInBackground() { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Loading Data Source..."); + scenarioPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + List errors = scenarioPanel.getScenario().getDataSource().validateData(); + if(errors.size() > 0) { + JPanel errorPanel = new JPanel(); + errorPanel.setLayout(new BoxLayout(errorPanel, BoxLayout.PAGE_AXIS)); + errorPanel.add(new JLabel("The following errors occurred: ")); + DefaultListModel errorsModel = new DefaultListModel(); + for(String e : errors) { + errorsModel.addElement(e); + } + errorPanel.add(new JScrollPane(new JList(errorsModel))); + errorPanel.add(new JLabel("Please make the necessary changes and reload database.")); + JOptionPane.showMessageDialog(getComponent(), errorPanel, "Load Error", JOptionPane.ERROR_MESSAGE); + } else { + if(dataSourceDialog==null) { + scenarioPanel.getScenario().getDataSource().loadLibraries(); + } else { + scenarioPanel.getScenario().getDataSource().loadLibraries( + dataSourceDialog.updateNodes(), + dataSourceDialog.updateEdges(), + dataSourceDialog.updateResources()); + } + if(dataSourceDialog!=null&&dataSourceDialog.updateInstantiatedElements()) { + for(I_Element element : scenarioPanel.getScenario().getElements()) { + if(element.getTid() > 0) { + I_Element mirror = scenarioPanel.getScenario().getDataSource().loadElement(element.getTid()); + if(mirror.getClass().equals(element.getClass())) { + element.setAccommodationMass(mirror.getAccommodationMass()); + element.setClassOfSupply(mirror.getClassOfSupply()); + element.setDescription(mirror.getDescription()); + element.setEnvironment(mirror.getEnvironment()); + element.setMass(mirror.getMass()); + element.setStates(mirror.getStates()); + element.setCurrentState(mirror.getCurrentState()); + element.setParts(mirror.getParts()); + element.setVolume(mirror.getVolume()); + element.setIconType(mirror.getIconType()); + if(element.getElementType()==ElementType.RESOURCE_CONTAINER) { + ((ResourceContainer)element).setMaxCargoMass(((ResourceContainer)mirror).getMaxCargoMass()); + ((ResourceContainer)element).setMaxCargoVolume(((ResourceContainer)mirror).getMaxCargoVolume()); + ((ResourceContainer)element).setCargoEnvironment(((ResourceContainer)mirror).getCargoEnvironment()); + // NOTE: presently does not carry over any changes to contents + } else if(element.getElementType()==ElementType.CARRIER) { + ((Carrier)element).setMaxCrewSize(((Carrier)mirror).getMaxCrewSize()); + ((Carrier)element).setMaxCargoMass(((Carrier)mirror).getMaxCargoMass()); + ((Carrier)element).setMaxCargoVolume(((Carrier)mirror).getMaxCargoVolume()); + ((Carrier)element).setCargoEnvironment(((Carrier)mirror).getCargoEnvironment()); + } else if(element.getElementType()==ElementType.PROPULSIVE_VEHICLE) { + ((PropulsiveVehicle)element).setMaxCrewSize(((PropulsiveVehicle)mirror).getMaxCrewSize()); + ((PropulsiveVehicle)element).setMaxCargoMass(((PropulsiveVehicle)mirror).getMaxCargoMass()); + ((PropulsiveVehicle)element).setMaxCargoVolume(((PropulsiveVehicle)mirror).getMaxCargoVolume()); + ((PropulsiveVehicle)element).setCargoEnvironment(((PropulsiveVehicle)mirror).getCargoEnvironment()); + ((PropulsiveVehicle)element).setOmsIsp(((PropulsiveVehicle)mirror).getOmsIsp()); + ((PropulsiveVehicle)element).setOmsFuelTank(((PropulsiveVehicle)mirror).getOmsFuelTank()); + ((PropulsiveVehicle)element).setRcsIsp(((PropulsiveVehicle)mirror).getRcsIsp()); + ((PropulsiveVehicle)element).setRcsFuelTank(((PropulsiveVehicle)mirror).getRcsFuelTank()); + } else if(element.getElementType()==ElementType.SURFACE_VEHICLE) { + ((SurfaceVehicle)element).setMaxCrewSize(((SurfaceVehicle)mirror).getMaxCrewSize()); + ((SurfaceVehicle)element).setMaxCargoMass(((SurfaceVehicle)mirror).getMaxCargoMass()); + ((SurfaceVehicle)element).setMaxCargoVolume(((SurfaceVehicle)mirror).getMaxCargoVolume()); + ((SurfaceVehicle)element).setCargoEnvironment(((SurfaceVehicle)mirror).getCargoEnvironment()); + ((SurfaceVehicle)element).setMaxSpeed(((SurfaceVehicle)mirror).getMaxSpeed()); + ((SurfaceVehicle)element).setFuelTank(((SurfaceVehicle)mirror).getFuelTank()); + } else if(element.getElementType()==ElementType.CREW_MEMBER) { + ((CrewMember)element).setAvailableTimeFraction(((CrewMember)mirror).getAvailableTimeFraction()); + } + } + } + } + } + } + } catch(Exception ex) { + JOptionPane.showMessageDialog(getComponent(), + "There was a problem opening the data source.", + "SpaceNet Error", JOptionPane.ERROR_MESSAGE); + ex.printStackTrace(); + } + return null; + } + public void done() { + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + scenarioPanel.setCursor(Cursor.getDefaultCursor()); + + if(scenarioPanel.getScenario().getNetwork().getLocations().size()==0) { + FilterNetworkCommand command = new FilterNetworkCommand(scenarioPanel.getScenario()); + command.execute(); + } + + if(dataSourceDialog!=null) dataSourceDialog.updateTables(); + scenarioPanel.updateView(); + } + }; + worker.execute(); + } + private Component getComponent() { + if(dataSourceDialog==null) return scenarioPanel; + else return dataSourceDialog; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/NewScenarioCommand.java b/src/main/java/edu/mit/spacenet/gui/command/NewScenarioCommand.java new file mode 100644 index 0000000..1f84479 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/NewScenarioCommand.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import edu.mit.spacenet.gui.SpaceNetFrame; + +/** + * The command to create a new scenario. + * + * @author Paul Grogan + */ +public class NewScenarioCommand implements I_Command { + private SpaceNetFrame spaceNetFrame; + + /** + * The constructor. + * + * @param spaceNetFrame the SpaceNet frame + */ + public NewScenarioCommand(SpaceNetFrame spaceNetFrame) { + this.spaceNetFrame=spaceNetFrame; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + spaceNetFrame.newScenario(); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/command/OpenScenarioCommand.java b/src/main/java/edu/mit/spacenet/gui/command/OpenScenarioCommand.java new file mode 100644 index 0000000..0186dff --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/OpenScenarioCommand.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import java.awt.Cursor; + +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; + +import edu.mit.spacenet.gui.SpaceNetFrame; + +/** + * The command to open a saved scenario. + * + * @author Paul Grogan + */ +public class OpenScenarioCommand implements I_Command { + private SpaceNetFrame spaceNetFrame; + + /** + * The constructor. + * + * @param spaceNetFrame the SpaceNet frame + */ + public OpenScenarioCommand(SpaceNetFrame spaceNetFrame) { + this.spaceNetFrame=spaceNetFrame; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + int returnVal = spaceNetFrame.getScenarioChooser().showOpenDialog(spaceNetFrame); + if(returnVal == JFileChooser.APPROVE_OPTION) { + SwingWorker worker = new SwingWorker() { + public Void doInBackground() { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Opening Scenario..."); + spaceNetFrame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + spaceNetFrame.openScenario(spaceNetFrame.getScenarioChooser().getSelectedFile().getAbsolutePath()); + } catch(Exception ex) { + // display error message if one occurs... since this + // is inside a worker thread, the stack trace will + // not be printed unless directed handled here + JOptionPane.showMessageDialog(null, + "An error of type \"" + + ex.getClass().getSimpleName() + + "\" occurred while opening " + + spaceNetFrame.getScenarioChooser().getSelectedFile() + + ".\n", + "SpaceNet Error", + JOptionPane.ERROR_MESSAGE); + ex.printStackTrace(); + } + return null; + } + public void done() { + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + spaceNetFrame.setCursor(Cursor.getDefaultCursor()); + } + }; + worker.execute(); + } + + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/command/RemoveMissionCommand.java b/src/main/java/edu/mit/spacenet/gui/command/RemoveMissionCommand.java new file mode 100644 index 0000000..d19ac34 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/RemoveMissionCommand.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.List; + +import javax.swing.DefaultListModel; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import edu.mit.spacenet.gui.mission.MissionsTab; +import edu.mit.spacenet.scenario.Mission; + +/** + * The command to remove one or more missions. + * + * @author Paul Grogan + */ +public class RemoveMissionCommand implements I_Command { + private MissionsTab missionsTab; + private List missions; + + /** + * The constructor. + * + * @param missionsTab the missions tab component + * @param missions the missions to remove + */ + public RemoveMissionCommand(MissionsTab missionsTab, List missions) { + this.missionsTab = missionsTab; + this.missions = missions; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + JPanel warningPanel = new JPanel(); + warningPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + warningPanel.add(new JLabel("Permanently delete the following missions?"), c); + c.gridy++; + c.weighty = 1; + DefaultListModel missionsList = new DefaultListModel(); + for(Mission m : missions) { + missionsList.addElement(m); + } + warningPanel.add(new JScrollPane(new JList(missionsList)), c); + int answer = JOptionPane.showOptionDialog(missionsTab, + warningPanel, + "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); + if (answer == JOptionPane.YES_OPTION) { + for(Mission mission : missions) { + missionsTab.getScenarioPanel().getScenario().getMissionList().remove(mission); + } + } + missionsTab.updateView(); + } + +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/SaveScenarioAsCommand.java b/src/main/java/edu/mit/spacenet/gui/command/SaveScenarioAsCommand.java new file mode 100644 index 0000000..beebeb8 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/SaveScenarioAsCommand.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import java.io.File; + +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; + +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.io.XMLFileFilter; + +/** + * The command to save a scenario with a new filename. + * + * @author Paul Grogan + */ +public class SaveScenarioAsCommand implements I_Command { + private SpaceNetFrame spaceNetFrame; + + /** + * The constructor. + * + * @param spaceNetFrame the SpaceNet frame + */ + public SaveScenarioAsCommand(SpaceNetFrame spaceNetFrame) { + this.spaceNetFrame=spaceNetFrame; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + JFileChooser fileChooser = new JFileChooser(SpaceNetSettings.getInstance().getDefaultDirectory()) { + private static final long serialVersionUID = 5853237903722516861L; + public void approveSelection() { + File file = getSelectedFile(); + if (file != null && file.exists()) { + int answer = JOptionPane.showOptionDialog(spaceNetFrame, + "File " + file.getAbsolutePath() + " already exists. Overwrite?", + "Save Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); + if (answer == JOptionPane.NO_OPTION) { + return; + } + } + super.approveSelection(); + } + }; + fileChooser.setFileFilter(new XMLFileFilter()); + if (fileChooser.showSaveDialog(spaceNetFrame) == JFileChooser.APPROVE_OPTION) { + String filepath = fileChooser.getSelectedFile().getAbsolutePath(); + if(!filepath.substring(filepath.length() - 4, filepath.length()).equals(".xml")) { + filepath += ".xml"; + } + spaceNetFrame.getScenarioPanel().getScenario().setFilePath(filepath); + SaveScenarioCommand command = new SaveScenarioCommand(spaceNetFrame); + command.execute(); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/command/SaveScenarioCommand.java b/src/main/java/edu/mit/spacenet/gui/command/SaveScenarioCommand.java new file mode 100644 index 0000000..0fe6070 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/command/SaveScenarioCommand.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.command; + +import java.awt.Cursor; + +import javax.swing.SwingWorker; + +import edu.mit.spacenet.gui.SpaceNetFrame; + +/** + * The command to save a scenario with the current filename (launches a save as + * command if no file name exists). + * + * @author Paul Grogan + */ +public class SaveScenarioCommand implements I_Command { + private SpaceNetFrame spaceNetFrame; + + /** + * The constructor. + * + * @param spaceNetFrame the SpaceNet frame + */ + public SaveScenarioCommand(SpaceNetFrame spaceNetFrame) { + this.spaceNetFrame=spaceNetFrame; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.command.I_Command#execute() + */ + public void execute() { + if(spaceNetFrame.getScenarioPanel().getScenario().getFilePath() == null) { + SaveScenarioAsCommand command = new SaveScenarioAsCommand(spaceNetFrame); + command.execute(); + } else { + SwingWorker worker = new SwingWorker() { + public Void doInBackground() { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Saving Scenario " + + spaceNetFrame.getScenarioPanel().getScenario().getFileName() + + "..."); + spaceNetFrame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + spaceNetFrame.saveScenario(); + return null; + } + public void done() { + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + spaceNetFrame.setCursor(Cursor.getDefaultCursor()); + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Scenario " + + spaceNetFrame.getScenarioPanel().getScenario().getFileName() + + " Saved Successfully", false); + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + Thread.sleep(3000); + } catch(InterruptedException e) { } + spaceNetFrame.getStatusBar().setStatusMessage("", false); + } + }); + + } + }; + worker.execute(); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/component/CapacityPanel.java b/src/main/java/edu/mit/spacenet/gui/component/CapacityPanel.java new file mode 100644 index 0000000..0cfdd93 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/CapacityPanel.java @@ -0,0 +1,254 @@ +package edu.mit.spacenet.gui.component; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.text.DecimalFormat; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; + +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * The CapacityPanel class displays capacity progress bars for mass, volume, + * (if volume-constrained), and crew (if carrier). + */ +public class CapacityPanel extends JPanel { + private static final long serialVersionUID = 8033464124593156155L; + private JProgressBar massCapacity, volumeCapacity, crewCapacity; + private JLabel environmentLabel, massLabel, volumeLabel, crewLabel; + private DecimalFormat massFormat = new DecimalFormat("0.0"), + volumeFormat = new DecimalFormat("0.000"); + + /** + * Instantiates a new capacity panel. + */ + public CapacityPanel() { + initializePanel(); + } + + /** + * Initialize panel. + */ + private void initializePanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.HORIZONTAL; + environmentLabel = new JLabel(); + environmentLabel.setHorizontalAlignment(JLabel.CENTER); + add(environmentLabel, c); + c.gridy++; + c.gridwidth = 1; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + massCapacity = new JProgressBar(0, 100); + massCapacity.setStringPainted(true); + massCapacity.setVisible(false); + add(massCapacity, c); + c.gridy++; + volumeCapacity = new JProgressBar(0, 100); + volumeCapacity.setStringPainted(true); + volumeCapacity.setVisible(false); + add(volumeCapacity, c); + c.gridy++; + crewCapacity = new JProgressBar(0, 100); + crewCapacity.setStringPainted(true); + crewCapacity.setVisible(false); + add(crewCapacity, c); + c.fill = GridBagConstraints.NONE; + c.gridx++; + c.gridy = 1; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_START; + massLabel = new JLabel(" Cargo Mass"); + massLabel.setVisible(false); + add(massLabel, c); + c.gridy++; + volumeLabel = new JLabel(" Cargo Volume"); + volumeLabel.setVisible(false); + add(volumeLabel, c); + c.gridy++; + crewLabel = new JLabel(" Crew"); + crewLabel.setVisible(false); + add(crewLabel, c); + } + + /** + * Update capacities. + * + * @param element the element + * @param mass the mass + * @param volume the volume + * @param crew the crew + * @return true, if successful + */ + public boolean updateCapacities(I_ResourceContainer container, double mass, double volume) { + boolean hasErrors = false; + if(GlobalParameters.isEnvironmentConstrained()) { + environmentLabel.setVisible(true); + environmentLabel.setText(container.getCargoEnvironment().getName()); + } else { + environmentLabel.setVisible(false); + } + massCapacity.setVisible(true); + massLabel.setVisible(true); + if(mass > container.getMaxCargoMass()) { + hasErrors = true; + massCapacity.setForeground(new Color(153, 0, 0)); + } else { + massCapacity.setForeground(new Color(0, 153, 0)); + } + if(container.getMaxCargoMass()==0) { + massCapacity.setValue(100); + } else { + massCapacity.setValue((int)(100*mass/container.getMaxCargoMass())); + } + massCapacity.setString(massFormat.format(mass) + " / " + + massFormat.format(container.getMaxCargoMass()) + " kg"); + if(GlobalParameters.isVolumeConstrained()) { + volumeCapacity.setVisible(true); + volumeLabel.setVisible(true); + if(volume > container.getMaxCargoVolume()) { + hasErrors = hasErrors||GlobalParameters.isVolumeConstrained(); + volumeCapacity.setForeground(new Color(153, 0, 0)); + } else { + volumeCapacity.setForeground(new Color(0, 153, 0)); + } + if(container.getMaxCargoVolume()==0) { + volumeCapacity.setValue(100); + } else { + volumeCapacity.setValue((int)(100*volume/container.getMaxCargoVolume())); + } + volumeCapacity.setString(volumeFormat.format(volume) + " / " + + volumeFormat.format(container.getMaxCargoVolume()) + " m^3"); + } else { + volumeCapacity.setVisible(false); + volumeLabel.setVisible(false); + } + crewCapacity.setVisible(false); + crewLabel.setVisible(false); + return hasErrors; + } + + /** + * Update capacities. + * + * @param carrier the carrier + * @param mass the mass + * @param volume the volume + * @param crew the crew + * @return true, if successful + */ + public boolean updateCapacities(I_Carrier carrier, double mass, double volume, int crew) { + boolean hasErrors = false; + if(GlobalParameters.isEnvironmentConstrained()) { + environmentLabel.setVisible(true); + environmentLabel.setText(carrier.getCargoEnvironment().getName()); + } else { + environmentLabel.setVisible(false); + } + massCapacity.setVisible(true); + massLabel.setVisible(true); + if(mass > carrier.getMaxCargoMass()) { + hasErrors = true; + massCapacity.setForeground(new Color(153, 0, 0)); + } else { + massCapacity.setForeground(new Color(0, 153, 0)); + } + if(carrier.getMaxCargoMass()==0) { + massCapacity.setValue(100); + } else { + massCapacity.setValue((int)(100*mass/carrier.getMaxCargoMass())); + } + massCapacity.setString(massFormat.format(mass) + " / " + + massFormat.format(carrier.getMaxCargoMass()) + " kg"); + if(GlobalParameters.isVolumeConstrained()) { + volumeCapacity.setVisible(true); + volumeLabel.setVisible(true); + if(volume > carrier.getMaxCargoVolume()) { + hasErrors = hasErrors||GlobalParameters.isVolumeConstrained(); + volumeCapacity.setForeground(new Color(153, 0, 0)); + } else { + volumeCapacity.setForeground(new Color(0, 153, 0)); + } + if(carrier.getMaxCargoVolume()==0) { + volumeCapacity.setValue(100); + } else { + volumeCapacity.setValue((int)(100*volume/carrier.getMaxCargoVolume())); + } + volumeCapacity.setString(volumeFormat.format(volume) + " / " + + volumeFormat.format(carrier.getMaxCargoVolume()) + " m^3"); + } else { + volumeCapacity.setVisible(false); + volumeLabel.setVisible(false); + } + crewCapacity.setVisible(true); + crewLabel.setVisible(true); + if(crew > carrier.getMaxCrewSize()) { + hasErrors = true; + crewCapacity.setForeground(new Color(153, 0, 0)); + } else { + crewCapacity.setForeground(new Color(0, 153, 0)); + } + if(carrier.getMaxCrewSize()==0) { + crewCapacity.setValue(100); + } else { + crewCapacity.setValue((int)(100*crew/carrier.getMaxCrewSize())); + } + crewCapacity.setString((int)crew + " / " + + carrier.getMaxCrewSize() + " crew"); + return hasErrors; + } + + /** + * Update capacities. + * + * @param location the location + * @param mass the mass + * @param volume the volume + * @param crew the crew + * @return true, if successful + */ + public boolean updateCapacities(Location location, double mass, double volume, int crew) { + if(GlobalParameters.isEnvironmentConstrained()) { + environmentLabel.setText(Environment.UNPRESSURIZED.getName()); + } else { + environmentLabel.setVisible(false); + } + massCapacity.setVisible(true); + massLabel.setVisible(true); + massCapacity.setForeground(new Color(0, 153, 0)); + massCapacity.setValue(0); + massCapacity.setString(massFormat.format(mass) + " kg"); + if(GlobalParameters.isVolumeConstrained()) { + volumeCapacity.setVisible(true); + volumeLabel.setVisible(true); + volumeCapacity.setForeground(new Color(0, 153, 0)); + volumeCapacity.setValue(0); + volumeCapacity.setString(volumeFormat.format(volume) + " m^3"); + } else { + volumeCapacity.setVisible(false); + volumeLabel.setVisible(false); + } + crewCapacity.setVisible(true); + crewLabel.setVisible(true); + crewCapacity.setForeground(new Color(0, 153, 0)); + crewCapacity.setValue(0); + crewCapacity.setString((int)crew + " crew"); + return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/component/CheckBoxNode.java b/src/main/java/edu/mit/spacenet/gui/component/CheckBoxNode.java new file mode 100644 index 0000000..1644940 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/CheckBoxNode.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.tree.DefaultMutableTreeNode; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.I_Element; + +/** + * Node for the associated CheckBoxTree that represents elements as a check box, + * so they can easily be checked or unchecked for selection. + * + * @author Paul Grogan + */ +public class CheckBoxNode extends DefaultMutableTreeNode { + private static final long serialVersionUID = -2315502537628420250L; + private CheckBoxNodeComponent component; + + /** + * The constructor. + * + * @param checkBox the underlying check box component + */ + public CheckBoxNode(CheckBoxNodeComponent checkBox) { + super(checkBox); + this.component = checkBox; + } + + /** + * Gets the check box component for display. + * + * @return the check box component + */ + public CheckBoxNodeComponent getCheckBox() { + return component; + } + + /** + * Gets the element packaged inside the node. + * + * @return the element + */ + public I_Element getElement() { + return component.getElement(); + } + + /** + * Gets whether the check box is checked. + * + * @return whether the check box is checked + */ + public boolean isChecked() { + return component.isChecked(); + } + + /** + * Sets whether the check box is checked. + * + * @param isChecked whether the check box is checked + */ + public void setChecked(boolean isChecked) { + component.setChecked(isChecked); + } + + /** + * Static method to create a new tree node hierarchy for elements and nested + * elements. + * + * @param object the root object + * + * @return the tree node + */ + public static DefaultMutableTreeNode createNode(Object object) { + DefaultMutableTreeNode node = null; + if(object instanceof I_Element) { + node = new CheckBoxNode(new CheckBoxNodeComponent((I_Element)object)); + } else { + node = new DefaultMutableTreeNode(object); + } + + if(object instanceof I_Container) { + int index = 0; + for(I_Element e : ((I_Container) object).getContents()) { + node.insert(createNode(e), index++); + } + } + return node; + } + + /** + * The Class CheckBoxNodeComponent. + * + * @author Paul Grogan + * The visual component of a check box node. Includes a reference to the + * underlying element to be represented along with a check box and a label + * (for display of the element icon). + */ + public static class CheckBoxNodeComponent extends JPanel { + private static final long serialVersionUID = -4070444077100724836L; + private I_Element element; + private JCheckBox checkBox; + private JLabel label; + + /** + * The constructor. + * + * @param element the element to represent + * @param isChecked whether the check box should initially be checked + */ + public CheckBoxNodeComponent(I_Element element, boolean isChecked) { + super(); + setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); + setOpaque(false); + checkBox = new JCheckBox("",isChecked); + checkBox.setOpaque(false); + this.element = element; + label = new JLabel(getElement().getName(), getElement().getIcon(), JLabel.LEFT); + label.setBorder(BorderFactory.createEmptyBorder(1,1,1,1)); + label.setOpaque(true); + add(checkBox); + add(label); + } + + /** + * The constructor. + * + * @param element the element to represent + */ + public CheckBoxNodeComponent(I_Element element) { + this(element, false); + } + + /** + * Gets the underlying element. + * + * @return the element + */ + public I_Element getElement() { + return element; + } + + /** + * Gets the check box component. + * + * @return the check box component + */ + public JCheckBox getCheckBox() { + return checkBox; + } + + /** + * Gets the label component. + * + * @return the label component + */ + public JLabel getLabel() { + return label; + } + + /** + * Gets whether the check box is checked. + * + * @return whether the check box is checked + */ + public boolean isChecked() { + return checkBox.isSelected(); + } + + /** + * Sets whether the check box is checked. + * + * @param isChecked whether the check box is checked + */ + public void setChecked(boolean isChecked) { + checkBox.setSelected(isChecked); + } + } + +} diff --git a/src/main/java/edu/mit/spacenet/gui/component/CheckBoxTableModel.java b/src/main/java/edu/mit/spacenet/gui/component/CheckBoxTableModel.java new file mode 100644 index 0000000..2153eb7 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/CheckBoxTableModel.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.table.AbstractTableModel; + +/** + * Table that creates a listing of objects with the first column reserved for + * a boolean marker, graphically represented by a check box. + * + * @param the object type to list + * + * @author Paul Grogan + */ +public class CheckBoxTableModel extends AbstractTableModel { + private static final long serialVersionUID = 4160394859308981241L; + private List objects; + private Map checked; + + /** + * The constructor. + */ + public CheckBoxTableModel() { + objects = new ArrayList(); + checked = new HashMap(); + } + + /** + * Adds a new object to the listing. + * + * @param t the object to add + */ + public void addObject(T t) { + if(!objects.contains(t)) { + objects.add(t); + checked.put(t, true); + fireTableRowsInserted(objects.indexOf(t), objects.indexOf(t)); + } + } + + /** + * Adds a new object to the listing with passed checked state. + * + * @param t the object to add + * @param isChecked whether the object should be checked + */ + public void addObject(T t, boolean isChecked) { + if(!objects.contains(t)) { + objects.add(t); + checked.put(t, isChecked); + fireTableRowsInserted(objects.indexOf(t), objects.indexOf(t)); + } + } + + /** + * Clears the list of objects. + */ + public void clear() { + objects.clear(); + checked.clear(); + fireTableDataChanged(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 2; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + return objects.size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) { + return checked.get(objects.get(row)); + } else { + return objects.get(row); + } + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int col) { + if(col==0) return true; + else return false; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnClass(int) + */ + public Class getColumnClass(int col) { + if(col==0) return Boolean.class; + else return Object.class; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int) + */ + public void setValueAt(Object value, int row, int col) { + if(col==0) { + checked.put(objects.get(row), (Boolean)value); + } else { + throw new RuntimeException("Cannot modify objects"); + } + fireTableCellUpdated(row, col); + } + + /** + * Gets a list of the unchecked objects. + * + * @return the list of unchecked objects + */ + public List getDeselectedObjects() { + ArrayList deselected = new ArrayList(); + for(T t : objects) { + if(checked.get(t).equals(Boolean.FALSE)) { + deselected.add(t); + } + } + return deselected; + } + + /** + * Gets a list of the checked objects. + * + * @return the list of checked objects + */ + public List getSelectedObjects() { + ArrayList selected = new ArrayList(); + for(T t : objects) { + if(checked.get(t).equals(Boolean.TRUE)) { + selected.add(t); + } + } + return selected; + } + + /** + * Gets all the objects. + * + * @return the objects + */ + public List getAllObjects() { + return objects; + } + + /** + * Checks an object. + * + * @param t the object + */ + public void selectObject(T t) { + if(checked.containsKey(t)) { + checked.put(t, true); + fireTableCellUpdated(objects.indexOf(t), 0); + } + } + + /** + * Unchecks an object. + * + * @param t the object to uncheck + */ + public void deselectObject(T t) { + if(checked.containsKey(t)) { + checked.put(t, false); + fireTableCellUpdated(objects.indexOf(t), 0); + } + } + + /** + * Checks all objects in the list. + */ + public void selectAll() { + for(T t : checked.keySet()) { + checked.put(t, Boolean.TRUE); + } + fireTableDataChanged(); + } + + /** + * Unchecks all objects in the list. + */ + public void deselectAll() { + for(T t : checked.keySet()) { + checked.put(t, Boolean.FALSE); + } + fireTableDataChanged(); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/component/CheckBoxTree.java b/src/main/java/edu/mit/spacenet/gui/component/CheckBoxTree.java new file mode 100644 index 0000000..c330acf --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/CheckBoxTree.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.awt.Color; +import java.awt.Component; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseEvent; +import java.util.EventObject; + +import javax.swing.BorderFactory; +import javax.swing.JTree; +import javax.swing.UIManager; +import javax.swing.tree.DefaultTreeCellEditor; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreePath; + +import edu.mit.spacenet.gui.component.CheckBoxNode.CheckBoxNodeComponent; + +/** + * A tree representation of check box nodes. + * + * @author Paul Grogan + */ +public class CheckBoxTree extends JTree { + private static final long serialVersionUID = 1702544297754862171L; + + /** + * The constructor. + * + * @param model the check box tree model + */ + public CheckBoxTree(CheckBoxTreeModel model) { + super(model); + setCellRenderer(new DefaultTreeCellRenderer() { + private static final long serialVersionUID = -1994646294945996581L; + public Component getTreeCellRendererComponent(JTree tree, Object value, + boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + if(value instanceof CheckBoxNode) { + CheckBoxNodeComponent component = ((CheckBoxNode)value).getCheckBox(); + if(selected) { + component.getLabel().setBackground(UIManager.getColor("Tree.selectionBackground")); + component.getLabel().setForeground(UIManager.getColor("Tree.selectionForeground")); + component.getLabel().setBorder(BorderFactory.createLineBorder(UIManager.getColor("Tree.selectionBorderColor"),1)); + } else { + component.getLabel().setBackground(UIManager.getColor("Tree.textBackground")); + component.getLabel().setForeground(UIManager.getColor("Tree.textForeground")); + component.getLabel().setBorder(BorderFactory.createEmptyBorder(1,1,1,1)); + } + return component; + } else { + return super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + } + } + }); + + setCellEditor(new DefaultTreeCellEditor(this, (DefaultTreeCellRenderer)getCellRenderer()) { + public boolean isCellEditable(EventObject event) { + boolean returnValue = false; + if (event instanceof MouseEvent) { + MouseEvent mouseEvent = (MouseEvent) event; + TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY()); + if (path != null) { + Object node = path.getLastPathComponent(); + if ((node != null) && (node instanceof CheckBoxNode)) { + returnValue = true; + } + } + } + return returnValue; + } + public Component getTreeCellEditorComponent(JTree tree, Object value, + boolean selected, boolean expanded, boolean leaf, int row) { + Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true); + if(editor instanceof CheckBoxNodeComponent) { + final CheckBoxNode node = (CheckBoxNode)value; + ItemListener itemListener = new ItemListener() { + public void itemStateChanged(ItemEvent itemEvent) { + getModel().nodeChanged(node); + if (itemEvent.getStateChange()==ItemEvent.SELECTED) { + getModel().checkChildren(node); + } else { + getModel().uncheckChildren(node); + } + } + }; + ((CheckBoxNodeComponent)editor).getCheckBox().addItemListener(itemListener); + } + return editor; + } + }); + + setEditable(true); + } + + /** + * Expands all nodes. + */ + public void expandAll() { + for(int i=0; i. + */ +package edu.mit.spacenet.gui.component; + +import java.util.HashSet; +import java.util.Set; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * The model for the check box tree. + * + * @author Paul Grogan + */ +public class CheckBoxTreeModel extends DefaultTreeModel { + private static final long serialVersionUID = 2682670639071078594L; + private boolean childrenChecked; + + /** + * The constructor. + * + * @param node the root of the model + */ + public CheckBoxTreeModel(Node node) { + super(CheckBoxNode.createNode(node)); + childrenChecked = true; + } + + /** + * The constructor which places a blank default node at the root. + */ + public CheckBoxTreeModel() { + super(new DefaultMutableTreeNode()); + childrenChecked = true; + } + private Set getCheckedElements(TreeNode node) { + HashSet elements = new HashSet(); + for(int i=0; i < node.getChildCount(); i++) { + if(node.getChildAt(i) instanceof CheckBoxNode) { + CheckBoxNode child = (CheckBoxNode)node.getChildAt(i); + if(child.isChecked()) { + elements.add(child.getElement()); + } else { + elements.addAll(getCheckedElements(child)); + } + } + } + return elements; + } + + /** + * Gets a set of elements from all of the checked nodes. + * + * @return the set of elements + */ + public Set getCheckedElements() { + return getCheckedElements(root); + } + + /** + * Gets a set of elements from only the top-level of checked nodes (no + * nested checked elements). + * + * @return the set of elements + */ + public Set getTopCheckedElements() { + return getTopCheckedElements(root); + } + private Set getTopCheckedElements(TreeNode node) { + HashSet elements = new HashSet(); + for(int i=0; i < node.getChildCount(); i++) { + CheckBoxNode child = (CheckBoxNode)node.getChildAt(i); + if(child.isChecked()) { + elements.add(child.getElement()); + } else { + elements.addAll(getTopCheckedElements(child)); + } + } + return elements; + } + + /** + * Checks whether the model contains an element. + * + * @param element the element + * + * @return whether the model contains the element + */ + public boolean containsElement(I_Element element) { + return containsElement(root, element); + } + private boolean containsElement(TreeNode node, I_Element element) { + for(int i=0; i < node.getChildCount(); i++) { + CheckBoxNode child = (CheckBoxNode)node.getChildAt(i); + if(child.getElement().equals(element)) { + return true; + } else { + if(containsElement(child, element)) return true; + } + } + return false; + } + /* TODO: suspect + public void checkElement(I_Element element) { + checkElement(root, element); + } + private void checkElement(TreeNode node, I_Element element) { + for(int i=0; i < node.getChildCount(); i++) { + CheckBoxNode child = (CheckBoxNode)node.getChildAt(i); + if(child.getElement().equals(element)) { + child.setChecked(true); + break; + } else { + checkElement(child, element); + } + } + }*/ + /** + * Checks a set of elements. + * + * @param elements the elements to check + */ + public void setCheckedElements(Set elements) { + setCheckedElements(root, elements); + } + private void setCheckedElements(TreeNode node, Set elements) { + for(int i=0; i < node.getChildCount(); i++) { + CheckBoxNode child = (CheckBoxNode)node.getChildAt(i); + for(I_Element element : elements) { + if(child.getElement().equals(element)) { + child.setChecked(true); + checkChildren(child, true); + nodeChanged(child); + } + } + setCheckedElements(child, elements); + } + } + private void checkChildren(TreeNode node, boolean isSelected) { + if(isChildrenChecked() + && node.getParent() instanceof CheckBoxNode + && ((CheckBoxNode)node.getParent()).isChecked() + && !isSelected) { + ((CheckBoxNode)node).setChecked(true); + checkChildren(node, true); + } else if(isChildrenChecked()) { + for(int i=0; i < node.getChildCount(); i++) { + if(node.getChildAt(i) instanceof CheckBoxNode) { + CheckBoxNode child = (CheckBoxNode)node.getChildAt(i); + child.setChecked(isSelected); + nodeChanged(child); + checkChildren(child, isSelected); + } + } + } + } + + /** + * Checks the children nodes of a parent node. + * + * @param node the parent node. + */ + public void checkChildren(TreeNode node) { + checkChildren(node, true); + } + + /** + * Unchecks the children nodes of a parent node. + * + * @param node the parent node + */ + public void uncheckChildren(TreeNode node) { + checkChildren(node, false); + } + + /** + * Checks all nodes. + */ + public void checkAll() { + checkChildren(root, true); + } + + /** + * Unchecks all nodes. + */ + public void uncheckAll() { + checkChildren(root, false); + } + + /** + * Gets whether children nodes are automatically checked. + * + * @return whether children nodes are automatically checked + */ + public boolean isChildrenChecked() { + return childrenChecked; + } + + /** + * Sets whether children nodes are automatically checked. + * + * @param childrenChecked whether children nodes are automatically checked + */ + public void setChildrenChecked(boolean childrenChecked) { + this.childrenChecked = childrenChecked; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/component/ContainerComboBox.java b/src/main/java/edu/mit/spacenet/gui/component/ContainerComboBox.java new file mode 100644 index 0000000..634132d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/ContainerComboBox.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.ImageIcon; +import javax.swing.JComboBox; +import javax.swing.JList; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * This class extends a combo box to provide icons for objects that implement + * the Container interface. + * + * @author Paul Grogan + */ +public class ContainerComboBox extends JComboBox { + private static final long serialVersionUID = -4738778912721458792L; + private ImageIcon transparentIcon = new ImageIcon(getClass().getClassLoader().getResource("icons/transparent_icon.png")); + + /** + * Instantiates a new container combo box. + */ + public ContainerComboBox() { + setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -2255885956722142642L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof I_Element) { + setIcon(((I_Element)value).getIcon()); + } else if(value instanceof Node) { + setIcon(((Node)value).getNodeType().getIcon()); + } else if(value instanceof Edge) { + setIcon(((Edge)value).getEdgeType().getIcon()); + } else if(value == null) { + setIcon(transparentIcon); + } + return this; + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/component/DemandTable.java b/src/main/java/edu/mit/spacenet/gui/component/DemandTable.java new file mode 100644 index 0000000..af6c83a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/DemandTable.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.awt.Component; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.DefaultCellEditor; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellEditor; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.domain.resource.Resource; +import edu.mit.spacenet.domain.resource.ResourceType; +import edu.mit.spacenet.gui.renderer.ResourceTypeTableCellRenderer; + +/** + * A table used to display a set of demands with editable fields. + * + * @author Paul Grogan + */ +public class DemandTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + + private List resourceTypeList; + private CustomTableModel model; + + /** + * The constructor. + * + * @param list the list of available resources + */ + public DemandTable(List list) { + super(); + this.resourceTypeList = list; + + model = new CustomTableModel(); + setModel(model); + getColumnModel().getColumn(0).setHeaderValue("Type"); + getColumnModel().getColumn(0).setCellRenderer(new ResourceTypeTableCellRenderer()); + getColumnModel().getColumn(0).setMaxWidth(100); + getColumnModel().getColumn(1).setHeaderValue("Resource"); + getColumnModel().getColumn(2).setHeaderValue("Amount"); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 2092491034324672219L; + private DecimalFormat format = new DecimalFormat("0.00"); + public Component getTableCellRendererComponent(JTable table, + Object value, boolean isSelected, boolean hasFocus, int row, int column) { + + super.getTableCellRendererComponent(table, format.format(value), isSelected, hasFocus, row, column); + return this; + } + }); + getColumnModel().getColumn(2).setMaxWidth(75); + getColumnModel().getColumn(3).setHeaderValue("Units"); + getColumnModel().getColumn(3).setMaxWidth(75); + DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); + renderer.setHorizontalAlignment(JLabel.CENTER); + getColumnModel().getColumn(3).setCellRenderer(renderer); + getTableHeader().setReorderingAllowed(false); + } + + /* (non-Javadoc) + * @see javax.swing.JTable#getCellEditor(int, int) + */ + public TableCellEditor getCellEditor(int row, int col) { + if(col==0) { + JComboBox comboBox = new JComboBox(); + comboBox.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -8350081466318995133L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + label.setIcon(((ResourceType)value).getIcon()); + return label; + } + }); + for(ResourceType t : ResourceType.values()) { + comboBox.addItem(t); + } + comboBox.setSelectedItem(getValueAt(row,col)); + return new DefaultCellEditor(comboBox); + } else if(col == 1){ + JComboBox comboBox = new JComboBox(); + for(I_Resource r : resourceTypeList) { + if(this.getModel().getValueAt(row, 0).equals(ResourceType.RESOURCE)) { + if(r.getClass().equals(Resource.class)) + comboBox.addItem(r); + } else if(this.getModel().getValueAt(row, 0).equals(ResourceType.ITEM)) { + if(r.getClass().equals(Item.class)) + comboBox.addItem(r); + } + } + if(this.getModel().getValueAt(row, 0).equals(ResourceType.GENERIC)) { + for(ClassOfSupply cos : ClassOfSupply.values()) { + comboBox.addItem(new GenericResource(cos)); + } + } + return new DefaultCellEditor(comboBox); + } else { + return super.getCellEditor(row, col); + } + } + private class CustomTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + private List data; + private Map dataType; + + public CustomTableModel() { + super(); + data = new ArrayList(); + dataType = new HashMap(); + } + public int getColumnCount() { + return 4; + } + public int getRowCount() { + return data.size(); + } + public boolean isCellEditable(int row, int col) { + if(col==3) return false; + else return true; + } + public Class getColumnClass(int col) { + if(col==0) { + return ResourceType.class; + } else if(col==1) { + return Demand.class; + } else if(col==2) { + return Double.class; + } else return String.class; + } + public Object getValueAt(int row, int col) { + if(col==0) { + return dataType.get(data.get(row)); + } else if(col==1) { + return data.get(row).getResource(); + } else if(col==2) { + return data.get(row).getAmount(); + } else { + if(data.get(row).getResource() != null) + return data.get(row).getResource().getUnits(); + else return ""; + } + } + public void setValueAt(Object value, int row, int col) { + if(col==0) { + dataType.put(data.get(row), (ResourceType)value); + } else if(col==1) { + data.get(row).setResource((I_Resource)value); + fireTableCellUpdated(row, 3); + } else { + data.get(row).setAmount((Double)value); + } + fireTableCellUpdated(row, col); + } + public List getData() { + return data; + } + public void addRow(Demand demand) { + data.add(demand); + if(demand.getResource() == null) { + dataType.put(demand, ResourceType.GENERIC); + } else if(demand.getResource().getResourceType()==ResourceType.GENERIC) { + dataType.put(demand, ResourceType.GENERIC); + } else if(demand.getResource().getResourceType()==ResourceType.RESOURCE) { + dataType.put(demand, ResourceType.RESOURCE); + } else { + dataType.put(demand, ResourceType.ITEM); + } + fireTableRowsInserted(data.indexOf(demand), data.indexOf(demand)); + } + public void remove(Demand demand) { + int index = data.indexOf(demand); + data.remove(demand); + fireTableRowsDeleted(index, index); + } + } + + /** + * Adds the demand. + * + * @param demand the demand + */ + public void addDemand(Demand demand) { + model.addRow(demand); + } + + /** + * Gets the demands. + * + * @return the demands + */ + public List getDemands() { + return model.getData(); + } + + /** + * Gets the demand. + * + * @param row the row + * + * @return the demand + */ + public Demand getDemand(int row) { + return model.getData().get(row); + } + + /** + * Removes the. + * + * @param demand the demand + */ + public void remove(Demand demand) { + model.remove(demand); + } + + /** + * Removes the all demands. + */ + public void removeAllDemands() { + while (model.getRowCount()>0){ + model.remove(getDemand(0)); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/component/DropDownButton.java b/src/main/java/edu/mit/spacenet/gui/component/DropDownButton.java new file mode 100644 index 0000000..e512c79 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/DropDownButton.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JMenu; +import javax.swing.JMenuBar; + +/** + * A component that appears to be a button but produces a pop-up menu when + * clicked. + */ +public class DropDownButton extends Box { + private static final long serialVersionUID = -3201696540484920791L; + private JButton button; + private DropDownMenu menu; + + /** + * Instantiates a new drop down button. + * + * @param text the text + * @param icon the icon + */ + public DropDownButton(String text, Icon icon) { + super(BoxLayout.X_AXIS); + + menu = new DropDownMenu(); + JMenuBar bar = new JMenuBar(); + bar.add(menu); + bar.setMaximumSize(new Dimension(0,100)); + bar.setMinimumSize(new Dimension(0,1)); + bar.setPreferredSize(new Dimension(0,1)); + add(bar); + + button = new JButton(text, icon); + button.addMouseListener(new MouseAdapter() { + boolean pressHidPopup = false; + public void mouseClicked(MouseEvent e) { + if (!pressHidPopup) menu.doClick(0); + } + public void mousePressed(MouseEvent e) { + menu.dispatchMouseEvent(e); + if (menu.isPopupMenuVisible()) + pressHidPopup = false; + else + pressHidPopup = true; + + } + }); + add(button); + } + + /** + * Gets the button. + * + * @return the button + */ + public JButton getButton() { + return button; + } + + /** + * Gets the menu. + * + * @return the menu + */ + public JMenu getMenu() { + return menu; + } + private class DropDownMenu extends JMenu { + private static final long serialVersionUID = 5291067347951781168L; + + public void dispatchMouseEvent(MouseEvent e) { + processMouseEvent(e); + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/component/ElementTree.java b/src/main/java/edu/mit/spacenet/gui/component/ElementTree.java new file mode 100644 index 0000000..3e22f5b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/ElementTree.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.awt.Component; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeSelectionModel; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * Displays elements in a tree view. + * + * @author Paul Grogan + */ +public class ElementTree extends JTree { + private static final long serialVersionUID = 3758692951781867272L; + private ElementTreeModel model; + + /** + * The constructor which creates an empty tree. + */ + public ElementTree() { + this(new ElementTreeModel()); + } + + /** + * The constructor. + * + * @param model the element tree model + */ + public ElementTree(ElementTreeModel model) { + super(model); + this.model = model; + expandAll(); + setRootVisible(false); + setShowsRootHandles(true); + getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + setCellRenderer(new DefaultTreeCellRenderer() { + private static final long serialVersionUID = 6981300046370175632L; + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, + boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + if(value instanceof DefaultMutableTreeNode && ((DefaultMutableTreeNode)value).getUserObject() instanceof I_Element) { + setIcon(((I_Element)((DefaultMutableTreeNode)value).getUserObject()).getIcon()); + } else if(value instanceof DefaultMutableTreeNode && ((DefaultMutableTreeNode)value).getUserObject() instanceof Node) { + setIcon(((Node)((DefaultMutableTreeNode)value).getUserObject()).getNodeType().getIcon()); + } else if(value instanceof DefaultMutableTreeNode && ((DefaultMutableTreeNode)value).getUserObject() instanceof Edge) { + setIcon(((Edge)((DefaultMutableTreeNode)value).getUserObject()).getEdgeType().getIcon()); + } + return this; + } + + }); + } + + /** + * Sets the root of the tree to a new object. + * + * @param object the root of the tree + */ + public void setRoot(Object object) { + model = new ElementTreeModel(object); + setModel(model); + expandAll(); + } + + /* (non-Javadoc) + * @see javax.swing.JTree#getModel() + */ + @Override + public ElementTreeModel getModel() { + return model; + } + + /** + * Expands all nodes of the tree. + */ + public void expandAll() { + for(int i=0; i 1) { + DefaultMutableTreeNode parent = (DefaultMutableTreeNode)getSelectionPath().getPathComponent(getSelectionPath().getPathCount()-2); + parent.remove((DefaultMutableTreeNode)getSelectionPath().getLastPathComponent()); + ((I_Container)parent.getUserObject()).remove(getElementSelection()); + model.nodeStructureChanged(parent); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/component/ElementTreeModel.java b/src/main/java/edu/mit/spacenet/gui/component/ElementTreeModel.java new file mode 100644 index 0000000..db7d00f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/ElementTreeModel.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * The model for the element tree. + * + * @author Paul Grogan + */ +public class ElementTreeModel extends DefaultTreeModel { + private static final long serialVersionUID = -2759958352258498303L; + private DefaultMutableTreeNode root; + private static boolean hideEmptyLocations = true; + + /** + * The constructor. + * + * @param object the root of the tree + */ + public ElementTreeModel(Object object) { + super(createNode(object)); + this.root = (DefaultMutableTreeNode)getRoot(); + } + + /** + * The constructor which sets the root to a new blank node. + */ + public ElementTreeModel() { + super(new DefaultMutableTreeNode()); + this.root = (DefaultMutableTreeNode)getRoot(); + } + + /** + * Static method to recursively create a new node and insert any child + * nodes as necessary to represent nested elements. + * + * @param object the parent object + * + * @return the node + */ + public static DefaultMutableTreeNode createNode(Object object) { + DefaultMutableTreeNode node = new DefaultMutableTreeNode(object); + if(object instanceof Network) { + int index = 0; + for(Node n : ((Network) object).getNodes()) { + if(hideEmptyLocations && n.getContents().size() > 0) + node.insert(createNode(n), index++); + } + for(Edge e: ((Network) object).getEdges()) { + if(hideEmptyLocations && e.getContents().size() > 0) + node.insert(createNode(e), index++); + } + if(((Network)object).getRemovedRegistrar().size()>0) { + DefaultMutableTreeNode removedNode = createNode("Removed"); + node.insert(removedNode, index++); + int removedIndex = 0; + for(I_Element e : ((Network)object).getRemovedRegistrar().values()) { + removedNode.insert(createNode(e), removedIndex++); + } + } + } else if(object instanceof I_Container) { + int index = 0; + for(I_Element e : ((I_Container) object).getContents()) { + node.insert(createNode(e), index++); + } + } + return node; + } + + /** + * Adds an element to the root. + * + * @param element the element + */ + public void addElement(I_Element element) { + if(root.getUserObject()==null || root.getUserObject() instanceof Node) { + root.insert(createNode(element), root.getChildCount()); + fireTreeStructureChanged(root, root.getPath(), null, null); + } else throw new RuntimeException("wrong root"); + } + + /** + * Removes an element from the model. + * + * @param element the element + */ + @SuppressWarnings("unchecked") + public void removeElement(I_Element element) { + Enumeration e = root.breadthFirstEnumeration(); + while(e.hasMoreElements()) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement(); + if(node.getUserObject() != null + && node.getUserObject().equals(element)) { + node.removeFromParent(); + fireTreeStructureChanged(root, root.getPath(), null, null); + } + } + } + + /** + * Shameless hack to force the model to update (simply fires a tree + * structure changed event... note that this usually loses information on + * the expanded and/or selected nodes). + */ + public void hackedUpdate() { + fireTreeStructureChanged(root, root.getPath(), null, null); + } + + /** + * Gets the child elements of the root. + * + * @return the set of elements + */ + public Set getElements() { + HashSet elements = new HashSet(); + for(int i=0; i. + */ +package edu.mit.spacenet.gui.component; + +import java.awt.Cursor; +import java.awt.Point; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.ImageIcon; + +import org.jfree.chart.ChartPanel; + +/** + * A subclass of a chart panel that sets some SpaceNet defaults. + * + * @author Paul Grogan, ptgrogan@mit.edu + */ +public class SNChartPanel extends ChartPanel { + private static final long serialVersionUID = 117468040756000184L; + private static final Cursor zoomCursor = Toolkit.getDefaultToolkit().createCustomCursor( + new ImageIcon(ClassLoader.getSystemResource("icons/zoom_icon.gif")).getImage(), new Point(15,15), "Zoom"); + + /** + * Instantiates a new SpaceNet chart panel. + */ + public SNChartPanel() { + super(null); + addMouseListener(new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + setCursor(zoomCursor); + } + public void mouseExited(MouseEvent e) { + setCursor(Cursor.getDefaultCursor()); + } + }); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/component/SearchTextField.java b/src/main/java/edu/mit/spacenet/gui/component/SearchTextField.java new file mode 100644 index 0000000..72f8d7d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/SearchTextField.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.awt.Color; +import java.awt.Font; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; + +import javax.swing.JTextField; + +/** + * A subclass of a text field that provides support for a default message + * prompting for a search term. + * + * @author Paul Grogan + */ +public class SearchTextField extends JTextField { + private static final long serialVersionUID = 3843718651416873933L; + private String defaultText; + + /** + * The constructor. + * + * @param defaultText the default prompt + */ + public SearchTextField(String defaultText) { + super(defaultText); + this.defaultText = defaultText; + + setFont(getFont().deriveFont(Font.ITALIC)); + setForeground(Color.LIGHT_GRAY); + + addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + if(getText().equals(getDefaultText())) { + setText(""); + setFont(getFont().deriveFont(Font.PLAIN)); + setForeground(Color.BLACK); + } + } + public void focusLost(FocusEvent e) { + if(getText().equals("")) { + setText(getDefaultText()); + setFont(getFont().deriveFont(Font.ITALIC)); + setForeground(Color.LIGHT_GRAY); + } + } + }); + } + + /** + * Gets the default prompt. + * + * @return the default prompt + */ + public String getDefaultText() { + return defaultText; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/component/UnitsWrapper.java b/src/main/java/edu/mit/spacenet/gui/component/UnitsWrapper.java new file mode 100644 index 0000000..ef0c021 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/component/UnitsWrapper.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.component; + +import java.awt.Component; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; + +/** + * A wrapper for components that adds units labels. + * + * @author Paul Grogan + */ +public class UnitsWrapper extends JPanel { + private static final long serialVersionUID = -7924295829431793990L; + private JLabel label; + + /** + * The constructor. + * + * @param input the input component + * @param units the units label + */ + public UnitsWrapper(Component input, String units) { + super(); + setOpaque(false); + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.weightx = 1; + c.gridx = 0; + c.fill = GridBagConstraints.HORIZONTAL; + add(input, c); + label = new JLabel(units); + label.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); + c.weightx = 0; + c.gridx = 1; + add(label, c); + } + + /** + * Sets the units label. + * + * @param units the units label + */ + public void setUnits(String units) { + label.setText(units); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/data/AbstractDataSourcePanel.java b/src/main/java/edu/mit/spacenet/gui/data/AbstractDataSourcePanel.java new file mode 100644 index 0000000..02630fc --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/data/AbstractDataSourcePanel.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.data; + +import javax.swing.JPanel; + +import edu.mit.spacenet.data.I_DataSource; + +/** + * Abstract panel to serve as an interface to the data source panels. + * + * @author Paul Grogan + */ +public abstract class AbstractDataSourcePanel extends JPanel { + private static final long serialVersionUID = 1391703151715305906L; + + private DataSourceDialog dataSourceDialog; + + /** + * The constructor. + * + * @param dataSourceDialog the data source dialog component + * @param dataSource the data source + */ + public AbstractDataSourcePanel(DataSourceDialog dataSourceDialog, I_DataSource dataSource) { + this.dataSourceDialog = dataSourceDialog; + } + + /** + * Requests the panel to save any inputs for the data source. + */ + public abstract void saveData(); + + /** + * Load and update view. + */ + public void loadAndUpdateView() { + dataSourceDialog.loadDataSource(); + dataSourceDialog.updateTables(); + } + + /** + * Gets the data source dialog. + * + * @return the data source dialog + */ + public DataSourceDialog getDialog() { + return dataSourceDialog; + } + + /** + * Gets the data source. + * + * @return the data source + */ + public abstract I_DataSource getDataSource(); + + /** + * Gets whether the data source can be loaded. + * + * @return whether the data source can be loaded + */ + public abstract boolean canLoad(); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/data/DataSourceDialog.java b/src/main/java/edu/mit/spacenet/gui/data/DataSourceDialog.java new file mode 100644 index 0000000..681e6ff --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/data/DataSourceDialog.java @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.data; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.data.DataSourceType; +import edu.mit.spacenet.data.Database; +import edu.mit.spacenet.data.ElementPreview; +import edu.mit.spacenet.data.I_DataSource; +import edu.mit.spacenet.data.Spreadsheet_2_5; +import edu.mit.spacenet.domain.element.Element; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.domain.resource.Resource; +import edu.mit.spacenet.gui.ScenarioPanel; +import edu.mit.spacenet.gui.command.LoadDataSourceCommand; +import edu.mit.spacenet.gui.edge.EdgeEditorDialog; +import edu.mit.spacenet.gui.element.ElementDialog; +import edu.mit.spacenet.gui.node.NodeEditorDialog; +import edu.mit.spacenet.gui.resource.ResourceEditorDialog; + +/** + * Dialog for editing loading data sources. + * + * @author Paul Grogan + */ +public class DataSourceDialog extends JDialog { + private static final long serialVersionUID = -3048824253945313736L; + + private ScenarioPanel scenarioPanel; + private I_DataSource dataSource; + + private JComboBox dataSourceTypeCombo; + private AbstractDataSourcePanel dataSourcePanel; + + private JCheckBox nodesCheck, edgesCheck, resourcesCheck, elementsCheck; + private JButton loadButton; + private JTabbedPane libraryTabs; + private DataSourceObjectTableModel nodeModel, edgeModel, resourceModel, elementModel; + private DataSourceObjectTable nodeTable, edgeTable, resourceTable, elementTable; + private JButton addButton, editButton, deleteButton; + + /** + * Instantiates a new data source dialog. + * + * @param scenarioPanel the scenario panel + */ + private DataSourceDialog(ScenarioPanel scenarioPanel) { + super(scenarioPanel.getSpaceNetFrame(), "Edit Data Source", true); + this.scenarioPanel = scenarioPanel; + if(scenarioPanel.getScenario()!=null) { + dataSource = scenarioPanel.getScenario().getDataSource(); + } + buildDialog(); + } + + private void buildDialog() { + final JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Type: "), c); + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + dataSourceTypeCombo = new JComboBox(); + for(DataSourceType t : DataSourceType.values()) { + dataSourceTypeCombo.addItem(t); + } + dataSourceTypeCombo.setSelectedItem(dataSource==null?DataSourceType.NONE:dataSource.getDataSourceType()); + dataSourceTypeCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -2255885956722142642L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setIcon(((DataSourceType)value).getIcon()); + return this; + } + }); + dataSourceTypeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED + && (dataSource==null&&e.getItem()!=DataSourceType.NONE + || dataSource.getDataSourceType()!=e.getItem())) { + int answer = JOptionPane.YES_OPTION; + if(getScenarioPanel().getScenario().getDataSource()!=null) { + answer = JOptionPane.showConfirmDialog(getThis(), + "Changing the data source will reset all data. Continue?", + "Confirm Data Source Change", JOptionPane.YES_NO_OPTION); + } + if(answer==JOptionPane.YES_OPTION) { + switch((DataSourceType)dataSourceTypeCombo.getSelectedItem()) { + case EXCEL_2_5: + getScenarioPanel().getScenario().setDataSource(new Spreadsheet_2_5()); + break; + case SQL_DB: + getScenarioPanel().getScenario().setDataSource(new Database()); + break; + case NONE: + getScenarioPanel().getScenario().setDataSource(null); + break; + } + + dispose(); + getScenarioPanel().updateView(); + DataSourceDialog.createAndShowGUI(getScenarioPanel()); + } else { + updateTables(); + } + } + } + }); + contentPanel.add(dataSourceTypeCombo, c); + + c.gridy++; + c.weightx = 0; + c.gridx = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + dataSourcePanel = DataSourcePanelFactory.createDataSourcePanel(this, dataSource); + contentPanel.add(dataSourcePanel, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.FIRST_LINE_END; + contentPanel.add(new JLabel("Update: "), c); + c.gridx++; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + JPanel checkPanel = new JPanel(new GridLayout(2,2)); + nodesCheck = new JCheckBox("Nodes", true); + checkPanel.add(nodesCheck); + edgesCheck = new JCheckBox("Edges", true); + checkPanel.add(edgesCheck); + resourcesCheck = new JCheckBox("Resources", true); + checkPanel.add(resourcesCheck); + elementsCheck = new JCheckBox("Instantiated Elements", false); + checkPanel.add(elementsCheck); + contentPanel.add(checkPanel, c); + + c.gridy++; + c.fill = GridBagConstraints.NONE; + loadButton = new JButton("Load", new ImageIcon(getClass().getClassLoader().getResource("icons/database_refresh.png"))); + loadButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + loadDataSource(); + } + }); + contentPanel.add(loadButton, c); + + c.gridy++; + c.gridx = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + contentPanel.add(new JLabel("Data: "), c); + c.gridx++; + c.weighty = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + libraryTabs = new JTabbedPane(); + contentPanel.add(libraryTabs, c); + + nodeModel = new DataSourceObjectTableModel(DataSourceObjectTableModel.NODE, dataSource); + nodeTable = new DataSourceObjectTable(nodeModel); + nodeTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + repaint(); + } + }); + nodeTable.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2&&nodeTable.getSelectedRowCount()==1) { + NodeEditorDialog.createAndShowGUI(getThis(), + dataSource.getNodeLibrary().get(nodeTable.getSelectedRow())); + } + } + }); + JScrollPane nodeScroll = new JScrollPane(nodeTable); + nodeScroll.setPreferredSize(new Dimension(400,200)); + libraryTabs.addTab("Nodes", new ImageIcon(getClass().getClassLoader().getResource("icons/bullet_black.png")), nodeScroll); + + edgeModel = new DataSourceObjectTableModel(DataSourceObjectTableModel.EDGE, dataSource); + edgeTable = new DataSourceObjectTable(edgeModel); + edgeTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + repaint(); + } + }); + edgeTable.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2&&edgeTable.getSelectedRowCount()==1) { + EdgeEditorDialog.createAndShowGUI(getThis(), + dataSource.getEdgeLibrary().get(edgeTable.getSelectedRow())); + } + } + }); + JScrollPane edgeScroll = new JScrollPane(edgeTable); + edgeScroll.setPreferredSize(new Dimension(400,200)); + libraryTabs.addTab("Edges", new ImageIcon(getClass().getClassLoader().getResource("icons/edge_red.png")), edgeScroll); + + resourceModel = new DataSourceObjectTableModel(DataSourceObjectTableModel.RESOURCE, dataSource); + resourceTable = new DataSourceObjectTable(resourceModel); + resourceTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + repaint(); + } + }); + resourceTable.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2&&resourceTable.getSelectedRowCount()==1) { + ResourceEditorDialog.createAndShowGUI(getThis(), + dataSource.getResourceLibrary().get(resourceTable.getSelectedRow())); + } + } + }); + JScrollPane resourceScroll = new JScrollPane(resourceTable); + resourceScroll.setPreferredSize(new Dimension(400,200)); + libraryTabs.addTab("Resources", new ImageIcon(getClass().getClassLoader().getResource("icons/bullet_blue.png")), resourceScroll); + + elementModel = new DataSourceObjectTableModel(DataSourceObjectTableModel.ELEMENT, dataSource); + elementTable = new DataSourceObjectTable(elementModel); + elementTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + repaint(); + } + }); + elementTable.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2&&elementTable.getSelectedRowCount()==1) { + ElementPreview elementpreview = dataSource.getElementPreviewLibrary().get(elementTable.getSelectedRow()); + int tid = elementpreview.ID; + try { + ElementDialog.createAndShowGUI(getThis(), (I_Element)dataSource.loadElement(tid)); + } catch(Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(getThis(), + "An error occurred while loading the element from the data source.", + "Element Load Error", + JOptionPane.ERROR_MESSAGE); + } + } + } + }); + JScrollPane elementScroll = new JScrollPane(elementTable); + elementScroll.setPreferredSize(new Dimension(400,200)); + libraryTabs.addTab("Elements", new ImageIcon(getClass().getClassLoader().getResource("icons/lunar_lander.png")), elementScroll); + libraryTabs.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + nodeTable.clearSelection(); + edgeTable.clearSelection(); + resourceTable.clearSelection(); + elementTable.clearSelection(); + repaint(); + } + }); + + c.gridy++; + c.gridwidth = 2; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + JPanel editButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + addButton = new JButton("Add New", new ImageIcon(getClass().getClassLoader().getResource("icons/add.png"))); + addButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + switch(libraryTabs.getSelectedIndex()) { + case 0: + NodeEditorDialog.createAndShowGUI(getThis(), new SurfaceNode()); + break; + case 1: + EdgeEditorDialog.createAndShowGUI(getThis(), new SurfaceEdge()); + break; + case 2: + ResourceEditorDialog.createAndShowGUI(getThis(), new Resource()); + break; + case 3: + ElementDialog.createAndShowGUI(getThis(), new Element()); + //TODO turn sizing model back on SizingModelDialogEditor.createAndShowGUI(getThis(), ElementType.ELEMENT); + break; + } + } + }); + editButtonPanel.add(addButton); + editButton = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/page_white_edit.png"))); + editButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + switch(libraryTabs.getSelectedIndex()) { + case 0: + NodeEditorDialog.createAndShowGUI(getThis(), + dataSource.getNodeLibrary().get(nodeTable.getSelectedRow())); + break; + case 1: + EdgeEditorDialog.createAndShowGUI(getThis(), + dataSource.getEdgeLibrary().get(edgeTable.getSelectedRow())); + break; + case 2: + ResourceEditorDialog.createAndShowGUI(getThis(), + dataSource.getResourceLibrary().get(resourceTable.getSelectedRow())); + break; + case 3: + ElementPreview elementpreview = dataSource.getElementPreviewLibrary().get(elementTable.getSelectedRow()); + int tid = elementpreview.ID; + try { + ElementDialog.createAndShowGUI(getThis(), (I_Element)dataSource.loadElement(tid)); + } catch(Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(getThis(), + "An error occurred while loading the element from the data source.", + "Element Load Error", + JOptionPane.ERROR_MESSAGE); + } + break; + } + + } + }); + editButton.setEnabled(false); + editButtonPanel.add(editButton); + deleteButton = new JButton("Delete", new ImageIcon(getClass().getClassLoader().getResource("icons/delete.png"))); + deleteButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int response = JOptionPane.showConfirmDialog(getThis(), + "Are you sure you want to permanently delete objects?", + "SpaceNet Warning", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.WARNING_MESSAGE); + if(response == JOptionPane.YES_OPTION) { + ArrayList errorMessages= new ArrayList(0); + switch(libraryTabs.getSelectedIndex()) { + case 0: + for(int i : reverse(nodeTable.getSelectedRows())) { + try { + boolean isSuccessful = dataSource.deleteNode(dataSource.getNodeLibrary().get(i).getTid()); + if(!isSuccessful) { + errorMessages.add("Node "+ dataSource.getNodeLibrary().get(i).getTid()); + } + } catch (Exception e1) { + e1.printStackTrace(); + } + } + loadDataSource(); + break; + case 1: + for(int i : reverse(edgeTable.getSelectedRows())) { + try { + boolean isSuccessful = dataSource.deleteEdge(dataSource.getEdgeLibrary().get(i).getTid()); + if(!isSuccessful) { + errorMessages.add("Edge "+ dataSource.getEdgeLibrary().get(i).getTid()); + } + } catch (Exception e1) { + e1.printStackTrace(); + } + } + loadDataSource(); + break; + case 2: + for (int i : reverse(resourceTable.getSelectedRows())) { + try { + boolean isSuccessful = dataSource.deleteResource(dataSource.getResourceLibrary().get(i).getTid()); + if(!isSuccessful) { + errorMessages.add("Resource "+ dataSource.getResourceLibrary().get(i).getTid()); + } + } catch (Exception e1) { + e1.printStackTrace(); + } + } + loadDataSource(); + break; + case 3: + for(int i : reverse(elementTable.getSelectedRows())){ + try { + boolean isSuccessful = dataSource.deleteElement(dataSource.getElementPreviewLibrary().get(i).ID); + if(!isSuccessful) { + errorMessages.add("Element "+dataSource.getElementPreviewLibrary().get(i).ID); + } + } catch (Exception e1) { + e1.printStackTrace(); + } + } + loadDataSource(); + break; + } + if(errorMessages.size() > 0) { + String tempError = "The following objects could not be deleted because of existing references: \n"; + for(int j=0; j0 + || edgeTable.getSelectedRowCount()>0 + || resourceTable.getSelectedRowCount()>0 + || elementTable.getSelectedRowCount()>0)); + } + + /** + * Requests that the dialog update its fields based on the model and also + * requests the data source panel to update itself. + */ + public void updateTables() { + nodeModel.setDataSource(getDataSource()); + edgeModel.setDataSource(getDataSource()); + resourceModel.setDataSource(getDataSource()); + elementModel.setDataSource(getDataSource()); + repaint(); + } + + /** + * Gets the this. + * + * @return the this + */ + private DataSourceDialog getThis() { + return this; + } + + /** + * Gets the scenario panel. + * + * @return the scenario panel + */ + public ScenarioPanel getScenarioPanel() { + return scenarioPanel; + } + + /** + * Gets the data source. + * + * @return the data source + */ + public I_DataSource getDataSource() { + return dataSource; + } + + /** + * Loads the data source. + */ + public void loadDataSource() { + dataSourcePanel.saveData(); + + LoadDataSourceCommand command = new LoadDataSourceCommand(this); + command.execute(); + } + + /** + * Gets whether the already-instantiated elements should be updated. + * + * @return whether the instantiated elements should be updated + */ + public boolean updateInstantiatedElements() { + return elementsCheck.isSelected(); + } + + /** + * Update nodes. + * + * @return true, if existing nodes are to be updated + */ + public boolean updateNodes() { + return nodesCheck.isSelected(); + } + + /** + * Update edges. + * + * @return true, if existing edges are to be updated + */ + public boolean updateEdges() { + return edgesCheck.isSelected(); + } + + /** + * Update resources. + * + * @return true, if existing resources are to be updated + */ + public boolean updateResources() { + return resourcesCheck.isSelected(); + } + + /** + * Builds and displays the data source dialog. + * + * @param scenarioPanel the scenario panel component + */ + public static void createAndShowGUI(ScenarioPanel scenarioPanel) { + DataSourceDialog dialog = new DataSourceDialog(scenarioPanel); + dialog.pack(); + dialog.setLocationRelativeTo(dialog.getParent()); + dialog.setVisible(true); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/data/DataSourceObjectTable.java b/src/main/java/edu/mit/spacenet/gui/data/DataSourceObjectTable.java new file mode 100644 index 0000000..c044a14 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/data/DataSourceObjectTable.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.data; + +import java.awt.Component; +import java.awt.Font; + +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableModel; + +import edu.mit.spacenet.data.ElementPreview; +import edu.mit.spacenet.domain.network.edge.EdgeType; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.NodeType; +import edu.mit.spacenet.domain.resource.ResourceType; + +/** + * A custom JTable that does not display horizontal or vertical lines and + * attempts to show an icons for associated object types. + */ +public class DataSourceObjectTable extends JTable { + private static final long serialVersionUID = -5232329542188811358L; + + /** + * Instantiates a new data source object table. + * + * @param tableModel the table model + */ + public DataSourceObjectTable(TableModel tableModel) { + super(tableModel); + getTableHeader().setReorderingAllowed(false); + getTableHeader().setFont(getTableHeader().getFont().deriveFont(Font.BOLD)); + if(getColumnModel().getColumnCount()>0) + getColumnModel().getColumn(0).setMaxWidth(30); + if(getColumnModel().getColumnCount()>1) + getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof ResourceType) + setIcon(((ResourceType)value).getIcon()); + else if(value instanceof EdgeType) + setIcon(((EdgeType)value).getIcon()); + else if(value instanceof NodeType) + setIcon(((NodeType)value).getIcon()); + else if(value instanceof ElementPreview) { + setText(((ElementPreview)value).TYPE.getName()); + setIcon(((ElementPreview)value).getIconType().getIcon()); + } return this; + } + }); + if(getColumnModel().getColumnCount()>3) + getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof Node) + setIcon(((Node)value).getNodeType().getIcon()); + return this; + } + }); + if(getColumnModel().getColumnCount()>4) + getColumnModel().getColumn(4).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof Node) + setIcon(((Node)value).getNodeType().getIcon()); + return this; + } + }); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/data/DataSourceObjectTableModel.java b/src/main/java/edu/mit/spacenet/gui/data/DataSourceObjectTableModel.java new file mode 100644 index 0000000..5301663 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/data/DataSourceObjectTableModel.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.data; + +import javax.swing.table.AbstractTableModel; + +import edu.mit.spacenet.data.I_DataSource; + +/** + * An implementation of a table model used to display the contents of a data + * source. + */ +public class DataSourceObjectTableModel extends AbstractTableModel { + private static final long serialVersionUID = 2710558664475507700L; + public static final int NODE = 1, EDGE = 2, RESOURCE = 3, ELEMENT = 4; + + private int objectType; + private I_DataSource dataSource; + + /** + * Instantiates a new data source object table model. + * + * @param objectType the object type + * @param dataSource the data source + */ + public DataSourceObjectTableModel(int objectType, I_DataSource dataSource) { + if(objectTypeELEMENT) + throw new IllegalArgumentException("Illegal Object Type"); + this.objectType = objectType; + this.dataSource = dataSource; + } + + /** + * Sets the data source. + * + * @param dataSource the new data source + */ + public void setDataSource(I_DataSource dataSource) { + this.dataSource = dataSource; + fireTableDataChanged(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + switch(objectType) { + case NODE: return 3; + case EDGE: return 5; + case RESOURCE: return 4; + case ELEMENT: return 3; + default: return 0; + } + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnName(int) + */ + public String getColumnName(int columnIndex) { + switch(objectType) { + case NODE: + switch(columnIndex) { + case 0: return "ID"; + case 1: return "Type"; + case 2: return "Name"; + default: return null; + } + case EDGE: + switch(columnIndex) { + case 0: return "ID"; + case 1: return "Type"; + case 2: return "Name"; + case 3: return "Origin"; + case 4: return "Destination"; + default: return null; + } + case RESOURCE: + switch(columnIndex) { + case 0: return "ID"; + case 1: return "Type"; + case 2: return "Name"; + case 3: return "Class of Supply"; + default: return null; + } + case ELEMENT: + switch(columnIndex) { + case 0: return "ID"; + case 1: return "Icon"; + case 2: return "Name"; + default: return null; + } + default: return null; + } + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + if(dataSource==null) return 0; + switch(objectType) { + case NODE: return dataSource.getNodeLibrary().size(); + case EDGE: return dataSource.getEdgeLibrary().size(); + case RESOURCE: return dataSource.getResourceLibrary().size(); + case ELEMENT: return dataSource.getElementPreviewLibrary().size(); + default: return 0; + } + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int rowIndex, int columnIndex) { + switch(objectType) { + case NODE: + switch(columnIndex) { + case 0: return dataSource.getNodeLibrary().get(rowIndex).getTid(); + case 1: return dataSource.getNodeLibrary().get(rowIndex).getNodeType(); + case 2: return dataSource.getNodeLibrary().get(rowIndex).getName(); + default: return null; + } + case EDGE: + switch(columnIndex) { + case 0: return dataSource.getEdgeLibrary().get(rowIndex).getTid(); + case 1: return dataSource.getEdgeLibrary().get(rowIndex).getEdgeType(); + case 2: return dataSource.getEdgeLibrary().get(rowIndex).getName(); + case 3: return dataSource.getEdgeLibrary().get(rowIndex).getOrigin(); + case 4: return dataSource.getEdgeLibrary().get(rowIndex).getDestination(); + default: return null; + } + case RESOURCE: + switch(columnIndex) { + case 0: return dataSource.getResourceLibrary().get(rowIndex).getTid(); + case 1: return dataSource.getResourceLibrary().get(rowIndex).getResourceType(); + case 2: return dataSource.getResourceLibrary().get(rowIndex).getName(); + case 3: return dataSource.getResourceLibrary().get(rowIndex).getClassOfSupply(); + default: return null; + } + case ELEMENT: + switch(columnIndex) { + case 0: return dataSource.getElementPreviewLibrary().get(rowIndex).ID; + case 1: return dataSource.getElementPreviewLibrary().get(rowIndex); + case 2: return dataSource.getElementPreviewLibrary().get(rowIndex).NAME; + default: return null; + } + default: return null; + } + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnClass(int) + */ + public Class getColumnClass(int col) { + if(col==0) return Integer.class; + else return Object.class; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int col) { + return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/data/DataSourcePanelFactory.java b/src/main/java/edu/mit/spacenet/gui/data/DataSourcePanelFactory.java new file mode 100644 index 0000000..6be7bd3 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/data/DataSourcePanelFactory.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.data; + +import edu.mit.spacenet.data.Database; +import edu.mit.spacenet.data.I_DataSource; +import edu.mit.spacenet.data.Spreadsheet_2_5; + +/** + * An abstract class to contain the factory method to create data source panels. + * + * @author Paul Grogan + */ +public abstract class DataSourcePanelFactory { + + /** + * Factory method to create a data source panel based on the data source + * type. + * + * @param dialog the data source dialog + * @param dataSource the data source + * + * @return the data source panel + */ + public static AbstractDataSourcePanel createDataSourcePanel(DataSourceDialog dialog, I_DataSource dataSource) { + if(dataSource==null) return new NoDataSourcePanel(dialog, dataSource); + + switch(dataSource.getDataSourceType()) { + case EXCEL_2_5: + return new ExcelDataSourcePanel(dialog, (Spreadsheet_2_5)dataSource); + case SQL_DB: + return new MySqlDataSourcePanel(dialog, (Database)dataSource); + default: throw new RuntimeException("Unsupported Data Source"); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/data/ExcelDataSourcePanel.java b/src/main/java/edu/mit/spacenet/gui/data/ExcelDataSourcePanel.java new file mode 100644 index 0000000..54bad34 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/data/ExcelDataSourcePanel.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.data; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JTextField; + +import edu.mit.spacenet.data.Spreadsheet_2_5; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.io.XLSFileFilter; + +/** + * A data source panel for excel spreadsheet data sources. + * + * @author Paul Grogan + */ +public class ExcelDataSourcePanel extends AbstractDataSourcePanel { + private static final long serialVersionUID = 2234336773732183925L; + + private Spreadsheet_2_5 dataSource; + private JTextField filePathText; + + /** + * Instantiates a new excel data source panel. + * + * @param dialog the dialog + * @param dataSource the data source + */ + protected ExcelDataSourcePanel(DataSourceDialog dialog, Spreadsheet_2_5 dataSource) { + super(dialog, dataSource); + this.dataSource = dataSource; + + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.weightx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("File Path: "), c); + + c.gridx++; + c.weightx = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; + filePathText = new JTextField(30); + filePathText.setEnabled(false); + filePathText.setText(dataSource.getFilePath()); + add(filePathText, c); + + c.gridx++; + c.weightx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + JButton browseButton = new JButton("Browse...", new ImageIcon(getClass().getClassLoader().getResource("icons/folder_explore.png"))); + browseButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JFileChooser fileChooser = new JFileChooser(SpaceNetSettings.getInstance().getDefaultDirectory()); + fileChooser.setFileFilter(new XLSFileFilter()); + int returnVal = fileChooser.showOpenDialog(getDialog()); + if(returnVal == JFileChooser.APPROVE_OPTION) { + filePathText.setText(fileChooser.getSelectedFile().getAbsolutePath()); + loadAndUpdateView(); + } + } + }); + add(browseButton, c); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#saveData() + */ + @Override + public void saveData() { + dataSource.setFilePath(filePathText.getText()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#getDataSource() + */ + @Override + public Spreadsheet_2_5 getDataSource() { + return dataSource; + } + + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#canLoad() + */ + @Override + public boolean canLoad() { + return filePathText.getText().length()>0; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/data/MySqlDataSourcePanel.java b/src/main/java/edu/mit/spacenet/gui/data/MySqlDataSourcePanel.java new file mode 100644 index 0000000..bf8a79c --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/data/MySqlDataSourcePanel.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.data; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPasswordField; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.data.Database; + +/** + * A data source panel for excel spreadsheet data sources. + * + * @author Paul Grogan + */ +public class MySqlDataSourcePanel extends AbstractDataSourcePanel { + private static final long serialVersionUID = 2234336773732183925L; + + private Database dataSource; + private JTextField hostText, databaseText, userText, passwordText; + private JSpinner portSpinner; + private SpinnerNumberModel portModel; + private JButton testButton; + + /** + * Instantiates a new my sql data source panel. + * + * @param dialog the dialog + * @param dataSource the data source + */ + protected MySqlDataSourcePanel(DataSourceDialog dialog, Database dataSource) { + super(dialog, dataSource); + this.dataSource = dataSource; + + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Host: "), c); + c.gridx+=2; + add(new JLabel("Port: "), c); + c.gridy++; + c.gridx = 0; + add(new JLabel("User: "), c); + c.gridx+=2; + add(new JLabel("Password: "), c); + c.gridy++; + c.gridx = 0; + add(new JLabel("Database: "), c); + + c.gridx = 1; + c.gridy = 0; + c.weightx = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; + hostText = new JTextField(); + hostText.setText(dataSource.getHost()); + add(hostText, c); + c.gridx+=2; + portModel = new SpinnerNumberModel(dataSource.getPort().intValue(),1,10000,1); + portSpinner = new JSpinner(portModel); + portSpinner.setPreferredSize(new Dimension(100,20)); + add(portSpinner, c); + c.gridy++; + c.gridx = 1; + userText = new JTextField(15); + userText.setText(dataSource.getUser()); + add(userText, c); + c.gridx+=2; + passwordText = new JPasswordField(); + passwordText.setText(dataSource.getPassword()); + add(passwordText, c); + c.gridy++; + c.gridx = 1; + databaseText = new JTextField(); + databaseText.setText(dataSource.getDatabase()); + add(databaseText, c); + c.gridx++; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.NONE; + testButton = new JButton("Test", new ImageIcon(getClass().getClassLoader().getResource("icons/database_go.png"))); + testButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveData(); + try { + dataSource.createConnection(); + dataSource.loadLibraries(); + JOptionPane.showMessageDialog(getDialog(), + "Success!", + "Test Connection", + JOptionPane.INFORMATION_MESSAGE); + } catch(Exception ex) { + JOptionPane.showMessageDialog(getDialog(), + "Failure", + "Test Connection", + JOptionPane.ERROR_MESSAGE); + } + } + }); + add(testButton, c); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#saveData() + */ + @Override + public void saveData() { + dataSource.setHost(hostText.getText()); + dataSource.setPort(portModel.getNumber().intValue()); + dataSource.setDatabase(databaseText.getText()); + dataSource.setUser(userText.getText()); + dataSource.setPassword(passwordText.getText()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#getDataSource() + */ + @Override + public Database getDataSource() { + return dataSource; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#canLoad() + */ + @Override + public boolean canLoad() { + return hostText.getText().length()>0 + && databaseText.getText().length()>0 + && userText.getText().length()>0; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/data/NoDataSourcePanel.java b/src/main/java/edu/mit/spacenet/gui/data/NoDataSourcePanel.java new file mode 100644 index 0000000..bb61ce6 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/data/NoDataSourcePanel.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.data; + +import edu.mit.spacenet.data.I_DataSource; + +/** + * A data source panel to display when no data source is present (blank). + * + * @author Paul Grogan + */ +public class NoDataSourcePanel extends AbstractDataSourcePanel { + private static final long serialVersionUID = 2234336773732183925L; + + /** + * Instantiates a new no data source panel. + * + * @param dialog the dialog + * @param dataSource the data source + */ + protected NoDataSourcePanel(DataSourceDialog dialog, I_DataSource dataSource) { + super(dialog, dataSource); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#saveData() + */ + @Override + public void saveData() {} + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#getDataSource() + */ + @Override + public I_DataSource getDataSource() { + return null; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.data.AbstractDataSourcePanel#canLoad() + */ + @Override + public boolean canLoad() { + return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/demand/CommonalityTab.java b/src/main/java/edu/mit/spacenet/gui/demand/CommonalityTab.java new file mode 100644 index 0000000..55d3ff2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/CommonalityTab.java @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.SimScavenge; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Component for commonality analysis. + * + * @author Paul Grogan + */ +public class CommonalityTab extends JSplitPane { + private static final long serialVersionUID = -6405124067606236705L; + private static final String CUMULATIVE_MASS = "Total Cumulative Mass"; + private static final String CUMULATIVE_UNITS = "Cumulative Units"; + private static final String MASS_BY_SOURCE = "Mass by Source"; + private DemandsTab demandsTab; + + private CommonalityTable commonalityTable; + private ChartPanel chartPanel; + private OptionsPanel optionsPanel; + + /** + * The constructor. + * + * @param tab the demands tab component + */ + public CommonalityTab(DemandsTab tab) { + super(JSplitPane.VERTICAL_SPLIT); + this.demandsTab = tab; + + buildPanel(); + + setName("Commonality Analysis"); + setDividerSize(0); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(100); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + commonalityTable = new CommonalityTable(this); + JScrollPane commonalityScroll = new JScrollPane(commonalityTable); + JPanel topPanel = new JPanel(); + topPanel.setPreferredSize(new Dimension(400,100)); + topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.LINE_AXIS)); + topPanel.setBorder(BorderFactory.createTitledBorder("Commonality Matrix (% of Mass Common)")); + topPanel.add(commonalityScroll); + setTopComponent(topPanel); + + JSplitPane bottomPanel = new JSplitPane(); + bottomPanel.setBorder(BorderFactory.createTitledBorder("Scavenging History")); + chartPanel = new ChartPanel(); + bottomPanel.setLeftComponent(chartPanel); + optionsPanel = new OptionsPanel(); + bottomPanel.setRightComponent(optionsPanel); + bottomPanel.setOneTouchExpandable(true); + bottomPanel.setDividerSize(10); + bottomPanel.setResizeWeight(1); + bottomPanel.setDividerLocation(490); + setBottomComponent(bottomPanel); + } + + /** + * Initializes the panel. + */ + public void initialize() { + commonalityTable.initialize(); + optionsPanel.initialize(); + chartPanel.initialize(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return demandsTab.getScenario(); + } + + /** + * Checks if auto refresh is enabled. + * + * @return true, if auto refresh is enabled + */ + private boolean isAutoRefresh() { + return SpaceNetSettings.getInstance().isAutoRefresh(); + } + + /** + * Requests that the component and associated charts update based on the + * underlying model. + */ + public void updateView() { + //TODO commonalityTable.updateView(); + optionsPanel.updateView(); + chartPanel.updateView(); + } + + /** + * The Class OptionsPanel. + */ + private class OptionsPanel extends JPanel { + private static final long serialVersionUID = -4853327538110812961L; + + private JComboBox optionCombo; + private CheckBoxTableModel partsModel; + private CheckBoxTableModel elementsModel; + private JButton refreshButton; + + /** + * Instantiates a new options panel. + */ + public OptionsPanel() { + setLayout(new GridBagLayout()); + setBorder(BorderFactory.createTitledBorder("Chart Options")); + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Display: "), c); + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + optionCombo = new JComboBox(); + optionCombo.addItem(CUMULATIVE_MASS); + optionCombo.addItem(CUMULATIVE_UNITS); + optionCombo.addItem(MASS_BY_SOURCE); + optionCombo.setSelectedItem(CUMULATIVE_MASS); + optionCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) + chartPanel.updateView(); + } + }); + add(optionCombo, c); + c.gridy++; + JPanel prop0 = new JPanel(); + prop0.setPreferredSize(new Dimension(1,15)); + add(prop0, c); + c.gridx = 0; + c.gridy++; + c.gridwidth = 2; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + elementsModel = new CheckBoxTableModel(); + elementsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) + chartPanel.updateView(); + } + }); + JTable elementsTable = new JTable(elementsModel); + elementsTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + elementsTable.getTableHeader().setReorderingAllowed(false); + elementsTable.getColumnModel().getColumn(0).setMaxWidth(25); + elementsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Source Elements"); + elementsTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 3205543512740776042L; + // custom renderer to show the element icons and id's + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof I_Element) { + setIcon(((I_Element)value).getIcon()); + setText(((I_Element)value).getName() + " [" + ((I_Element)value).getUid() + "]"); + } + return this; + } + }); + elementsTable.setShowGrid(false); + JScrollPane elementsScroll = new JScrollPane(elementsTable); + elementsScroll.setPreferredSize(new Dimension(150,150)); + add(elementsScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel elementsButtonPanel = new JPanel(); + elementsButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllElementsButton = new JButton("Select All"); + selectAllElementsButton.setToolTipText("Select All Elements"); + selectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + elementsModel.selectAll(); + } + }); + elementsButtonPanel.add(selectAllElementsButton); + JButton deselectAllElementsButton = new JButton("Deselect All"); + deselectAllElementsButton.setToolTipText("Deselect All Elements"); + deselectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + elementsModel.deselectAll(); + } + }); + elementsButtonPanel.add(deselectAllElementsButton); + add(elementsButtonPanel, c); + c.weightx = 0; + c.fill = GridBagConstraints.BOTH; + c.gridy++; + JPanel prop2 = new JPanel(); + prop2.setPreferredSize(new Dimension(1,15)); + add(prop2, c); + c.gridy++; + c.weighty = 1; + partsModel = new CheckBoxTableModel(); + partsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) + chartPanel.updateView(); + } + }); + JTable partsTable = new JTable(partsModel); + partsTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + partsTable.getTableHeader().setReorderingAllowed(false); + partsTable.getColumnModel().getColumn(0).setMaxWidth(25); + partsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Parts"); + partsTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 3205543512740776042L; + // custom renderer to show the part icons and id's + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof I_Item) { + setIcon(((I_Item)value).getResourceType().getIcon()); + setText(((I_Item)value).getName() + " [" + ((I_Item)value).getTid() + "]"); + } + return this; + } + }); + partsTable.setShowGrid(false); + JScrollPane partsScroll = new JScrollPane(partsTable); + partsScroll.setPreferredSize(new Dimension(150,200)); + add(partsScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel partsButtonPanel = new JPanel(); + partsButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllPartsButton = new JButton("Select All"); + selectAllPartsButton.setToolTipText("Select All Parts"); + selectAllPartsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + partsModel.selectAll(); + } + }); + partsButtonPanel.add(selectAllPartsButton); + JButton deselectAllPartsButton = new JButton("Deselect All"); + deselectAllPartsButton.setToolTipText("Deselect All Parts"); + deselectAllPartsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + partsModel.deselectAll(); + } + }); + partsButtonPanel.add(deselectAllPartsButton); + add(partsButtonPanel, c); + c.gridy++; + JPanel prop3 = new JPanel(); + prop3.setPreferredSize(new Dimension(1,15)); + add(prop3, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + refreshButton = new JButton("Refresh", new ImageIcon(getClass().getClassLoader().getResource("icons/arrow_refresh.png"))); + refreshButton.setVisible(false); + refreshButton.setToolTipText("Refresh Chart"); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + chartPanel.updateChart(); + } + }); + add(refreshButton, c); + } + + /** + * Initialize. + */ + public void initialize() { + elementsModel.clear(); + updateView(); + } + + /** + * Update view. + */ + public void updateView() { + SortedSet scavengedElements = new TreeSet(); + SortedSet scavengedItems = new TreeSet(); + for(SimScavenge scavenge : demandsTab.getSimulator().getScavengedParts()) { + scavengedElements.add(scavenge.getElement()); + scavengedItems.add(scavenge.getItem()); + } + // update scavenged elements + List deselectedElements = elementsModel.getDeselectedObjects(); + TableModelListener[] modelListeners = elementsModel.getTableModelListeners(); + for(TableModelListener l : modelListeners) { + elementsModel.removeTableModelListener(l); + } + elementsModel.clear(); + if(demandsTab.getSimulator()!=null) { + for(I_Element element : scavengedElements) { + elementsModel.addObject(element, !deselectedElements.contains(element)); + } + } + for(TableModelListener l : modelListeners) { + elementsModel.addTableModelListener(l); + } + elementsModel.fireTableDataChanged(); + + // update scavenged parts + List deselectedParts = partsModel.getDeselectedObjects(); + modelListeners = partsModel.getTableModelListeners(); + for(TableModelListener l : modelListeners) { + partsModel.removeTableModelListener(l); + } + partsModel.clear(); + if(demandsTab.getSimulator()!=null) { + for(I_Item item : scavengedItems) { + partsModel.addObject(item, !deselectedParts.contains(item)); + } + } + for(TableModelListener l : modelListeners) { + partsModel.addTableModelListener(l); + } + partsModel.fireTableDataChanged(); + + // update auto refresh button visibility + if(isAutoRefresh()) { + refreshButton.setVisible(false); + } else { + refreshButton.setVisible(true); + } + } + } + + /** + * The Class ChartPanel. + */ + private class ChartPanel extends SNChartPanel { + private static final long serialVersionUID = -4805521416303511037L; + + /** + * Instantiates a new chart panel. + */ + public ChartPanel() { + setPreferredSize(new Dimension(600,400)); + } + /** + * Initializes the chart. + */ + public void initialize() { + updateChart(); + } + + /** + * Updates the view. + */ + public void updateView() { + if(isAutoRefresh()) updateChart(); + } + + /** + * Update chart. + */ + public void updateChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, + null, + optionsPanel.optionCombo.getSelectedItem().equals(CUMULATIVE_UNITS)?"Units":"Mass (kg)", + dataset, + !optionsPanel.optionCombo.getSelectedItem().equals(CUMULATIVE_MASS), // legend + true, + false); + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + if(optionsPanel.optionCombo.getSelectedItem().equals(CUMULATIVE_UNITS)) { + for(I_Item item : optionsPanel.partsModel.getSelectedObjects()) { + TimeSeries s = new TimeSeries(item.getName() + " [" + item.getTid() + "]", Hour.class); + double amount = 0; + for(SimScavenge scavenge : demandsTab.getSimulator().getScavengedParts()) { + if(optionsPanel.elementsModel.getSelectedObjects().contains(scavenge.getElement()) + && scavenge.getItem().equals(item)) { + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), scavenge.getTime())).previous(), amount); + amount += scavenge.getAmount(); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), scavenge.getTime())), amount); + } + } + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(0,0,0,0)); + } + } else if(optionsPanel.optionCombo.getSelectedItem().equals(CUMULATIVE_MASS)) { + TimeSeries s = new TimeSeries("Total", Hour.class); + double amount = 0; + for(SimScavenge scavenge : demandsTab.getSimulator().getScavengedParts()) { + if(optionsPanel.elementsModel.getSelectedObjects().contains(scavenge.getElement()) + && optionsPanel.partsModel.getSelectedObjects().contains(scavenge.getItem())) { + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), scavenge.getTime())).previous(), amount); + amount += scavenge.getItem().getUnitMass()*scavenge.getAmount(); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), scavenge.getTime())), amount); + } + } + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(0,0,0,0)); + + } else { + for(I_Element element : optionsPanel.elementsModel.getSelectedObjects()) { + TimeSeries s = new TimeSeries(element.getName() + " [" + element.getUid() + "]", Hour.class); + double amount = 0; + for(SimScavenge scavenge : demandsTab.getSimulator().getScavengedParts()) { + if(scavenge.getElement().equals(element) + && optionsPanel.partsModel.getSelectedObjects().contains(scavenge.getItem())) { + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), scavenge.getTime())).previous(), amount); + amount += scavenge.getItem().getUnitMass()*scavenge.getAmount(); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), scavenge.getTime())), amount); + } + } + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(0,0,0,0)); + } + } + setChart(chart); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/demand/CommonalityTable.java b/src/main/java/edu/mit/spacenet/gui/demand/CommonalityTable.java new file mode 100644 index 0000000..b5616a4 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/CommonalityTable.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JOptionPane; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; + +import edu.mit.spacenet.data.ElementPreview; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.scenario.Scenario; + +/** + * Table component for displaying the commonality of parts between elements. + * + * @author Paul Grogan + */ +public class CommonalityTable extends JTable { + private static final long serialVersionUID = -59617276707632343L; + private CommonalityTab commonalityTab; + private CustomTableModel model; + + /** + * The constructor. + * + * @param commonalityTab the commonality tab + */ + public CommonalityTable(CommonalityTab commonalityTab) { + this.commonalityTab = commonalityTab; + } + + /** + * Initializes the table for a new or updated scenario. + */ + public void initialize() { + model = new CustomTableModel(commonalityTab.getScenario()); + setModel(model); + updateView(); + } + + /** + * Requests that the table update its information. + */ + public void updateView() { + ((CustomTableModel)getModel()).forceUpdate(); + DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); + getColumnModel().getColumn(0).setHeaderValue("Part Type"); + getColumnModel().getColumn(0).setPreferredWidth(75); + renderer.setHorizontalAlignment(DefaultTableCellRenderer.CENTER); + for(ElementPreview element : ((CustomTableModel)getModel()).getElements()) { + getColumnModel().getColumn(((CustomTableModel)getModel()).getElements().indexOf(element)+1).setHeaderValue(element.NAME); + getColumnModel().getColumn(((CustomTableModel)getModel()).getElements().indexOf(element)+1).setCellRenderer(renderer); + } + } + + /** + * The Class CustomTableModel. + */ + private class CustomTableModel extends DefaultTableModel { + private static final long serialVersionUID = -4268705523869375904L; + private Scenario scenario; + private List parts; + private List elements; + + /** + * Instantiates a new custom table model. + * + * @param scenario the scenario + */ + public CustomTableModel(Scenario scenario) { + this.scenario = scenario; + parts = new ArrayList(); + elements = new ArrayList(); + } + + /** + * Force update. + */ + public void forceUpdate() { + parts.clear(); + elements.clear(); + + ArrayList tids = new ArrayList(); + for(I_Element element : scenario.getElements()) { + if(!tids.contains(element.getTid())) { + if(element.getParts().size() > 0) { + for(ElementPreview e :scenario.getDataSource().getElementPreviewLibrary()) { + if(e.ID==element.getTid()) { + elements.add(e); + tids.add(element.getTid()); + for(PartApplication a : element.getParts()) { + if(!parts.contains(a.getPart())) parts.add(a.getPart()); + } + break; + } + } + } + } + } + fireTableStructureChanged(); + } + + /** + * Gets the elements. + * + * @return the elements + */ + public List getElements() { + return elements; + } + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableModel#getColumnCount() + */ + public int getColumnCount() { + if(elements == null) return 1; + else return elements.size() + 1; + } + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableModel#getRowCount() + */ + public int getRowCount() { + if(parts == null) return 0; + else return parts.size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int col) { + return false; + } + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) { + return parts.get(row); + } else { + ElementPreview e = elements.get(col-1); + try { + I_Element element = scenario.getDataSource().loadElement(e.ID); + for(PartApplication a : element.getParts()) { + if(a.getPart().equals(parts.get(row))) { + DecimalFormat format = new DecimalFormat("0.0%"); + return format.format(a.getPart().getUnitMass()*a.getQuantity()/element.getMass()); + } + } + } catch(Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(null, + "An error occurred while accessing the data source to load the element", + "SpaceNet Error", + JOptionPane.ERROR_MESSAGE); + } + return "0.0%"; + } + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/demand/DemandsTab.java b/src/main/java/edu/mit/spacenet/gui/demand/DemandsTab.java new file mode 100644 index 0000000..7a2a5a4 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/DemandsTab.java @@ -0,0 +1,703 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Hashtable; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSlider; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SwingWorker; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.ScenarioPanel; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.scenario.ItemDiscretization; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.scenario.SupplyEdge; +import edu.mit.spacenet.scenario.SupplyEdge.SupplyPoint; +import edu.mit.spacenet.simulator.DemandSimulator; +import edu.mit.spacenet.simulator.SimDemand; + +/** + * Component for viewing and editing the demands associated with a scenario. + * + * @author Paul Grogan + */ +public class DemandsTab extends JSplitPane { + private static final long serialVersionUID = 1065899429343403823L; + private static String RAW_DEMANDS = "Raw Demands"; + private static String AGGREGATED_DEMANDS = "Aggregated Demands"; + private static String ID_OUTPUT = "Object IDs"; + private static String NAME_OUTPUT = "Object Names"; + private static String COMMA_DELIMITED = "Comma Delimited"; + private static String SEMICOLON_DELIMITED = "Semicolon Delimited"; + private static String TAB_DELIMITED = "Tab Delimited"; + + private JPanel controlPanel; + private JComboBox discretizationCombo; + private JSlider aggregationSlider; + private JCheckBox scavengeSparesCheck, packingDemandsCheck, demandsSatisfiedCheck; + + private JTextField directoryPathText, fileNameText; + private JCheckBox overwriteCheck; + private JButton browseButton, exportButton; + private JComboBox demandsCombo, referenceCombo, delimiterCombo; + private JFileChooser directoryChooser; + private ExportWorker exportWorker; + + private JTabbedPane tabbedPane; + + private ScenarioFeasibilityTab feasibilityTab; + private SupplyNetworkTab networkTab; + private ElementDemandsTab elementDemandsTab; + private MissionDemandsTab missionDemandTab; + private LocationDemandsTab locationDemandTab; + private CommonalityTab commonalityTab; + private RepairabilityTab repairabilityTab; + + private ScenarioPanel scenarioPanel; + private DemandSimulator simulator; + private SimWorker simWorker; + + /** + * The constructor. + * + * @param scenarioPanel the scenario panel + */ + public DemandsTab(ScenarioPanel scenarioPanel) { + this.scenarioPanel = scenarioPanel; + + controlPanel = new JPanel(); + controlPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + controlPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + c.weightx = 1; + controlPanel.add(buildOptionsPanel(), c); + c.gridy++; + controlPanel.add(buildDisplayPanel(), c); + c.gridy++; + controlPanel.add(buildExportPanel(), c); + c.gridy++; + c.weighty = 1; + controlPanel.add(new JPanel(), c); + + setLeftComponent(new JScrollPane(controlPanel)); + + tabbedPane = new JTabbedPane(); + networkTab = new SupplyNetworkTab(this); + tabbedPane.add(networkTab); + feasibilityTab = new ScenarioFeasibilityTab(this); + tabbedPane.add(feasibilityTab); + elementDemandsTab = new ElementDemandsTab(this); + tabbedPane.add(elementDemandsTab); + missionDemandTab = new MissionDemandsTab(this); + tabbedPane.add(missionDemandTab); + locationDemandTab = new LocationDemandsTab(this); + tabbedPane.add(locationDemandTab); + commonalityTab = new CommonalityTab(this); + tabbedPane.add(commonalityTab); + repairabilityTab = new RepairabilityTab(this); + tabbedPane.add(repairabilityTab); + tabbedPane.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + updateTab(); + } + }); + setRightComponent(tabbedPane); + + setResizeWeight(.1); + setDividerLocation(250); + setBorder(BorderFactory.createEmptyBorder()); + } + + /** + * Initializes the demands tab. + */ + public void initialize() { + discretizationCombo.setEnabled(getScenario()!=null); + aggregationSlider.setEnabled(getScenario()!=null); + scavengeSparesCheck.setEnabled(getScenario()!=null); + packingDemandsCheck.setEnabled(getScenario()!=null); + + browseButton.setEnabled(getScenario()!=null); + fileNameText.setEnabled(getScenario()!=null); + demandsCombo.setEnabled(getScenario()!=null); + referenceCombo.setEnabled(getScenario()!=null); + delimiterCombo.setEnabled(getScenario()!=null); + + if(getScenario()!=null) { + discretizationCombo.setSelectedItem(getScenario().getItemDiscretization()); + aggregationSlider.setValue((int)(getScenario().getItemAggregation()*4)); + aggregationSlider.setEnabled(getScenario().getItemDiscretization()!=ItemDiscretization.NONE); + scavengeSparesCheck.setSelected(getScenario().isScavengeSpares()); + + fileNameText.setText("demands.txt"); + + //TODO: this is a hack, simulator should be initialized, not re-created + simulator = new DemandSimulator(getScenario()); + simulator.setDemandsSatisfied(false); + packingDemandsCheck.setSelected(simulator.isPackingDemandsAdded()); + demandsSatisfiedCheck.setSelected(simulator.isDemandsSatisfied()); + simWorker = new SimWorker(true); + simWorker.execute(); + } + } + + /** + * Builds the options panel, used for accessing scenario options. + * + * @return the options panel + */ + private JPanel buildOptionsPanel() { + JPanel optionsPanel = new JPanel(); + optionsPanel.setBorder(BorderFactory.createTitledBorder("Demand Options")); + optionsPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + c.gridx = 0; + c.gridy = 0; + c.weighty = 0; + c.weightx = 0; + optionsPanel.add(new JLabel("Item Discretization by: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + optionsPanel.add(new JLabel("Item Aggregation at: "), c); + c.gridy = 0; + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + discretizationCombo = new JComboBox(); + discretizationCombo.setToolTipText("Discretize demands for items to integer values at the selected level"); + for(ItemDiscretization t : ItemDiscretization.values()) { + discretizationCombo.addItem(t); + } + discretizationCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(!discretizationCombo.getSelectedItem().equals(getScenario().getItemDiscretization())) { + getScenario().setItemDiscretization((ItemDiscretization)discretizationCombo.getSelectedItem()); + aggregationSlider.setEnabled(getScenario().getItemDiscretization()!=ItemDiscretization.NONE); + updateView(); + } + } + }); + optionsPanel.add(discretizationCombo, c); + c.gridy++; + aggregationSlider = new JSlider(JSlider.VERTICAL, 0,4,1); + aggregationSlider.setToolTipText("Aggregate discretized item demands ahead or behind demands."); + Hashtable labelTable = new Hashtable(); + labelTable.put(new Integer(0), new JLabel("First Demand", JLabel.LEFT)); + labelTable.put(new Integer(2), new JLabel("Half Demand", JLabel.LEFT)); + labelTable.put(new Integer(4), new JLabel("Unit Demand", JLabel.RIGHT)); + aggregationSlider.setLabelTable(labelTable); + aggregationSlider.setPaintLabels(true); + aggregationSlider.setMajorTickSpacing(1); + aggregationSlider.setSnapToTicks(true); + aggregationSlider.setPaintTicks(true); + aggregationSlider.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + if(!aggregationSlider.getValueIsAdjusting() + && aggregationSlider.getValue()/4d!= getScenario().getItemAggregation()) { + getScenario().setItemAggregation(aggregationSlider.getValue()/4d); + updateView(); + } + } + }); + aggregationSlider.setPreferredSize(new Dimension(50,100)); + optionsPanel.add(aggregationSlider, c); + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + scavengeSparesCheck = new JCheckBox("Scavenge Spares"); + scavengeSparesCheck.setToolTipText("Scavenge spare parts from co-located decommissioned elements"); + scavengeSparesCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(scavengeSparesCheck.isSelected()!=getScenario().isScavengeSpares()) { + getScenario().setScavengeSpares(scavengeSparesCheck.isSelected()); + updateView(); + } + } + }); + optionsPanel.add(scavengeSparesCheck, c); + return optionsPanel; + } + + /** + * Builds the display panel, used for controlling the display options. + * + * @return the display panel + */ + private JPanel buildDisplayPanel() { + JPanel displayPanel = new JPanel(); + displayPanel.setLayout(new BoxLayout(displayPanel, BoxLayout.PAGE_AXIS)); + displayPanel.setBorder(BorderFactory.createTitledBorder("Display Options")); + packingDemandsCheck = new JCheckBox("Estimate Logistics Container Masses"); + packingDemandsCheck.setToolTipText("Estimate mass (Generic COS 5) for containers using resource packing factors."); + packingDemandsCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(packingDemandsCheck.isSelected()!=simulator.isPackingDemandsAdded()) { + simulator.setPackingDemandsAdded(e.getStateChange()==ItemEvent.SELECTED); + updateView(); + } + } + }); + displayPanel.add(packingDemandsCheck); + demandsSatisfiedCheck = new JCheckBox("Consume Existing Resources"); + demandsSatisfiedCheck.setToolTipText("Consume existing resources when demanded."); + demandsSatisfiedCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(demandsSatisfiedCheck.isSelected()!=simulator.isDemandsSatisfied()) { + simulator.setDemandsSatisfied(e.getStateChange()==ItemEvent.SELECTED); + updateView(); + } + } + }); + displayPanel.add(demandsSatisfiedCheck); + return displayPanel; + } + + private JPanel buildExportPanel() { + directoryChooser = new JFileChooser(); + directoryChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + JPanel exportPanel = new JPanel(); + exportPanel.setBorder(BorderFactory.createTitledBorder("Export Demands")); + exportPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.insets = new Insets(2,2,2,2); + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + exportPanel.add(new JLabel("Directory: "), c); + c.gridy++; + exportPanel.add(new JLabel("File Name: "), c); + c.gridy+=2; + exportPanel.add(new JLabel("Demands: "), c); + c.gridy++; + exportPanel.add(new JLabel("Output: "), c); + c.gridy++; + exportPanel.add(new JLabel("Delimiter: "), c); + c.gridy = 0; + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + directoryPathText = new JTextField(); + directoryPathText.setEnabled(false); + exportPanel.add(directoryPathText, c); + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + c.gridx++; + c.weightx = 0; + browseButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/folder_explore.png"))); + browseButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(directoryPathText.getText()=="") { + directoryChooser.setCurrentDirectory( + new File(SpaceNetSettings.getInstance().getDefaultDirectory())); + } + int returnVal = directoryChooser.showOpenDialog(getThis()); + if(returnVal == JFileChooser.APPROVE_OPTION) { + directoryPathText.setText(directoryChooser.getSelectedFile().getAbsolutePath()); + } + exportButton.setEnabled(directoryPathText.getText()!="" + && fileNameText.getText()!=""); + } + }); + exportPanel.add(browseButton, c); + c.gridy++; + c.gridx--; + c.gridwidth = 2; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + fileNameText = new JTextField(15); + fileNameText.addKeyListener(new KeyAdapter() { + public void keyTyped(KeyEvent e) { + exportButton.setEnabled(directoryPathText.getText()!="" + && fileNameText.getText()!=""); + } + }); + exportPanel.add(fileNameText, c); + c.gridy++; + overwriteCheck = new JCheckBox("Overwrite existing files", false); + exportPanel.add(overwriteCheck, c); + c.gridy++; + demandsCombo = new JComboBox(); + demandsCombo.addItem(RAW_DEMANDS); + demandsCombo.addItem(AGGREGATED_DEMANDS); + exportPanel.add(demandsCombo, c); + c.gridy++; + referenceCombo = new JComboBox(); + referenceCombo.addItem(ID_OUTPUT); + referenceCombo.addItem(NAME_OUTPUT); + exportPanel.add(referenceCombo, c); + c.gridy++; + delimiterCombo = new JComboBox(); + delimiterCombo.addItem(TAB_DELIMITED); + delimiterCombo.addItem(COMMA_DELIMITED); + delimiterCombo.addItem(SEMICOLON_DELIMITED); + exportPanel.add(delimiterCombo, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + exportButton = new JButton("Export", new ImageIcon(getClass().getClassLoader().getResource("icons/page_white_edit.png"))); + exportButton.setEnabled(false); + exportButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + exportDemands(); + } + }); + exportPanel.add(exportButton, c); + return exportPanel; + } + + /** + * Gets the scenario panel component. + * + * @return the scenario panel + */ + public ScenarioPanel getScenarioPanel() { + return scenarioPanel; + } + + /** + * Gets this. + * + * @return this + */ + private DemandsTab getThis() { + return this; + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return scenarioPanel.getScenario(); + } + + /** + * Gets the demand simulator. + * + * @return the demand simulator + */ + public DemandSimulator getSimulator() { + return simulator; + } + + /** + * A SwingWorker subclass that manages the time-intensive simulation in a + * separate thread. + */ + private class SimWorker extends SwingWorker { + private boolean isInitialization; + + /** + * Instantiates a new sim worker. + * + * @param isInitialization the is initialization + */ + public SimWorker(boolean isInitialization) { + this.isInitialization = isInitialization; + } + + /** + * Instantiates a new sim worker. + */ + public SimWorker() { + this(false); + } + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#doInBackground() + */ + public Void doInBackground() { + try { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Simulating Demands..."); + scenarioPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + simulator.simulate(); + scenarioPanel.setCursor(Cursor.getDefaultCursor()); + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#done() + */ + public void done() { + // update tab only after simulation has completed + if(isInitialization) { + feasibilityTab.initialize(); + networkTab.initialize(); + elementDemandsTab.initialize(); + missionDemandTab.initialize(); + locationDemandTab.initialize(); + commonalityTab.initialize(); + repairabilityTab.initialize(); + } else { + updateTab(); + } + } + } + + /** + * Export demands. + */ + private void exportDemands() { + while(exportWorker != null && !exportWorker.isDone() + && simWorker != null && !simWorker.isDone()) { + // wait until previous simulation and export is complete + } + exportWorker = new ExportWorker(); + exportWorker.execute(); + } + + /** + * Write file. + */ + private void writeFile() { + String filePath = directoryPathText.getText() + + System.getProperty("file.separator") + fileNameText.getText(); + char delimiter = ','; + if(delimiterCombo.getSelectedItem()==COMMA_DELIMITED) { + delimiter = ','; + } else if(delimiterCombo.getSelectedItem()==SEMICOLON_DELIMITED) { + delimiter = ';'; + } else if(delimiterCombo.getSelectedItem()==TAB_DELIMITED) { + delimiter = '\t'; + } + try { + File file = new File(filePath); + if(file.exists() && !overwriteCheck.isSelected()) { + int answer = JOptionPane.showOptionDialog(getThis(), + "Overwrite existing file " + fileNameText.getText() + "?", + "SpaceNet Warning", JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, null, null, null); + if (answer == JOptionPane.NO_OPTION) return; + else overwriteCheck.setSelected(true); + } + BufferedWriter out = new BufferedWriter(new FileWriter(filePath)); + if(demandsCombo.getSelectedItem()==RAW_DEMANDS) { + out.write("Time" + delimiter + "Location" + delimiter + + "Element" + delimiter + "Resource" + delimiter + + "Amount" + System.getProperty("line.separator")); + for(SimDemand simDemand : simulator.getUnsatisfiedDemands()) { + for(Demand demand : simDemand.getDemands()) { + if(referenceCombo.getSelectedItem()==ID_OUTPUT) { + out.write("" + simDemand.getTime()); + out.write(delimiter); + out.write("" + simDemand.getLocation().getTid()); + out.write(delimiter); + if(simDemand.getElement()!=null) { + out.write("" + simDemand.getElement().getUid()); + } + out.write(delimiter); + out.write("" + demand.getResource().getTid()); + out.write(delimiter); + out.write("" + demand.getAmount()); + } else if(referenceCombo.getSelectedItem()==NAME_OUTPUT) { + out.write("" + simDemand.getTime()); + out.write(delimiter); + out.write(simDemand.getLocation().getName()); + out.write(delimiter); + if(simDemand.getElement()!=null) { + out.write("" + simDemand.getElement().getName()); + } + out.write(delimiter); + out.write(demand.getResource().getName()); + out.write(delimiter); + out.write("" + demand.getAmount()); + } + out.write(System.getProperty("line.separator")); + } + } + } else if(demandsCombo.getSelectedItem()==AGGREGATED_DEMANDS) { + out.write("Time1" + delimiter + "Time2" + delimiter + "Node1" + + delimiter + "Node2" + delimiter + "Resource" + + delimiter + "Amount" + System.getProperty("line.separator")); + for(SupplyEdge supplyEdge : simulator.getSupplyEdges()) { + for(Demand demand : simulator.getAggregatedEdgeDemands().get(supplyEdge)) { + if(referenceCombo.getSelectedItem()==ID_OUTPUT) { + out.write("" + supplyEdge.getStartTime()); + out.write(delimiter); + out.write("" + supplyEdge.getEndTime()); + out.write(delimiter); + out.write("" + supplyEdge.getOrigin().getTid()); + out.write(delimiter); + out.write("" + supplyEdge.getDestination().getTid()); + out.write(delimiter); + out.write("" + demand.getResource().getTid()); + out.write(delimiter); + out.write("" + demand.getAmount()); + } else if(referenceCombo.getSelectedItem()==NAME_OUTPUT) { + out.write("" + supplyEdge.getStartTime()); + out.write(delimiter); + out.write("" + supplyEdge.getEndTime()); + out.write(delimiter); + out.write(supplyEdge.getOrigin().getName()); + out.write(delimiter); + out.write(supplyEdge.getDestination().getName()); + out.write(delimiter); + out.write(demand.getResource().getName()); + out.write(delimiter); + out.write("" + demand.getAmount()); + } + out.write(System.getProperty("line.separator")); + } + SupplyPoint supplyPoint = supplyEdge.getPoint(); + for(Demand demand : simulator.getAggregatedNodeDemands().get(supplyPoint)) { + if(referenceCombo.getSelectedItem()==ID_OUTPUT) { + out.write("" + supplyPoint.getNode().getTid()); + out.write(delimiter); + out.write(delimiter); + out.write("" + supplyPoint.getTime()); + out.write(delimiter); + out.write(delimiter); + out.write("" + demand.getResource().getTid()); + out.write(delimiter); + out.write("" + demand.getAmount()); + } else if(referenceCombo.getSelectedItem()==NAME_OUTPUT) { + out.write(supplyPoint.getNode().getName()); + out.write(delimiter); + out.write(delimiter); + out.write("" + supplyPoint.getTime()); + out.write(delimiter); + out.write(delimiter); + out.write(demand.getResource().getName()); + out.write(delimiter); + out.write("" + demand.getAmount()); + } + out.write(System.getProperty("line.separator")); + } + } + } + out.close(); + } catch(IOException ex) { + JOptionPane.showMessageDialog(this, + "An error of type \"" + + ex.getClass().getSimpleName() + + "\" occurred while exporting the demands", + "SpaceNet Error", JOptionPane.ERROR_MESSAGE); + } + } + + /** + * The Class ExportWorker. + */ + private class ExportWorker extends SwingWorker { + + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#doInBackground() + */ + protected Void doInBackground() { + try { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Exporting Demands..."); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + writeFile(); + setCursor(Cursor.getDefaultCursor()); + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + } + + /** + * Requests that the component and any nested components update themselves. + */ + public void updateView() { + discretizationCombo.setSelectedItem(getScenario().getItemDiscretization()); + aggregationSlider.setValue((int)(getScenario().getItemAggregation()*4)); + aggregationSlider.setEnabled(getScenario().getItemDiscretization()!=ItemDiscretization.NONE); + scavengeSparesCheck.setSelected(getScenario().isScavengeSpares()); + + while(simWorker != null && !simWorker.isDone()) { + // lock UI while previous simulation is running + } + simWorker = new SimWorker(); + simWorker.execute(); + } + + /** + * Updates the currently-visible tab. + */ + private void updateTab() { + if(tabbedPane.getSelectedComponent().equals(feasibilityTab)) { + feasibilityTab.updateView(); + } else if(tabbedPane.getSelectedComponent().equals(networkTab)) { + networkTab.updateView(); + } else if(tabbedPane.getSelectedComponent().equals(elementDemandsTab)) { + elementDemandsTab.updateView(); + } else if(tabbedPane.getSelectedComponent().equals(missionDemandTab)) { + missionDemandTab.updateView(); + } else if(tabbedPane.getSelectedComponent().equals(locationDemandTab)) { + locationDemandTab.updateView(); + } else if(tabbedPane.getSelectedComponent().equals(repairabilityTab)) { + repairabilityTab.updateView(); + } else if(tabbedPane.getSelectedComponent().equals(commonalityTab)) { + commonalityTab.updateView(); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/demand/ElementDemandsTab.java b/src/main/java/edu/mit/spacenet/gui/demand/ElementDemandsTab.java new file mode 100644 index 0000000..bf5f3c2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/ElementDemandsTab.java @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.util.Date; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.CategoryLabelPositions; +import org.jfree.chart.plot.CategoryPlot; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.category.CategoryItemRenderer; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.category.DefaultCategoryDataset; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.SimDemand; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Component for displaying the element-level demands. + * + * @author Paul Grogan + */ +public class ElementDemandsTab extends JSplitPane { + private static final long serialVersionUID = -4728295622221432580L; + + private DemandsTab demandsTab; + + private OptionsPanel optionsPanel; + private ChartPanel chartPanel; + + public ElementDemandsTab(DemandsTab demandsTab) { + this.demandsTab = demandsTab; + + chartPanel = new ChartPanel(); + setLeftComponent(chartPanel); + + optionsPanel = new OptionsPanel(); + setRightComponent(optionsPanel); + + setName("Demands by Element"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(490); + } + + /** + * Initializes the tab for a new scenario. + */ + public void initialize() { + optionsPanel.initialize(); + chartPanel.initialize(); + } + + /** + * Updates the tab. + */ + public void updateView() { + optionsPanel.updateView(); + chartPanel.updateView(); + } + + /** + * Checks if auto refresh is enabled. + * + * @return true, if auto refresh is enabled + */ + private boolean isAutoRefresh() { + return SpaceNetSettings.getInstance().isAutoRefresh(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return demandsTab.getScenario(); + } + + /** + * The Class OptionsPanel. + */ + private class OptionsPanel extends JPanel { + private static final long serialVersionUID = -4714468679105858517L; + + private CheckBoxTableModel elementsModel; + private CheckBoxTableModel cosModel; + private JCheckBox displayTotalCheck, smoothDemandsCheck; + private JButton refreshButton; + + /** + * Instantiates a new options panel. + * + * @param networkTab the network tab + */ + private OptionsPanel() { + setLayout(new GridBagLayout()); + setBorder(BorderFactory.createTitledBorder("Chart Options")); + + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.gridy++; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_END; + elementsModel = new CheckBoxTableModel(); + elementsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) { + chartPanel.updateView(); + } + displayTotalCheck.setEnabled(elementsModel.getSelectedObjects().size()==1); + smoothDemandsCheck.setEnabled(elementsModel.getSelectedObjects().size()==1); + } + }); + JTable elementsTable = new JTable(elementsModel); + elementsTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + elementsTable.getTableHeader().setReorderingAllowed(false); + elementsTable.getColumnModel().getColumn(0).setMaxWidth(25); + elementsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Elements"); + elementsTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 3205543512740776042L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof I_Element) { + setIcon(((I_Element)value).getIcon()); + setText(((I_Element)value).getName() + " [" + ((I_Element)value).getUid() + "]"); + } + return this; + } + }); + elementsTable.setShowGrid(false); + JScrollPane elementsScroll = new JScrollPane(elementsTable); + elementsScroll.setPreferredSize(new Dimension(150,200)); + add(elementsScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel elementsButtonPanel = new JPanel(); + elementsButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllElementsButton = new JButton("Select All"); + selectAllElementsButton.setToolTipText("Select All Elements"); + selectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + elementsModel.selectAll(); + } + }); + elementsButtonPanel.add(selectAllElementsButton); + JButton deselectAllElementsButton = new JButton("Deselect All"); + deselectAllElementsButton.setToolTipText("Deselect All Elements"); + deselectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + elementsModel.deselectAll(); + } + }); + elementsButtonPanel.add(deselectAllElementsButton); + add(elementsButtonPanel, c); + c.weightx = 0; + c.fill = GridBagConstraints.BOTH; + c.gridy++; + JPanel prop2 = new JPanel(); + prop2.setPreferredSize(new Dimension(1,15)); + add(prop2, c); + c.gridy++; + c.weighty = 1; + cosModel = new CheckBoxTableModel(); + for(int i=1; i<=10; i++) { + cosModel.addObject(ClassOfSupply.getInstance(i)); + } + cosModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) + chartPanel.updateView(); + } + }); + JTable cosTable = new JTable(cosModel); + cosTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + cosTable.getTableHeader().setReorderingAllowed(false); + cosTable.getColumnModel().getColumn(0).setMaxWidth(25); + cosTable.getColumnModel().getColumn(1).setHeaderValue("Filter Classes of Supply"); + cosTable.setShowGrid(false); + JScrollPane cosScroll = new JScrollPane(cosTable); + cosScroll.setPreferredSize(new Dimension(150,150)); + add(cosScroll, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + JPanel dataButtonPanel = new JPanel(); + dataButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllDataButton = new JButton("Select All"); + selectAllDataButton.setToolTipText("Select All COS"); + selectAllDataButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.selectAll(); + } + }); + dataButtonPanel.add(selectAllDataButton); + JButton deselectAllDataButton = new JButton("Deselect All"); + deselectAllDataButton.setToolTipText("Deselect All COS"); + deselectAllDataButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.deselectAll(); + } + }); + dataButtonPanel.add(deselectAllDataButton); + add(dataButtonPanel, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + displayTotalCheck = new JCheckBox("Display Total", true); + displayTotalCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(displayTotalCheck, c); + c.gridy++; + smoothDemandsCheck = new JCheckBox("Smooth Demands", true); + smoothDemandsCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(smoothDemandsCheck, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + refreshButton = new JButton("Refresh", new ImageIcon(getClass().getClassLoader().getResource("icons/arrow_refresh.png"))); + refreshButton.setVisible(false); + refreshButton.setToolTipText("Refresh Chart"); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + chartPanel.updateChart(); + } + }); + add(refreshButton, c); + } + + /** + * Initializes the panel. + */ + public void initialize() { + elementsModel.clear(); + updateView(); + } + + /** + * Updates the view. + */ + public void updateView() { + // update elements + List selectedElements = elementsModel.getSelectedObjects(); + TableModelListener[] modelListeners = elementsModel.getTableModelListeners(); + for(TableModelListener l : modelListeners) { + elementsModel.removeTableModelListener(l); + } + elementsModel.clear(); + if(demandsTab.getSimulator()!=null) { + for(I_Element element : demandsTab.getScenario().getElements()) { + elementsModel.addObject(element, selectedElements.contains(element)); + } + } + for(TableModelListener l : modelListeners) { + elementsModel.addTableModelListener(l); + } + elementsModel.fireTableDataChanged(); + + // update auto refresh button visibility + if(isAutoRefresh()) { + refreshButton.setVisible(false); + } else { + refreshButton.setVisible(true); + } + } + } + + /** + * The Class ChartPanel. + */ + private class ChartPanel extends SNChartPanel { + private static final long serialVersionUID = 4671269489085267359L; + + private ChartUpdater chartUpdater; + + /** + * Initializes the chart. + */ + public void initialize() { + updateChart(); + } + + /** + * Updates the view. + */ + public void updateView() { + if(isAutoRefresh()) updateChart(); + } + + /** + * Updates the chart. + */ + public void updateChart() { + if(optionsPanel.elementsModel.getSelectedObjects().size()==1) { + setChart(buildTimeSeriesChart()); + } else { + while(chartUpdater != null && !chartUpdater.isDone()) { + // wait for previous update to finish + } + chartUpdater = new ChartUpdater(); + chartUpdater.execute(); + } + } + + private JFreeChart buildTimeSeriesChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + TimeSeries[] s = new TimeSeries[11]; + s[0] = new TimeSeries("Total", Hour.class); + for(int i = 1; i <= 10; i++) { + s[i] = new TimeSeries("COS " + i, Hour.class); + } + + double amount[] = new double[11]; + for(SimDemand demand : demandsTab.getSimulator().getDemandHistory(optionsPanel.elementsModel.getSelectedObjects().get(0))) { + Date date = DateFunctions.getDate(demandsTab.getScenario().getStartDate(), demand.getTime()); + if(!optionsPanel.smoothDemandsCheck.isSelected() && amount[0]>0) { + for(int i = 0; i <=10; i++) { + // replicate step function + s[i].addOrUpdate(new Hour(date).previous(), amount[i]); + } + } + for(Demand d : demand.getDemands()) { + if(d.getMass()<0) continue; + amount[0] += d.getMass(); + int cos = d.getResource().getClassOfSupply().getBaseClass().getId(); + amount[cos] += d.getMass(); + } + for(int i = 0; i <=10; i++) { + s[i].addOrUpdate(new Hour(date), amount[i]); + } + } + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, // title + null, // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + true, // legend + true, + false); + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + for(int i = 0; i <=10; i++) { + if(i==0&&optionsPanel.displayTotalCheck.isSelected()) { + dataset.addSeries(s[i]); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-1,-1,2,2)); + r.setSeriesPaint(dataset.getSeriesCount() - 1, + Color.BLACK); + } else if(optionsPanel.cosModel.getSelectedObjects().contains(ClassOfSupply.getInstance(i))) { + dataset.addSeries(s[i]); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-1,-1,2,2)); + r.setSeriesPaint(dataset.getSeriesCount() - 1, + ClassOfSupply.getInstance(i).getColor()); + } + } + return chart; + } + + private JFreeChart buildBarChart() { + DefaultCategoryDataset dataset = new DefaultCategoryDataset(); + + JFreeChart chart = ChartFactory.createStackedBarChart( + null, // title + "", // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + PlotOrientation.VERTICAL, // plot orientation + true, // legend + true, + false); + + CategoryPlot plot = (CategoryPlot) chart.getPlot(); + plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + + CategoryItemRenderer r = chart.getCategoryPlot().getRenderer(); + + for(I_Element element : optionsPanel.elementsModel.getSelectedObjects()) { + for(int i=1; i<=10; i++) { + if(optionsPanel.cosModel.getSelectedObjects().contains(ClassOfSupply.getInstance(i))) { + dataset.addValue(demandsTab.getSimulator().getDemands(element, + ClassOfSupply.getInstance(i)).getTotalMass(), + "COS " + i, element.getName() + " [" + element.getUid() + "]"); + r.setSeriesPaint(dataset.getRowCount() - 1, ClassOfSupply.getInstance(i).getColor()); + } + } + } + return chart; + } + + private class ChartUpdater extends SwingWorker { + protected Void doInBackground() { + try { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Refreshing Chart..."); + demandsTab.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + setChart(buildBarChart()); + demandsTab.setCursor(Cursor.getDefaultCursor()); + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/demand/LocationDemandsTab.java b/src/main/java/edu/mit/spacenet/gui/demand/LocationDemandsTab.java new file mode 100644 index 0000000..e768aa9 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/LocationDemandsTab.java @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.util.Date; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.CategoryLabelPositions; +import org.jfree.chart.plot.CategoryPlot; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.category.CategoryItemRenderer; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.category.DefaultCategoryDataset; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.SimDemand; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Component for showing the demands filtered by location. + * + * @author Paul Grogan + */ +public class LocationDemandsTab extends JSplitPane { + private static final long serialVersionUID = -4728295622221432580L; + + private DemandsTab demandsTab; + + private OptionsPanel optionsPanel; + private ChartPanel chartPanel; + + public LocationDemandsTab(DemandsTab demandsTab) { + this.demandsTab = demandsTab; + + chartPanel = new ChartPanel(); + setLeftComponent(chartPanel); + + optionsPanel = new OptionsPanel(); + setRightComponent(optionsPanel); + + setName("Demands by Location"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(490); + } + + /** + * Initializes the tab for a new scenario. + */ + public void initialize() { + optionsPanel.initialize(); + chartPanel.initialize(); + } + + /** + * Updates the tab. + */ + public void updateView() { + optionsPanel.updateView(); + chartPanel.updateView(); + } + + /** + * Checks if auto refresh is enabled. + * + * @return true, if auto refresh is enabled + */ + private boolean isAutoRefresh() { + return SpaceNetSettings.getInstance().isAutoRefresh(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return demandsTab.getScenario(); + } + + /** + * The Class OptionsPanel. + */ + private class OptionsPanel extends JPanel { + private static final long serialVersionUID = -4714468679105858517L; + + private CheckBoxTableModel locationsModel; + private CheckBoxTableModel cosModel; + private JCheckBox displayTotalCheck, smoothDemandsCheck; + private JButton refreshButton; + + /** + * Instantiates a new options panel. + * + * @param networkTab the network tab + */ + private OptionsPanel() { + setLayout(new GridBagLayout()); + setBorder(BorderFactory.createTitledBorder("Chart Options")); + + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.gridy++; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_END; + locationsModel = new CheckBoxTableModel(); + locationsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) { + chartPanel.updateView(); + } + displayTotalCheck.setEnabled(locationsModel.getSelectedObjects().size()==1); + smoothDemandsCheck.setEnabled(locationsModel.getSelectedObjects().size()==1); + } + }); + JTable locationsTable = new JTable(locationsModel); + locationsTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + locationsTable.getTableHeader().setReorderingAllowed(false); + locationsTable.getColumnModel().getColumn(0).setMaxWidth(25); + locationsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Locations"); + locationsTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 3205543512740776042L; + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof Node) { + setIcon(((Node)value).getNodeType().getIcon()); + } else if(value instanceof Edge) { + setIcon(((Edge)value).getEdgeType().getIcon()); + } + return this; + } + }); + locationsTable.setShowGrid(false); + JScrollPane elementsScroll = new JScrollPane(locationsTable); + elementsScroll.setPreferredSize(new Dimension(150,200)); + add(elementsScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel elementsButtonPanel = new JPanel(); + elementsButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllElementsButton = new JButton("Select All"); + selectAllElementsButton.setToolTipText("Select All Locations"); + selectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + locationsModel.selectAll(); + } + }); + elementsButtonPanel.add(selectAllElementsButton); + JButton deselectAllElementsButton = new JButton("Deselect All"); + deselectAllElementsButton.setToolTipText("Deselect All Locations"); + deselectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + locationsModel.deselectAll(); + } + }); + elementsButtonPanel.add(deselectAllElementsButton); + add(elementsButtonPanel, c); + c.weightx = 0; + c.fill = GridBagConstraints.BOTH; + c.gridy++; + JPanel prop2 = new JPanel(); + prop2.setPreferredSize(new Dimension(1,15)); + add(prop2, c); + c.gridy++; + c.weighty = 1; + cosModel = new CheckBoxTableModel(); + for(int i=1; i<=10; i++) { + cosModel.addObject(ClassOfSupply.getInstance(i)); + } + cosModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) + chartPanel.updateView(); + } + }); + JTable cosTable = new JTable(cosModel); + cosTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + cosTable.getTableHeader().setReorderingAllowed(false); + cosTable.getColumnModel().getColumn(0).setMaxWidth(25); + cosTable.getColumnModel().getColumn(1).setHeaderValue("Filter Classes of Supply"); + cosTable.setShowGrid(false); + JScrollPane cosScroll = new JScrollPane(cosTable); + cosScroll.setPreferredSize(new Dimension(150,150)); + add(cosScroll, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + JPanel dataButtonPanel = new JPanel(); + dataButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllDataButton = new JButton("Select All"); + selectAllDataButton.setToolTipText("Select All COS"); + selectAllDataButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.selectAll(); + } + }); + dataButtonPanel.add(selectAllDataButton); + JButton deselectAllDataButton = new JButton("Deselect All"); + deselectAllDataButton.setToolTipText("Deselect All COS"); + deselectAllDataButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.deselectAll(); + } + }); + dataButtonPanel.add(deselectAllDataButton); + add(dataButtonPanel, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + displayTotalCheck = new JCheckBox("Display Total", true); + displayTotalCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent arg0) { + chartPanel.updateView(); + } + }); + add(displayTotalCheck, c); + c.gridy++; + smoothDemandsCheck = new JCheckBox("Smooth Demands", true); + smoothDemandsCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(smoothDemandsCheck, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + refreshButton = new JButton("Refresh", new ImageIcon(getClass().getClassLoader().getResource("icons/arrow_refresh.png"))); + refreshButton.setVisible(false); + refreshButton.setToolTipText("Refresh Chart"); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + chartPanel.updateChart(); + } + }); + add(refreshButton, c); + } + + /** + * Initializes the panel. + */ + public void initialize() { + locationsModel.clear(); + updateView(); + } + + /** + * Updates the view. + */ + public void updateView() { + // update locations + List selectedLocations = locationsModel.getSelectedObjects(); + TableModelListener[] modelListeners = locationsModel.getTableModelListeners(); + for(TableModelListener l : modelListeners) { + locationsModel.removeTableModelListener(l); + } + locationsModel.clear(); + for(Location location : getScenario().getNetwork().getNodes()) { + locationsModel.addObject(location, selectedLocations.contains(location)); + } + for(Location location : getScenario().getNetwork().getEdges()) { + locationsModel.addObject(location, selectedLocations.contains(location)); + } + for(TableModelListener l : modelListeners) { + locationsModel.addTableModelListener(l); + } + locationsModel.fireTableDataChanged(); + + // update auto refresh button visibility + if(isAutoRefresh()) { + refreshButton.setVisible(false); + } else { + refreshButton.setVisible(true); + } + } + } + + /** + * The Class ChartPanel. + */ + private class ChartPanel extends SNChartPanel { + private static final long serialVersionUID = 4671269489085267359L; + + /** + * Initializes the chart. + */ + public void initialize() { + updateChart(); + } + + /** + * Updates the view. + */ + public void updateView() { + if(isAutoRefresh()) updateChart(); + } + + /** + * Updates the chart. + */ + public void updateChart() { + if(optionsPanel.locationsModel.getSelectedObjects().size()==1) { + setChart(buildTimeSeriesChart()); + } else { + setChart(buildBarChart()); + } + } + + private JFreeChart buildTimeSeriesChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + TimeSeries[] s = new TimeSeries[11]; + s[0] = new TimeSeries("Total", Hour.class); + for(int i = 1; i <= 10; i++) { + s[i] = new TimeSeries("COS " + i, Hour.class); + } + + double amount[] = new double[11]; + for(SimDemand demand : demandsTab.getSimulator().getDemandHistory(optionsPanel.locationsModel.getSelectedObjects().get(0))) { + Date date = DateFunctions.getDate(demandsTab.getScenario().getStartDate(), demand.getTime()); + if(!optionsPanel.smoothDemandsCheck.isSelected() && amount[0]>0) { + for(int i = 0; i <=10; i++) { + // replicate step function + s[i].addOrUpdate(new Hour(date).previous(), amount[i]); + } + } + for(Demand d : demand.getDemands()) { + if(d.getMass()<0) continue; + amount[0] += d.getMass(); + int cos = d.getResource().getClassOfSupply().getBaseClass().getId(); + amount[cos] += d.getMass(); + } + for(int i = 0; i <=10; i++) { + s[i].addOrUpdate(new Hour(date), amount[i]); + } + } + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, // title + null, // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + true, // legend + true, + false); + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + for(int i = 0; i <=10; i++) { + if(i==0&&optionsPanel.displayTotalCheck.isSelected()) { + dataset.addSeries(s[i]); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-1,-1,2,2)); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.BLACK); + } else if(optionsPanel.cosModel.getSelectedObjects().contains(ClassOfSupply.getInstance(i))) { + dataset.addSeries(s[i]); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-1,-1,2,2)); + r.setSeriesPaint(dataset.getSeriesCount() - 1, + ClassOfSupply.getInstance(i).getColor()); + } + } + return chart; + } + + private JFreeChart buildBarChart() { + DefaultCategoryDataset dataset = new DefaultCategoryDataset(); + + JFreeChart chart = ChartFactory.createStackedBarChart( + null, // title + "", // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + PlotOrientation.VERTICAL, // plot orientation + true, // legend + true, + false); + + CategoryPlot plot = (CategoryPlot) chart.getPlot(); + plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + + CategoryItemRenderer r = chart.getCategoryPlot().getRenderer(); + + for(Location location : optionsPanel.locationsModel.getSelectedObjects()) { + for(int i=1; i<=10; i++) { + if(optionsPanel.cosModel.getSelectedObjects().contains(ClassOfSupply.getInstance(i))) { + dataset.addValue(demandsTab.getSimulator().getDemands(location, ClassOfSupply.getInstance(i)).getTotalMass(), + "COS " + i, location.getName()); + r.setSeriesPaint(dataset.getRowCount() - 1, ClassOfSupply.getInstance(i).getColor()); + } + } + } + return chart; + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/demand/MissionDemandsTab.java b/src/main/java/edu/mit/spacenet/gui/demand/MissionDemandsTab.java new file mode 100644 index 0000000..98cb4c1 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/MissionDemandsTab.java @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.util.Date; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.CategoryLabelPositions; +import org.jfree.chart.plot.CategoryPlot; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.category.CategoryItemRenderer; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.category.DefaultCategoryDataset; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.SimDemand; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Component for showing the demands filtered by mission. + * + * @author Paul Grogan + */ +public class MissionDemandsTab extends JSplitPane { + private static final long serialVersionUID = -4728295622221432580L; + + private DemandsTab demandsTab; + + private OptionsPanel optionsPanel; + private ChartPanel chartPanel; + + public MissionDemandsTab(DemandsTab demandsTab) { + this.demandsTab = demandsTab; + + chartPanel = new ChartPanel(); + setLeftComponent(chartPanel); + + optionsPanel = new OptionsPanel(); + setRightComponent(optionsPanel); + + setName("Demands by Mission"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(490); + } + + /** + * Initializes the tab for a new scenario. + */ + public void initialize() { + optionsPanel.initialize(); + chartPanel.initialize(); + } + + /** + * Updates the tab. + */ + public void updateView() { + optionsPanel.updateView(); + chartPanel.updateView(); + } + + /** + * Checks if auto refresh is enabled. + * + * @return true, if auto refresh is enabled + */ + private boolean isAutoRefresh() { + return SpaceNetSettings.getInstance().isAutoRefresh(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return demandsTab.getScenario(); + } + + /** + * The Class OptionsPanel. + */ + private class OptionsPanel extends JPanel { + private static final long serialVersionUID = -4714468679105858517L; + + private CheckBoxTableModel missionsModel; + private CheckBoxTableModel cosModel; + private JCheckBox displayTotalCheck, smoothDemandsCheck; + private JButton refreshButton; + + /** + * Instantiates a new options panel. + * + * @param networkTab the network tab + */ + private OptionsPanel() { + setLayout(new GridBagLayout()); + setBorder(BorderFactory.createTitledBorder("Chart Options")); + + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.gridy++; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_END; + missionsModel = new CheckBoxTableModel(); + missionsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) { + chartPanel.updateView(); + } + displayTotalCheck.setEnabled(missionsModel.getSelectedObjects().size()==1); + smoothDemandsCheck.setEnabled(missionsModel.getSelectedObjects().size()==1); + } + }); + JTable missionsTable = new JTable(missionsModel); + missionsTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + missionsTable.getTableHeader().setReorderingAllowed(false); + missionsTable.getColumnModel().getColumn(0).setMaxWidth(25); + missionsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Missions"); + missionsTable.setShowGrid(false); + JScrollPane elementsScroll = new JScrollPane(missionsTable); + elementsScroll.setPreferredSize(new Dimension(150,200)); + add(elementsScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel elementsButtonPanel = new JPanel(); + elementsButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllElementsButton = new JButton("Select All"); + selectAllElementsButton.setToolTipText("Select All Missions"); + selectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + missionsModel.selectAll(); + } + }); + elementsButtonPanel.add(selectAllElementsButton); + JButton deselectAllElementsButton = new JButton("Deselect All"); + deselectAllElementsButton.setToolTipText("Deselect All Missions"); + deselectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + missionsModel.deselectAll(); + } + }); + elementsButtonPanel.add(deselectAllElementsButton); + add(elementsButtonPanel, c); + c.weightx = 0; + c.fill = GridBagConstraints.BOTH; + c.gridy++; + JPanel prop2 = new JPanel(); + prop2.setPreferredSize(new Dimension(1,15)); + add(prop2, c); + c.gridy++; + c.weighty = 1; + cosModel = new CheckBoxTableModel(); + for(int i=1; i<=10; i++) { + cosModel.addObject(ClassOfSupply.getInstance(i)); + } + cosModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) + chartPanel.updateView(); + } + }); + JTable cosTable = new JTable(cosModel); + cosTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + cosTable.getTableHeader().setReorderingAllowed(false); + cosTable.getColumnModel().getColumn(0).setMaxWidth(25); + cosTable.getColumnModel().getColumn(1).setHeaderValue("Filter Classes of Supply"); + cosTable.setShowGrid(false); + JScrollPane cosScroll = new JScrollPane(cosTable); + cosScroll.setPreferredSize(new Dimension(150,150)); + add(cosScroll, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + JPanel dataButtonPanel = new JPanel(); + dataButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllDataButton = new JButton("Select All"); + selectAllDataButton.setToolTipText("Select All COS"); + selectAllDataButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.selectAll(); + } + }); + dataButtonPanel.add(selectAllDataButton); + JButton deselectAllDataButton = new JButton("Deselect All"); + deselectAllDataButton.setToolTipText("Deselect All COS"); + deselectAllDataButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.deselectAll(); + } + }); + dataButtonPanel.add(deselectAllDataButton); + add(dataButtonPanel, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + displayTotalCheck = new JCheckBox("Display Total", true); + displayTotalCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent arg0) { + chartPanel.updateView(); + } + }); + add(displayTotalCheck, c); + c.gridy++; + smoothDemandsCheck = new JCheckBox("Smooth Demands", true); + smoothDemandsCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(smoothDemandsCheck, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + refreshButton = new JButton("Refresh", new ImageIcon(getClass().getClassLoader().getResource("icons/arrow_refresh.png"))); + refreshButton.setVisible(false); + refreshButton.setToolTipText("Refresh Chart"); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + chartPanel.updateChart(); + } + }); + add(refreshButton, c); + } + + /** + * Initializes the panel. + */ + public void initialize() { + missionsModel.clear(); + updateView(); + } + + /** + * Updates the view. + */ + public void updateView() { + // update elements + List deselectedMissions = missionsModel.getDeselectedObjects(); + TableModelListener[] modelListeners = missionsModel.getTableModelListeners(); + for(TableModelListener l : modelListeners) { + missionsModel.removeTableModelListener(l); + } + missionsModel.clear(); + for(Mission mission : getScenario().getMissionList()) { + missionsModel.addObject(mission, !deselectedMissions.contains(mission)); + } + for(TableModelListener l : modelListeners) { + missionsModel.addTableModelListener(l); + } + missionsModel.fireTableDataChanged(); + + // update auto refresh button visibility + if(isAutoRefresh()) { + refreshButton.setVisible(false); + } else { + refreshButton.setVisible(true); + } + } + } + + /** + * The Class ChartPanel. + */ + private class ChartPanel extends SNChartPanel { + private static final long serialVersionUID = 4671269489085267359L; + + /** + * Initializes the chart. + */ + public void initialize() { + updateChart(); + } + + /** + * Updates the view. + */ + public void updateView() { + if(isAutoRefresh()) updateChart(); + } + + /** + * Updates the chart. + */ + public void updateChart() { + if(optionsPanel.missionsModel.getSelectedObjects().size()==1) { + setChart(buildTimeSeriesChart()); + } else { + setChart(buildBarChart()); + } + } + + private JFreeChart buildTimeSeriesChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + TimeSeries[] s = new TimeSeries[11]; + s[0] = new TimeSeries("Total", Hour.class); + for(int i = 1; i <= 10; i++) { + s[i] = new TimeSeries("COS " + i, Hour.class); + } + + double amount[] = new double[11]; + for(SimDemand demand : demandsTab.getSimulator().getDemandHistory(optionsPanel.missionsModel.getSelectedObjects().get(0))) { + Date date = DateFunctions.getDate(demandsTab.getScenario().getStartDate(), demand.getTime()); + if(!optionsPanel.smoothDemandsCheck.isSelected() && amount[0]>0) { + for(int i = 0; i <=10; i++) { + // replicate step function + s[i].addOrUpdate(new Hour(date).previous(), amount[i]); + } + } + for(Demand d : demand.getDemands()) { + if(d.getMass()<0) continue; + amount[0] += d.getMass(); + int cos = d.getResource().getClassOfSupply().getBaseClass().getId(); + amount[cos] += d.getMass(); + } + for(int i = 0; i <=10; i++) { + s[i].addOrUpdate(new Hour(date), amount[i]); + } + } + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, // title + null, // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + true, // legend + true, + false); + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + for(int i = 0; i <=10; i++) { + if(i==0&&optionsPanel.displayTotalCheck.isSelected()) { + dataset.addSeries(s[i]); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-1,-1,2,2)); + r.setSeriesPaint(dataset.getSeriesCount() - 1, + Color.BLACK); + } else if(optionsPanel.cosModel.getSelectedObjects().contains(ClassOfSupply.getInstance(i))) { + dataset.addSeries(s[i]); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-1,-1,2,2)); + r.setSeriesPaint(dataset.getSeriesCount() - 1, + ClassOfSupply.getInstance(i).getColor()); + } + } + return chart; + } + + private JFreeChart buildBarChart() { + DefaultCategoryDataset dataset = new DefaultCategoryDataset(); + + JFreeChart chart = ChartFactory.createStackedBarChart( + null, // title + "", // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + PlotOrientation.VERTICAL, // plot orientation + true, // legend + true, + false); + + CategoryPlot plot = (CategoryPlot) chart.getPlot(); + plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + + CategoryItemRenderer r = chart.getCategoryPlot().getRenderer(); + + for(Mission mission : optionsPanel.missionsModel.getSelectedObjects()) { + for(int i=1; i<=10; i++) { + if(optionsPanel.cosModel.getSelectedObjects().contains(ClassOfSupply.getInstance(i))) { + dataset.addValue(demandsTab.getSimulator().getDemands(mission, ClassOfSupply.getInstance(i)).getTotalMass(), + "COS " + i, mission.getName()); + r.setSeriesPaint(dataset.getRowCount() - 1, ClassOfSupply.getInstance(i).getColor()); + } + } + } + return chart; + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/demand/RepairSummaryTable.java b/src/main/java/edu/mit/spacenet/gui/demand/RepairSummaryTable.java new file mode 100644 index 0000000..cf2ef1d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/RepairSummaryTable.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Component; +import java.text.DecimalFormat; + +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.RepairItem; +import edu.mit.spacenet.scenario.Scenario; + +public class RepairSummaryTable extends JTable { + private static final long serialVersionUID = -5981730193560436124L; + + private RepairabilityTab repairabilityTab; + private RepairSummaryModel model; + + /** + * Instantiates a new repair summary table. + * + * @param repairabilityTab the repairability tab + */ + public RepairSummaryTable(RepairabilityTab repairabilityTab) { + this.repairabilityTab = repairabilityTab; + + model = new RepairSummaryModel(); + setModel(model); + + getColumnModel().getColumn(0).setHeaderValue(" "); + getColumnModel().getColumn(0).setMaxWidth(20); + getColumnModel().getColumn(1).setHeaderValue("Mission"); + getColumnModel().getColumn(2).setHeaderValue("Repair Time"); + getColumnModel().getColumn(2).setMaxWidth(75); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format time and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " hr"); + return this; + } + }); + getColumnModel().getColumn(3).setHeaderValue("Mass"); + getColumnModel().getColumn(3).setMaxWidth(75); + getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format mass and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " kg"); + return this; + } + }); + getTableHeader().setReorderingAllowed(false); + } + + /** + * Initializes the table for a new scenario. + */ + public void initialize() { + model.fireTableDataChanged(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + private Scenario getScenario() { + return repairabilityTab.getScenario(); + } + + /** + * Gets the selected mission. + * + * @return the selected mission + */ + public Mission getSelectedMission() { + if(getSelectedRow()>=0) + return (Mission)getValueAt(getSelectedRow(), 1); + else return null; + } + + /** + * Updates the data within the currently selected row (assumes that only + * the current mission can be edited). + */ + public void updateView() { + if(getSelectedRow() >= 0) + model.fireTableRowsUpdated(getSelectedRow(), getSelectedRow()); + } + + /** + * The Class RepairSummaryModel. + */ + private class RepairSummaryModel extends AbstractTableModel { + private static final long serialVersionUID = -1788294077902504936L; + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 4; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + return getScenario()==null?0:getScenario().getMissionList().size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) return row; + if(col==1) return getScenario().getMissionList().get(row); + if(col==2) return getDeltaTime(row); + else return getDeltaMass(row); + } + + /** + * Gets the delta time. + * + * @param row the row + * + * @return the delta time + */ + private double getDeltaTime(int row) { + double amount = 0; + if(getScenario().getRepairedItems().get(getScenario().getMissionList().get(row))!=null) { + for(RepairItem item : getScenario().getRepairedItems().get(getScenario().getMissionList().get(row))) { + amount += item.getMeanRepairTime(); + } + } + return amount; + } + + /** + * Gets the delta mass. + * + * @param row the row + * + * @return the delta mass + */ + private double getDeltaMass(int row) { + double amount = 0; + if(getScenario().getRepairedItems().get(getScenario().getMissionList().get(row))!=null) { + for(RepairItem item : getScenario().getRepairedItems().get(getScenario().getMissionList().get(row))) { + amount += item.getDemand().getMass() - item.getMassToRepair(); + } + } + return amount; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/demand/RepairabilityTab.java b/src/main/java/edu/mit/spacenet/gui/demand/RepairabilityTab.java new file mode 100644 index 0000000..ad14060 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/RepairabilityTab.java @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.HashSet; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JSplitPane; +import javax.swing.ListSelectionModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.scenario.ItemDiscretization; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.RepairItem; +import edu.mit.spacenet.scenario.Scenario; + +/** + * Component for performing repairability analysis. + * + * @author Paul Grogan + */ +public class RepairabilityTab extends JSplitPane { + private static final long serialVersionUID = -6405124067606236705L; + private DemandsTab demandsTab; + + private ListSelectionListener summaryListener; + private RepairSummaryTable summaryTable; + private ChartPanel chartPanel; + + private SpinnerNumberModel autoRepairModel; + private JSpinner autoRepairSpinner; + private JButton autoRepairButton; + private RepairableDemandsTable repairTable; + + /** + * Instantiates a new repairability tab. + * + * @param tab the demands tab + */ + public RepairabilityTab(DemandsTab tab) { + super(JSplitPane.VERTICAL_SPLIT); + this.demandsTab = tab; + + JSplitPane topPanel = new JSplitPane(); + summaryTable = new RepairSummaryTable(this); + summaryListener = new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(!e.getValueIsAdjusting() && e.getFirstIndex()>=0) { + autoRepairModel.setValue(summaryTable.getValueAt(summaryTable.getSelectedRow(), 2)); + updateView(); + } + autoRepairButton.setEnabled(summaryTable.getSelectedRow() >=0 ); + } + }; + summaryTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + summaryTable.getSelectionModel().addListSelectionListener(summaryListener); + JScrollPane summaryScroll = new JScrollPane(summaryTable); + topPanel.setLeftComponent(summaryScroll); + + chartPanel = new ChartPanel(); + topPanel.setRightComponent(chartPanel); + topPanel.setBorder(BorderFactory.createEmptyBorder()); + topPanel.setDividerLocation(300); + topPanel.setResizeWeight(0.5); + setTopComponent(topPanel); + + JPanel repairPanel = new JPanel(); + repairPanel.setLayout(new GridBagLayout()); + repairPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx=0; + c.gridy=0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + repairPanel.add(new JLabel("Auto-Repair: "), c); + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + autoRepairModel = new SpinnerNumberModel(0,0,10000,0.25); + autoRepairSpinner = new JSpinner(autoRepairModel); + repairPanel.add(new UnitsWrapper(autoRepairSpinner, "hours"), c); + c.gridx++; + c.weightx = 1; + autoRepairButton = new JButton ("Auto-Repair", new ImageIcon(getClass().getClassLoader().getResource("icons/lightning.png"))); + autoRepairButton.setEnabled(false); + autoRepairButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + autoRepair(); + updateView(); + } + }); + repairPanel.add(autoRepairButton, c); + c.gridx = 0; + c.gridy++; + c.gridwidth = 3; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + repairTable = new RepairableDemandsTable(this); + repairTable.getModel().addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + summaryTable.updateView(); + chartPanel.updateView(); + } + }); + JScrollPane repairScroll = new JScrollPane(repairTable); + repairPanel.add(repairScroll, c); + setBottomComponent(repairPanel); + + setBorder(BorderFactory.createEmptyBorder()); + setDividerLocation(300); + setResizeWeight(.25); + setName("Repairability Analysis"); + } + + /** + * Initialize. + */ + public void initialize() { + summaryTable.initialize(); + repairTable.initialize(); + chartPanel.initialize(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return demandsTab.getScenario(); + } + + /** + * Gets the repair summary table. + * + * @return the repair summary table + */ + public RepairSummaryTable getRepairSummaryTable() { + return summaryTable; + } + + /** + * Update view. + */ + public void updateView() { + summaryTable.updateView(); + repairTable.updateView(); + chartPanel.updateView(); + } + + /** + * Automatically selects the best set of items to repair for a single + * mission. + */ + private void autoRepair() { + Mission mission = summaryTable.getSelectedMission(); + int index = getScenario().getMissionList().indexOf(mission); + if(getScenario().getRepairedItems().get(mission)==null) { + getScenario().getRepairedItems().put(mission, new HashSet()); + } else { + getScenario().getRepairedItems().get(mission).clear(); + } + + double repairTime = autoRepairModel.getNumber().doubleValue(); + ArrayList repairItems = new ArrayList(); + if(demandsTab.getSimulator().getSortedRepairItems().get(index)!=null) { + for(RepairItem i : demandsTab.getSimulator().getSortedRepairItems().get(index)) { + repairItems.add(i); + } + } + for(RepairItem item : repairItems) { + if(repairTime >= item.getMeanRepairTime()) { + // can repair entire item + repairTime -= item.getMeanRepairTime(); + logRepairItem(index, + item.getDemand().getResource(), + item.getDemand().getAmount(), + item.getElement()); + } else if(getScenario().getItemDiscretization().equals(ItemDiscretization.NONE) + && repairTime > 0) { + // else if there is no discretization of items, can repair + // a fraction of the item + double amount = item.getDemand().getAmount()*repairTime/item.getMeanRepairTime(); + repairTime = 0; + logRepairItem(index, + item.getDemand().getResource(), + amount, + item.getElement()); + } else if(repairTime >= item.getUnitMeanRepairTime()) { + // otherwise can repair a whole portion of the demand + int quantity = (int)Math.floor(Math.min(item.getDemand().getAmount(), repairTime/item.getUnitMeanRepairTime())); + repairTime -= quantity*item.getUnitMeanRepairTime(); + logRepairItem(index, + item.getDemand().getResource(), + quantity, + item.getElement()); + } + } + } + + /** + * Log repair item. + * + * @param missionIndex the mission index + * @param resource the resource + * @param amountRepaired the amount repaired + * @param element the element + */ + private void logRepairItem(int missionIndex, I_Resource resource, + double amountRepaired, I_Element element) { + Mission mission = getScenario().getMissionList().get(missionIndex); + for(RepairItem item : getScenario().getRepairedItems().get(mission)) { + if(item.getDemand().getResource().equals(resource) + && item.getElement().equals(element)) { + // if equivalent repair item already exists, add the + // corresponding new amount repaired + item.getDemand().setAmount(item.getDemand().getAmount() + amountRepaired); + return; + } + } + // otherwise create new repair item and log amount repaired + getScenario().getRepairedItems().get(mission).add(new RepairItem( + new Demand(resource, amountRepaired), element)); + } + + /** + * Gets the demands tab. + * + * @return the demands tab + */ + public DemandsTab getDemandsTab() { + return demandsTab; + } + + /** + * The Class ChartPanel. + */ + private class ChartPanel extends SNChartPanel { + private static final long serialVersionUID = -3883762777518801995L; + + /** + * Instantiates a new chart panel. + */ + public ChartPanel() { + setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY)); + setPreferredSize(new Dimension(600,400)); + } + + /** + * Initialize. + */ + public void initialize() { + updateView(); + } + + /** + * Update view. + */ + public void updateView() { + if(summaryTable.getSelectedRowCount()==0) { + setChart(null); + } else { + Mission mission = summaryTable.getSelectedMission(); + int index = getScenario().getMissionList().indexOf(mission); + + XYSeriesCollection dataset = new XYSeriesCollection(); + JFreeChart chart = ChartFactory.createXYLineChart( + null, // title + "Repair Time (hr)", // x-axis label + "Spares Mass Savings (kg)", // y-axis label + dataset, // data + PlotOrientation.VERTICAL, // orientation + true, // legend + true, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + XYSeries s = new XYSeries("Unsorted"); + double mass = 0; + double time = 0; + s.addOrUpdate(mass, time); + if(demandsTab.getSimulator().getUnsortedRepairItems().get(index)!=null) { + for(RepairItem i : demandsTab.getSimulator().getUnsortedRepairItems().get(index)) { + mass += i.getDemand().getMass()-i.getMassToRepair(); + time += i.getMeanRepairTime(); + s.addOrUpdate(time, mass); + } + } + dataset.addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.RED); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(0, 0, 0, 0)); + + mass = 0; + time = 0; + XYSeries s2 = new XYSeries("Optimal Order"); + s2.addOrUpdate(0, 0); + if(demandsTab.getSimulator().getSortedRepairItems().get(index)!=null) { + for(RepairItem i :demandsTab.getSimulator().getSortedRepairItems().get(index)) { + mass += i.getDemand().getMass()-i.getMassToRepair(); + time += i.getMeanRepairTime(); + s2.addOrUpdate(time, mass); + } + } + dataset.addSeries(s2); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.BLUE); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(0, 0, 0, 0)); + + XYSeries s3 = new XYSeries("Repair Selection"); + mass = 0; + time = 0; + if(getScenario().getRepairedItems().get(mission) != null) { + for(RepairItem i : getScenario().getRepairedItems().get(mission)) { + mass += (i.getDemand().getMass()-i.getMassToRepair()); + time += i.getMeanRepairTime(); + } + } + s3.addOrUpdate(time, mass); + dataset.addSeries(s3); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.BLACK); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + + setChart(chart); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/demand/RepairableDemandsTable.java b/src/main/java/edu/mit/spacenet/gui/demand/RepairableDemandsTable.java new file mode 100644 index 0000000..88b8d49 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/RepairableDemandsTable.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Component; +import java.text.DecimalFormat; +import java.util.HashSet; + +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.scenario.RepairItem; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.DemandSimulator; + +/** + * The Class RepairableDemandsTable. + */ +public class RepairableDemandsTable extends JTable { + private static final long serialVersionUID = -8427772886041511648L; + + private RepairabilityTab repairabilityTab; + + private RepairableDemandsModel model; + + /** + * Instantiates a new repairable demands table. + */ + public RepairableDemandsTable(RepairabilityTab repairabilityTab) { + this.repairabilityTab = repairabilityTab; + + model = new RepairableDemandsModel(); + setModel(model); + + getColumnModel().getColumn(0).setHeaderValue("Element"); + getColumnModel().getColumn(1).setHeaderValue("Item"); + getColumnModel().getColumn(2).setHeaderValue("Amount"); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format the amount and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " " + ((RepairableDemandsModel)getModel()).getDemand(row).getResource().getUnits()); + return this; + } + }); + getColumnModel().getColumn(3).setHeaderValue("Mass"); + getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format the mass and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " kg"); + return this; + } + }); + getColumnModel().getColumn(4).setHeaderValue("Mass to Repair"); + getColumnModel().getColumn(4).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format the mass and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " kg"); + return this; + } + }); + getColumnModel().getColumn(5).setHeaderValue("Time to Repair"); + getColumnModel().getColumn(5).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format the time and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " hr"); + return this; + } + }); + getColumnModel().getColumn(6).setHeaderValue("Amount Repaired"); + getColumnModel().getColumn(6).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format the amount and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " " + ((RepairableDemandsModel)getModel()).getDemand(row).getResource().getUnits()); + return this; + } + }); + getTableHeader().setReorderingAllowed(false); + } + + /** + * Initializes the table for a new scenario. + */ + public void initialize() { + model.fireTableDataChanged(); + } + + /** + * Update view. + */ + public void updateView() { + model.fireTableDataChanged(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + private Scenario getScenario() { + return repairabilityTab.getScenario(); + } + + /** + * Gets the simulator. + * + * @return the simulator + */ + private DemandSimulator getSimulator() { + return repairabilityTab.getDemandsTab().getSimulator(); + } + + /** + * The Class RepairableDemandsModel. + */ + private class RepairableDemandsModel extends AbstractTableModel { + private static final long serialVersionUID = -2630916184656214544L; + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 7; + } + + /** + * Gets the mission index. + * + * @return the mission index + */ + private int getMissionIndex() { + return repairabilityTab.getRepairSummaryTable().getSelectedRow(); + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnClass(int) + */ + public Class getColumnClass(int column) { + if(column!=0 && column!=1) return Double.class; + else return Object.class; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + if(getScenario()==null||getSimulator()==null) return 0; + else if(getSimulator().getUnsortedRepairItems().get(getMissionIndex())==null) return 0; + else return getSimulator().getUnsortedRepairItems().get(getMissionIndex()).size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int column) { + if(column==0) return getElement(row); + else if(column==1) return getDemand(row).getResource(); + else if(column==2) return getDemand(row).getAmount(); + else if(column==3) return getDemand(row).getMass(); + else if(column==4) return getRepairItem(row).getMassToRepair(); + else if(column==5) return getRepairItem(row).getMeanRepairTime(); + else if(column==6) { + HashSet repairedItems = new HashSet(); + if(getScenario().getRepairedItems().get(getScenario().getMissionList().get(getMissionIndex()))!=null) { + for(RepairItem item : getScenario().getRepairedItems().get(getScenario().getMissionList().get(getMissionIndex()))) { + repairedItems.add(new RepairItem(new Demand(item.getDemand().getResource(), item.getDemand().getAmount()), item.getElement())); + } + } + for(RepairItem simItem : getSimulator().getUnsortedRepairItems().get(getMissionIndex())) { + double amountRepaired = 0; + for(RepairItem item : repairedItems) { + if(simItem.getDemand().getResource().equals(item.getDemand().getResource()) + && simItem.getElement().equals(item.getElement())) { + double amountNewlyRepaired = Math.min(simItem.getDemand().getAmount() - amountRepaired, item.getDemand().getAmount()); + item.getDemand().setAmount(item.getDemand().getAmount()-amountNewlyRepaired); + amountRepaired = amountRepaired + amountNewlyRepaired; + } + } + if(getRepairItem(row).equals(simItem)) return amountRepaired; + } + return 0; + } + else return null; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int) + */ + public void setValueAt(Object value, int row, int column) { + if(column==6) { + double oldValue = (Double)getValueAt(row, column); + double newValue = Math.min(getDemand(row).getAmount(), (Double)value); + + if(newValue > oldValue) { + if(getScenario().getRepairedItems().get(getScenario().getMissionList().get(getMissionIndex()))==null) { + getScenario().getRepairedItems().put(getScenario().getMissionList().get(getMissionIndex()), new HashSet()); + } + boolean isFound = false; + for(RepairItem item : getScenario().getRepairedItems().get(getScenario().getMissionList().get(getMissionIndex()))) { + if(item.getDemand().getResource().equals(getDemand(row).getResource()) + && item.getElement().equals(getElement(row))) { + isFound = true; + item.getDemand().setAmount(item.getDemand().getAmount() + (newValue - oldValue)); + } + } + if(!isFound) { + getScenario().getRepairedItems().get(getScenario().getMissionList().get(getMissionIndex())).add( + new RepairItem(new Demand(getDemand(row).getResource(), newValue - oldValue), + getElement(row))); + } + } else if(newValue < oldValue) { + for(RepairItem item : getScenario().getRepairedItems().get(getScenario().getMissionList().get(getMissionIndex()))) { + if(item.getDemand().getResource().equals(getDemand(row).getResource()) + && item.getElement().equals(getElement(row))) { + item.getDemand().setAmount(item.getDemand().getAmount() + (newValue - oldValue)); + } + } + } + fireTableRowsUpdated(row, row); + } + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int column) { + if(column==6) return true; + else return false; + } + + /** + * Gets the repair item. + * + * @param row the row + * + * @return the repair item + */ + private RepairItem getRepairItem(int row) { + return getSimulator().getUnsortedRepairItems().get(getMissionIndex()).get(row); + } + + /** + * Gets the element. + * + * @param row the row + * + * @return the element + */ + private I_Element getElement(int row) { + return getRepairItem(row).getElement(); + } + + /** + * Gets the demand. + * + * @param row the row + * + * @return the demand + */ + private Demand getDemand(int row) { + return getRepairItem(row).getDemand(); + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/demand/ScenarioFeasibilityTab.java b/src/main/java/edu/mit/spacenet/gui/demand/ScenarioFeasibilityTab.java new file mode 100644 index 0000000..ee9b983 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/ScenarioFeasibilityTab.java @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.CategoryLabelPositions; +import org.jfree.chart.plot.CategoryPlot; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.category.BarRenderer; +import org.jfree.chart.renderer.category.CategoryItemRenderer; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.category.DefaultCategoryDataset; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.NodeListCellRenderer; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.scenario.SupplyEdge; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Component for visualizing the feasibility of a scenario based on the used and + * remaining delivery capacity. + * + * @author Paul Grogan + */ +public class ScenarioFeasibilityTab extends JSplitPane { + private static final long serialVersionUID = -7246327673230474018L; + + private static final String RAW_CAPACITY = "Raw Delivery Capacity"; + private static final String REMAINING_CAPACITY = "Remaining Delivery Capacity"; + private static final String ESTIMATED_DEMANDS = "Estimated Demands"; + + private DemandsTab demandsTab; + + private OptionsPanel optionsPanel; + private ChartPanel chartPanel; + + /** + * Instantiates a new scenario feasibility tab. + * + * @param demandsTab the demands tab + */ + public ScenarioFeasibilityTab(DemandsTab demandsTab) { + this.demandsTab = demandsTab; + + chartPanel = new ChartPanel(); + setLeftComponent(chartPanel); + + optionsPanel = new OptionsPanel(this); + setRightComponent(optionsPanel); + + setName("Scenario Feasibility"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(490); + } + + /** + * Initializes the tab for a new scenario. + */ + public void initialize() { + optionsPanel.initialize(); + chartPanel.initialize(); + } + + /** + * Updates the tab. + */ + public void updateView() { + optionsPanel.updateView(); + chartPanel.updateView(); + } + + /** + * Checks if auto refresh is enabled. + * + * @return true, if auto refresh is enabled + */ + private boolean isAutoRefresh() { + return SpaceNetSettings.getInstance().isAutoRefresh(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return demandsTab.getScenario(); + } + + /** + * A custom JPanel to hold the scenario feasibility chart options. + */ + private class OptionsPanel extends JPanel { + private static final long serialVersionUID = -8521945559229981641L; + + private ScenarioFeasibilityTab feasibilityTab; + + private JComboBox nodeCombo; + private CheckBoxTableModel supplyEdgesModel; + private CheckBoxTableModel dataModel; + private JCheckBox cumulativeCheck, timeDomainCheck, legendCheck, smoothDemandsCheck; + private JButton refreshButton; + + /** + * Instantiates a new options panel. + */ + public OptionsPanel(ScenarioFeasibilityTab feasibilityTab) { + this.feasibilityTab = feasibilityTab; + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + setBorder(BorderFactory.createTitledBorder("Chart Options")); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.gridwidth = 2; + nodeCombo = new JComboBox(); + nodeCombo.setRenderer(new NodeListCellRenderer()); + nodeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) + feasibilityTab.updateView(); + } + }); + JPanel nodePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + nodePanel.add(new JLabel("Feasibility at Node: ")); + nodePanel.add(nodeCombo); + add(nodePanel, c); + c.gridwidth = 1; + c.gridy++; + cumulativeCheck = new JCheckBox("Cumulative Plot"); + cumulativeCheck.setSelected(true); + cumulativeCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + timeDomainCheck.setEnabled(cumulativeCheck.isSelected()); + if(!cumulativeCheck.isSelected()) + timeDomainCheck.setSelected(false); + } + }); + add(cumulativeCheck, c); + c.gridx++; + timeDomainCheck = new JCheckBox("Time Domain"); + timeDomainCheck.setSelected(true); + timeDomainCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(timeDomainCheck, c); + c.gridy++; + c.gridx = 0; + legendCheck = new JCheckBox("Legend"); + legendCheck.setSelected(true); + legendCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(legendCheck, c); + c.gridx++; + smoothDemandsCheck = new JCheckBox("Smooth Demands", true); + smoothDemandsCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(smoothDemandsCheck, c); + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + supplyEdgesModel = new CheckBoxTableModel(); + supplyEdgesModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) + chartPanel.updateView(); + } + }); + JTable supplyEdgesTable = new JTable(supplyEdgesModel); + supplyEdgesTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + supplyEdgesTable.getTableHeader().setReorderingAllowed(false); + supplyEdgesTable.getColumnModel().getColumn(0).setMaxWidth(25); + supplyEdgesTable.getColumnModel().getColumn(1).setHeaderValue("Filter Supply Edges"); + supplyEdgesTable.setShowGrid(false); + JScrollPane supplyEdgesScroll = new JScrollPane(supplyEdgesTable); + supplyEdgesScroll.setPreferredSize(new Dimension(150,150)); + add(supplyEdgesScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel supplyEdgesButtonPanel = new JPanel(); + supplyEdgesButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllSupplyEdgesButton = new JButton("Select All"); + selectAllSupplyEdgesButton.setToolTipText("Select All Supply Edges"); + selectAllSupplyEdgesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + supplyEdgesModel.selectAll(); + } + }); + supplyEdgesButtonPanel.add(selectAllSupplyEdgesButton); + JButton deselectAllSupplyEdgesButton = new JButton("Deselect All"); + deselectAllSupplyEdgesButton.setToolTipText("Deselect All Supply Edges"); + deselectAllSupplyEdgesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + supplyEdgesModel.deselectAll(); + } + }); + supplyEdgesButtonPanel.add(deselectAllSupplyEdgesButton); + add(supplyEdgesButtonPanel, c); + c.weightx = 0; + c.fill = GridBagConstraints.BOTH; + c.gridy++; + c.weighty = 1; + dataModel = new CheckBoxTableModel(); + dataModel.addObject(RAW_CAPACITY); + dataModel.addObject(REMAINING_CAPACITY); + dataModel.addObject(ESTIMATED_DEMANDS); + dataModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) + chartPanel.updateView(); + } + }); + JTable dataTable = new JTable(dataModel); + dataTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + dataTable.getTableHeader().setReorderingAllowed(false); + dataTable.getColumnModel().getColumn(0).setMaxWidth(25); + dataTable.getColumnModel().getColumn(1).setHeaderValue("Filter Data"); + dataTable.setShowGrid(false); + JScrollPane dataScroll = new JScrollPane(dataTable); + dataScroll.setPreferredSize(new Dimension(150,50)); + add(dataScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel dataButtonPanel = new JPanel(); + dataButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllDataButton = new JButton("Select All"); + selectAllDataButton.setToolTipText("Select All Data"); + selectAllDataButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dataModel.selectAll(); + } + }); + dataButtonPanel.add(selectAllDataButton); + JButton deselectAllDataButton = new JButton("Deselect All"); + deselectAllDataButton.setToolTipText("Deselect All Data"); + deselectAllDataButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dataModel.deselectAll(); + } + }); + dataButtonPanel.add(deselectAllDataButton); + add(dataButtonPanel, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + refreshButton = new JButton("Refresh", new ImageIcon(getClass().getClassLoader().getResource("icons/arrow_refresh.png"))); + refreshButton.setVisible(false); + refreshButton.setToolTipText("Refresh Chart"); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + chartPanel.updateChart(); + } + }); + add(refreshButton, c); + } + + /** + * Initializes the options panel. + */ + public void initialize() { + nodeCombo.setEnabled(getScenario()!=null); + cumulativeCheck.setEnabled(getScenario()!=null); + timeDomainCheck.setEnabled(getScenario()!=null); + + if(getScenario()!=null) { + // initialize nodes + Object selectedNode = nodeCombo.getSelectedItem(); + ItemListener[] nodeListeners = nodeCombo.getItemListeners(); + for(ItemListener l : nodeListeners) { + nodeCombo.removeItemListener(l); + } + nodeCombo.removeAllItems(); + for(Node node : getScenario().getNetwork().getNodes()) { + nodeCombo.addItem(node); + } + if(selectedNode!=null) { + nodeCombo.setSelectedItem(selectedNode); + } else if(getScenario().getMissionList().size()>0 + && getScenario().getMissionList().get(0).getDestination()!=null) { + nodeCombo.setSelectedItem(getScenario().getMissionList().get(0).getDestination()); + } else { + nodeCombo.setSelectedIndex(0); + } + for(ItemListener l : nodeListeners) { + nodeCombo.addItemListener(l); + } + } + supplyEdgesModel.clear(); + updateView(); + } + + /** + * Updates the options panel. + */ + public void updateView() { + // update supply edges + List deselectedSupplyEdges = supplyEdgesModel.getDeselectedObjects(); + TableModelListener[] modelListeners = supplyEdgesModel.getTableModelListeners(); + for(TableModelListener l : modelListeners) { + supplyEdgesModel.removeTableModelListener(l); + } + supplyEdgesModel.clear(); + ArrayList edges = new ArrayList(); + if(demandsTab.getSimulator()!=null) { + for(SupplyEdge edge : demandsTab.getSimulator().getSupplyEdges()) { + if(edge.getDestination().equals(nodeCombo.getSelectedItem())) + edges.add(edge); + } + } + Collections.reverse(edges); + for(SupplyEdge edge : edges) { + if(edge.getDestination().equals(nodeCombo.getSelectedItem())) { + supplyEdgesModel.addObject(edge, !deselectedSupplyEdges.contains(edge)); + } + } + for(TableModelListener l : modelListeners) { + supplyEdgesModel.addTableModelListener(l); + } + supplyEdgesModel.fireTableDataChanged(); + + // update auto refresh button visibility + if(isAutoRefresh()) { + refreshButton.setVisible(false); + } else { + refreshButton.setVisible(true); + } + } + } + + private class ChartPanel extends SNChartPanel { + private static final long serialVersionUID = -4706484000256730980L; + + public ChartPanel() { + setPreferredSize(new Dimension(600,400)); + } + + /** + * Initialize the chart panel for a new scenario. + */ + public void initialize() { + updateChart(); + } + + /** + * Updates the chart panel. + */ + public void updateView() { + if(isAutoRefresh()) updateChart(); + } + + /** + * Updates the chart. + */ + public void updateChart() { + JFreeChart chart; + if(optionsPanel.cumulativeCheck.isSelected() + && optionsPanel.timeDomainCheck.isSelected()) { + chart = buildTimeSeriesChart(); + } else if(optionsPanel.cumulativeCheck.isSelected()) { + chart = buildLineChart(); + } else { + chart = buildBarChart(); + } + setChart(chart); + } + + /** + * Builds the time series chart. + * + * @return the chart + */ + private JFreeChart buildTimeSeriesChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, // title + null, // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + optionsPanel.legendCheck.isSelected(), // legend + true, // + false); // + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + TimeSeries rawCapacitySeries = new TimeSeries("Raw Capacity", Hour.class); + dataset.addSeries(rawCapacitySeries); + r.setSeriesPaint(dataset.getSeriesCount()-1, Color.BLUE); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + TimeSeries remainingCapacitySeries = new TimeSeries("Remaining Capacity", Hour.class); + dataset.addSeries(remainingCapacitySeries); + r.setSeriesPaint(dataset.getSeriesCount()-1, Color.GREEN); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + TimeSeries estimatedDemandsSeries = new TimeSeries("Estimated Demands", Hour.class); + dataset.addSeries(estimatedDemandsSeries); + r.setSeriesPaint(dataset.getSeriesCount()-1, Color.RED); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + + double rawCapacity = 0; + double remainingCapacity = 0; + double estimatedDemands = 0; + SupplyEdge prevEdge = null; + + for(SupplyEdge edge : optionsPanel.supplyEdgesModel.getAllObjects()) { + Hour hour = new Hour(DateFunctions.getDate(demandsTab.getScenario().getStartDate(), edge.getStartTime())); + + if(optionsPanel.supplyEdgesModel.getSelectedObjects().contains(edge) + && prevEdge != null) { + if(optionsPanel.dataModel.getSelectedObjects().contains(ESTIMATED_DEMANDS) + && !optionsPanel.smoothDemandsCheck.isSelected()) + estimatedDemandsSeries.addOrUpdate(hour.previous(), estimatedDemands); + if(optionsPanel.dataModel.getSelectedObjects().contains(RAW_CAPACITY)) + rawCapacitySeries.addOrUpdate(hour.previous(), rawCapacity); + if(optionsPanel.dataModel.getSelectedObjects().contains(REMAINING_CAPACITY)) + remainingCapacitySeries.addOrUpdate(hour.previous(), remainingCapacity); + } + + estimatedDemands += demandsTab.getSimulator().getAggregatedEdgeDemands().get(edge).getTotalMass(); + estimatedDemands += demandsTab.getSimulator().getAggregatedNodeDemands().get(edge.getPoint()).getTotalMass(); + + if(optionsPanel.supplyEdgesModel.getSelectedObjects().contains(edge)) { + rawCapacity += edge.getRawCapacity(); + remainingCapacity += edge.getCapacity(); + + if(optionsPanel.dataModel.getSelectedObjects().contains(ESTIMATED_DEMANDS)) + estimatedDemandsSeries.addOrUpdate(hour, estimatedDemands); + if(optionsPanel.dataModel.getSelectedObjects().contains(RAW_CAPACITY)) + rawCapacitySeries.addOrUpdate(hour, rawCapacity); + if(optionsPanel.dataModel.getSelectedObjects().contains(REMAINING_CAPACITY)) + remainingCapacitySeries.addOrUpdate(hour, remainingCapacity); + + prevEdge = edge; + } + } + return chart; + } + + /** + * Builds the line chart. + * + * @return the chart + */ + private JFreeChart buildLineChart() { + DefaultCategoryDataset dataset = new DefaultCategoryDataset(); + + JFreeChart chart = ChartFactory.createLineChart( + null, // title + "", // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + PlotOrientation.VERTICAL, // chart orientation + optionsPanel.legendCheck.isSelected(), // legend + true, // + false); // + + CategoryItemRenderer r = chart.getCategoryPlot().getRenderer(); + + double rawCapacity = 0; + double remainingCapacity = 0; + double estimatedDemands = 0; + + for(SupplyEdge edge : optionsPanel.supplyEdgesModel.getAllObjects()) { + estimatedDemands += demandsTab.getSimulator().getAggregatedEdgeDemands().get(edge).getTotalMass(); + estimatedDemands += demandsTab.getSimulator().getAggregatedNodeDemands().get(edge.getPoint()).getTotalMass(); + + if(optionsPanel.supplyEdgesModel.getSelectedObjects().contains(edge)) { + rawCapacity += edge.getRawCapacity(); + remainingCapacity += edge.getCapacity(); + + if(optionsPanel.dataModel.getSelectedObjects().contains(ESTIMATED_DEMANDS)) { + dataset.addValue(estimatedDemands, ESTIMATED_DEMANDS, edge); + r.setSeriesPaint(dataset.getRowCount() - 1, Color.RED); + } + if(optionsPanel.dataModel.getSelectedObjects().contains(RAW_CAPACITY)) { + dataset.addValue(rawCapacity, RAW_CAPACITY, edge); + r.setSeriesPaint(dataset.getRowCount() - 1, Color.BLUE); + } + if(optionsPanel.dataModel.getSelectedObjects().contains(REMAINING_CAPACITY)) { + dataset.addValue(remainingCapacity, REMAINING_CAPACITY, edge); + r.setSeriesPaint(dataset.getRowCount() - 1, Color.GREEN); + } + } + } + + CategoryPlot plot = (CategoryPlot) chart.getPlot(); + plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + return chart; + } + + /** + * Builds the bar chart. + * + * @return the chart + */ + private JFreeChart buildBarChart() { + DefaultCategoryDataset dataset = new DefaultCategoryDataset(); + + JFreeChart chart = ChartFactory.createBarChart( + null, // title + "", // x-axis label + "Mass (kg)", // y-axis label + dataset, // data + PlotOrientation.VERTICAL, // chart orientation + optionsPanel.legendCheck.isSelected(), // legend + true, // + false); // + + BarRenderer r = (BarRenderer) chart.getCategoryPlot().getRenderer(); + r.setItemMargin(0); + + for(SupplyEdge edge : optionsPanel.supplyEdgesModel.getSelectedObjects()) { + if(optionsPanel.dataModel.getSelectedObjects().contains(ESTIMATED_DEMANDS) + && optionsPanel.supplyEdgesModel.getSelectedObjects().contains(edge)) { + dataset.addValue(demandsTab.getSimulator().getAggregatedEdgeDemands().get(edge).getTotalMass() + + demandsTab.getSimulator().getAggregatedNodeDemands().get(edge.getPoint()).getTotalMass(), + ESTIMATED_DEMANDS, edge); + r.setSeriesPaint(dataset.getRowCount() - 1, Color.RED); + } + if(optionsPanel.dataModel.getSelectedObjects().contains(RAW_CAPACITY) + && optionsPanel.supplyEdgesModel.getSelectedObjects().contains(edge)) { + dataset.addValue(edge.getRawCapacity(), RAW_CAPACITY, edge); + r.setSeriesPaint(dataset.getRowCount() - 1, Color.BLUE); + } + if(optionsPanel.dataModel.getSelectedObjects().contains(REMAINING_CAPACITY) + && optionsPanel.supplyEdgesModel.getSelectedObjects().contains(edge)) { + dataset.addValue(edge.getCapacity(), REMAINING_CAPACITY, edge); + r.setSeriesPaint(dataset.getRowCount() - 1, Color.GREEN); + } + } + + CategoryPlot plot = (CategoryPlot) chart.getPlot(); + plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + plot.setRangeGridlinesVisible(true); + plot.setDomainGridlinesVisible(true); + return chart; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/demand/SupplyNetworkTab.java b/src/main/java/edu/mit/spacenet/gui/demand/SupplyNetworkTab.java new file mode 100644 index 0000000..bc843cb --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/demand/SupplyNetworkTab.java @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.demand; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Vector; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.axis.SymbolAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import com.toedter.calendar.JDateChooser; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.scenario.SupplyEdge; +import edu.mit.spacenet.scenario.SupplyEdge.SupplyPoint; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Component for visualizing the supply network of the scenario. + * + * @author Paul Grogan + */ +public class SupplyNetworkTab extends JSplitPane { + private static final long serialVersionUID = -4728295622221432580L; + private static String DEMANDS = "Transport Demands"; + private static String RAW_CAPACITY = "Raw Capacity"; + private static String REMAINING_CAPACITY = "Remaining Capacity"; + private static String NET_CAPACITY = "Net Capacity"; + private static int MIN_THICKNESS = 1; + private static int MAX_THICKNESS = 8; + private static int MIN_SIZE = 4; + private static int MAX_SIZE = 20; + + private DemandsTab demandsTab; + + private OptionsPanel optionsPanel; + private ChartPanel chartPanel; + + public SupplyNetworkTab(DemandsTab demandsTab) { + this.demandsTab = demandsTab; + + chartPanel = new ChartPanel(); + setLeftComponent(chartPanel); + + optionsPanel = new OptionsPanel(); + setRightComponent(optionsPanel); + + setName("Supply Network"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(525); + } + + /** + * Initializes the tab for a new scenario. + */ + public void initialize() { + optionsPanel.initialize(); + chartPanel.initialize(); + } + + /** + * Updates the tab. + */ + public void updateView() { + optionsPanel.updateView(); + chartPanel.updateView(); + } + + /** + * Checks if auto refresh is enabled. + * + * @return true, if auto refresh is enabled + */ + private boolean isAutoRefresh() { + return SpaceNetSettings.getInstance().isAutoRefresh(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return demandsTab.getScenario(); + } + + /** + * The Class OptionsPanel. + */ + private class OptionsPanel extends JPanel { + private static final long serialVersionUID = -4714468679105858517L; + + private JDateChooser startDate, endDate; + private JCheckBox demandsCheck, capacitiesCheck; + private JComboBox transportDisplayCombo; + private CheckBoxTableModel supplyEdgesModel; + + private JButton refreshButton; + + /** + * Instantiates a new options panel. + * + * @param networkTab the network tab + */ + private OptionsPanel() { + setLayout(new GridBagLayout()); + setBorder(BorderFactory.createTitledBorder("Chart Options")); + + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Start Date: "), c); + c.gridy++; + add(new JLabel("End Date: "), c); + c.gridy++; + add(new JLabel("Display: "), c); + c.gridy = 0; + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + startDate = new JDateChooser(); + startDate.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + if(e.getPropertyName().equals("date")) + chartPanel.updateView(); + } + }); + add(startDate, c); + c.gridy++; + endDate = new JDateChooser(); + endDate.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + if(e.getPropertyName().equals("date")) + chartPanel.updateView(); + } + }); + add(endDate, c); + c.gridy++; + transportDisplayCombo = new JComboBox(); + transportDisplayCombo.addItem(DEMANDS); + transportDisplayCombo.addItem(RAW_CAPACITY); + transportDisplayCombo.addItem(REMAINING_CAPACITY); + transportDisplayCombo.addItem(NET_CAPACITY); + transportDisplayCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(transportDisplayCombo, c); + c.gridx--; + c.gridy++; + c.gridwidth = 2; + c.weightx = 1; + c.anchor = GridBagConstraints.FIRST_LINE_START; + demandsCheck = new JCheckBox("Label Aggregated Demands", true); + demandsCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(demandsCheck, c); + c.gridy++; + capacitiesCheck = new JCheckBox("Label Transports", true); + capacitiesCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + chartPanel.updateView(); + } + }); + add(capacitiesCheck, c); + c.gridy++; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + supplyEdgesModel = new CheckBoxTableModel(); + supplyEdgesModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE) + chartPanel.updateView(); + } + }); + JTable supplyEdgesTable = new JTable(supplyEdgesModel); + supplyEdgesTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + supplyEdgesTable.getTableHeader().setReorderingAllowed(false); + supplyEdgesTable.getColumnModel().getColumn(0).setMaxWidth(25); + supplyEdgesTable.getColumnModel().getColumn(1).setHeaderValue("Filter Supply Edges"); + supplyEdgesTable.setShowGrid(false); + JScrollPane supplyEdgesScroll = new JScrollPane(supplyEdgesTable); + supplyEdgesScroll.setPreferredSize(new Dimension(150,150)); + add(supplyEdgesScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel supplyEdgesButtonPanel = new JPanel(); + supplyEdgesButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllSupplyEdgesButton = new JButton("Select All"); + selectAllSupplyEdgesButton.setToolTipText("Select All Supply Edges"); + selectAllSupplyEdgesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + supplyEdgesModel.selectAll(); + } + }); + supplyEdgesButtonPanel.add(selectAllSupplyEdgesButton); + JButton deselectAllSupplyEdgesButton = new JButton("Deselect All"); + deselectAllSupplyEdgesButton.setToolTipText("Deselect All Supply Edges"); + deselectAllSupplyEdgesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + supplyEdgesModel.deselectAll(); + } + }); + supplyEdgesButtonPanel.add(deselectAllSupplyEdgesButton); + add(supplyEdgesButtonPanel, c); + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + refreshButton = new JButton("Refresh", new ImageIcon(getClass().getClassLoader().getResource("icons/arrow_refresh.png"))); + refreshButton.setVisible(false); + refreshButton.setToolTipText("Refresh Chart"); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + chartPanel.updateChart(); + } + }); + add(refreshButton, c); + } + + /** + * Initializes the panel. + */ + public void initialize() { + startDate.setEnabled(getScenario()!=null); + endDate.setEnabled(getScenario()!=null); + transportDisplayCombo.setEnabled(getScenario()!=null); + demandsCheck.setEnabled(getScenario()!=null); + capacitiesCheck.setEnabled(getScenario()!=null); + + if(getScenario()!=null) { + startDate.setSelectableDateRange(getScenario().getStartDate(), null); + endDate.setSelectableDateRange(getScenario().getStartDate(), null); + } + + supplyEdgesModel.clear(); + updateView(); + } + + /** + * Updates the view. + */ + public void updateView() { + // update supply edges + List deselectedSupplyEdges = supplyEdgesModel.getDeselectedObjects(); + TableModelListener[] modelListeners = supplyEdgesModel.getTableModelListeners(); + for(TableModelListener l : modelListeners) { + supplyEdgesModel.removeTableModelListener(l); + } + supplyEdgesModel.clear(); + ArrayList edges = new ArrayList(); + if(demandsTab.getSimulator()!=null) { + for(SupplyEdge edge : demandsTab.getSimulator().getSupplyEdges()) { + edges.add(edge); + } + } + Collections.reverse(edges); + for(SupplyEdge edge : edges) { + supplyEdgesModel.addObject(edge, !deselectedSupplyEdges.contains(edge)); + } + for(TableModelListener l : modelListeners) { + supplyEdgesModel.addTableModelListener(l); + } + supplyEdgesModel.fireTableDataChanged(); + + // update auto refresh button visibility + if(isAutoRefresh()) { + refreshButton.setVisible(false); + } else { + refreshButton.setVisible(true); + } + } + } + + /** + * The Class ChartPanel. + */ + private class ChartPanel extends SNChartPanel { + private static final long serialVersionUID = 4671269489085267359L; + + /** + * Initializes the chart. + */ + public void initialize() { + updateChart(); + } + + /** + * Updates the view. + */ + public void updateView() { + if(isAutoRefresh()) updateChart(); + } + + /** + * Updates the chart. + */ + public void updateChart() { + double minTime = optionsPanel.startDate.getDate()==null? + 0:Math.max(0, + DateFunctions.getDaysBetween( + getScenario().getStartDate(), + optionsPanel.startDate.getDate())); + double maxTime = optionsPanel.endDate.getDate()==null? + Double.MAX_VALUE:Math.max(minTime, + DateFunctions.getDaysBetween( + getScenario().getStartDate(), + optionsPanel.endDate.getDate())); + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, // title + "Date", // x-axis label + "Node", // y-axis label + dataset, // data + false, + true, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + SymbolAxis rangeAxis = createRangeAxis(); + plot.setRangeAxis(rangeAxis); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + double maxCapacity = 0; + double minCapacity = Double.MAX_VALUE; + double maxDemands = 0; + double minDemands = Double.MAX_VALUE; + for(SupplyEdge e : optionsPanel.supplyEdgesModel.getSelectedObjects()) { + double capacity = getCapacity(e); + if(Math.abs(capacity)maxCapacity) maxCapacity = Math.abs(capacity); + + SupplyPoint p = e.getPoint(); + if(demandsTab.getSimulator().getAggregatedNodeDemands().get(p).getTotalMass()maxDemands) + maxDemands = demandsTab.getSimulator().getAggregatedNodeDemands().get(p).getTotalMass(); + } + for(SupplyEdge e : optionsPanel.supplyEdgesModel.getSelectedObjects()) { + if(e.getStartTime() >= minTime && e.getEndTime() <= maxTime) { + double capacity = getCapacity(e); + TimeSeries s = new TimeSeries(e.toString(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), e.getStartTime())), + node2Number(e.getOrigin(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), e.getEndTime())), + node2Number(e.getDestination(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(0,0,0,0)); + int thickness = (int)(MIN_THICKNESS + (MAX_THICKNESS-MIN_THICKNESS)*(Math.abs(capacity)-minCapacity)/(maxCapacity-minCapacity+1)); + r.setSeriesStroke(dataset.getSeriesCount() - 1, new BasicStroke(thickness)); + if(capacity > 0) r.setSeriesPaint(dataset.getSeriesCount() - 1, new Color(0x66,0xff,0x66)); + else if(capacity == 0) r.setSeriesPaint(dataset.getSeriesCount() - 1, new Color(0x66,0x66,0x66)); + else r.setSeriesPaint(dataset.getSeriesCount() - 1, new Color(0xff,0,0)); + } + + SupplyPoint p = e.getPoint(); + if(p.getTime() >= minTime && p.getTime() <= maxTime) { + TimeSeries s = new TimeSeries(p.toString(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), p.getTime())), + node2Number(p.getNode(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, new Color(0x00,0x99,0xff)); + double size; + if(demandsTab.getSimulator().getAggregatedNodeDemands().get(p).getTotalMass()==0) { + size = 0; + } else { + size = MIN_SIZE+(MAX_SIZE-MIN_SIZE)*(demandsTab.getSimulator().getAggregatedNodeDemands().get(p).getTotalMass()-minDemands)/(maxDemands-minDemands+1); + } + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-size/2D, -size/2D, size, size)); + } + if(optionsPanel.demandsCheck.isSelected()&&demandsTab.getSimulator().getAggregatedNodeDemands().get(p).getTotalMass()>0) { + double x = new Hour(DateFunctions.getDate(getScenario().getStartDate(), p.getTime())).getFirstMillisecond(); + //x -= (p.getEdge().getEndTime()-p.getEdge().getStartTime())*24*3600*1000*2; + double y = node2Number(p.getNode(), rangeAxis);// + 0.25; + DecimalFormat format = new DecimalFormat("0"); + XYTextAnnotation annotation = new XYTextAnnotation(format.format(demandsTab.getSimulator().getAggregatedNodeDemands().get(p).getTotalMass()) + " kg", x, y); + annotation.setPaint(Color.BLACK); + r.addAnnotation(annotation); + } + } + if(optionsPanel.capacitiesCheck.isSelected()) { + for(SupplyEdge e : demandsTab.getSimulator().getSupplyEdges()) { + double x1 = new Hour(DateFunctions.getDate(getScenario().getStartDate(), (e.getStartTime()+e.getEndTime())/2D)).getFirstMillisecond(); + //x -= (e.getEndTime()-e.getStartTime())*24*3600*1000/2D; + double y1 = (node2Number(e.getDestination(), rangeAxis) + node2Number(e.getOrigin(), rangeAxis))/2D; + DecimalFormat format = new DecimalFormat("0"); + double capacity = getCapacity(e); + XYTextAnnotation capacityAnnotation; + if(optionsPanel.transportDisplayCombo.getSelectedItem()==DEMANDS) { + capacityAnnotation = new XYTextAnnotation( + format.format(Math.abs(capacity)) + " kg", x1, y1); + } else { + capacityAnnotation = new XYTextAnnotation( + format.format(capacity) + " kg", x1, y1); + } + double angle1 = Math.atan(-( + (node2Number(e.getDestination(), rangeAxis)-node2Number(e.getOrigin(), rangeAxis)) + /(plot.getRangeAxis().getUpperBound()-plot.getRangeAxis().getLowerBound())) + /((new Hour(DateFunctions.getDate(getScenario().getStartDate(), e.getEndTime())).getFirstMillisecond()-new Hour(DateFunctions.getDate(getScenario().getStartDate(), e.getStartTime())).getFirstMillisecond()) + /(plot.getDomainAxis().getUpperBound()-plot.getDomainAxis().getLowerBound()))); + capacityAnnotation.setRotationAngle(angle1); + capacityAnnotation.setPaint(Color.BLACK); + r.addAnnotation(capacityAnnotation); + } + } + + setChart(chart); + } + + private double getCapacity(SupplyEdge edge) { + double capacity = 0; + if(optionsPanel.transportDisplayCombo.getSelectedItem()==RAW_CAPACITY) { + for(I_Carrier carrier : edge.getCarriers()) { + capacity += carrier.getMaxCargoMass(); + } + } else if(optionsPanel.transportDisplayCombo.getSelectedItem()==REMAINING_CAPACITY) + capacity = edge.getCapacity(); + else if(optionsPanel.transportDisplayCombo.getSelectedItem()==DEMANDS) + capacity = -demandsTab.getSimulator().getAggregatedEdgeDemands().get(edge).getTotalMass(); + else + capacity = edge.getCapacity() - demandsTab.getSimulator().getAggregatedEdgeDemands().get(edge).getTotalMass(); + return capacity; + } + + /** + * Creates the range axis. + * + * @return the symbol axis + */ + private SymbolAxis createRangeAxis() { + Vector nodeLabels = new Vector(); + for (Node n : getScenario().getNetwork().getNodes()) { + nodeLabels.add(n.getName()); + } + String[] array = {}; + return new SymbolAxis(null, nodeLabels.toArray(array)); + } + + /** + * Node2 number. + * + * @param node the node + * @param axis the axis + * + * @return the int + */ + private int node2Number(Node node, SymbolAxis axis) { + for (int i = 0; i < axis.getSymbols().length; i++) { + if (axis.getSymbols()[i].equals(node.getName())) { + return i; + } + } + return -1; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/edge/AbstractEdgeEditorPanel.java b/src/main/java/edu/mit/spacenet/gui/edge/AbstractEdgeEditorPanel.java new file mode 100644 index 0000000..8985627 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/edge/AbstractEdgeEditorPanel.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.edge; + +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.network.edge.Edge; + +/** + * An abstract edge editor panel. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class AbstractEdgeEditorPanel extends JPanel { + private static final long serialVersionUID = 1827177893914135006L; + + private EdgeEditorDialog dialog; + + /** + * Instantiates a new abstract edge editor panel. + * + * @param dialog the dialog + */ + public AbstractEdgeEditorPanel(EdgeEditorDialog dialog) { + this.dialog = dialog; + } + + /** + * Gets the dialog. + * + * @return the dialog + */ + public EdgeEditorDialog getDialog() { + return dialog; + } + + /** + * Checks if is edge valid. + * + * @return true, if is edge valid + */ + public abstract boolean isEdgeValid(); + + /** + * Gets the edge. + * + * @return the edge + */ + public abstract Edge getEdge(); + + /** + * Save edge. + */ + public abstract void saveEdge(); +} diff --git a/src/main/java/edu/mit/spacenet/gui/edge/BurnEditorDialog.java b/src/main/java/edu/mit/spacenet/gui/edge/BurnEditorDialog.java new file mode 100644 index 0000000..0b0c022 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/edge/BurnEditorDialog.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.edge; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextArea; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.domain.network.edge.BurnType; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class BurnEditorDialog extends JDialog { + private static final long serialVersionUID = 4910581442994056108L; + + private Burn burn; + private SpaceEdgeEditorPanel panel; + + private JButton okButton; + private JButton cancelButton; + private JComboBox burnTypeCombo; + private SpinnerNumberModel timeModel, deltaVModel; + private JSpinner timeSpinner, deltaVSpinner; + private JTextArea descriptionText; + + /** + * Instantiates a new burn editor dialog. + * + * @param edgeDialog the edge dialog + * @param burn the burn + */ + private BurnEditorDialog(SpaceEdgeEditorPanel panel, Burn burn) { + super(panel.getDialog(), "Edit Burn", true); + this.burn = burn; + this.panel = panel; + buildDialog(); + initialize(); + } + + /** + * Builds the dialog. + */ + public void buildDialog(){ + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Burn Type: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + burnTypeCombo = new JComboBox(); + for(BurnType t : BurnType.values()) burnTypeCombo.addItem(t); + burnTypeCombo.setToolTipText("Type of burn: orbital maneuvering system (OMS) or reaction control system (RCS)"); + contentPanel.add(burnTypeCombo, c); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Burn Time: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + timeModel = new SpinnerNumberModel(0, 0, panel.getEdgeDuration(), GlobalParameters.getTimePrecision()); + timeSpinner = new JSpinner(timeModel); + timeSpinner.setPreferredSize(new Dimension(75,20)); + timeSpinner.setToolTipText("Time (after transport start) to perform burn [days]"); + contentPanel.add(new UnitsWrapper(timeSpinner, "days"), c); + + c.gridy++; + c.gridx=0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Delta-V: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + deltaVModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, 0.01); + deltaVSpinner = new JSpinner(deltaVModel); + deltaVSpinner.setPreferredSize(new Dimension(75,20)); + deltaVSpinner.setToolTipText("Required change in velocity to achieve [meters per second]"); + contentPanel.add(new UnitsWrapper(deltaVSpinner, "m/s"), c); + + c.gridy++; + c.gridx=0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Description: "), c); + + c.gridx++; + c.weightx = 1; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(5,10); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + contentPanel.add(new JScrollPane(descriptionText), c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.weighty = 0; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + okButton = new JButton(burn.getTid()<0?"Save":"Save", new ImageIcon(getClass().getClassLoader().getResource("icons/database_go.png"))); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveBurn(); + } + }); + buttonPanel.add(okButton); + + cancelButton = new JButton("Cancel", new ImageIcon(getClass().getClassLoader().getResource("icons/database.png"))); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPanel.add(cancelButton); + contentPanel.add(buttonPanel, c); + + setContentPane(contentPanel); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(burn!= null){ + burnTypeCombo.setSelectedItem(burn.getBurnType()); + timeModel.setValue(burn.getTime()); + deltaVModel.setValue(burn.getDeltaV()); + descriptionText.setText(burn.getDescription()); + } + } + + /** + * Gets the burn. + * + * @return the burn + */ + public Burn getBurn(){ + return this.burn; + } + + /** + * Saves the burn. + */ + public void saveBurn(){ + if(isBurnValid()) { + try { + burn.setBurnType((BurnType)burnTypeCombo.getSelectedItem()); + burn.setTime(timeModel.getNumber().doubleValue()); + burn.setDeltaV(deltaVModel.getNumber().doubleValue()); + burn.setDescription(descriptionText.getText()); + if(!panel.getBurnListModel().contains(burn)) { + panel.getBurnListModel().addElement(burn); + } + dispose(); + } catch (Exception e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(panel.getDialog(), + "SpaceNet Errror", + "An error occurred while saving the edge.", + JOptionPane.ERROR_MESSAGE); + } + } + } + + /** + * Checks if is burn valid. + * + * @return true, if is burn valid + */ + public boolean isBurnValid(){ + if(deltaVModel.getNumber().doubleValue()==0) { + JOptionPane.showMessageDialog(this, + "Please select a non-zero delta-v.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + return true; + } + + /** + * Creates and shows the and GUI. + * + * @param spaceEdgePanel the space edge panel + * @param burn the burn + * @param burnDuration the burn duration + */ + public static void createAndShowGUI(SpaceEdgeEditorPanel spaceEdgePanel, Burn burn) { + BurnEditorDialog d = new BurnEditorDialog(spaceEdgePanel, burn); + d.setMinimumSize(new Dimension(300,150)); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/edge/EdgeEditorDialog.java b/src/main/java/edu/mit/spacenet/gui/edge/EdgeEditorDialog.java new file mode 100644 index 0000000..26095ab --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/edge/EdgeEditorDialog.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.edge; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.EdgeType; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.gui.data.DataSourceDialog; +import edu.mit.spacenet.gui.renderer.EdgeTypeListCellRenderer; + +/** + * A dialog box used to edit edges. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class EdgeEditorDialog extends JDialog { + private static final long serialVersionUID = -2553839031446779844L; + + private Edge edge; + private AbstractEdgeEditorPanel edgePanel; + private DataSourceDialog dialog; + + private JButton okButton; + private JButton cancelButton; + private JComboBox edgeTypeCombo; + + /** + * Instantiates a new edge editor dialog editor. + * + * @param editorFrame the editor frame + * @param edge the edge + */ + private EdgeEditorDialog(DataSourceDialog dialog, Edge edge) { + super(dialog, "Edit Edge", true); + this.dialog = dialog; + this.edge = edge; + buildDialog(); + initialize(); + } + + /** + * Builds the dialog. + */ + private void buildDialog(){ + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Type: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + edgeTypeCombo = new JComboBox(); + for(EdgeType t : EdgeType.values()) + if (t.getName()!="Time-Dependent") edgeTypeCombo.addItem(t); + edgeTypeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED && (edge.getEdgeType()!=e.getItem())) { + switch((EdgeType)e.getItem()) { + case FLIGHT: + edge = new FlightEdge(); + reset(); + break; + case SPACE: + edge = new SpaceEdge(); + reset(); + break; + case SURFACE: + edge = new SurfaceEdge(); + reset(); + break; + } + } + } + }); + edgeTypeCombo.setRenderer(new EdgeTypeListCellRenderer()); + edgeTypeCombo.setEnabled(edge.getTid()<0); + contentPanel.add(edgeTypeCombo, c); + + /* + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + JButton addNodeButton = new JButton("Add Nodes", new ImageIcon(getClass().getClassLoader().getResource("icons/asterisk_add.png"))); + addNodeButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + NodeEditorDialog.createAndShowGUI(dialog, new OrbitalNode()); + } + }); + contentPanel.add(addNodeButton,c); + */ + + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.weightx = 1; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + edgePanel = EdgeEditorPanelFactory.createEdgePanel(this, edge); + contentPanel.add(edgePanel, c); + + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + okButton = new JButton(edge.getTid()<0?"Add":"Save", new ImageIcon(getClass().getClassLoader().getResource("icons/database_go.png"))); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveEdge(); + } + }); + buttonPanel.add(okButton); + + cancelButton = new JButton("Cancel", new ImageIcon(getClass().getClassLoader().getResource("icons/database.png"))); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPanel.add(cancelButton); + contentPanel.add(buttonPanel, c); + + setContentPane(contentPanel); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(edge!=null){ + edgeTypeCombo.setSelectedItem(edge.getEdgeType()); + } + } + + /** + * Resets the components after the edge type is changed. + */ + private void reset() { + getContentPane().remove(edgePanel); + edgePanel = EdgeEditorPanelFactory.createEdgePanel(this, edge); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 1; + c.weightx = 1; + c.weighty = 1; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + getContentPane().add(edgePanel, c); + validate(); + pack(); + repaint(); + } + + /** + * Gets the edge panel. + * + * @return the edge panel + */ + public AbstractEdgeEditorPanel getEdgePanel(){ + return this.edgePanel; + } + + /** + * Gets the edge. + * + * @return the edge + */ + public Edge getEdge(){ + return this.edge; + } + + /** + * Gets the dialog. + * + * @return the dialog + */ + public DataSourceDialog getDialog() { + return dialog; + } + + /** + * Save the edge. + */ + public void saveEdge(){ + if(edgePanel.isEdgeValid()) { + edgePanel.saveEdge(); + try { + dialog.getDataSource().saveEdge(getEdge()); + dialog.loadDataSource(); + dispose(); + } catch (Exception e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(dialog, + "SpaceNet Errror", + "An error occurred while saving the edge.", + JOptionPane.ERROR_MESSAGE); + } + } + } + + /** + * Creates and shows the GUI. + * + * @param editorFrame the editor frame + * @param edge the edge + */ + public static void createAndShowGUI(DataSourceDialog dialog, Edge edge) { + EdgeEditorDialog d = new EdgeEditorDialog(dialog, edge); + d.setMinimumSize(new Dimension(300,150)); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/edge/EdgeEditorPanelFactory.java b/src/main/java/edu/mit/spacenet/gui/edge/EdgeEditorPanelFactory.java new file mode 100644 index 0000000..a8f80b8 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/edge/EdgeEditorPanelFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.edge; + +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.EdgeType; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; + +/** + * A factory for creating EdgePanelEditor objects. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class EdgeEditorPanelFactory { + + /** + * Creates a new EdgePanelEditor object. + * + * @param edge the edge + * + * @return the abstract edge panel editor + */ + public static AbstractEdgeEditorPanel createEdgePanel(EdgeEditorDialog dialog, Edge edge) { + if(edge.getEdgeType()==EdgeType.SPACE) + return new SpaceEdgeEditorPanel(dialog, (SpaceEdge)edge); + else if (edge.getEdgeType()==EdgeType.FLIGHT){ + return new FlightEdgeEditorPanel(dialog, (FlightEdge)edge); + } + else if (edge.getEdgeType()==EdgeType.SURFACE){ + return new SurfaceEdgeEditorPanel(dialog, (SurfaceEdge)edge); + } + else return null; // check for other types of edges + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/edge/FlightEdgeEditorPanel.java b/src/main/java/edu/mit/spacenet/gui/edge/FlightEdgeEditorPanel.java new file mode 100644 index 0000000..ae2d4e6 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/edge/FlightEdgeEditorPanel.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.edge; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.renderer.NodeListCellRenderer; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A panel used to edit flight edges. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class FlightEdgeEditorPanel extends AbstractEdgeEditorPanel { + private static final long serialVersionUID = 6489837201474688317L; + + private FlightEdge edge; + + private JComboBox originCombo, destinationCombo; + private JTextField nameText; + private SpinnerNumberModel durationModel, maxCargoModel, maxCrewModel; + private JSpinner durationSpinner, maxCargoSpinner, maxCrewSpinner; + private JTextArea descriptionText; + + /** + * Instantiates a new flight edge panel editor. + * + * @param edge the edge + */ + public FlightEdgeEditorPanel(EdgeEditorDialog dialog, FlightEdge edge) { + super(dialog); + this.edge = edge; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + public void buildPanel(){ + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Name: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText= new JTextField(); + add(nameText, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Origin: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + originCombo = new JComboBox(); + originCombo.setRenderer(new NodeListCellRenderer()); + for(Node t : getDialog().getDialog().getDataSource().getNodeLibrary()) + originCombo.addItem(t); + originCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + edge.setOrigin((Node)e.getItem());}} + }); + add(originCombo, c); + originCombo.setToolTipText("Origin node of the abstracted flight"); + + c.gridx++; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Destination: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + destinationCombo = new JComboBox(); + destinationCombo.setRenderer(new NodeListCellRenderer()); + for(Node t : getDialog().getDialog().getDataSource().getNodeLibrary()) + destinationCombo.addItem(t); + destinationCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + edge.setDestination((Node)e.getItem());}} + }); + add(destinationCombo, c); + destinationCombo.setToolTipText("Destination node of the abstracted flight"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Time Duration:"), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + durationModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, GlobalParameters.getTimePrecision()); + durationSpinner = new JSpinner(durationModel); + durationSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(durationSpinner, "days"), c); + durationSpinner.setToolTipText("Total duration of the abstracted flight between origin and destination [days]"); + + c.gridx = 0; + c.gridy++; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Maximum Crew: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + maxCrewModel = new SpinnerNumberModel(0,0,Integer.MAX_VALUE, 1); + maxCrewSpinner = new JSpinner(maxCrewModel); + maxCrewSpinner.setPreferredSize(new Dimension(75,20)); + add(maxCrewSpinner, c); + maxCrewSpinner.setToolTipText("Maximum number of human crew members allowed"); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Maximum Mass: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + maxCargoModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, GlobalParameters.getMassPrecision()); + maxCargoSpinner = new JSpinner(maxCargoModel); + maxCargoSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(maxCargoSpinner, "kg"), c); + maxCargoSpinner.setToolTipText("Maximum cargo mass allowed [kilograms]"); + + c.gridy++; + c.gridx = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Description: "), c); + + c.gridx++; + c.weighty = 1; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(5,10); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + add(new JScrollPane(descriptionText), c); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(edge!= null){ + originCombo.setSelectedItem(edge.getOrigin()); + destinationCombo.setSelectedItem(edge.getDestination()); + nameText.setText(edge.getName()); + durationModel.setValue(edge.getDuration()); + maxCrewModel.setValue(edge.getMaxCrewSize()); + maxCargoModel.setValue(edge.getMaxCargoMass()); + descriptionText.setText(edge.getDescription()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.edge.AbstractEdgePanelEditor#getEdge() + */ + public FlightEdge getEdge() { + return edge; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.edge.AbstractEdgePanelEditor#isEdgeValid() + */ + public boolean isEdgeValid() { + if(nameText.getText().length()==0){ + JOptionPane.showMessageDialog(getDialog(), + "Please enter an edge name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(originCombo.getSelectedItem()==null){ + JOptionPane.showMessageDialog(getDialog(), + "Please select an origin node.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(destinationCombo.getSelectedItem()==null){ + JOptionPane.showMessageDialog(getDialog(), + "Please select a destination node.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(originCombo.getSelectedItem()==destinationCombo.getSelectedItem()){ + JOptionPane.showMessageDialog(getDialog(), + "Origin node cannot also be the destination node.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.edge.AbstractEdgePanelEditor#saveEdge() + */ + public void saveEdge() { + edge.setName(nameText.getText()); + edge.setOrigin((Node)originCombo.getSelectedItem()); + edge.setDestination((Node)destinationCombo.getSelectedItem()); + edge.setDuration(durationModel.getNumber().doubleValue()); + edge.setMaxCargoMass(maxCargoModel.getNumber().doubleValue()); + edge.setMaxCrewSize(maxCrewModel.getNumber().intValue()); + edge.setDescription(descriptionText.getText()); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/edge/SpaceEdgeEditorPanel.java b/src/main/java/edu/mit/spacenet/gui/edge/SpaceEdgeEditorPanel.java new file mode 100644 index 0000000..8ec1b76 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/edge/SpaceEdgeEditorPanel.java @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.edge; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.renderer.BurnListCellRenderer; +import edu.mit.spacenet.gui.renderer.NodeListCellRenderer; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A panel used to edit space edges. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class SpaceEdgeEditorPanel extends AbstractEdgeEditorPanel { + private static final long serialVersionUID = -2875579231969740002L; + + private SpaceEdge edge; + + private JComboBox originCombo, destinationCombo; + private JTextField nameText; + private SpinnerNumberModel durationModel; + private JSpinner durationSpinner; + private JTextArea descriptionText; + private DefaultListModel burnListModel; + private JList burnList; + private JButton addBurnButton, editBurnButton, removeBurnButton, + moveBurnUpButton, moveBurnDownButton; + + /** + * Instantiates a new space edge editor panel. + * + * @param edge the edge + */ + public SpaceEdgeEditorPanel(EdgeEditorDialog dialog, SpaceEdge edge) { + super(dialog); + this.edge = edge; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + public void buildPanel(){ + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Name: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText= new JTextField(); + add(nameText, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Origin: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + originCombo = new JComboBox(); + originCombo.setRenderer(new NodeListCellRenderer()); + for(Node t : getDialog().getDialog().getDataSource().getNodeLibrary()) + originCombo.addItem(t); + originCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + edge.setOrigin((Node)e.getItem());}} + }); + add(originCombo, c); + originCombo.setToolTipText("Origin node of trajectory"); + + c.gridx++; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Destination: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + destinationCombo = new JComboBox(); + destinationCombo.setRenderer(new NodeListCellRenderer()); + for(Node t : getDialog().getDialog().getDataSource().getNodeLibrary()) + destinationCombo.addItem(t); + destinationCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + edge.setDestination((Node)e.getItem());}} + }); + add(destinationCombo, c); + destinationCombo.setToolTipText("Destination node of trajectory"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Duration:"), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + durationModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, GlobalParameters.getTimePrecision()); + durationSpinner = new JSpinner(durationModel); + durationSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(durationSpinner, "days"), c); + durationSpinner.setToolTipText("Total duration for the trajectory between origin and destination [days]"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.weighty = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Burns: "), c); + + c.gridx++; + c.weighty = 1; + c.weightx = 1; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + burnListModel = new DefaultListModel(); + burnList = new JList(burnListModel); + burnList.setCellRenderer(new BurnListCellRenderer()); + burnList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + updateButtons(); + } + }); + JScrollPane burnScroll = new JScrollPane(burnList); + burnScroll.setPreferredSize(new Dimension(200,75)); + add(burnScroll, c); + + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0)); + buttonPanel.setOpaque(false); + addBurnButton = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/add.png"))); + addBurnButton.setOpaque(false); + addBurnButton.setMargin(new Insets(3,3,3,3)); + addBurnButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + BurnEditorDialog.createAndShowGUI(getThis(), new Burn()); + } + }); + buttonPanel.add(addBurnButton); + editBurnButton = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/cog.png"))); + editBurnButton.setOpaque(false); + editBurnButton.setMargin(new Insets(3,3,3,3)); + editBurnButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + BurnEditorDialog.createAndShowGUI(getThis(), (Burn)burnListModel.getElementAt(burnList.getSelectedIndex())); + } + }); + buttonPanel.add(editBurnButton); + removeBurnButton = new JButton("Delete", new ImageIcon(getClass().getClassLoader().getResource("icons/delete.png"))); + removeBurnButton.setOpaque(false); + removeBurnButton.setMargin(new Insets(3,3,3,3)); + removeBurnButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for(int i : burnList.getSelectedIndices()){ + burnListModel.remove(i); + } + burnList.clearSelection(); + burnList.repaint(); + }} + ); + buttonPanel.add(removeBurnButton); + moveBurnUpButton = new JButton("Up"); + moveBurnUpButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Burn burn = (Burn)burnList.getSelectedValue(); + burnListModel.set(burnList.getSelectedIndex(), burnListModel.get(burnList.getSelectedIndex()-1)); + burnListModel.set(burnList.getSelectedIndex()-1, burn); + burnList.setSelectedIndex(burnList.getSelectedIndex()-1); + burnList.repaint(); + }} + ); + moveBurnUpButton.setEnabled(false); + buttonPanel.add(moveBurnUpButton); + moveBurnDownButton = new JButton("Down"); + moveBurnDownButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Burn burn = (Burn)burnList.getSelectedValue(); + burnListModel.set(burnList.getSelectedIndex(), burnListModel.get(burnList.getSelectedIndex()+1)); + burnListModel.set(burnList.getSelectedIndex()+1, burn); + burnList.setSelectedIndex(burnList.getSelectedIndex()+1); + burnList.repaint(); + }} + ); + moveBurnDownButton.setEnabled(false); + buttonPanel.add(moveBurnDownButton); + + add(buttonPanel, c); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Description: "), c); + + c.gridx++; + c.weighty = 1; + c.weightx = 1; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(5,5); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + add(new JScrollPane(descriptionText), c); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(edge!= null){ + originCombo.setSelectedItem(edge.getOrigin()); + destinationCombo.setSelectedItem(edge.getDestination()); + nameText.setText(edge.getName()); + durationModel.setValue(edge.getDuration()); + descriptionText.setText(edge.getDescription()); + burnListModel.clear(); + for(Burn burn : edge.getBurns()) { + burnListModel.addElement(burn); + } + } + } + + /* (non-Javadoc) + * @see javax.swing.JComponent#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + super.paint(g); + burnList.repaint(); + updateButtons(); + } + + /** + * Gets the burn list model. + * + * @return the burn list model + */ + public DefaultListModel getBurnListModel() { + return burnListModel; + } + + /** + * Gets the burn list. + * + * @return the burn list + */ + public JList getBurnList() { + return burnList; + } + + /** + * Update buttons. + */ + private void updateButtons() { + editBurnButton.setEnabled(burnList.getSelectedIndices().length==1); + removeBurnButton.setEnabled(burnList.getSelectedIndices().length>0); + moveBurnUpButton.setEnabled(burnList.getSelectedIndices().length==1 + && burnListModel.size()>1 + && burnList.getSelectedIndex()>0 + && ((Burn)burnListModel.get(burnList.getSelectedIndex())).getTime() + == ((Burn)burnListModel.get(burnList.getSelectedIndex()-1)).getTime()); + moveBurnDownButton.setEnabled(burnList.getSelectedIndices().length>0 + && burnListModel.size()>1 + && burnList.getSelectedIndex(). + */ +package edu.mit.spacenet.gui.edge; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.NodeType; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.renderer.NodeListCellRenderer; + +/** + * A panel used to edit a surface edge. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class SurfaceEdgeEditorPanel extends AbstractEdgeEditorPanel { + private static final long serialVersionUID = -2875579231969740002L; + + private SurfaceEdge edge; + + private JComboBox originCombo, destinationCombo; + private JTextField nameText; + private SpinnerNumberModel distanceModel; + private JSpinner distanceSpinner; + private JTextArea descriptionText; + + /** + * Instantiates a new surface edge panel editor. + * + * @param edge the edge + */ + public SurfaceEdgeEditorPanel(EdgeEditorDialog dialog, SurfaceEdge edge) { + super(dialog); + this.edge = edge; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel(){ + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Name: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText= new JTextField(); + add(nameText, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Origin: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + originCombo = new JComboBox(); + originCombo.setRenderer(new NodeListCellRenderer()); + for(Node t : getDialog().getDialog().getDataSource().getNodeLibrary()) + if(t.getNodeType()==NodeType.SURFACE) originCombo.addItem(t); + originCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + edge.setOrigin((Node)e.getItem());}} + }); + add(originCombo, c); + originCombo.setToolTipText("Origin node of path"); + + c.gridx++; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Destination: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + destinationCombo = new JComboBox(); + destinationCombo.setRenderer(new NodeListCellRenderer()); + for(Node t : getDialog().getDialog().getDataSource().getNodeLibrary()) + if(t.getNodeType()==NodeType.SURFACE) destinationCombo.addItem(t); + destinationCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + edge.setDestination((Node)e.getItem());}} + }); + add(destinationCombo, c); + destinationCombo.setToolTipText("Destination node of path"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Distance: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + distanceModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, 0.01); + distanceSpinner = new JSpinner(distanceModel); + distanceSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(distanceSpinner, "km"), c); + distanceSpinner.setToolTipText("Distance between origin and destination along path [kilometers]"); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Description: "), c); + + c.gridx++; + c.weighty = 1; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(5,10); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + add(new JScrollPane(descriptionText), c); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(edge!= null){ + originCombo.setSelectedItem(edge.getOrigin()); + destinationCombo.setSelectedItem(edge.getDestination()); + nameText.setText(edge.getName()); + distanceModel.setValue(edge.getDistance()); + descriptionText.setText(edge.getDescription()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.edge.AbstractEdgePanelEditor#getEdge() + */ + public SurfaceEdge getEdge() { + return edge; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.edge.AbstractEdgePanelEditor#isEdgeValid() + */ + public boolean isEdgeValid() { + if(nameText.getText().length()==0){ + JOptionPane.showMessageDialog(getDialog(), + "Please enter an edge name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(originCombo.getSelectedItem()==null){ + JOptionPane.showMessageDialog(getDialog(), + "Please select an origin node.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(destinationCombo.getSelectedItem()==null){ + JOptionPane.showMessageDialog(getDialog(), + "Please select a destination node.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(originCombo.getSelectedItem()==destinationCombo.getSelectedItem()){ + JOptionPane.showMessageDialog(getDialog(), + "Origin node cannot also be the destination node.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.edge.AbstractEdgePanelEditor#saveEdge() + */ + public void saveEdge() { + edge.setName(nameText.getText()); + edge.setOrigin((Node)originCombo.getSelectedItem()); + edge.setDestination((Node)destinationCombo.getSelectedItem()); + edge.setDistance(distanceModel.getNumber().doubleValue()); + edge.setDescription(descriptionText.getText()); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/AbstractElementPanel.java b/src/main/java/edu/mit/spacenet/gui/element/AbstractElementPanel.java new file mode 100644 index 0000000..4beae4a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/AbstractElementPanel.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.element.I_Element; + +/** + * Abstract component that serves as an interface to the various element panels. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class AbstractElementPanel extends JPanel { + private static final long serialVersionUID = 4132394191670439311L; + + private ElementDialog elementDialog; + + /** + * The constructor. + * + * @param elementDialog the element dialog component + * @param element the element + */ + public AbstractElementPanel(ElementDialog elementDialog, I_Element element) { + this.elementDialog = elementDialog; + } + + /** + * Requests that the dialog save all element-specific data. + */ + public abstract void saveElement(); + + /** + * Gets the element dialog component. + * + * @return the element dialog + */ + public ElementDialog getElementDialog() { + return elementDialog; + } + + /** + * Checks if is vertically expandable. + * + * @return true, if is vertically expandable + */ + public abstract boolean isVerticallyExpandable(); + + /** + * Gets the element. + * + * @return the element + */ + public abstract I_Element getElement(); + + /** + * Checks if is element valid. + * + * @return true, if is element valid + */ + public abstract boolean isElementValid(); + +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/CarrierPanel.java b/src/main/java/edu/mit/spacenet/gui/element/CarrierPanel.java new file mode 100644 index 0000000..9b186ed --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/CarrierPanel.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.element.Carrier; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Element panel for viewing and editing carrier-specific inputs. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class CarrierPanel extends AbstractElementPanel { + private static final long serialVersionUID = 6335483106289763369L; + + private Carrier carrier; + + private JSpinner maxCrewSpinner, maxCargoMassSpinner, maxCargoVolumeSpinner; + private SpinnerNumberModel maxCargoMassModel, maxCargoVolumeModel, maxCrewModel; + private JComboBox cargoEnvironmentCombo; + + /** + * Instantiates a new carrier panel. + * + * @param elementDialog the element dialog + * @param carrier the carrier + */ + public CarrierPanel(ElementDialog elementDialog, Carrier carrier) { + super(elementDialog, carrier); + this.carrier = carrier; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridy = 0; + c.gridx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Cargo Environment: "), c); + c.gridx+=2; + add(new JLabel("Max Crew Size: "), c); + c.gridx = 0; + c.gridy++; + add(new JLabel("Max Cargo Mass: "), c); + c.gridx+=2; + add(new JLabel("Max Cargo Volume: "), c); + + c.gridy = 0; + c.gridx = 1; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + cargoEnvironmentCombo = new JComboBox(); + for(Environment e : Environment.values()) { + cargoEnvironmentCombo.addItem(e); + } + add(cargoEnvironmentCombo, c); + cargoEnvironmentCombo.setToolTipText("Storage environment available for nested elements"); + + c.gridx+=2; + maxCrewModel = new SpinnerNumberModel(0,0,Integer.MAX_VALUE,1); + maxCrewSpinner = new JSpinner(maxCrewModel); + maxCrewSpinner.setPreferredSize(new Dimension(150,20)); + add(maxCrewSpinner, c); + maxCrewSpinner.setToolTipText("Maximum number of nested crew"); + + c.gridx = 1; + c.gridy++; + maxCargoMassModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + maxCargoMassSpinner = new JSpinner(maxCargoMassModel); + maxCargoMassSpinner.setPreferredSize(new Dimension(150,20)); + add(new UnitsWrapper(maxCargoMassSpinner, "kg"),c); + maxCargoMassSpinner.setToolTipText("Maximum mass of nested elements [kilograms]"); + + c.gridx+=2; + maxCargoVolumeModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getVolumePrecision()); + maxCargoVolumeSpinner = new JSpinner(maxCargoVolumeModel); + maxCargoVolumeSpinner.setPreferredSize(new Dimension(150,20)); + add(new UnitsWrapper(maxCargoVolumeSpinner, "m^3"),c); + maxCargoVolumeSpinner.setToolTipText("Maximum volume of nested elements [cubic meters]"); + } + + /** + * Initializes the panel components for a carrier. + */ + private void initialize() { + cargoEnvironmentCombo.setSelectedItem(carrier.getCargoEnvironment()); + maxCargoMassModel.setValue(carrier.getMaxCargoMass()); + maxCargoVolumeModel.setValue(carrier.getMaxCargoVolume()); + maxCrewModel.setValue(carrier.getMaxCrewSize()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#getElement() + */ + @Override + public Carrier getElement() { + return carrier; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#saveElement() + */ + @Override + public void saveElement() { + carrier.setCargoEnvironment((Environment)cargoEnvironmentCombo.getSelectedItem()); + carrier.setMaxCargoMass(maxCargoMassModel.getNumber().doubleValue()); + carrier.setMaxCargoVolume(maxCargoVolumeModel.getNumber().doubleValue()); + carrier.setMaxCrewSize(maxCrewModel.getNumber().intValue()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isElementValid() + */ + @Override + public boolean isElementValid() { + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isVerticallyExpandable() + */ + public boolean isVerticallyExpandable() { + return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/CrewMemberPanel.java b/src/main/java/edu/mit/spacenet/gui/element/CrewMemberPanel.java new file mode 100644 index 0000000..e3130cb --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/CrewMemberPanel.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.Dimension; +import java.awt.FlowLayout; + +import javax.swing.JLabel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.gui.component.UnitsWrapper; + +/** + * Element panel for viewing and editing crew member-specific inputs. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class CrewMemberPanel extends AbstractElementPanel { + private static final long serialVersionUID = 6335483106289763369L; + + private CrewMember person; + + private SpinnerNumberModel availableTimeFractionModel; + private JSpinner availableTimeFractionSpinner; + + /** + * Instantiates a new crew member panel. + * + * @param elementDialog the element dialog + * @param person the person + */ + public CrewMemberPanel(ElementDialog elementDialog, CrewMember person) { + super(elementDialog, person); + this.person = person; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setOpaque(false); + setLayout(new FlowLayout(FlowLayout.LEFT)); + add(new JLabel("Available Time Fraction: ")); + + availableTimeFractionModel = new SpinnerNumberModel(0,0,1,0.01); + availableTimeFractionSpinner = new JSpinner(availableTimeFractionModel); + availableTimeFractionSpinner.setPreferredSize(new Dimension(60,20)); + add(new UnitsWrapper(availableTimeFractionSpinner, "")); + availableTimeFractionSpinner.setToolTipText("Fraction of time crew member is available to perform tasks or exploration"); + } + + /** + * Initializes the panel for a new crew member. + */ + private void initialize() { + availableTimeFractionModel.setValue(person.getAvailableTimeFraction()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#getElement() + */ + @Override + public CrewMember getElement() { + return person; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#saveElement() + */ + @Override + public void saveElement() { + person.setAvailableTimeFraction(availableTimeFractionModel.getNumber().doubleValue()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isElementValid() + */ + @Override + public boolean isElementValid() { + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isVerticallyExpandable() + */ + public boolean isVerticallyExpandable() { + return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/ElementDialog.java b/src/main/java/edu/mit/spacenet/gui/element/ElementDialog.java new file mode 100644 index 0000000..4589ff6 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/ElementDialog.java @@ -0,0 +1,722 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.element.ElementFactory; +import edu.mit.spacenet.domain.element.ElementIcon; +import edu.mit.spacenet.domain.element.ElementType; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.element.State; +import edu.mit.spacenet.domain.resource.ResourceType; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.data.DataSourceDialog; +import edu.mit.spacenet.gui.event.EventDialog; +import edu.mit.spacenet.gui.renderer.ElementTypeListCellRenderer; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Component for viewing and editing elements. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class ElementDialog extends JDialog { + private static final long serialVersionUID = 5400688589831319535L; + + private I_Element element; + private EventDialog eventDialog; + private DataSourceDialog dataSourceDialog; + + private JComboBox typeCombo; + private JTextField nameText; + private JComboBox iconCombo, classOfSupplyCombo, environmentCombo; + private SpinnerNumberModel accommodationMassModel, massModel, volumeModel; + private JSpinner accommodationMassSpinner, massSpinner, volumeSpinner; + private I_State initialState; + private DefaultListModel statesModel, partsModel; + private JList statesList, partsList; + private JButton editStateButton, setInitialStateButton, removeStateButton, + editPartButton, removePartButton; + private List elementPanels; + private JButton okButton; + + /** + * The constructor. + * + * @param dialog the event dialog + * @param element the element + */ + public ElementDialog(EventDialog dialog, I_Element element) { + super(dialog, "Edit Element", true); + this.eventDialog = dialog; + this.element = element; + buildDialog(); + initialize(); + setMinimumSize(new Dimension(300,150)); + setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + } + + /** + * Instantiates a new element dialog. + * + * @param dialog the dialog + * @param element the element + */ + public ElementDialog(DataSourceDialog dialog, I_Element element) { + super(dialog, "Edit Element", true); + this.dataSourceDialog = dialog; + this.element = element; + buildDialog(); + initialize(); + setMinimumSize(new Dimension(300,150)); + } + + /** + * Builds the dialog. + */ + private void buildDialog() { + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + contentPanel.add(new JLabel("Type: "), c); + c.gridy++; + contentPanel.add(new JLabel("Name: "), c); + c.gridy++; + contentPanel.add(new JLabel("Icon: "), c); + c.gridy++; + contentPanel.add(new JLabel("Class of Supply: "), c); + c.gridy++; + contentPanel.add(new JLabel("Environment: "), c); + c.gridx+=2; + contentPanel.add(new JLabel("Accommodation Mass: "), c); + c.gridy++; + c.gridx = 0; + contentPanel.add(new JLabel("Mass: "), c); + c.gridx+=2; + contentPanel.add(new JLabel("Volume: "), c); + + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.gridx = 1; + c.gridy = 0; + c.gridwidth = 3; + typeCombo = new JComboBox(); + for(ElementType t : ElementType.values()) + if(t!=ElementType.RESOURCE_TANK) typeCombo.addItem(t); // TODO add support / datasource + typeCombo.setRenderer(new ElementTypeListCellRenderer()); + typeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(typeCombo.getSelectedItem()!=element.getElementType()) + reset((ElementType)typeCombo.getSelectedItem()); + } + }); + contentPanel.add(typeCombo, c); + + c.gridy++; + c.fill = GridBagConstraints.HORIZONTAL; + nameText = new JTextField(); + contentPanel.add(nameText, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + c.gridwidth = 3; + JPanel iconPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); + iconCombo = new JComboBox(); + for(ElementIcon i : ElementIcon.values()) { + iconCombo.addItem(i); + } + iconCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -2255885956722142642L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setIcon(((ElementIcon)value).getIcon()); + setText(((ElementIcon)value).getName()); + return this; + } + }); + iconPanel.add(iconCombo); + JPanel dividerPanel = new JPanel(); + dividerPanel.setPreferredSize(new Dimension(5,1)); + iconPanel.add(dividerPanel); + JButton resetIconButton = new JButton("Reset"); + resetIconButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + iconCombo.setSelectedItem(element.getElementType().getIconType()); + } + }); + iconPanel.add(resetIconButton); + contentPanel.add(iconPanel, c); + + c.gridy++; + c.fill = GridBagConstraints.NONE; + c.gridwidth = 3; + classOfSupplyCombo = new JComboBox(); + for(ClassOfSupply cos : ClassOfSupply.values()) + classOfSupplyCombo.addItem(cos); + contentPanel.add(classOfSupplyCombo, c); + + c.gridy++; + c.gridwidth = 1; + environmentCombo = new JComboBox(); + for(Environment e : Environment.values()) + environmentCombo.addItem(e); + contentPanel.add(environmentCombo, c); + environmentCombo.setToolTipText("Required environment for nesting"); + + c.gridx+=2; + accommodationMassModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + accommodationMassSpinner = new JSpinner(accommodationMassModel); + accommodationMassSpinner.setPreferredSize(new Dimension(150,20)); + accommodationMassSpinner.setEnabled(false); // TODO disabled + contentPanel.add(new UnitsWrapper(accommodationMassSpinner, "kg"), c); + accommodationMassSpinner.setToolTipText("Additional mass of COS 5 required to nest inside a carrier [kilograms]"); + + c.gridy++; + c.gridx = 1; + c.weightx = 1; + massModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + massSpinner = new JSpinner(massModel); + massSpinner.setPreferredSize(new Dimension(150,20)); + contentPanel.add(new UnitsWrapper(massSpinner, "kg"), c); + massSpinner.setToolTipText("Dry element mass [kilograms]"); + + c.gridx+=2; + c.weightx = 1; + volumeModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getVolumePrecision()); + volumeSpinner = new JSpinner(volumeModel); + volumeSpinner.setPreferredSize(new Dimension(150,20)); + contentPanel.add(new UnitsWrapper(volumeSpinner, "m^3"), c); + volumeSpinner.setToolTipText("Element volume [cubic meters]"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + c.weighty = 1; + contentPanel.add(buildStatesPanel(), c); + + c.gridx+=2; + contentPanel.add(buildPartsPanel(), c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 4; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + elementPanels = ElementPanelFactory.createElementPanel(this, element); + for(AbstractElementPanel panel : elementPanels) { + c.weighty = panel.isVerticallyExpandable()?1:0; + contentPanel.add(panel, c); + c.gridy++; + } + + c.gridy+=10; // give space for up to 10 more element panels + c.weighty = 0; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + contentPanel.add(buttonPanel, c); + okButton = new JButton("OK", new ImageIcon(getClass().getClassLoader().getResource("icons/brick_go.png"))); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveElement(); + } + }); + buttonPanel.add(okButton); + JButton cancelButton = new JButton("Cancel", new ImageIcon(getClass().getClassLoader().getResource("icons/brick_delete.png"))); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPanel.add(cancelButton); + + getRootPane().setDefaultButton(okButton); + setContentPane(contentPanel); + } + + /** + * Builds the states panel. + * + * @return the j panel + */ + private JPanel buildStatesPanel() { + JPanel statesPanel = new JPanel(); + statesPanel.setBorder(BorderFactory.createTitledBorder("States")); + statesPanel.setLayout(new BorderLayout()); + + statesModel = new DefaultListModel(); + statesList = new JList(statesModel); + statesList.setCellRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + label.setIcon((((I_State)value).getStateType()).getIcon()); + if(value.equals(initialState)) { + label.setFont(label.getFont().deriveFont(Font.BOLD)); + } else { + label.setFont(label.getFont().deriveFont(Font.PLAIN)); + } + return label; + } + }); + statesList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2 && statesList.getSelectedIndex()>=0) { + StateDialog.createAndShowGUI(getThis(), (I_State)statesList.getSelectedValue()); + } + } + }); + statesList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(!statesList.isSelectionEmpty()) { + partsList.clearSelection(); + } + if(statesList.getSelectedIndices().length == 1) { + editStateButton.setEnabled(true); + removeStateButton.setEnabled(true); + setInitialStateButton.setEnabled(!statesList.getSelectedValue().equals(initialState)); + } else if(statesList.getSelectedIndices().length > 1) { + editStateButton.setEnabled(false); + setInitialStateButton.setEnabled(false); + removeStateButton.setEnabled(true); + } else { + editStateButton.setEnabled(false); + setInitialStateButton.setEnabled(false); + removeStateButton.setEnabled(false); + } + } + }); + JScrollPane statesScroll = new JScrollPane(statesList); + statesScroll.setPreferredSize(new Dimension(250,75)); + statesPanel.add(statesScroll, BorderLayout.CENTER); + + JPanel statesButtonPanel = new JPanel(); + statesButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + JButton addStateButton = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/clock_add.png"))); + addStateButton.setToolTipText("Add State"); + addStateButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + StateDialog.createAndShowGUI(getThis(), new State()); + } + }); + statesButtonPanel.add(addStateButton); + editStateButton = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/clock_edit.png"))); + editStateButton.setToolTipText("Edit State"); + editStateButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + StateDialog.createAndShowGUI(getThis(), (I_State)statesList.getSelectedValue()); + } + }); + editStateButton.setEnabled(false); + statesButtonPanel.add(editStateButton); + setInitialStateButton = new JButton("Set Initial", new ImageIcon(getClass().getClassLoader().getResource("icons/clock.png"))); + setInitialStateButton.setToolTipText("Set Initial"); + setInitialStateButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + initialState = (I_State)statesList.getSelectedValue(); + statesList.repaint(); + } + }); + setInitialStateButton.setEnabled(false); + statesButtonPanel.add(setInitialStateButton); + removeStateButton = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/clock_delete.png"))); + removeStateButton.setToolTipText("Remove State"); + removeStateButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for(Object state : statesList.getSelectedValues()) { + statesModel.removeElement(state); + if(state.equals(initialState)) { + if(statesModel.size()>0) { + initialState = (I_State)statesModel.toArray()[0]; + } else { + initialState = null; + } + } + } + statesList.repaint(); + } + }); + removeStateButton.setEnabled(false); + statesButtonPanel.add(removeStateButton); + statesPanel.add(statesButtonPanel, BorderLayout.SOUTH); + + return statesPanel; + } + + private JPanel buildPartsPanel() { + JPanel partsPanel = new JPanel(); + partsPanel.setBorder(BorderFactory.createTitledBorder("Parts")); + partsPanel.setLayout(new BorderLayout()); + + partsModel = new DefaultListModel(); + partsList = new JList(partsModel); + partsList.setCellRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + label.setIcon(ResourceType.ITEM.getIcon()); + return label; + } + }); + partsList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2 && partsList.getSelectedIndex()>=0) { + PartApplicationDialog.createAndShowGUI(getThis(), (PartApplication)partsList.getSelectedValue()); + } + } + }); + partsList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(!partsList.isSelectionEmpty()) { + statesList.clearSelection(); + } + if(partsList.getSelectedIndices().length == 1) { + editPartButton.setEnabled(true); + removePartButton.setEnabled(true); + } else if(statesList.getSelectedIndices().length > 1) { + editPartButton.setEnabled(false); + removePartButton.setEnabled(true); + } else { + editPartButton.setEnabled(false); + removePartButton.setEnabled(false); + } + } + }); + JScrollPane partsScroll = new JScrollPane(partsList); + partsScroll.setPreferredSize(new Dimension(250,75)); + partsPanel.add(partsScroll, BorderLayout.CENTER); + + JPanel partsButtonPanel = new JPanel(); + partsButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + JButton addPartButton = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/wrench_add.png"))); + addPartButton.setToolTipText("Add Part"); + addPartButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + PartApplicationDialog.createAndShowGUI(getThis(), new PartApplication()); + } + }); + partsButtonPanel.add(addPartButton); + editPartButton = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/wrench_edit.png"))); + editPartButton.setToolTipText("Edit Part"); + editPartButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + PartApplicationDialog.createAndShowGUI(getThis(), (PartApplication)partsList.getSelectedValue()); + } + }); + editPartButton.setEnabled(false); + partsButtonPanel.add(editPartButton); + removePartButton = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/wrench_delete.png"))); + removePartButton.setToolTipText("Remove Part"); + removePartButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for(Object part : partsList.getSelectedValues()) { + partsModel.removeElement(part); + } + } + }); + removePartButton.setEnabled(false); + partsButtonPanel.add(removePartButton); + partsPanel.add(partsButtonPanel, BorderLayout.SOUTH); + + return partsPanel; + } + + /** + * Initializes the dialog for a new element. + */ + private void initialize() { + typeCombo.setSelectedItem(element.getElementType()); + typeCombo.setEnabled(element.getTid()<=0); + nameText.setText(element.getName()); + iconCombo.setSelectedItem(element.getIconType()); + if(element.getClassOfSupply()!=null) + classOfSupplyCombo.setSelectedItem(element.getClassOfSupply()); + environmentCombo.setSelectedItem(element.getEnvironment()); + massModel.setValue(element.getMass()); + volumeModel.setValue(element.getVolume()); + for(I_State state : element.getStates()) { + statesModel.addElement(state); + } + initialState = element.getCurrentState(); + for(PartApplication part : element.getParts()) { + partsModel.addElement(part); + } + } + + /** + * Resets the dialog to accommodate a different element type. + */ + private void reset(ElementType type) { + element = ElementFactory.createElement(type); + for(AbstractElementPanel elementPanel : elementPanels) { + getContentPane().remove(elementPanel); + } + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridy = 6; + c.gridx = 0; + c.gridwidth = 4; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + elementPanels = ElementPanelFactory.createElementPanel(this, element); + for(AbstractElementPanel panel : elementPanels) { + getContentPane().add(panel, c); + c.gridy++; + } + initialize(); + pack(); + validate(); + repaint(); + } + + /** + * Checks if is element valid. + * + * @return true, if is element valid + */ + public boolean isElementValid() { + if(nameText.getText()==""){ + JOptionPane.showMessageDialog(this, + "Please enter an element name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + for(AbstractElementPanel panel : elementPanels) { + if(!panel.isElementValid()) return false; + } + return true; + } + + /** + * Saves the element. + */ + private void saveElement() { + if(isElementValid()) { + element.setName(nameText.getText()); + if(eventDialog!=null) { + if(element.getElementType().equals(iconCombo.getSelectedItem())) { + element.setIconType(null); + } else element.setIconType((ElementIcon)iconCombo.getSelectedItem()); + } + element.setClassOfSupply((ClassOfSupply)classOfSupplyCombo.getSelectedItem()); + element.setEnvironment((Environment)environmentCombo.getSelectedItem()); + element.setMass(massModel.getNumber().doubleValue()); + element.setVolume(volumeModel.getNumber().doubleValue()); + element.getStates().clear(); + for(Object state : statesModel.toArray()) { + element.getStates().add((I_State)state); + } + element.setCurrentState(initialState); + element.getParts().clear(); + for(Object part : partsModel.toArray()) { + element.getParts().add((PartApplication)part); + } + for(AbstractElementPanel panel : elementPanels) { + panel.saveElement(); + } + + if(dataSourceDialog!=null) { + try { + dataSourceDialog.getDataSource().saveElement(getElement()); + dataSourceDialog.loadDataSource(); + } catch (Exception e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(dataSourceDialog, + "SpaceNet Errror", + "An error occurred while saving the element.", + JOptionPane.ERROR_MESSAGE); + } + } + if(eventDialog!=null) + eventDialog.repaint(); + else if(dataSourceDialog!=null) + dataSourceDialog.repaint(); + dispose(); + } + } + + /** + * Gets this. + * + * @return this + */ + private ElementDialog getThis() { + return this; + } + + /** + * Gets the element. + * + * @return the element + */ + public I_Element getElement() { + return element; + } + + /** + * Gets the event dialog. + * + * @return the event dialog + */ + public EventDialog getCreateEventDialog() { + return eventDialog; + } + + /** + * Gets the data source dialog. + * + * @return the data source dialog + */ + public DataSourceDialog getDataSourceDialog() { + return dataSourceDialog; + } + + /** + * Gets whether the states model contains a state. + * + * @param state the state + * + * @return whether the model contains the state + */ + public boolean containsState(I_State state) { + return statesModel.contains(state); + } + + /** + * Adds a state to the states model. + * + * @param state the state + */ + public void addState(I_State state) { + if(initialState==null) initialState = state; + statesModel.addElement(state); + } + + /** + * Gets whether the parts application model contains a part. + * + * @param part the part + * + * @return whether the model contains the part + */ + public boolean containsPart(PartApplication part) { + return partsModel.contains(part); + } + + /** + * Adds a part to the parts application model. + * + * @param part the part + */ + public void addPart(PartApplication part) { + partsModel.addElement(part); + } + + /* (non-Javadoc) + * @see java.awt.Container#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + super.paint(g); + partsList.repaint(); + statesList.repaint(); + } + + /** + * Creates and shows the dialog. + * + * @param eventDialog the parent event dialog component + * @param element the element + */ + public static void createAndShowGUI(EventDialog eventDialog, I_Element element) { + ElementDialog d = new ElementDialog(eventDialog, element); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } + + /** + * Creates and shows the dialog. + * + * @param element the element + * @param dialog the dialog + */ + public static void createAndShowGUI(DataSourceDialog dialog, I_Element element) { + ElementDialog d = new ElementDialog(dialog, element); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/element/ElementPanelFactory.java b/src/main/java/edu/mit/spacenet/gui/element/ElementPanelFactory.java new file mode 100644 index 0000000..2871694 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/ElementPanelFactory.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.util.ArrayList; +import java.util.List; + +import edu.mit.spacenet.domain.element.Carrier; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.element.ResourceContainer; +import edu.mit.spacenet.domain.element.ResourceTank; +import edu.mit.spacenet.domain.element.SurfaceVehicle; + +/** + * An abstract class that contains a factory method to build the appropriate + * combination of element panels. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class ElementPanelFactory { + + /** + * A factory method that returns a list of element panels appropriate for + * viewing and editing the element. + * + * @param elementDialog the parent element dialog component + * @param element the element + * + * @return a list of element panels + */ + public static List createElementPanel(ElementDialog elementDialog, I_Element element) { + List panels = new ArrayList(); + + switch(element.getElementType()) { + case ELEMENT: + break; + case RESOURCE_CONTAINER: + panels.add(new ResourceContainerPanel(elementDialog, (ResourceContainer)element)); + break; + case RESOURCE_TANK: + panels.add(new ResourceTankPanel(elementDialog, (ResourceTank)element)); + break; + case CREW_MEMBER: + panels.add(new CrewMemberPanel(elementDialog, (CrewMember)element)); + break; + case CARRIER: + panels.add(new CarrierPanel(elementDialog, (Carrier)element)); + break; + case PROPULSIVE_VEHICLE: + panels.add(new CarrierPanel(elementDialog, (PropulsiveVehicle)element)); + panels.add(new PropulsiveVehiclePanel(elementDialog, (PropulsiveVehicle)element)); + break; + case SURFACE_VEHICLE: + panels.add(new CarrierPanel(elementDialog, (SurfaceVehicle)element)); + panels.add(new SurfaceVehiclePanel(elementDialog, (SurfaceVehicle)element)); + break; + default: throw new RuntimeException("Unsupported Element"); + } + + return panels; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/PartApplicationDialog.java b/src/main/java/edu/mit/spacenet/gui/element/PartApplicationDialog.java new file mode 100644 index 0000000..cdc0216 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/PartApplicationDialog.java @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.renderer.ResourceListCellRenderer; + +/** + * A component for viewing and editing part applications for an element. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class PartApplicationDialog extends JDialog { + private static final long serialVersionUID = -9173211009538452900L; + + private JComboBox partCombo; + private JCheckBox failureCheck, repairCheck; + private SpinnerNumberModel mttfModel, mttrModel, repairMassModel, quantityModel, dutyCycleModel; + private JSpinner mttfSpinner, mttrSpinner, repairMassSpinner, quantitySpinner, dutyCycleSpinner; + private JButton btnOk, btnCancel; + + private ElementDialog elementDialog; + private PartApplication partApplication; + + /** + * Instantiates a new part application dialog. + * + * @param elementDialog the element dialog + * @param partApplication the part application + */ + public PartApplicationDialog(ElementDialog elementDialog, PartApplication partApplication) { + super(elementDialog, "Part Application"); + this.elementDialog = elementDialog; + this.partApplication = partApplication; + + buildDialog(); + initialize(); + } + + /** + * Builds the dialog. + */ + private void buildDialog() { + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(3,3,3,3); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + contentPanel.add(new JLabel("Resource: "), c); + c.gridy++; + contentPanel.add(new JLabel("Quantity: "), c); + + c.anchor = GridBagConstraints.LINE_START; + c.gridx = 1; + c.gridy = 0; + c.weightx = 1; + partCombo = new JComboBox(); + partCombo.setRenderer(new ResourceListCellRenderer()); + contentPanel.add(partCombo, c); + c.gridy++; + quantityModel = new SpinnerNumberModel(1,0,100,1); + quantitySpinner = new JSpinner(quantityModel); + contentPanel.add(quantitySpinner, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + contentPanel.add(buildFailurePanel(), c); + + c.gridy++; + contentPanel.add(buildRepairPanel(), c); + + c.gridy++; + c.gridx=0; + c.gridwidth=4; + c.weighty = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + btnOk = new JButton("OK"); + btnOk.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + savePart(); + } + }); + getRootPane().setDefaultButton(btnOk); + btnCancel = new JButton("Cancel"); + btnCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + buttonPanel.add(btnOk); + buttonPanel.add(btnCancel); + contentPanel.add(buttonPanel, c); + + setContentPane(contentPanel); + setModal(true); + } + + /** + * Builds the failure panel. + * + * @return the j panel + */ + private JPanel buildFailurePanel() { + JPanel failurePanel = new JPanel(); + failurePanel.setBorder(BorderFactory.createTitledBorder("Failure Analysis")); + failurePanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + + failureCheck = new JCheckBox("Enable Failure Analysis"); + failureCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + dutyCycleSpinner.setEnabled(true); + mttfSpinner.setEnabled(true); + } else { + dutyCycleSpinner.setEnabled(false); + dutyCycleSpinner.setValue(0); + mttfSpinner.setEnabled(false); + mttfSpinner.setValue(0); + } + } + }); + failurePanel.add(failureCheck, c); + + c.gridy++; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + failurePanel.add(new JLabel("Duty Cycle: "), c); + c.gridy++; + failurePanel.add(new JLabel("Mean Time to Failure: "), c); + + c.gridy--; + c.gridx = 1; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + dutyCycleModel = new SpinnerNumberModel(1,0,1,.1); + dutyCycleSpinner = new JSpinner(dutyCycleModel); + dutyCycleSpinner.setPreferredSize(new Dimension(50,20)); + failurePanel.add(dutyCycleSpinner, c); + dutyCycleSpinner.setToolTipText("Fraction of time this part is used [unitless]"); + + c.gridy++; + mttfModel = new SpinnerNumberModel(0,0,1000000,100.); + mttfSpinner = new JSpinner(mttfModel); + failurePanel.add(new UnitsWrapper(mttfSpinner, "hours"), c); + mttfSpinner.setToolTipText("Mean time to failure of part [hours]"); + + return failurePanel; + } + + /** + * Builds the repair panel. + * + * @return the j panel + */ + private JPanel buildRepairPanel() { + JPanel repairPanel = new JPanel(); + repairPanel.setBorder(BorderFactory.createTitledBorder("Repair Analysis")); + repairPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + + repairCheck = new JCheckBox("Enable Repair Analysis"); + repairCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + mttrSpinner.setEnabled(true); + repairMassSpinner.setEnabled(true); + } else { + mttrSpinner.setEnabled(false); + mttrSpinner.setValue(0); + repairMassSpinner.setEnabled(false); + repairMassSpinner.setValue(0); + } + } + }); + repairPanel.add(repairCheck, c); + + c.gridy++; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + repairPanel.add(new JLabel("Mean Time to Repair: "), c); + c.gridy++; + repairPanel.add(new JLabel("Mean Repair Mass: "), c); + + c.gridy--; + c.gridx = 1; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + mttrModel = new SpinnerNumberModel(0,0,1000, 1.); + mttrSpinner = new JSpinner(mttrModel); + repairPanel.add(new UnitsWrapper(mttrSpinner, "hours"), c); + mttrSpinner.setToolTipText("Time to repair this part [hours]"); + + c.gridy++; + repairMassModel = new SpinnerNumberModel(0,0,1000, .5); + repairMassSpinner = new JSpinner(repairMassModel); + repairPanel.add(new UnitsWrapper(repairMassSpinner, "kg"), c); + repairMassSpinner.setToolTipText("Mass required to repair this part [kilograms]"); + + return repairPanel; + } + + /** + * Initializes the dialog for a new part application. + */ + private void initialize() { + for(I_Item item : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getItemLibrary()) { + partCombo.addItem(item); + if(item.equals(partApplication.getPart())) + partCombo.setSelectedItem(item); + } + quantityModel.setValue(partApplication.getQuantity()); + + mttfModel.setValue(partApplication.getMeanTimeToFailure()); + dutyCycleModel.setValue(partApplication.getDutyCycle()); + + failureCheck.setSelected(partApplication.getMeanTimeToFailure()>0); + mttfSpinner.setEnabled(partApplication.getMeanTimeToFailure()>0); + dutyCycleSpinner.setEnabled(partApplication.getMeanTimeToFailure()>0); + + mttrModel.setValue(partApplication.getMeanTimeToRepair()); + repairMassModel.setValue(partApplication.getMassToRepair()); + + repairCheck.setSelected(partApplication.getMeanTimeToRepair()>0); + mttrSpinner.setEnabled(partApplication.getMeanTimeToRepair()>0); + repairMassSpinner.setEnabled(partApplication.getMeanTimeToRepair()>0); + } + + /** + * Gets the element dialog. + * + * @return the element dialog + */ + public ElementDialog getElementDialog() { + return elementDialog; + } + + /** + * Checks if is part valid. + * + * @return true, if is part valid + */ + private boolean isPartValid() { + if(partCombo.getSelectedItem()==null) { + JOptionPane.showMessageDialog(this, + "Please select a resource.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + return true; + } + + /** + * Save part. + */ + private void savePart() { + if(isPartValid()) { + partApplication.setPart((Item)partCombo.getSelectedItem()); + partApplication.setMeanTimeToFailure(mttfModel.getNumber().doubleValue()); + partApplication.setMeanTimeToRepair(mttrModel.getNumber().doubleValue()); + partApplication.setMassToRepair(repairMassModel.getNumber().doubleValue()); + partApplication.setQuantity(quantityModel.getNumber().intValue()); + partApplication.setDutyCycle(dutyCycleModel.getNumber().doubleValue()); + if(!elementDialog.containsPart(partApplication)) { + elementDialog.addPart(partApplication); + } + elementDialog.repaint(); + dispose(); + } + } + + /** + * Creates the and shows the gui. + * + * @param elementDialog the element dialog + * @param part the part + */ + public static void createAndShowGUI(ElementDialog elementDialog, PartApplication part) { + PartApplicationDialog d = new PartApplicationDialog(elementDialog, part); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/PropulsiveVehiclePanel.java b/src/main/java/edu/mit/spacenet/gui/element/PropulsiveVehiclePanel.java new file mode 100644 index 0000000..5794065 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/PropulsiveVehiclePanel.java @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.element.ResourceTank; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.renderer.ResourceListCellRenderer; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * The element panel for viewing and editing propulsive vehicle-specific inputs. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class PropulsiveVehiclePanel extends AbstractElementPanel { + private static final long serialVersionUID = 6335483106289763369L; + + private PropulsiveVehicle vehicle; + + private JCheckBox omsCheck, rcsCheck, sharedCheck; + private SpinnerNumberModel omsIspModel, maxOmsFuelModel, omsFuelModel, + rcsIspModel, maxRcsFuelModel, rcsFuelModel; + private JSpinner omsIspSpinner, maxOmsFuelSpinner, omsFuelSpinner, + rcsIspSpinner, maxRcsFuelSpinner, rcsFuelSpinner; + private UnitsWrapper maxOmsFuelWrapper, omsFuelWrapper, maxRcsFuelWrapper, rcsFuelWrapper; + private JComboBox omsResourceCombo, rcsResourceCombo; + + /** + * Instantiates a new propulsive vehicle panel. + * + * @param elementDialog the element dialog + * @param vehicle the vehicle + */ + public PropulsiveVehiclePanel(ElementDialog elementDialog, PropulsiveVehicle vehicle) { + super(elementDialog, vehicle); + this.vehicle = vehicle; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); + + JPanel omsPanel = new JPanel(); + omsPanel.setLayout(new GridBagLayout()); + omsPanel.setBorder(BorderFactory.createTitledBorder("OMS Engine")); + add(omsPanel); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + c.gridx = 0; + c.gridy = 1; + c.weightx = 0; + omsPanel.add(new JLabel("Isp: "), c); + c.gridy++; + omsPanel.add(new JLabel("Fuel Type: "), c); + c.gridy++; + omsPanel.add(new JLabel("Max Fuel: "), c); + c.gridy++; + if(getElementDialog().getDataSourceDialog()==null) + omsPanel.add(new JLabel("Initial Fuel: "), c); + + c.gridx = 1; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.weightx = 1; + omsCheck = new JCheckBox("OMS Capabilities"); + omsPanel.add(omsCheck, c); + + c.gridy++; + omsIspModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,0.1); + omsIspSpinner = new JSpinner(omsIspModel); + omsIspSpinner.setPreferredSize(new Dimension(50,20)); + omsPanel.add(new UnitsWrapper(omsIspSpinner, "s"), c); + omsIspSpinner.setToolTipText("Specific impulse of orbital maneuvering system [seconds]"); + + c.gridy++; + omsResourceCombo = new JComboBox(); + omsResourceCombo.setRenderer(new ResourceListCellRenderer()); + omsResourceCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED + && omsResourceCombo.getSelectedItem() != null + && omsResourceCombo.getSelectedItem() instanceof I_Resource) { + String fuelUnits = ((I_Resource)omsResourceCombo.getSelectedItem()).getUnits(); + maxOmsFuelWrapper.setUnits(fuelUnits); + omsFuelWrapper.setUnits(fuelUnits); + } + } + }); + omsPanel.add(omsResourceCombo, c); + + c.gridy++; + maxOmsFuelModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + maxOmsFuelSpinner = new JSpinner(maxOmsFuelModel); + maxOmsFuelSpinner.setPreferredSize(new Dimension(150,20)); + maxOmsFuelSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + omsFuelSpinner.setValue(maxOmsFuelSpinner.getValue()); + } + }); + maxOmsFuelWrapper = new UnitsWrapper(maxOmsFuelSpinner, ""); + omsPanel.add(maxOmsFuelWrapper, c); + maxOmsFuelSpinner.setToolTipText("Maximum amount of orbital maneuvering system fuel"); + + c.gridy++; + omsFuelModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + omsFuelSpinner = new JSpinner(omsFuelModel); + omsFuelSpinner.setPreferredSize(new Dimension(150,20)); + omsFuelWrapper = new UnitsWrapper(omsFuelSpinner, ""); + if(getElementDialog().getDataSourceDialog()==null) + omsPanel.add(omsFuelWrapper, c); + omsFuelSpinner.setToolTipText("Initial amount of orbital maneuvering system fuel"); + + + JPanel rcsPanel = new JPanel(); + rcsPanel.setLayout(new GridBagLayout()); + rcsPanel.setBorder(BorderFactory.createTitledBorder("RCS Engine")); + add(rcsPanel); + + c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + c.gridx = 0; + c.gridy = 1; + c.weightx = 0; + rcsPanel.add(new JLabel("Isp: "), c); + c.gridy+=2; + rcsPanel.add(new JLabel("Fuel Type: "), c); + c.gridy++; + rcsPanel.add(new JLabel("Max Fuel: "), c); + c.gridy++; + if(getElementDialog().getDataSourceDialog()==null) + rcsPanel.add(new JLabel("Initial Fuel: "), c); + + c.gridx = 1; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.weightx = 1; + rcsCheck = new JCheckBox("RCS Capabilities"); + rcsPanel.add(rcsCheck, c); + c.gridy++; + + rcsIspModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,0.1); + rcsIspSpinner = new JSpinner(rcsIspModel); + rcsIspSpinner.setPreferredSize(new Dimension(50,20)); + rcsPanel.add(new UnitsWrapper(rcsIspSpinner, "s"), c); + rcsIspSpinner.setToolTipText("Specific impulse of reaction control system [seconds]"); + + c.gridy++; + sharedCheck = new JCheckBox("Shared OMS Fuel Tank"); + sharedCheck.setOpaque(false); + rcsPanel.add(sharedCheck, c); + sharedCheck.setToolTipText("Share fuel between the orbital maneuvering and reaction control systems"); + + c.gridy++; + rcsResourceCombo = new JComboBox(); + rcsResourceCombo.setRenderer(new ResourceListCellRenderer()); + rcsResourceCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED + && rcsResourceCombo.getSelectedItem() != null + && rcsResourceCombo.getSelectedItem() instanceof I_Resource) { + String fuelUnits = ((I_Resource)rcsResourceCombo.getSelectedItem()).getUnits(); + maxRcsFuelWrapper.setUnits(fuelUnits); + rcsFuelWrapper.setUnits(fuelUnits); + } + } + }); + rcsPanel.add(rcsResourceCombo, c); + + c.gridy++; + maxRcsFuelModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + maxRcsFuelSpinner = new JSpinner(maxRcsFuelModel); + maxRcsFuelSpinner.setPreferredSize(new Dimension(150,20)); + maxRcsFuelSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + rcsFuelSpinner.setValue(maxRcsFuelSpinner.getValue()); + } + }); + maxRcsFuelWrapper = new UnitsWrapper(maxRcsFuelSpinner, ""); + rcsPanel.add(maxRcsFuelWrapper, c); + maxRcsFuelSpinner.setToolTipText("Maximum amount of reaction control system fuel"); + + c.gridy++; + rcsFuelModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + rcsFuelSpinner = new JSpinner(rcsFuelModel); + rcsFuelSpinner.setPreferredSize(new Dimension(150,20)); + rcsFuelWrapper = new UnitsWrapper(rcsFuelSpinner, ""); + if(getElementDialog().getDataSourceDialog()==null) + rcsPanel.add(rcsFuelWrapper, c); + rcsFuelSpinner.setToolTipText("Initial amount of reaction control system fuel"); + } + + /** + * Initializes the panel components for a new propulsive vehicle. + */ + private void initialize() { + omsResourceCombo.addItem(null); + rcsResourceCombo.addItem(null); + for(I_Resource r : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()) { + if(r.getClassOfSupply().equals(ClassOfSupply.COS1) + || r.getClassOfSupply().isSubclassOf(ClassOfSupply.COS1)) { + omsResourceCombo.addItem(r); + rcsResourceCombo.addItem(r); + } + } + for(ClassOfSupply cos : ClassOfSupply.values()) { + if(cos.equals(ClassOfSupply.COS1) + || cos.isSubclassOf(ClassOfSupply.COS1)) { + omsResourceCombo.addItem(new GenericResource(cos)); + rcsResourceCombo.addItem(new GenericResource(cos)); + } + } + if(vehicle.getOmsIsp() > 0) omsCheck.setSelected(true); + else omsCheck.setSelected(false); + + if(vehicle.getRcsIsp() > 0) rcsCheck.setSelected(true); + else rcsCheck.setSelected(false); + + if(vehicle.getOmsFuelTank() == vehicle.getRcsFuelTank()) + sharedCheck.setSelected(true); + else sharedCheck.setSelected(false); + + omsCheck.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + repaint(); + } + }); + rcsCheck.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + repaint(); + } + }); + sharedCheck.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + repaint(); + } + }); + + if(omsCheck.isSelected()) { + omsIspModel.setValue(vehicle.getOmsIsp()); + if(vehicle.getOmsFuelTank() != null) { + maxOmsFuelModel.setValue(vehicle.getOmsFuelTank().getMaxAmount()); + omsFuelModel.setValue(vehicle.getOmsFuelTank().getAmount()); + omsResourceCombo.setSelectedItem(vehicle.getOmsFuelTank().getResource()); + } + } + if(rcsCheck.isSelected() && sharedCheck.isSelected()) { + rcsIspModel.setValue(vehicle.getRcsIsp()); + } else if(rcsCheck.isSelected()) { + rcsIspModel.setValue(vehicle.getRcsIsp()); + if(vehicle.getRcsFuelTank() != null) { + maxRcsFuelModel.setValue(vehicle.getRcsFuelTank().getMaxAmount()); + rcsFuelModel.setValue(vehicle.getRcsFuelTank().getAmount()); + rcsResourceCombo.setSelectedItem(vehicle.getRcsFuelTank().getResource()); + } + } + repaint(); + } + + /* (non-Javadoc) + * @see javax.swing.JComponent#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + super.paint(g); + if(omsCheck.isSelected()) { + omsIspSpinner.setEnabled(true); + maxOmsFuelSpinner.setEnabled(true); + omsFuelSpinner.setEnabled(true); + omsResourceCombo.setEnabled(true); + } else { + omsIspModel.setValue(0); + omsIspSpinner.setEnabled(false); + maxOmsFuelModel.setValue(0); + maxOmsFuelSpinner.setEnabled(false); + omsFuelModel.setValue(0); + omsFuelSpinner.setEnabled(false); + omsResourceCombo.setSelectedItem(null); + omsResourceCombo.setEnabled(false); + } + if(rcsCheck.isSelected() && sharedCheck.isSelected()) { + rcsIspSpinner.setEnabled(true); + sharedCheck.setEnabled(true); + maxRcsFuelModel.setValue(0); + maxRcsFuelSpinner.setEnabled(false); + rcsFuelModel.setValue(0); + rcsFuelSpinner.setEnabled(false); + rcsResourceCombo.setSelectedItem(null); + rcsResourceCombo.setEnabled(false); + } else if(rcsCheck.isSelected()) { + rcsIspSpinner.setEnabled(true); + sharedCheck.setEnabled(true); + maxRcsFuelSpinner.setEnabled(true); + rcsFuelSpinner.setEnabled(true); + rcsResourceCombo.setEnabled(true); + } else { + sharedCheck.setSelected(false); + sharedCheck.setEnabled(false); + rcsIspModel.setValue(0); + rcsIspSpinner.setEnabled(false); + maxRcsFuelModel.setValue(0); + maxRcsFuelSpinner.setEnabled(false); + rcsFuelModel.setValue(0); + rcsFuelSpinner.setEnabled(false); + rcsResourceCombo.setSelectedItem(null); + rcsResourceCombo.setEnabled(false); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#getElement() + */ + @Override + public PropulsiveVehicle getElement() { + return vehicle; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#saveElement() + */ + @Override + public void saveElement() { + if(omsCheck.isSelected()) { + vehicle.setOmsIsp(omsIspModel.getNumber().doubleValue()); + ResourceTank omsFuelTank; + if(vehicle.getOmsFuelTank()!=null) omsFuelTank = vehicle.getOmsFuelTank(); + else { + omsFuelTank = new ResourceTank(); + vehicle.setOmsFuelTank(omsFuelTank); + } + omsFuelTank.setMaxAmount(maxOmsFuelModel.getNumber().doubleValue()); + omsFuelTank.setAmount(Math.min(maxOmsFuelModel.getNumber().doubleValue(), + omsFuelModel.getNumber().doubleValue())); + omsFuelTank.setResource((I_Resource)omsResourceCombo.getSelectedItem()); + } else { + vehicle.setOmsIsp(0); + vehicle.setOmsFuelTank(null); + } + if(rcsCheck.isSelected() && !sharedCheck.isSelected()) { + vehicle.setRcsIsp(rcsIspModel.getNumber().doubleValue()); + ResourceTank rcsFuelTank; + if(vehicle.getRcsFuelTank()!=null) rcsFuelTank = vehicle.getRcsFuelTank(); + else { + rcsFuelTank = new ResourceTank(); + vehicle.setRcsFuelTank(rcsFuelTank); + } + rcsFuelTank.setMaxAmount(maxRcsFuelModel.getNumber().doubleValue()); + rcsFuelTank.setAmount(Math.min(maxRcsFuelModel.getNumber().doubleValue(), + rcsFuelModel.getNumber().doubleValue())); + rcsFuelTank.setResource((I_Resource)rcsResourceCombo.getSelectedItem()); + } else if(rcsCheck.isSelected() && sharedCheck.isSelected()) { + vehicle.setRcsIsp(rcsIspModel.getNumber().doubleValue()); + vehicle.setRcsFuelTank(vehicle.getOmsFuelTank()); + } else { + vehicle.setRcsIsp(0); + vehicle.setRcsFuelTank(null); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isElementValid() + */ + @Override + public boolean isElementValid() { + if((maxOmsFuelModel.getNumber().doubleValue() > 0 + || omsFuelModel.getNumber().doubleValue() > 0) + && omsResourceCombo.getSelectedItem()==null) + return false; + if((maxRcsFuelModel.getNumber().doubleValue() > 0 + || rcsFuelModel.getNumber().doubleValue() > 0) + && rcsResourceCombo.getSelectedItem()==null) + return false; + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isVerticallyExpandable() + */ + public boolean isVerticallyExpandable() { + return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/ResourceContainerPanel.java b/src/main/java/edu/mit/spacenet/gui/element/ResourceContainerPanel.java new file mode 100644 index 0000000..8db67bc --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/ResourceContainerPanel.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.ListSelectionModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.element.ResourceContainer; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * An element panel for viewing and editing resource container-specific inputs. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class ResourceContainerPanel extends AbstractElementPanel { + private static final long serialVersionUID = 6335483106289763369L; + + private ResourceContainer container; + + private SpinnerNumberModel maxCargoMassModel, maxCargoVolumeModel; + private JSpinner maxCargoMassSpinner, maxCargoVolumeSpinner; + private JComboBox environmentCombo; + private DemandTable resourcesList; + private JButton removeResourceButton; + + /** + * Instantiates a new resource container panel. + * + * @param elementDialog the element dialog + * @param container the container + */ + public ResourceContainerPanel(ElementDialog elementDialog, ResourceContainer container) { + super(elementDialog, container); + this.container = container; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Max Cargo Mass: "), c); + c.gridx+=2; + add(new JLabel("Max Cargo Volume: "), c); + c.gridy++; + c.gridx = 0; + add(new JLabel("Cargo Environment: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Resources: "), c); + + c.anchor = GridBagConstraints.LINE_START; + c.gridx = 1; + c.gridy = 0; + c.weightx = 1; + maxCargoMassModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + maxCargoMassSpinner = new JSpinner(maxCargoMassModel); + maxCargoMassSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(maxCargoMassSpinner, "kg"), c); + maxCargoMassSpinner.setToolTipText("Maximum mass of nested resources [kilograms]"); + + c.gridx+=2; + maxCargoVolumeModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getVolumePrecision()); + maxCargoVolumeSpinner = new JSpinner(maxCargoVolumeModel); + maxCargoVolumeSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(maxCargoVolumeSpinner, "m^3"), c); + maxCargoVolumeSpinner.setToolTipText("Maximum volume of nested resources [cubic meters]"); + + c.gridy++; + c.gridx = 1; + c.gridwidth = 3; + environmentCombo = new JComboBox(); + for(Environment e : Environment.values()) { + environmentCombo.addItem(e); + } + add(environmentCombo, c); + environmentCombo.setToolTipText("Storage environment available for nested resources"); + + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.weighty = 1; + resourcesList = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + resourcesList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + resourcesList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(resourcesList.getSelectedRows().length >= 1) { + removeResourceButton.setEnabled(true); + } else { + removeResourceButton.setEnabled(false); + } + } + }); + JScrollPane demandsScroll = new JScrollPane(resourcesList); + demandsScroll.setPreferredSize(new Dimension(400,75)); + add(demandsScroll, c); + + c.gridy++; + c.fill = GridBagConstraints.NONE; + c.weighty = 0; + JPanel demandButtonPanel = new JPanel(); + demandButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + add(demandButtonPanel, c); + + JButton addResourceButton = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_put.png"))); + addResourceButton.setToolTipText("Add a Resource"); + addResourceButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + resourcesList.addDemand(new Demand()); + } + }); + demandButtonPanel.add(addResourceButton); + removeResourceButton = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_remove.png"))); + removeResourceButton.setToolTipText("Remove Resource"); + removeResourceButton.setEnabled(false); + removeResourceButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList demands = new ArrayList(); + for(int row : resourcesList.getSelectedRows()) { + demands.add(resourcesList.getDemand(row)); + } + for(Demand demand : demands) { + resourcesList.remove(demand); + } + } + }); + demandButtonPanel.add(removeResourceButton); + } + + /** + * Initializes the panel components for a new resource container. + */ + private void initialize() { + maxCargoMassModel.setValue(container.getMaxCargoMass()); + maxCargoVolumeModel.setValue(container.getMaxCargoVolume()); + environmentCombo.setSelectedItem(container.getCargoEnvironment()); + for(I_Resource r : container.getContents().keySet()) { + resourcesList.addDemand(new Demand(r, container.getContents().get(r))); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#getElement() + */ + @Override + public ResourceContainer getElement() { + return container; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#saveElement() + */ + @Override + public void saveElement() { + if(resourcesList.isEditing()) resourcesList.getCellEditor().stopCellEditing(); + container.setMaxCargoMass(maxCargoMassModel.getNumber().doubleValue()); + container.setMaxCargoVolume(maxCargoVolumeModel.getNumber().doubleValue()); + container.setCargoEnvironment((Environment)environmentCombo.getSelectedItem()); + container.getContents().clear(); + for(Demand demand : resourcesList.getDemands()) { + if(demand.getResource()!=null) + container.add(demand.getResource(), demand.getAmount()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isElementValid() + */ + @Override + public boolean isElementValid() { + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isVerticallyExpandable() + */ + public boolean isVerticallyExpandable() { + return true; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/ResourceTankPanel.java b/src/main/java/edu/mit/spacenet/gui/element/ResourceTankPanel.java new file mode 100644 index 0000000..1bfb03b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/ResourceTankPanel.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.ResourceTank; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.renderer.ResourceListCellRenderer; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * An element panel used for viewing and editing resource tank-specific inputs. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class ResourceTankPanel extends AbstractElementPanel { + private static final long serialVersionUID = 6335483106289763369L; + + private ResourceTank tank; + + private JComboBox resourceCombo; + private SpinnerNumberModel amountModel, maxAmountModel; + private JSpinner amountSpinner, maxAmountSpinner; + private UnitsWrapper amountWrapper, maxAmountWrapper; + + /** + * Instantiates a new resource tank panel. + * + * @param elementDialog the element dialog + * @param tank the tank + */ + public ResourceTankPanel(ElementDialog elementDialog, ResourceTank tank) { + super(elementDialog, tank); + this.tank = tank; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Resource: "), c); + c.gridy++; + add(new JLabel("Max Amount: "), c); + c.gridx+=2; + add(new JLabel("Amount: "), c); + + c.gridy = 0; + c.gridx = 1; + c.gridwidth = 3; + c.weightx = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + resourceCombo = new JComboBox(); + for(I_Resource resource : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()) { + resourceCombo.addItem(resource); + } + for(ClassOfSupply cos : ClassOfSupply.values()) { + resourceCombo.addItem(new GenericResource(cos)); + } + resourceCombo.setRenderer(new ResourceListCellRenderer()); + resourceCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED + && resourceCombo.getSelectedItem() != null) { + String resourceUnits = ((I_Resource)resourceCombo.getSelectedItem()).getUnits(); + maxAmountWrapper.setUnits(resourceUnits); + amountWrapper.setUnits(resourceUnits); + } + } + }); + add(resourceCombo, c); + + c.gridy++; + c.gridwidth = 1; + c.fill = GridBagConstraints.HORIZONTAL; + maxAmountModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + maxAmountSpinner = new JSpinner(maxAmountModel); + maxAmountSpinner.setPreferredSize(new Dimension(150,20)); + maxAmountWrapper = new UnitsWrapper(maxAmountSpinner, "units"); + add(maxAmountWrapper, c); + maxAmountSpinner.setToolTipText("Maximum amount of resource to nest"); + + c.gridx+=2; + amountModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + amountSpinner = new JSpinner(amountModel); + amountSpinner.setPreferredSize(new Dimension(150,20)); + amountWrapper = new UnitsWrapper(amountSpinner, "units"); + add(amountWrapper, c); + amountSpinner.setToolTipText("Initial amount of resource to nest"); + } + + /** + * Initializes the panel components for a new resource tank. + */ + private void initialize() { + resourceCombo.setSelectedItem(tank.getResource()); + maxAmountModel.setValue(tank.getMaxAmount()); + amountModel.setValue(tank.getAmount()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#getElement() + */ + @Override + public ResourceTank getElement() { + return tank; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#saveElement() + */ + @Override + public void saveElement() { + tank.setResource((I_Resource)resourceCombo.getSelectedItem()); + tank.setMaxAmount(maxAmountModel.getNumber().doubleValue()); + tank.setAmount(amountModel.getNumber().doubleValue()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isElementValid() + */ + @Override + public boolean isElementValid() { + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isVerticallyExpandable() + */ + public boolean isVerticallyExpandable() { + return true; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/StateDialog.java b/src/main/java/edu/mit/spacenet/gui/element/StateDialog.java new file mode 100644 index 0000000..45eac2e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/StateDialog.java @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.element.StateType; +import edu.mit.spacenet.domain.model.DemandModelFactory; +import edu.mit.spacenet.domain.model.DemandModelType; +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.gui.component.DropDownButton; +import edu.mit.spacenet.gui.model.DemandModelDialog; +import edu.mit.spacenet.gui.renderer.DemandModelListCellRenderer; +import edu.mit.spacenet.gui.renderer.StateTypeListCellRenderer; + +/** + * A dialog for viewing and editing element operational states. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class StateDialog extends JDialog { + private static final long serialVersionUID = -2572640622351398778L; + + private JTextField txtName; + private JComboBox ddlType; + private DefaultListModel demandModelsModel; + private JList demandModelsList; + private JScrollPane demandModelsScroll; + private DropDownButton btnAddDemandModel; + private JMenuItem addTimedImpulseDemandModel, addRatedDemandModel, + addSparingByMassDemandModel; + private JButton btnEditDemandModel, btnRemoveDemandModel, btnOk, btnCancel; + private JPanel demandModelButtonPanel, buttonPanel; + + private I_State state; + private ElementDialog elementDialog; + + /** + * Instantiates a new state dialog. + * + * @param elementDialog the element dialog + * @param state the state + */ + public StateDialog(ElementDialog elementDialog, I_State state) { + super(elementDialog, "Operational State"); + this.elementDialog = elementDialog; + this.state = state; + + buildDialog(); + initialize(); + } + + /** + * Builds the dialog. + */ + private void buildDialog() { + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + + contentPanel.add(new JLabel("Name"), c); + c.gridy++; + contentPanel.add(new JLabel("Type: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + contentPanel.add(new JLabel("Demand Models: "), c); + + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridy = 0; + c.gridx = 1; + c.weightx = 1; + txtName = new JTextField(25); + contentPanel.add(txtName, c); + + c.gridy++; + c.fill = GridBagConstraints.NONE; + ddlType = new JComboBox(); + for(StateType t : StateType.values()) ddlType.addItem(t); + ddlType.setRenderer(new StateTypeListCellRenderer()); + contentPanel.add(ddlType, c); + + c.gridy++; + c.fill = GridBagConstraints.BOTH; + c.weighty = 1; + demandModelsModel = new DefaultListModel(); + demandModelsList = new JList(demandModelsModel); + demandModelsList.setCellRenderer(new DemandModelListCellRenderer()); + demandModelsList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2 && demandModelsList.getSelectedIndex()>=0) { + DemandModelDialog.createAndShowGUI(getThis(), (I_DemandModel)demandModelsList.getSelectedValue()); + } + } + }); + demandModelsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + demandModelsList.setVisibleRowCount(3); + demandModelsList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(demandModelsList.getSelectedIndex() >= 0) { + btnEditDemandModel.setEnabled(true); + btnRemoveDemandModel.setEnabled(true); + } else { + btnEditDemandModel.setEnabled(false); + btnRemoveDemandModel.setEnabled(false); + } + } + }); + demandModelsScroll = new JScrollPane(demandModelsList); + contentPanel.add(demandModelsScroll, c); + + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + demandModelButtonPanel = new JPanel(); + demandModelButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + contentPanel.add(demandModelButtonPanel, c); + + btnAddDemandModel = new DropDownButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/comment_add.png"))); + btnAddDemandModel.setToolTipText("Add Demand Model"); + demandModelButtonPanel.add(btnAddDemandModel); + + addTimedImpulseDemandModel = new JMenuItem(DemandModelType.TIMED_IMPULSE.getName(), DemandModelType.TIMED_IMPULSE.getIcon()); + addTimedImpulseDemandModel.setToolTipText("Add a one-time demand for resources at a given time"); + addTimedImpulseDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DemandModelDialog.createAndShowGUI(getThis(), + DemandModelFactory.createDemandModel(getElementDialog().getElement(), DemandModelType.TIMED_IMPULSE)); + } + }); + btnAddDemandModel.getMenu().add(addTimedImpulseDemandModel); + addRatedDemandModel = new JMenuItem(DemandModelType.RATED.getName(), DemandModelType.RATED.getIcon()); + addRatedDemandModel.setToolTipText("Add a recurring demand for resources based on a demand rate"); + addRatedDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DemandModelDialog.createAndShowGUI(getThis(), + DemandModelFactory.createDemandModel(getElementDialog().getElement(), DemandModelType.RATED)); + } + }); + btnAddDemandModel.getMenu().add(addRatedDemandModel); + addSparingByMassDemandModel = new JMenuItem(DemandModelType.SPARING_BY_MASS.getName(), DemandModelType.SPARING_BY_MASS.getIcon()); + addSparingByMassDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DemandModelDialog.createAndShowGUI(getThis(), + DemandModelFactory.createDemandModel(getElementDialog().getElement(), DemandModelType.SPARING_BY_MASS)); + } + }); + btnAddDemandModel.getMenu().add(addSparingByMassDemandModel); + demandModelButtonPanel.add(btnAddDemandModel); + + btnEditDemandModel = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/comment_edit.png"))); + btnEditDemandModel.setToolTipText("Edit Demand Model"); + btnEditDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DemandModelDialog.createAndShowGUI(getThis(), (I_DemandModel)demandModelsList.getSelectedValue()); + } + }); + btnEditDemandModel.setEnabled(false); + demandModelButtonPanel.add(btnEditDemandModel); + + btnRemoveDemandModel = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/comment_delete.png"))); + btnRemoveDemandModel.setToolTipText("Remove Demand Model"); + btnRemoveDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + demandModelsModel.removeElement(demandModelsList.getSelectedValue()); + repaint(); + } + }); + btnRemoveDemandModel.setEnabled(false); + demandModelButtonPanel.add(btnRemoveDemandModel); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_END; + btnOk = new JButton("OK", new ImageIcon(getClass().getClassLoader().getResource("icons/clock_go.png"))); + btnOk.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveState(); + } + }); + getRootPane().setDefaultButton(btnOk); + btnCancel = new JButton("Cancel", new ImageIcon(getClass().getClassLoader().getResource("icons/clock_delete.png"))); + btnCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + buttonPanel.add(btnOk); + buttonPanel.add(btnCancel); + contentPanel.add(buttonPanel, c); + + setContentPane(contentPanel); + setModal(true); + } + + /** + * Initializes the dialog components for a new state. + */ + private void initialize() { + txtName.setText(state.getName()); + ddlType.setSelectedItem(state.getStateType()); + for(I_DemandModel model : state.getDemandModels()) { + demandModelsModel.addElement(model); + } + repaint(); + } + + /** + * Checks if is state valid. + * + * @return true, if is state valid + */ + private boolean isStateValid() { + if(txtName.getText().length()==0) { + JOptionPane.showMessageDialog(this, + "Please enter a state name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + return true; + } + + /** + * Save state. + */ + private void saveState() { + if(isStateValid()) { + state.setName(txtName.getText()); + state.setStateType((StateType)ddlType.getSelectedItem()); + state.getDemandModels().clear(); + for(Object o : demandModelsModel.toArray()) { + state.getDemandModels().add((I_DemandModel)o); + } + if(!elementDialog.containsState(state)) { + elementDialog.addState(state); + } + elementDialog.repaint(); + dispose(); + } + } + + /** + * Gets the this. + * + * @return the this + */ + public StateDialog getThis() { + return this; + } + + /** + * Gets the element dialog. + * + * @return the element dialog + */ + public ElementDialog getElementDialog() { + return elementDialog; + } + + /** + * Gets the state. + * + * @return the state + */ + public I_State getState() { + return state; + } + + /** + * Contains demand model. + * + * @param demandModel the demand model + * + * @return true, if successful + */ + public boolean containsDemandModel(I_DemandModel demandModel) { + return demandModelsModel.contains(demandModel); + } + + /** + * Adds the demand model. + * + * @param demandModel the demand model + */ + public void addDemandModel(I_DemandModel demandModel) { + demandModelsModel.addElement(demandModel); + } + + /** + * Creates the and show gui. + * + * @param elementDialog the element dialog + * @param state the state + */ + public static void createAndShowGUI(ElementDialog elementDialog, I_State state) { + StateDialog d = new StateDialog(elementDialog, state); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/element/SurfaceVehiclePanel.java b/src/main/java/edu/mit/spacenet/gui/element/SurfaceVehiclePanel.java new file mode 100644 index 0000000..24f7c1c --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/element/SurfaceVehiclePanel.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.element; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.SurfaceVehicle; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.renderer.ResourceListCellRenderer; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * An element panel for viewing and editing surface vehicle-specific inputs. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class SurfaceVehiclePanel extends AbstractElementPanel { + private static final long serialVersionUID = 6335483106289763369L; + + private SurfaceVehicle vehicle; + + private JSpinner maxSpeedSpinner, maxFuelSpinner, fuelSpinner; + private SpinnerNumberModel maxSpeedModel, maxFuelModel, fuelModel; + private UnitsWrapper maxFuelWrapper, fuelWrapper; + private JComboBox resourceCombo; + + /** + * Instantiates a new surface vehicle panel. + * + * @param elementDialog the element dialog + * @param vehicle the vehicle + */ + public SurfaceVehiclePanel(ElementDialog elementDialog, SurfaceVehicle vehicle) { + super(elementDialog, vehicle); + this.vehicle = vehicle; + setLayout(new GridBagLayout()); + setOpaque(false); + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridy = 0; + c.gridx = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Maximum Speed: "), c); + c.gridy++; + add(new JLabel("Fuel Type: "), c); + c.gridy++; + add(new JLabel("Max Fuel: "), c); + c.gridx+=2; + c.weightx = 1; + add(new JLabel("Initial Fuel: "), c); + + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.gridx = 1; + c.gridy = 0; + c.weightx = 1; + c.gridwidth = 3; + maxSpeedModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,0.1); + maxSpeedSpinner = new JSpinner(maxSpeedModel); + maxSpeedSpinner.setPreferredSize(new Dimension(50,20)); + add(new UnitsWrapper(maxSpeedSpinner, "km/hr"), c); + maxSpeedSpinner.setToolTipText("Maximum surface transport speed [kilometers per hour]"); + + c.gridy++; + resourceCombo = new JComboBox(); + resourceCombo.addItem(null); + for(I_Resource r : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()) { + if(r.getClassOfSupply().equals(ClassOfSupply.COS1) + || r.getClassOfSupply().isSubclassOf(ClassOfSupply.COS1)) { + resourceCombo.addItem(r); + } + } + for(ClassOfSupply cos : ClassOfSupply.values()) { + if(cos.equals(ClassOfSupply.COS1) + || cos.isSubclassOf(ClassOfSupply.COS1)) { + resourceCombo.addItem(new GenericResource(cos)); + } + } + resourceCombo.setRenderer(new ResourceListCellRenderer()); + resourceCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED + && resourceCombo.getSelectedItem() != null) { + String fuelUnits = ((I_Resource)resourceCombo.getSelectedItem()).getUnits(); + maxFuelWrapper.setUnits(fuelUnits); + fuelWrapper.setUnits(fuelUnits); + } + } + }); + add(resourceCombo, c); + + c.gridy++; + c.gridwidth = 1; + maxFuelModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + maxFuelSpinner = new JSpinner(maxFuelModel); + maxFuelSpinner.setPreferredSize(new Dimension(75,20)); + maxFuelWrapper = new UnitsWrapper(maxFuelSpinner, ""); + add(maxFuelWrapper, c); + maxFuelSpinner.setToolTipText("Maximum amount of fuel"); + + c.gridx+=2; + fuelModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE,GlobalParameters.getMassPrecision()); + fuelSpinner = new JSpinner(fuelModel); + fuelSpinner.setPreferredSize(new Dimension(75,20)); + fuelWrapper = new UnitsWrapper(fuelSpinner, ""); + add(fuelWrapper, c); + fuelSpinner.setToolTipText("Initial amount of fuel"); + } + + /** + * Initializes the panel components for a new surface vehicle. + */ + private void initialize() { + maxSpeedModel.setValue(vehicle.getMaxSpeed()); + maxFuelModel.setValue(vehicle.getFuelTank().getMaxAmount()); + fuelModel.setValue(vehicle.getFuelTank().getAmount()); + resourceCombo.setSelectedItem(vehicle.getFuelTank().getResource()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#getElement() + */ + @Override + public SurfaceVehicle getElement() { + return vehicle; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#saveElement() + */ + @Override + public void saveElement() { + vehicle.setMaxSpeed(maxSpeedModel.getNumber().doubleValue()); + vehicle.getFuelTank().setMaxAmount(maxFuelModel.getNumber().doubleValue()); + vehicle.getFuelTank().setAmount(Math.min(maxFuelModel.getNumber().doubleValue(), fuelModel.getNumber().doubleValue())); + vehicle.getFuelTank().setResource((I_Resource)resourceCombo.getSelectedItem()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isElementValid() + */ + @Override + public boolean isElementValid() { + if((maxFuelModel.getNumber().doubleValue() > 0 + || fuelModel.getNumber().doubleValue() > 0) + && resourceCombo.getSelectedItem()==null) + return false; + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.element.AbstractElementPanel#isVerticallyExpandable() + */ + public boolean isVerticallyExpandable() { + return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/AbstractEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/AbstractEventPanel.java new file mode 100644 index 0000000..687a77c --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/AbstractEventPanel.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import javax.swing.JPanel; + +import edu.mit.spacenet.simulator.event.I_Event; + +/** + * The Class AbstractEventPanel. + * + * @author Paul Grogan + */ +public abstract class AbstractEventPanel extends JPanel { + private static final long serialVersionUID = 1383454658585330190L; + + private EventDialog eventDialog; + + /** + * Instantiates a new abstract event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public AbstractEventPanel(EventDialog eventDialog, I_Event event) { + this.eventDialog = eventDialog; + } + + /** + * Saves the event. + */ + public abstract void saveEvent(); + + /** + * Updates the view. + */ + public abstract void updateView(); + + /** + * Gets the event dialog. + * + * @return the event dialog + */ + public EventDialog getEventDialog() { + return eventDialog; + } + + /** + * Gets the event. + * + * @return the event + */ + public abstract I_Event getEvent(); +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/AddEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/AddEventPanel.java new file mode 100644 index 0000000..ccfe067 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/AddEventPanel.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.text.DecimalFormat; +import java.util.ArrayList; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.simulator.event.AddEvent; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A panel for viewing and editing an add event. + * + * @author Paul Grogan + */ +public class AddEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private AddEvent event; + + private ElementTree elementTree; + private JLabel containerEnvironmentLabel; + private JProgressBar containerMassCapacity, containerVolumeCapacity; + private DemandTable demandsList; + private JScrollPane demandsScroll; + private JButton addDemandButton, removeDemandButton; + + /** + * Instantiates a new adds the event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public AddEventPanel(EventDialog eventDialog, AddEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.weightx = 0; + c.weighty = 0; + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Element: "), c); + c.gridy++; + add(new JLabel("Environment: "), c); + c.gridy++; + add(new JLabel("Cargo Mass: "), c); + c.gridy++; + add(new JLabel("Cargo Volume: "), c); + c.gridy++; + add(new JLabel("Resources: "), c); + + c.gridx = 1; + c.gridy = 0; + c.weighty = .5; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + elementTree = new ElementTree(); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,100)); + add(elementScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + containerEnvironmentLabel = new JLabel(); + add(containerEnvironmentLabel, c); + c.gridy++; + containerMassCapacity = new JProgressBar(0,100); + containerMassCapacity.setStringPainted(true); + containerMassCapacity.setString(""); + add(containerMassCapacity, c); + c.gridy++; + containerVolumeCapacity = new JProgressBar(0,100); + containerVolumeCapacity.setStringPainted(true); + containerVolumeCapacity.setString(""); + add(containerVolumeCapacity, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + demandsList = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + demandsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + demandsScroll = new JScrollPane(demandsList); + demandsScroll.setPreferredSize(new Dimension(400,50)); + demandsScroll.setBackground(Color.WHITE); + demandsScroll.getViewport().setBackground(Color.WHITE); + add(demandsScroll, c); + + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + JPanel demandButtonPanel = new JPanel(); + demandButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + addDemandButton = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_put.png"))); + addDemandButton.setMargin(new Insets(3,3,3,3)); + addDemandButton.setToolTipText("Add Resource"); + demandButtonPanel.add(addDemandButton); + removeDemandButton = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_remove.png"))); + removeDemandButton.setMargin(new Insets(3,3,3,3)); + removeDemandButton.setToolTipText("Remove Resource"); + removeDemandButton.setEnabled(false); + demandButtonPanel.add(removeDemandButton); + add(demandButtonPanel, c); + } + private void initialize() { + elementTree.setRoot(getEventDialog().getSimNode()); + if(event.getContainer()!=null) { + elementTree.setSelection(getEventDialog().getSimElement(event.getContainer().getUid())); + } + elementTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + updateCapacities(); + } + }); + for(Demand demand : event.getDemands()) { + demandsList.addDemand(demand); + } + demandsList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(demandsList.getSelectedRows().length >= 1) { + removeDemandButton.setEnabled(true); + } else { + removeDemandButton.setEnabled(false); + } + } + }); + demandsList.getModel().addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + updateCapacities(); + } + }); + addDemandButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + demandsList.addDemand(new Demand()); + } + }); + removeDemandButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList demands = new ArrayList(); + for(int row : demandsList.getSelectedRows()) { + demands.add(demandsList.getDemand(row)); + } + for(Demand demand : demands) { + demandsList.remove(demand); + } + updateView(); + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public AddEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setContainer((I_ResourceContainer)getEventDialog().getElement((elementTree.getElementSelection().getUid()))); + event.getDemands().clear(); + for(Demand demand: demandsList.getDemands()) { + if(demand.getResource()!=null) + event.getDemands().add(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + I_Element selectedItem = elementTree.getElementSelection(); + elementTree.setRoot(getEventDialog().getSimNode()); + if(selectedItem!=null) + elementTree.setSelection(getEventDialog().getSimElement(selectedItem.getUid())); + updateCapacities(); + } + private void updateCapacities() { + if(elementTree.getSelection() instanceof I_ResourceContainer) { + I_ResourceContainer container = (I_ResourceContainer)elementTree.getSelection(); + double cargoMass = container.getCargoMass(); + double cargoVolume = container.getCargoVolume(); + + for(Demand demand : demandsList.getDemands()) { + cargoMass += demand.getMass(); + cargoVolume += demand.getVolume(); + } + + DecimalFormat massFormat = new DecimalFormat("0.00"); + DecimalFormat volumeFormat = new DecimalFormat("0.000"); + containerEnvironmentLabel.setText(container.getCargoEnvironment().toString()); + + boolean hasErrors = false; + + if(cargoMass > container.getMaxCargoMass()) { + containerMassCapacity.setForeground(new Color(153, 0, 0)); + hasErrors = true; + } + else { + containerMassCapacity.setForeground(new Color(0, 153, 0)); + } + if(container.getMaxCargoMass()==0) containerMassCapacity.setValue(100); + else containerMassCapacity.setValue((int)(100*cargoMass/container.getMaxCargoMass())); + containerMassCapacity.setString(massFormat.format(cargoMass) + " / " + massFormat.format(container.getMaxCargoMass()) + " kg"); + + if(cargoVolume > container.getMaxCargoVolume()) { + containerVolumeCapacity.setForeground(new Color(153, 0, 0)); + hasErrors = hasErrors||GlobalParameters.isVolumeConstrained(); + } + else { + containerVolumeCapacity.setForeground(new Color(0, 153, 0)); + } + if(container.getMaxCargoVolume()==0) containerVolumeCapacity.setValue(100); + else containerVolumeCapacity.setValue((int)(100*cargoVolume/container.getMaxCargoVolume())); + containerVolumeCapacity.setString(volumeFormat.format(cargoVolume) + " / " + volumeFormat.format(container.getMaxCargoVolume()) + " m^3"); + + getEventDialog().setOkButtonEnabled(!hasErrors); + } else { + containerEnvironmentLabel.setText(null); + containerMassCapacity.setValue(0); + containerMassCapacity.setString(""); + containerVolumeCapacity.setValue(0); + containerVolumeCapacity.setString(""); + getEventDialog().setOkButtonEnabled(false); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/BurnEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/BurnEventPanel.java new file mode 100644 index 0000000..63192f2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/BurnEventPanel.java @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Set; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.ListSelectionModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.TreeSelectionModel; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.domain.network.edge.BurnType; +import edu.mit.spacenet.gui.component.CheckBoxNode; +import edu.mit.spacenet.gui.component.CheckBoxTree; +import edu.mit.spacenet.gui.component.CheckBoxTreeModel; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.simulator.event.BurnEvent; +import edu.mit.spacenet.simulator.event.BurnStageItem; +import edu.mit.spacenet.util.Formulae; + +/** + * A panel for viewing and editing a burn event. + * + * @author Paul Grogan + */ +public class BurnEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private BurnEvent event; + + private JComboBox ddlBurnType; + private SpinnerNumberModel burnDeltaVModel; + private JSpinner burnDeltaVSpinner; + private JButton btnAddBurn, btnAddStage, btnClear; + private DefaultListModel sequenceModel; + private JList sequenceList; + private JProgressBar deltaV; + private JLabel stackMassLabel; + + private CheckBoxTreeModel elementModel; + private CheckBoxTree elementTree; + + /** + * Instantiates a new burn event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public BurnEventPanel(EventDialog eventDialog, BurnEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Burn Type: "), c); + c.gridy++; + add(new JLabel("Required Delta-V: "), c); + c.gridx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.gridy = 0; + ddlBurnType = new JComboBox(); + for(BurnType t : BurnType.values()) + ddlBurnType.addItem(t); + add(ddlBurnType, c); + c.gridy++; + burnDeltaVModel = new SpinnerNumberModel(0, 0, 10000, 1.0); + burnDeltaVSpinner = new JSpinner(burnDeltaVModel); + add(new UnitsWrapper(burnDeltaVSpinner, "m/s"), c); + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Elements: "), c); + c.gridy+=2; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Delta-V: "), c); + c.gridy++; + add(new JLabel("Stack Mass: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Sequence: "), c); + + c.gridy = 2; + c.gridx = 1; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + elementModel = new CheckBoxTreeModel(); + elementTree = new CheckBoxTree(elementModel); + elementTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + elementTree.setRootVisible(false); + elementTree.setShowsRootHandles(true); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,100)); + add(elementScroll, c); + + c.gridy++; + c.weighty = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel sequenceButtonPanel = new JPanel(); + sequenceButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + btnAddBurn = new JButton("Burn"); + btnAddBurn.setToolTipText("Burn the selected propulsive vehicles"); + btnAddBurn.setIcon(BurnStageItem.BURN_ICON); + btnAddBurn.setMargin(new Insets(3,3,3,3)); + sequenceButtonPanel.add(btnAddBurn); + btnAddStage = new JButton("Stage"); + btnAddStage.setToolTipText("Stage the selected elements"); + btnAddStage.setIcon(BurnStageItem.STAGE_ICON); + btnAddStage.setMargin(new Insets(3,3,3,3)); + sequenceButtonPanel.add(btnAddStage); + add(sequenceButtonPanel, c); + + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + deltaV = new JProgressBar(0, 100); + deltaV.setStringPainted(true); + add(deltaV, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + stackMassLabel = new JLabel(); + add(new UnitsWrapper(stackMassLabel, "kg"), c); + + c.gridy++; + c.weighty = 1; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + sequenceModel = new DefaultListModel(); + sequenceList = new JList(sequenceModel); + sequenceList.setCellRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(((BurnStageItem)value).getBurnStage().equals(BurnStageItem.BURN)) { + label.setIcon(BurnStageItem.BURN_ICON); + } else { + label.setIcon(BurnStageItem.STAGE_ICON); + } + + return label; + } + }); + sequenceList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + JScrollPane sequenceScroll = new JScrollPane(sequenceList); + sequenceScroll.setPreferredSize(new Dimension(200,100)); + add(sequenceScroll, c); + + c.gridy++; + c.weighty = 0; + c.weightx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + btnClear = new JButton("Clear"); + btnClear.setToolTipText("Clear the selected burns or stages"); + btnClear.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/cross.png"))); + btnClear.setMargin(new Insets(3,3,3,3)); + add(btnClear, c); + } + private void initialize() { + ddlBurnType.setSelectedItem(event.getBurn().getBurnType()); + burnDeltaVModel.setValue(event.getBurn().getDeltaV()); + for(BurnStageItem i : event.getBurnStageSequence()) { + BurnStageItem bs = new BurnStageItem(); + bs.setBurnStage(i.getBurnStage()); + bs.setElement(getEventDialog().getSimElement(i.getElement().getUid())); + sequenceModel.addElement(bs); + } + ddlBurnType.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + BurnEvent event = (BurnEvent)getEvent(); + if(!ddlBurnType.getSelectedItem().equals(event.getBurn().getBurnType())) { + event.getBurn().setBurnType(BurnType.getInstance(ddlBurnType.getSelectedItem().toString())); + updateView(); + } + } + }); + burnDeltaVSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + ((BurnEvent)getEvent()).getBurn().setDeltaV(burnDeltaVModel.getNumber().doubleValue()); + updateView(); + } + }); + + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(event.getElements()); + elementModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + updateView(); + updateButtons(); + } + public void treeNodesInserted(TreeModelEvent e) { } + public void treeNodesRemoved(TreeModelEvent e) { } + public void treeStructureChanged(TreeModelEvent e) { } + }); + + elementTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + if(!elementTree.isSelectionEmpty()) { + sequenceList.clearSelection(); + } + updateButtons(); + } + }); + btnAddBurn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + sequenceModel.addElement(new BurnStageItem(BurnStageItem.BURN, + ((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement())); + updateView(); + } + }); + btnAddStage.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + sequenceModel.addElement(new BurnStageItem(BurnStageItem.STAGE, + ((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement())); + updateView(); + } + }); + sequenceList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(!sequenceList.isSelectionEmpty()) { + elementTree.clearSelection(); + } + updateButtons(); + } + }); + btnClear.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for(Object o : sequenceList.getSelectedValues()) + sequenceModel.removeElement(o); + updateView(); + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public BurnEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setBurn(new Burn(0, + BurnType.getInstance(ddlBurnType.getSelectedItem().toString()), + burnDeltaVModel.getNumber().doubleValue())); + + event.getElements().clear(); + for(I_Element element : elementModel.getTopCheckedElements()) { + event.getElements().add(getEventDialog().getElement(element.getUid())); + } + + ArrayList sequence = new ArrayList(); + for(Object o : sequenceModel.toArray()) { + BurnStageItem i = new BurnStageItem(); + i.setBurnStage(((BurnStageItem)o).getBurnStage()); + i.setElement(getEventDialog().getElement(((BurnStageItem)o).getElement().getUid())); + sequence.add(i); + } + event.setBurnStateSequence(sequence); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + Set checkedElements = elementModel.getTopCheckedElements(); + int[] selectionRows = elementTree.getSelectionRows(); + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(checkedElements); + elementTree.setSelectionRows(selectionRows); + elementModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + updateView(); + updateButtons(); + } + public void treeNodesInserted(TreeModelEvent e) { } + public void treeNodesRemoved(TreeModelEvent e) { } + public void treeStructureChanged(TreeModelEvent e) { } + }); + + for(Object o : sequenceModel.toArray()) { + boolean isFound = false; + for(I_Element element : elementModel.getTopCheckedElements()) { + if(element.equals(((BurnStageItem)o).getElement())) isFound = true; + } + if(!isFound) sequenceModel.clear(); + } + updateDeltaV(); + } + private void updateButtons() { + if(elementTree.getSelectionCount() > 0) { + if(elementTree.getSelectionCount() == 1 + && ((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).isChecked() + && elementModel.getTopCheckedElements().contains(((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement())) { + boolean isStaged = false; + for(Object o : sequenceModel.toArray()) { + if(((BurnStageItem)o).getElement().equals(((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement()) + && ((BurnStageItem)o).getBurnStage().equals(BurnStageItem.STAGE)) { + isStaged = true; + break; + } + } + if(isStaged) { + btnAddStage.setEnabled(false); + btnAddBurn.setEnabled(false); + } else { + btnAddStage.setEnabled(true); + if(((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement() instanceof PropulsiveVehicle) { + PropulsiveVehicle v = (PropulsiveVehicle)((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement(); + BurnEvent event = (BurnEvent)this.event; + if((event.getBurn().getBurnType().equals(BurnType.OMS) && v.getOmsFuelTank() != null) + ||(event.getBurn().getBurnType().equals(BurnType.RCS) && v.getRcsFuelTank() != null)) + btnAddBurn.setEnabled(true); + else + btnAddBurn.setEnabled(false); + } else { + btnAddBurn.setEnabled(false); + } + } + } else { + btnAddStage.setEnabled(false); + btnAddBurn.setEnabled(false); + } + } else { + btnAddStage.setEnabled(false); + btnAddBurn.setEnabled(false); + } + if(sequenceList.getSelectedIndices().length > 0) { + btnClear.setEnabled(true); + } else { + btnClear.setEnabled(false); + } + } + private void updateDeltaV() { + double stackMass = 0; + double deltaVReq = burnDeltaVModel.getNumber().doubleValue(); + + //System.out.println("deltaVReq: " + deltaVReq); + + for(I_Element e : elementModel.getTopCheckedElements()) + stackMass += e.getTotalMass(); + + for(Object o : sequenceModel.toArray()) { + BurnStageItem i = (BurnStageItem)o; + if(i.getBurnStage().equals(BurnStageItem.STAGE)) { + // staged elements are no longer in the contents model + stackMass += i.getElement().getTotalMass(); + } + } + + //System.out.println("stackMass: " + stackMass); + + for(Object o : sequenceModel.toArray()) { + BurnStageItem i = (BurnStageItem)o; + if(i.getBurnStage().equals(BurnStageItem.STAGE)) { + //System.out.println("stage: " + i.getElement().getName()); + stackMass -= i.getElement().getTotalMass(); + } else if(i.getBurnStage().equals(BurnStageItem.BURN)) { + //System.out.println("burn: " + i.getElement().getName()); + PropulsiveVehicle v = (PropulsiveVehicle)i.getElement(); + if(((BurnType)ddlBurnType.getSelectedItem()).equals(BurnType.OMS)) { + if(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getOmsIsp()) > v.getOmsFuelTank().getAmount()) { + double deltaVAchieved = Formulae.getAchievedDeltaV(stackMass, v.getOmsIsp(), v.getOmsFuelTank().getAmount()); + //System.out.println("dv achieved: " + deltaVAchieved); + deltaVReq -= deltaVAchieved; + stackMass -= v.getOmsFuelTank().getAmount(); + } else { + //System.out.println("dv achieved: " + deltaVReq); + stackMass -= Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getOmsIsp()); + deltaVReq = 0; + } + } else { + if(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getRcsIsp()) > v.getRcsFuelTank().getAmount()) { + double deltaVAchieved = Formulae.getAchievedDeltaV(stackMass, v.getRcsIsp(), v.getRcsFuelTank().getAmount()); + //System.out.println("dv achieved: " + deltaVAchieved); + deltaVReq -= deltaVAchieved; + stackMass -= v.getRcsFuelTank().getAmount(); + } else { + //System.out.println("dv achieved: " + deltaVReq); + stackMass -= Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getRcsIsp()); + deltaVReq = 0; + } + } + } + } + if(deltaVReq == 0) { + deltaV.setForeground(new Color(0, 153, 0)); + getEventDialog().setOkButtonEnabled(true); + } else { + deltaV.setForeground(new Color(153, 0, 0)); + getEventDialog().setOkButtonEnabled(false); + } + DecimalFormat format = new DecimalFormat("0.0"); + stackMassLabel.setText(format.format(stackMass)); + deltaV.setValue((int)(100*((burnDeltaVModel.getNumber().doubleValue() - deltaVReq)/burnDeltaVModel.getNumber().doubleValue()))); + deltaV.setString(format.format(burnDeltaVModel.getNumber().doubleValue() - deltaVReq) + " / " + burnDeltaVModel.getNumber() + " m/s"); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/CreateEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/CreateEventPanel.java new file mode 100644 index 0000000..6e70afe --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/CreateEventPanel.java @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.HashSet; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; + +import edu.mit.spacenet.data.ElementPreview; +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.ElementType; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.CapacityPanel; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.gui.component.SearchTextField; +import edu.mit.spacenet.gui.element.ElementDialog; +import edu.mit.spacenet.gui.renderer.ElementPreviewListCellRenderer; +import edu.mit.spacenet.simulator.event.CreateEvent; + +/** + * A panel for viewing and editing a create event. + * + * @author Paul Grogan + */ +public class CreateEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private CreateEvent event; + + private JComboBox containerCombo, elementTypeCombo; + private CapacityPanel capacityPanel; + private JList elementLibraryList; + private ElementTree elementTree; + private SearchTextField searchText; + private JButton addElementButton, editElementButton, removeElementButton; + + private DefaultListModel elementLibraryModel; + + /** + * Instantiates a new creates the event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public CreateEventPanel(EventDialog eventDialog, CreateEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + add(buildLeftPanel(), c); + c.gridx++; + add(buildRightPanel(), c); + } + + /** + * Builds the left panel. + * + * @return the left panel + */ + private JPanel buildLeftPanel() { + JPanel leftPanel = new JPanel(); + leftPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + leftPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + leftPanel.add(new JLabel("Create in: "), c); + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + containerCombo = new ContainerComboBox(); + leftPanel.add(containerCombo, c); + c.gridy++; + c.weightx = 0; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.HORIZONTAL; + capacityPanel = new CapacityPanel(); + leftPanel.add(capacityPanel, c); + c.gridy++; + c.gridx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.FIRST_LINE_END; + leftPanel.add(new JLabel("Elements: "), c); + c.gridy++; + c.gridwidth = 2; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + elementTree = new ElementTree(); + elementTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + editElementButton.setEnabled(elementTree.getSelectionCount() == 1); + removeElementButton.setEnabled(elementTree.getSelectionCount() >= 1); + } + }); + elementTree.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2 && elementTree.getSelectionCount()==1) { + ElementDialog.createAndShowGUI(getEventDialog(), elementTree.getElementSelection()); + } + } + }); + elementTree.setRootVisible(false); + elementTree.setShowsRootHandles(true); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(100,200)); + leftPanel.add(elementScroll, c); + c.weighty = 0; + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + editElementButton = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/brick_edit.png"))); + editElementButton.setToolTipText("Edit Element"); + editElementButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ElementDialog.createAndShowGUI(getEventDialog(), elementTree.getElementSelection()); + } + }); + editElementButton.setEnabled(false); + buttonPanel.add(editElementButton); + removeElementButton = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/brick_delete.png"))); + removeElementButton.setToolTipText("Remove Element"); + removeElementButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + HashSet elements = new HashSet(); + for(TreePath p : elementTree.getSelectionPaths()) { + elements.add((I_Element)((DefaultMutableTreeNode)p.getLastPathComponent()).getUserObject()); + } + for(I_Element element : elements) { + elementTree.getModel().removeElement(element); + } + updateView(); + } + }); + removeElementButton.setEnabled(false); + buttonPanel.add(removeElementButton); + leftPanel.add(buttonPanel, c); + return leftPanel; + } + + /** + * Builds the right panel. + * + * @return the right panel + */ + private JPanel buildRightPanel() { + JPanel rightPanel = new JPanel(); + rightPanel.setBorder(BorderFactory.createTitledBorder("Element Library")); + rightPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + JPanel filterPanel = new JPanel(); + filterPanel.setLayout(new BoxLayout(filterPanel, BoxLayout.LINE_AXIS)); + searchText = new SearchTextField("Enter Search Term"); + searchText.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent e) { + updateElementLibrary(); + } + }); + filterPanel.add(searchText); + elementTypeCombo = new JComboBox(); + elementTypeCombo.addItem("All"); + for(ElementType t : ElementType.values()) { + elementTypeCombo.addItem(t); + } + elementTypeCombo.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + updateElementLibrary(); + } + }); + filterPanel.add(elementTypeCombo); + rightPanel.add(filterPanel, c); + c.gridy++; + c.weighty = 1; + elementLibraryModel = new DefaultListModel(); + elementLibraryList = new JList(elementLibraryModel); + elementLibraryList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + addElementButton.setEnabled(elementLibraryList.getSelectedIndex()>=0); + } + }); + elementLibraryList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2 && elementLibraryList.getSelectedIndex()>=0) { + try { + addElement(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().loadElement( + ((ElementPreview)elementLibraryList.getSelectedValue()).ID)); + } catch(Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(null, + "An error occurred while accessing the data source to load the element", + "Error Loading Element", + JOptionPane.ERROR_MESSAGE); + } + } + } + }); + elementLibraryList.setCellRenderer(new ElementPreviewListCellRenderer()); + JScrollPane elementLibraryScroll = new JScrollPane(elementLibraryList); + rightPanel.add(elementLibraryScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + addElementButton = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/brick_add.png"))); + addElementButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for (Object o : elementLibraryList.getSelectedValues()) { + try { + addElement(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().loadElement(((ElementPreview)o).ID)); + } catch(Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(null, + "An error occurred while accessing the data source to load the element", + "Error Loading Element", + JOptionPane.ERROR_MESSAGE); + } + } + } + }); + addElementButton.setEnabled(false); + rightPanel.add(addElementButton, c); + return rightPanel; + } + + /** + * Initializes the panel. + */ + private void initialize() { + containerCombo.addItem(event.getContainer()); + containerCombo.setSelectedItem(event.getContainer()); + + containerCombo.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + updateCapacities(); + } + }); + for(I_Element element : event.getElements()) { + elementTree.getModel().addElement(element); + } + updateElementLibrary(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public CreateEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + if(containerCombo.getSelectedItem() instanceof I_Element) { + event.setContainer((I_Container)getEventDialog().getElement(((I_Element)containerCombo.getSelectedItem()).getUid())); + } else { + event.setContainer((I_Container)containerCombo.getSelectedItem()); + } + event.getElements().clear(); + for(I_Element element : elementTree.getModel().getElements()) { + event.getElements().add(element); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + I_Container container = (I_Container)containerCombo.getSelectedItem(); + containerCombo.removeAllItems(); + containerCombo.addItem(getEventDialog().getNode()); + if(getEventDialog().getNode().equals(container)) + containerCombo.setSelectedItem(container); + for(I_Element element: getEventDialog().getSimNode().getCompleteContents()) { + if(element instanceof I_Container) { + containerCombo.addItem(element); + if(element.equals(container)) { + containerCombo.setSelectedItem(element); + } + } + } + updateCapacities(); + elementTree.getModel().hackedUpdate(); + } + + /** + * Gets the letter for copying elements. + * + * @param copyNumber the copy number + * @return the letter + */ + private String getLetter(int copyNumber) { + switch(copyNumber) { + case 1:return "A"; case 2:return "B"; case 3:return "C"; + case 4:return "D"; case 5:return "E"; case 6:return "F"; + case 7:return "G"; case 8:return "H"; case 9:return "I"; + case 10:return "J"; case 11:return "K"; case 12:return "L"; + case 13:return "M"; case 14:return "N"; case 15:return "O"; + case 16:return "P"; case 17:return "Q"; case 18:return "R"; + case 19:return "S"; case 20:return "T"; case 21:return "U"; + case 22:return "V"; case 23:return "W"; case 24:return "X"; + case 25:return "Y"; case 26:return "Z"; default:return "?"; + } + } + + /** + * Adds the element. + * + * @param element the element + */ + private void addElement(I_Element element) { + element.setName(getEventDialog().getMissionPanel().getMissionSplitPane().getMission().getName().substring(0,Math.min(getEventDialog().getMissionPanel().getMissionSplitPane().getMission().getName().length(), 5)) + " | " + element.getName()); + int numElements = 0; + for(I_Element existing : elementTree.getModel().getElements()) { + if(element.getTid()==existing.getTid()) { + numElements++; + } + } + if(numElements == 1) { + for(I_Element existing : elementTree.getModel().getElements()) { + if(element.getTid()==existing.getTid() + && !existing.getName().subSequence(existing.getName().length()-2, existing.getName().length()).equals(" A")) { + existing.setName(existing.getName() + " " + getLetter(numElements)); + } + } + } + if(numElements > 0) element.setName(element.getName() + " " + getLetter(++numElements)); + elementTree.getModel().addElement(element); + updateCapacities(); + } + + /** + * Update element library. + */ + private void updateElementLibrary() { + elementLibraryModel.removeAllElements(); + for(ElementPreview prev : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getElementPreviewLibrary()) { + if((searchText.getText().equals(searchText.getDefaultText()) + || prev.NAME.toLowerCase().contains(searchText.getText().toLowerCase())) + && (elementTypeCombo.getSelectedItem().equals("All") + || prev.TYPE == ((ElementType)elementTypeCombo.getSelectedItem()))) { + elementLibraryModel.addElement(prev); + } + } + } + + /** + * Update capacities. + */ + private void updateCapacities() { + double mass = 0; + double volume = 0; + int crew = 0; + for(I_Element e : elementTree.getModel().getElements()) { + if(e instanceof CrewMember) + crew++; + else { + mass += e.getTotalMass(); + volume += e.getTotalVolume(); + } + } + if(containerCombo.getSelectedItem() instanceof I_Carrier) { + I_Carrier v = (I_Carrier)containerCombo.getSelectedItem(); + mass += v.getCargoMass(); + volume += v.getCargoVolume(); + crew += v.getCrewSize(); + capacityPanel.updateCapacities(v, mass, volume, crew); + } else { + mass += getEventDialog().getSimNode().getCargoMass(); + volume += getEventDialog().getSimNode().getCargoVolume(); + crew += getEventDialog().getSimNode().getCrewSize(); + capacityPanel.updateCapacities(getEventDialog().getSimNode(), mass, volume, crew); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/DemandEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/DemandEventPanel.java new file mode 100644 index 0000000..3cce6e4 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/DemandEventPanel.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.simulator.event.DemandEvent; + +/** + * A panel for viewing and editing a demand event. + * + * @author Paul Grogan + */ +public class DemandEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private DemandEvent event; + + private ElementTree elementTree; + private DemandTable demandsList; + private JScrollPane demandsScroll; + private JButton btnAddDemand, btnRemoveDemand; + + /** + * Instantiates a new demand event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public DemandEventPanel(EventDialog eventDialog, DemandEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.weightx = 0; + c.weighty = 0; + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Element: "), c); + c.gridy++; + add(new JLabel("Demands: "), c); + + c.gridx = 1; + c.gridy = 0; + c.weighty = .5; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + elementTree = new ElementTree(); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,100)); + add(elementScroll, c); + + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + c.weightx = 1; + c.weighty = 1; + demandsList = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + demandsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + demandsScroll = new JScrollPane(demandsList); + demandsScroll.setPreferredSize(new Dimension(400,50)); + demandsScroll.setBackground(Color.WHITE); + demandsScroll.getViewport().setBackground(Color.WHITE); + add(demandsScroll, c); + + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + JPanel demandButtonPanel = new JPanel(); + demandButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + btnAddDemand = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_put.png"))); + btnAddDemand.setMargin(new Insets(3,3,3,3)); + btnAddDemand.setToolTipText("Add Demand"); + demandButtonPanel.add(btnAddDemand); + btnRemoveDemand = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_remove.png"))); + btnRemoveDemand.setMargin(new Insets(3,3,3,3)); + btnAddDemand.setToolTipText("Remove Demand"); + btnRemoveDemand.setEnabled(false); + demandButtonPanel.add(btnRemoveDemand); + add(demandButtonPanel, c); + } + private void initialize() { + elementTree.setRoot(getEventDialog().getSimNode()); + if(event.getElement()!=null) { + elementTree.setSelection(getEventDialog().getSimElement(event.getElement().getUid())); + } + elementTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + getEventDialog().setOkButtonEnabled(elementTree.getSelection()!=null); + } + }); + for(Demand demand : event.getDemands()) { + demandsList.addDemand(demand); + } + demandsList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(demandsList.getSelectedRows().length >= 1) { + btnRemoveDemand.setEnabled(true); + } else { + btnRemoveDemand.setEnabled(false); + } + } + }); + btnAddDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + demandsList.addDemand(new Demand()); + } + }); + btnRemoveDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList demands = new ArrayList(); + for(int row : demandsList.getSelectedRows()) { + demands.add(demandsList.getDemand(row)); + } + for(Demand demand : demands) { + demandsList.remove(demand); + } + updateView(); + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public DemandEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setElement(getEventDialog().getElement(elementTree.getElementSelection().getUid())); + + event.getDemands().clear(); + for(Demand demand: demandsList.getDemands()) { + if(demand.getResource()!=null) + event.getDemands().add(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + I_Element selectedElement = elementTree.getElementSelection(); + elementTree.setRoot(getEventDialog().getSimNode()); + if(selectedElement != null + && getEventDialog().getSimElement(selectedElement.getUid())!=null) + elementTree.setSelection(getEventDialog().getSimElement(selectedElement.getUid())); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/event/EvaEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/EvaEventPanel.java new file mode 100644 index 0000000..42f01ce --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/EvaEventPanel.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.SortedMap; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.ListSelectionModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.simulator.event.EvaEvent; + +/** + * A panel for viewing and editing a EVA event. + * + * @author Paul Grogan + */ +public class EvaEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private EvaEvent event; + + private SpinnerNumberModel evaDurationModel; + private JSpinner evaDurationSpinner; + private ElementTree elementTree; + private JButton btnAddDemand, btnRemoveDemand; + private DemandTable demandsList; + + private EvaTable contentsTable; + + /** + * Instantiates a new eva event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public EvaEventPanel(EventDialog eventDialog, EvaEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel ("EVA Duration: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Crew Location: "), c); + c.gridy++; + add(new JLabel("Crew: "), c); + c.gridy++; + add(new JLabel("Add'l Demands: "), c); + + c.gridx = 1; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + evaDurationModel = new SpinnerNumberModel(0, 0, 20, 0.5); + evaDurationSpinner = new JSpinner(evaDurationModel); + evaDurationSpinner.setPreferredSize(new Dimension(75, 20)); + add(new UnitsWrapper(evaDurationSpinner, "hours"), c); + c.gridy++; + c.weightx = 1; + c.weighty = 0.5; + c.fill = GridBagConstraints.BOTH; + elementTree = new ElementTree(); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setBackground(Color.WHITE); + elementScroll.getViewport().setBackground(Color.WHITE); + elementScroll.setPreferredSize(new Dimension(300,100)); + add(elementScroll, c); + c.gridy++; + contentsTable = new EvaTable(); + contentsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + JScrollPane contentsScroll = new JScrollPane(contentsTable); + contentsScroll.setBackground(Color.WHITE); + contentsScroll.getViewport().setBackground(Color.WHITE); + contentsScroll.setPreferredSize(new Dimension(300,100)); + add(contentsScroll, c); + c.gridy++; + demandsList = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + JScrollPane demandsScroll = new JScrollPane(demandsList); + demandsScroll.setBackground(Color.WHITE); + demandsScroll.getViewport().setBackground(Color.WHITE); + demandsScroll.setPreferredSize(new Dimension(200,50)); + add(demandsScroll, c); + + c.gridy = 5; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.weighty = 0; + c.gridy++; + JPanel demandsButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + btnAddDemand = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_put.png"))); + btnAddDemand.setMargin(new Insets(3,3,3,3)); + btnAddDemand.setToolTipText("Add Demand"); + demandsButtonPanel.add(btnAddDemand); + btnRemoveDemand = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_remove.png"))); + btnRemoveDemand.setMargin(new Insets(3,3,3,3)); + btnRemoveDemand.setToolTipText("Remove Demand"); + btnRemoveDemand.setEnabled(false); + demandsButtonPanel.add(btnRemoveDemand); + add(demandsButtonPanel, c); + } + private void initialize() { + evaDurationModel.setValue(event.getEvaDuration()); + + elementTree.setRoot(getEventDialog().getSimNode()); + if(event.getVehicle()!=null + && getEventDialog().getSimElement(event.getVehicle().getUid())!=null) { + elementTree.setSelection(getEventDialog().getSimElement(event.getVehicle().getUid())); + } + + elementTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + getEventDialog().setOkButtonEnabled(elementTree.getSelectionCount() > 0 + && elementTree.getSelection() instanceof I_Carrier); + updateView(); + } + }); + + for(CrewMember c : event.getStateMap().keySet()) { + CrewMember simCrew = (CrewMember)getEventDialog().getSimElement(c.getUid()); + if(simCrew != null) { + if(event.getStateMap().get(c) == null) { + contentsTable.getModel().put(simCrew, null, true); + } else { + for(I_State simState : simCrew.getStates()) { + if(simState.equals(event.getStateMap().get(c))) { + contentsTable.getModel().put(simCrew, simState, true); + } + } + } + } + } + + for(Demand demand : event.getDemands()) { + demandsList.addDemand(demand); + } + + contentsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(contentsTable.getSelectedRowCount()>0) { + demandsList.clearSelection(); + } + } + }); + demandsList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(!demandsList.getSelectionModel().isSelectionEmpty()) { + contentsTable.clearSelection(); + btnRemoveDemand.setEnabled(true); + } else { + btnRemoveDemand.setEnabled(true); + } + } + }); + btnAddDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + demandsList.addDemand(new Demand()); + } + }); + btnRemoveDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList demands = new ArrayList(); + for(int row : demandsList.getSelectedRows()) { + demands.add(demandsList.getDemand(row)); + } + for(Demand demand : demands) { + demandsList.remove(demand); + } + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public EvaEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setEvaDuration(evaDurationModel.getNumber().doubleValue()); + + event.setVehicle((I_Carrier)getEventDialog().getElement(elementTree.getElementSelection().getUid())); + + event.getStateMap().clear(); + for(CrewMember simCrew : contentsTable.getModel().getData().keySet()) { + CrewMember crew = (CrewMember)getEventDialog().getElement(simCrew.getUid()); + if(crew != null) { + if(contentsTable.getModel().getData().get(simCrew)==null) { + event.getStateMap().put(crew, null); + } else { + for(I_State state : crew.getStates()) { + if(state.equals(contentsTable.getModel().getData().get(simCrew))) { + event.getStateMap().put(crew, state); + break; + } + } + } + } + } + + event.getDemands().clear(); + for(Demand demand: demandsList.getDemands()) { + if(demand.getResource()!=null) + event.getDemands().add(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + I_Element selectedItem = (I_Element)elementTree.getElementSelection(); + TreeSelectionListener treeListener = elementTree.getTreeSelectionListeners()[0]; + elementTree.removeTreeSelectionListener(treeListener); + elementTree.setRoot(getEventDialog().getSimNode()); + if(selectedItem!=null + && getEventDialog().getSimElement(selectedItem.getUid())!=null) { + elementTree.setSelection(getEventDialog().getSimElement(selectedItem.getUid())); + } + elementTree.addTreeSelectionListener(treeListener); + + if(elementTree.getElementSelection() instanceof I_Carrier) { + SortedMap stateMap = contentsTable.getModel().getData(); + contentsTable.getModel().clear(); + for(I_Element element : ((I_Carrier)elementTree.getElementSelection()).getContents()) { + if(element instanceof CrewMember) { + if(stateMap.keySet().contains(element)) { + contentsTable.getModel().put((CrewMember)element, stateMap.get(element), true); + } else { + contentsTable.getModel().put((CrewMember)element, stateMap.get(element), false); + } + } + } + } else { + contentsTable.getModel().clear(); + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/event/EvaTable.java b/src/main/java/edu/mit/spacenet/gui/event/EvaTable.java new file mode 100644 index 0000000..2828915 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/EvaTable.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Component; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import javax.swing.DefaultCellEditor; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JList; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellEditor; + +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.ElementType; +import edu.mit.spacenet.domain.element.I_State; + +/** + * A table for managing EVAs and explorations by selecting crew and EVA states. + * + * @author Paul Grogan + */ +public class EvaTable extends JTable { + private static final long serialVersionUID = 764356022370707951L; + private EvaTableModel model; + + /** + * Instantiates a new eva table. + */ + public EvaTable() { + model = new EvaTableModel(); + setModel(model); + + getColumnModel().getColumn(0).setHeaderValue("EVA?"); + getColumnModel().getColumn(0).setMaxWidth(50); + getColumnModel().getColumn(1).setHeaderValue("Crew Member"); + getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof CrewMember) + setIcon(ElementType.CREW_MEMBER.getIconType().getIcon()); + return this; + } + }); + getColumnModel().getColumn(2).setHeaderValue("EVA State"); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value!=null && value instanceof I_State) + setIcon(((I_State)value).getStateType().getIcon()); + else + setIcon(null); + return this; + } + }); + } + + /* (non-Javadoc) + * @see javax.swing.JTable#getModel() + */ + public EvaTableModel getModel() { + return model; + } + + /* (non-Javadoc) + * @see javax.swing.JTable#getCellEditor(int, int) + */ + public TableCellEditor getCellEditor(int row, int column) { + if(column==2) { + JComboBox stateCombo = new JComboBox(); + stateCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -2255885956722142642L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof I_State) + setIcon(((I_State)value).getStateType().getIcon()); + return this; + } + }); + for(I_State state : ((CrewMember)getValueAt(row, 1)).getStates()) { + stateCombo.addItem(state); + } + return new DefaultCellEditor(stateCombo); + } else return super.getCellEditor(row, column); + } + + /** + * The Class EvaTableModel. + */ + public class EvaTableModel extends AbstractTableModel { + private static final long serialVersionUID = -6033117922087345936L; + private SortedMap data; + private Map visibility; + + /** + * Instantiates a new eva table model. + */ + public EvaTableModel() { + data = new TreeMap(); + visibility = new HashMap(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 3; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + return data.size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) return visibility.get(getValueAt(row,1)); + else if(col==1) return data.keySet().toArray()[row]; + else { + if(visibility.get(getValueAt(row,1))) + return data.get(getValueAt(row,1)); + else return null; + } + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnClass(int) + */ + public Class getColumnClass(int col) { + if(col==0) return Boolean.class; + else if(col==1) return Object.class; + else return Object.class; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int col) { + if(col==0) return true; + else if(col==1) return false; + else return (Boolean)getValueAt(row, 0); + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int) + */ + public void setValueAt(Object value, int row, int col) { + if(col==0) { + if((Boolean)value) { + I_State evaState = ((CrewMember)getValueAt(row,1)).getCurrentState(); + for(I_State s : ((CrewMember)getValueAt(row,1)).getStates()) { + if(s.getName().toLowerCase().contains("eva")) { + evaState = s; + break; + } + } + data.put((CrewMember)getValueAt(row,1),evaState); + } + visibility.put((CrewMember)getValueAt(row,1), (Boolean)value); + } + else data.put((CrewMember)getValueAt(row,1),(I_State)value); + fireTableRowsUpdated(row, row); + } + + /** + * Put. + * + * @param c the c + * @param s the s + * @param isVisible the is visible + */ + public void put(CrewMember c, I_State s, boolean isVisible) { + data.put(c, s); + visibility.put(c, isVisible); + fireTableDataChanged(); + } + + /** + * Clear. + */ + public void clear() { + data.clear(); + visibility.clear(); + fireTableDataChanged(); + } + + /** + * Gets the data. + * + * @return the data + */ + public SortedMap getData() { + TreeMap retData = new TreeMap(); + for(CrewMember c : data.keySet()) { + if(visibility.get(c)) { + retData.put(c, data.get(c)); + } + } + return retData; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/EventDialog.java b/src/main/java/edu/mit/spacenet/gui/event/EventDialog.java new file mode 100644 index 0000000..43c8534 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/EventDialog.java @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; +import javax.swing.SwingWorker; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.mission.MissionPanel; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.PreSimulator; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.util.DateFunctions; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * The dialog used to view and edit events. + * + * @author Paul Grogan + */ +public class EventDialog extends JDialog { + private static final long serialVersionUID = -4959320811142445509L; + + private MissionPanel missionPanel; + private I_Event event; + protected PreSimulator preSim; + + private double initTime; + private int initPriority; + private Location initLocation; + + private SpinnerNumberModel timeModel; + private JSpinner timeSpinner; + private JTextField nameText; + private JComboBox priorityCombo, nodeCombo; + private JButton okButton, cancelButton; + + private AbstractEventPanel eventPanel; + + /** + * Instantiates a new event dialog. + * + * @param missionPanel the mission panel + * @param event the event + */ + public EventDialog(MissionPanel missionPanel, I_Event event) { + super(SpaceNetFrame.getInstance(), event.getEventType().getName(), true); + this.missionPanel = missionPanel; + this.event = event; + initTime = event.getTime(); + initPriority = event.getPriority(); + initLocation = event.getLocation(); + preSim = new PreSimulator(missionPanel.getMissionSplitPane().getMission().getScenario()); + preSim.simulate(DateFunctions.getDaysBetween(missionPanel.getMissionSplitPane().getMission().getScenario().getStartDate(), + missionPanel.getMissionSplitPane().getMission().getStartDate()) + initTime, initPriority); + buildDialog(); + initialize(); + } + + /** + * Builds the dialog. + */ + private void buildDialog() { + JPanel contentPanel = new JPanel(new GridBagLayout()); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + contentPanel.add(buildHeaderPanel(), c); + c.gridy++; + JSeparator separator = new JSeparator(JSeparator.HORIZONTAL); + separator.setPreferredSize(new Dimension(1,1)); + contentPanel.add(separator, c); + c.gridy++; + c.weighty = 1; + eventPanel = EventPanelFactory.createEventPanel(this, event); + contentPanel.add(eventPanel, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + contentPanel.add(buttonPanel, c); + okButton = new JButton("OK", new ImageIcon(getClass().getClassLoader().getResource("icons/cog_go.png"))); + buttonPanel.add(okButton); + cancelButton = new JButton("Cancel", new ImageIcon(getClass().getClassLoader().getResource("icons/cog_delete.png"))); + buttonPanel.add(cancelButton); + + setContentPane(contentPanel); + getRootPane().setDefaultButton(okButton); + if(eventPanel instanceof SpaceTransportPanel) + setMinimumSize(new Dimension(400,600)); // hack for panic layout + else + setMinimumSize(new Dimension(300,400)); + } + + /* (non-Javadoc) + * @see java.awt.Window#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + super.paint(g); + eventPanel.updateView(); // TODO this should not be needed + } + + /** + * Builds the header panel. + * + * @return the header panel + */ + private JPanel buildHeaderPanel() { + JPanel headerPanel = new JPanel(); + headerPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + headerPanel.add(new JLabel("Name: "), c); + c.gridy = 1; + headerPanel.add(new JLabel("Node: "), c); + c.gridy = 2; + headerPanel.add(new JLabel("Time: "), c); + c.gridx+=2; + c.weightx = .5; + headerPanel.add(new JLabel("Priority: "), c); + + c.gridx = 1; + c.gridy = 0; + c.gridwidth = 3; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText = new JTextField(event.getName()); + headerPanel.add(nameText, c); + + c.gridy++; + c.fill = GridBagConstraints.NONE; + nodeCombo = new ContainerComboBox(); + for(Node n : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getNetwork().getNodes()) { + nodeCombo.addItem(n); + if(n.equals(event.getLocation())) nodeCombo.setSelectedItem(n); + } + headerPanel.add(nodeCombo, c); + + c.gridy++; + c.gridwidth = 1; + c.fill = GridBagConstraints.HORIZONTAL; + timeModel = new SpinnerNumberModel(event.getTime(), 0, Double.MAX_VALUE, GlobalParameters.getTimePrecision()); + timeSpinner = new JSpinner(timeModel); + timeSpinner.setPreferredSize(new Dimension(100,20)); + timeSpinner.setToolTipText("Execution time (days) relative to the start of the mission"); + headerPanel.add(new UnitsWrapper(timeSpinner, "days"), c); + + c.gridx+=2; + c.weightx = 1; + c.fill = GridBagConstraints.NONE; + priorityCombo = new JComboBox(); + priorityCombo.setPreferredSize(new Dimension(50,20)); + priorityCombo.setToolTipText("Priority over concurrent events"); + for(int i = 1; i <= 5; i++) priorityCombo.addItem(i); + priorityCombo.setSelectedItem(Math.max(1, Math.min(event.getPriority(),5))); + headerPanel.add(priorityCombo, c); + return headerPanel; + } + + /** + * Initializes the panel for a new event. + */ + private void initialize() { + nodeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + event.setLocation((Node)nodeCombo.getSelectedItem()); + runSimulation(); + } + } + }); + priorityCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + event.setPriority(((Integer)priorityCombo.getSelectedItem()).intValue()); + runSimulation(); + } + } + }); + timeSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + event.setTime(Double.parseDouble(timeModel.getValue().toString())); + runSimulation(); + } + }); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveEvent(); + missionPanel.getMissionSplitPane().getMissionsTab().updateView(); + dispose(); + } + }); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + event.setTime(initTime); + event.setPriority(initPriority); + event.setLocation(initLocation); + dispose(); + } + }); + } + + /** + * Save event. + */ + private void saveEvent() { + event.setTime(timeModel.getNumber().doubleValue()); + event.setPriority((Integer)priorityCombo.getSelectedItem()); + event.setName(nameText.getText()); + event.setLocation((Node)nodeCombo.getSelectedItem()); + eventPanel.saveEvent(); + if(!missionPanel.getMissionSplitPane().getMission().getEventList().contains(event)) { + missionPanel.getMissionSplitPane().getMission().getEventList().add(event); + } + } + + /** + * Runs the simulation. + */ + private void runSimulation() { + SwingWorker worker = new SwingWorker() { + public Void doInBackground() throws Exception { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Pre-simulating..."); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + preSim = new PreSimulator(missionPanel.getMissionSplitPane().getMissionsTab().getScenarioPanel().getScenario()); + double time = DateFunctions.getDaysBetween(getScenario().getStartDate(), + missionPanel.getMissionSplitPane().getMission().getStartDate()) + timeModel.getNumber().doubleValue(); + int priority = ((Integer)priorityCombo.getSelectedItem()).intValue(); + preSim.simulate(time, priority); + return null; + } + public void done() { + eventPanel.updateView(); // TODO change to repaint method call + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + setCursor(Cursor.getDefaultCursor()); + } + }; + worker.execute(); + } + + /** + * Gets the event. + * + * @return the event + */ + public I_Event getEvent() { + return event; + } + + /** + * Gets the mission panel. + * + * @return the mission panel + */ + public MissionPanel getMissionPanel() { + return missionPanel; + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + private Scenario getScenario() { + return missionPanel.getMissionSplitPane().getMissionsTab().getScenarioPanel().getScenario(); + } + + /** + * Sets the ok button enabled. + * + * @param enabled the new ok button enabled + */ + public void setOkButtonEnabled(boolean enabled) { + okButton.setEnabled(enabled); + } + + /** + * Creates the and show gui. + * + * @param missionPanel the mission panel + * @param event the event + */ + public static void createAndShowGUI(MissionPanel missionPanel, I_Event event) { + EventDialog d = new EventDialog(missionPanel, event); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } + + /** + * Gets the node. + * + * @return the node + */ + public Node getNode() { + return (Node)nodeCombo.getSelectedItem(); + } + + /** + * Gets the sim node. + * + * @return the sim node + */ + public Node getSimNode() { + return preSim.getScenario().getNetwork().getNodeByTid(((Node)nodeCombo.getSelectedItem()).getTid()); + } + + /** + * Gets the sim element. + * + * @param uid the uid + * + * @return the sim element + */ + public I_Element getSimElement(int uid) { + return preSim.getScenario().getNetwork().getRegistrar().get(uid); + } + + /** + * Gets the element. + * + * @param uid the uid + * + * @return the element + */ + public I_Element getElement(int uid) { + return getScenario().getElementByUid(uid); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/EventPanelFactory.java b/src/main/java/edu/mit/spacenet/gui/event/EventPanelFactory.java new file mode 100644 index 0000000..239cbac --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/EventPanelFactory.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import edu.mit.spacenet.simulator.event.AddEvent; +import edu.mit.spacenet.simulator.event.BurnEvent; +import edu.mit.spacenet.simulator.event.CreateEvent; +import edu.mit.spacenet.simulator.event.DemandEvent; +import edu.mit.spacenet.simulator.event.EvaEvent; +import edu.mit.spacenet.simulator.event.ExplorationProcess; +import edu.mit.spacenet.simulator.event.FlightTransport; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.MoveEvent; +import edu.mit.spacenet.simulator.event.ReconfigureEvent; +import edu.mit.spacenet.simulator.event.ReconfigureGroupEvent; +import edu.mit.spacenet.simulator.event.RemoveEvent; +import edu.mit.spacenet.simulator.event.SpaceTransport; +import edu.mit.spacenet.simulator.event.SurfaceTransport; +import edu.mit.spacenet.simulator.event.TransferEvent; + +/** + * A factory for creating event panels. + * + * @author Paul Grogan + */ +public class EventPanelFactory { + + /** + * Creates a new EventPanel object. + * + * @param eventDialog the event dialog + * @param event the event + * + * @return the abstract event panel + */ + public static AbstractEventPanel createEventPanel(EventDialog eventDialog, I_Event event) { + switch(event.getEventType()) { + case CREATE: return new CreateEventPanel(eventDialog, (CreateEvent)event); + case MOVE: return new MoveEventPanel(eventDialog, (MoveEvent)event); + case REMOVE: return new RemoveEventPanel(eventDialog, (RemoveEvent)event); + case RECONFIGURE: return new ReconfigureEventPanel(eventDialog, (ReconfigureEvent)event); + case RECONFIGURE_GROUP: return new ReconfigureGroupEventPanel(eventDialog, (ReconfigureGroupEvent)event); + case ADD: return new AddEventPanel(eventDialog, (AddEvent)event); + case TRANSFER: return new TransferEventPanel(eventDialog, (TransferEvent)event); + case DEMAND: return new DemandEventPanel(eventDialog, (DemandEvent)event); + case EVA: return new EvaEventPanel(eventDialog, (EvaEvent)event); + case EXPLORATION: return new ExplorationProcessPanel(eventDialog, (ExplorationProcess)event); + case BURN: return new BurnEventPanel(eventDialog, (BurnEvent)event); + case SPACE_TRANSPORT: return new SpaceTransportPanel(eventDialog, (SpaceTransport)event); + case SURFACE_TRANSPORT: return new SurfaceTransportPanel(eventDialog, (SurfaceTransport)event); + case FLIGHT_TRANSPORT: return new FlightTransportPanel(eventDialog, (FlightTransport)event); + default: throw new RuntimeException("Unsupported Event"); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/ExplorationProcessPanel.java b/src/main/java/edu/mit/spacenet/gui/event/ExplorationProcessPanel.java new file mode 100644 index 0000000..b8795dd --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/ExplorationProcessPanel.java @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.SortedMap; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.ListSelectionModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.simulator.event.ExplorationProcess; + +/** + * A panel for viewing and editing an exploration process. + * + * @author Paul Grogan + */ +public class ExplorationProcessPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private ExplorationProcess event; + + private SpinnerNumberModel durationModel, evaPerWeekModel, evaDurationModel; + private JSpinner durationSpinner, evaPerWeekSpinner, evaDurationSpinner; + private ElementTree elementTree; + private JButton btnAddDemand, btnRemoveDemand; + private DemandTable demandsList; + + private EvaTable contentsTable; + + /** + * Instantiates a new exploration process panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public ExplorationProcessPanel(EventDialog eventDialog, ExplorationProcess event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Duration: "), c); + c.gridy++; + add(new JLabel("Number EVAs: "), c); + c.gridy++; + add(new JLabel ("EVA Duration: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Crew Location: "), c); + c.gridy++; + add(new JLabel("Crew: "), c); + c.gridy++; + add(new JLabel("Add'l Demands: "), c); + + c.gridx = 1; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + durationModel = new SpinnerNumberModel(0, 0, 1000,.1); + durationSpinner = new JSpinner(durationModel); + durationSpinner.setPreferredSize(new Dimension(75, 20)); + add(new UnitsWrapper(durationSpinner, "days"), c); + c.gridy++; + evaPerWeekModel = new SpinnerNumberModel(0, 0, 14, 0.1); + evaPerWeekSpinner = new JSpinner(evaPerWeekModel); + evaPerWeekSpinner.setPreferredSize(new Dimension(75, 20)); + add(new UnitsWrapper(evaPerWeekSpinner, "per week"), c); + c.gridy++; + evaDurationModel = new SpinnerNumberModel(0, 0, 20, 0.5); + evaDurationSpinner = new JSpinner(evaDurationModel); + evaDurationSpinner.setPreferredSize(new Dimension(75, 20)); + add(new UnitsWrapper(evaDurationSpinner, "hours"), c); + c.gridy++; + c.weightx = 1; + c.weighty = 0.5; + c.fill = GridBagConstraints.BOTH; + elementTree = new ElementTree(); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setBackground(Color.WHITE); + elementScroll.getViewport().setBackground(Color.WHITE); + elementScroll.setPreferredSize(new Dimension(300,100)); + add(elementScroll, c); + c.gridy++; + contentsTable = new EvaTable(); + contentsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + JScrollPane contentsScroll = new JScrollPane(contentsTable); + contentsScroll.setBackground(Color.WHITE); + contentsScroll.getViewport().setBackground(Color.WHITE); + contentsScroll.setPreferredSize(new Dimension(300,100)); + add(contentsScroll, c); + c.gridy++; + demandsList = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + JScrollPane demandsScroll = new JScrollPane(demandsList); + demandsScroll.setBackground(Color.WHITE); + demandsScroll.getViewport().setBackground(Color.WHITE); + demandsScroll.setPreferredSize(new Dimension(200,50)); + add(demandsScroll, c); + + c.gridy = 5; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.weighty = 0; + c.gridy++; + JPanel demandsButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + btnAddDemand = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_put.png"))); + btnAddDemand.setMargin(new Insets(3,3,3,3)); + btnAddDemand.setToolTipText("Add Demand"); + demandsButtonPanel.add(btnAddDemand); + btnRemoveDemand = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_remove.png"))); + btnRemoveDemand.setMargin(new Insets(3,3,3,3)); + btnRemoveDemand.setToolTipText("Remove Demand"); + btnRemoveDemand.setEnabled(false); + demandsButtonPanel.add(btnRemoveDemand); + add(demandsButtonPanel, c); + } + private void initialize() { + durationModel.setValue(event.getDuration()); + evaPerWeekModel.setValue(event.getEvaPerWeek()); + evaDurationModel.setValue(event.getEvaDuration()); + + elementTree.setRoot(getEventDialog().getSimNode()); + if(event.getVehicle()!=null + && getEventDialog().getSimElement(event.getVehicle().getUid())!=null) { + elementTree.setSelection(getEventDialog().getSimElement(event.getVehicle().getUid())); + } + + elementTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + getEventDialog().setOkButtonEnabled(elementTree.getSelectionCount() > 0 + && elementTree.getSelection() instanceof I_Carrier); + updateView(); + } + }); + + for(CrewMember c : event.getStateMap().keySet()) { + CrewMember simCrew = (CrewMember)getEventDialog().getSimElement(c.getUid()); + if(simCrew != null) { + if(event.getStateMap().get(c) == null) { + contentsTable.getModel().put(simCrew, null, true); + } else { + for(I_State simState : simCrew.getStates()) { + if(simState.equals(event.getStateMap().get(c))) { + contentsTable.getModel().put(simCrew, simState, true); + } + } + } + } + } + + for(Demand demand : event.getDemands()) { + demandsList.addDemand(demand); + } + + contentsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(contentsTable.getSelectedRowCount()>0) { + demandsList.clearSelection(); + } + } + }); + demandsList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(!demandsList.getSelectionModel().isSelectionEmpty()) { + contentsTable.clearSelection(); + btnRemoveDemand.setEnabled(true); + } else { + btnRemoveDemand.setEnabled(true); + } + } + }); + btnAddDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + demandsList.addDemand(new Demand()); + } + }); + btnRemoveDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList demands = new ArrayList(); + for(int row : demandsList.getSelectedRows()) { + demands.add(demandsList.getDemand(row)); + } + for(Demand demand : demands) { + demandsList.remove(demand); + } + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public ExplorationProcess getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setDuration(durationModel.getNumber().doubleValue()); + event.setEvaPerWeek(evaPerWeekModel.getNumber().doubleValue()); + event.setEvaDuration(evaDurationModel.getNumber().doubleValue()); + + event.setVehicle((I_Carrier)getEventDialog().getElement(elementTree.getElementSelection().getUid())); + + event.getStateMap().clear(); + for(CrewMember simCrew : contentsTable.getModel().getData().keySet()) { + CrewMember crew = (CrewMember)getEventDialog().getElement(simCrew.getUid()); + if(crew != null) { + if(contentsTable.getModel().getData().get(simCrew)==null) { + event.getStateMap().put(crew, null); + } else { + for(I_State state : crew.getStates()) { + if(state.equals(contentsTable.getModel().getData().get(simCrew))) { + event.getStateMap().put(crew, state); + break; + } + } + } + } + } + + event.getDemands().clear(); + for(Demand demand: demandsList.getDemands()) { + if(demand.getResource()!=null) + event.getDemands().add(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + I_Element selectedItem = (I_Element)elementTree.getElementSelection(); + TreeSelectionListener treeListener = elementTree.getTreeSelectionListeners()[0]; + elementTree.removeTreeSelectionListener(treeListener); + elementTree.setRoot(getEventDialog().getSimNode()); + if(selectedItem!=null + && getEventDialog().getSimElement(selectedItem.getUid())!=null) { + elementTree.setSelection(getEventDialog().getSimElement(selectedItem.getUid())); + } + elementTree.addTreeSelectionListener(treeListener); + + if(elementTree.getElementSelection() instanceof I_Carrier) { + SortedMap stateMap = contentsTable.getModel().getData(); + contentsTable.getModel().clear(); + for(I_Element element : ((I_Carrier)elementTree.getElementSelection()).getContents()) { + if(element instanceof CrewMember) { + if(stateMap.keySet().contains(element)) { + contentsTable.getModel().put((CrewMember)element, stateMap.get(element), true); + } else { + contentsTable.getModel().put((CrewMember)element, stateMap.get(element), false); + } + } + } + } else { + contentsTable.getModel().clear(); + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/event/FlightTransportPanel.java b/src/main/java/edu/mit/spacenet/gui/event/FlightTransportPanel.java new file mode 100644 index 0000000..c79c144 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/FlightTransportPanel.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.text.DecimalFormat; +import java.util.Set; + +import javax.swing.BoxLayout; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.CheckBoxTree; +import edu.mit.spacenet.gui.component.CheckBoxTreeModel; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.simulator.event.FlightTransport; + +/** + * A panel for viewing and editing a flight transport. + * + * @author Paul Grogan + */ +public class FlightTransportPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private FlightTransport event; + + private JComboBox ddlFlight; + private JProgressBar cargoCapacity, crewCapacity; + + private JLabel lblDestination, lblDuration; + private CheckBoxTreeModel elementModel; + private CheckBoxTree elementTree; + + /** + * Instantiates a new flight transport panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public FlightTransportPanel(EventDialog eventDialog, FlightTransport event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Flight: "), c); + c.gridy = 2; + add(new JLabel("Capacity: "), c); + c.gridx = 2; + c.anchor = GridBagConstraints.LINE_START; + add(new JLabel("(Cargo)"), c); + c.gridy = 3; + add(new JLabel("(Crew)"), c); + c.gridy = 4; + c.gridx = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Elements: "), c); + + c.gridx = 1; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + ddlFlight = new ContainerComboBox(); + add(ddlFlight, c); + c.gridy = 1; + JPanel flightPanel = new JPanel(); + flightPanel.setLayout(new BoxLayout(flightPanel, BoxLayout.PAGE_AXIS)); + lblDestination = new JLabel(); + flightPanel.add(lblDestination); + lblDuration = new JLabel(); + flightPanel.add(lblDuration); + add(flightPanel, c); + c.gridx = 1; + c.gridy = 2; + cargoCapacity = new JProgressBar(0, 100); + cargoCapacity.setStringPainted(true); + add(cargoCapacity, c); + c.gridy = 3; + crewCapacity = new JProgressBar(0, 100); + crewCapacity.setStringPainted(true); + add(crewCapacity, c); + + c.gridx = 1; + c.gridwidth = 2; + c.fill = GridBagConstraints.BOTH; + c.gridy = 4; + c.weightx = 1; + c.weighty = 1; + elementModel = new CheckBoxTreeModel(); + elementTree = new CheckBoxTree(elementModel); + elementTree.setRootVisible(false); + elementTree.setShowsRootHandles(true); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,50)); + add(elementScroll, c); + } + private void initialize() { + ddlFlight.addItem(event.getEdge()); + ddlFlight.setSelectedItem(event.getEdge()); + ddlFlight.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + updateCapacities(); + } + }); + + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(event.getElements()); + elementModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + updateCapacities(); + } + public void treeNodesInserted(TreeModelEvent e) { } + public void treeNodesRemoved(TreeModelEvent e) { } + public void treeStructureChanged(TreeModelEvent e) { } + }); + elementTree.expandAll(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public FlightTransport getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setEdge((FlightEdge)ddlFlight.getSelectedItem()); + + event.getElements().clear(); + for(I_Element element : elementModel.getTopCheckedElements()) { + event.getElements().add(getEventDialog().getElement(element.getUid())); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + FlightEdge flight = (FlightEdge)ddlFlight.getSelectedItem(); + ActionListener flightListener = ddlFlight.getActionListeners()[0]; + ddlFlight.removeActionListener(flightListener); + ddlFlight.removeAllItems(); + for(Edge e : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getNetwork().getEdges()) { + if(e.getOrigin().equals(getEventDialog().getNode()) + && e instanceof FlightEdge) { + ddlFlight.addItem(e); + if(e.equals(flight)) { + ddlFlight.setSelectedItem(e); + } + } + } + lblDestination.setText("Destination: " + + ((FlightEdge)ddlFlight.getSelectedItem()).getDestination()); + lblDuration.setText("Duration: " + + ((FlightEdge)ddlFlight.getSelectedItem()).getDuration() + " days"); + ddlFlight.addActionListener(flightListener); + + Set checkedElements = elementModel.getTopCheckedElements(); + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(checkedElements); + elementModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + updateCapacities(); + } + public void treeNodesInserted(TreeModelEvent e) { } + public void treeNodesRemoved(TreeModelEvent e) { } + public void treeStructureChanged(TreeModelEvent e) { } + }); + elementTree.expandAll(); + updateCapacities(); + } + private void updateCapacities() { + double mass = 0; + double crew = 0; + DecimalFormat format = new DecimalFormat("0.0"); + + boolean hasErrors = false; + + for(I_Element e : elementModel.getTopCheckedElements()) { + if(e instanceof I_Container) { + mass += ((I_Container)e).getCargoMass(); + crew += ((I_Container)e).getCrewSize(); + } + } + FlightEdge flight = (FlightEdge)(ddlFlight).getSelectedItem(); + if(flight != null) { + if(mass > flight.getMaxCargoMass()) { + hasErrors = true; + cargoCapacity.setForeground(new Color(153, 0, 0)); + } else { + cargoCapacity.setForeground(new Color(0, 153, 0)); + } + + if(flight.getMaxCargoMass()==0) { + cargoCapacity.setValue(100); + } else { + cargoCapacity.setValue((int)(100*mass/flight.getMaxCargoMass())); + } + cargoCapacity.setString(mass + " / " + flight.getMaxCargoMass() + " kg"); + + if(crew > flight.getMaxCrewSize()) { + hasErrors = true; + crewCapacity.setForeground(new Color(153, 0, 0)); + } else { + crewCapacity.setForeground(new Color(0, 153, 0)); + } + if(flight.getMaxCrewSize()==0) { + crewCapacity.setValue(100); + } else { + crewCapacity.setValue((int)(100*crew/flight.getMaxCrewSize())); + } + crewCapacity.setString((int)crew + " / " + flight.getMaxCrewSize() + " crew"); + } else { + cargoCapacity.setForeground(Color.WHITE); + cargoCapacity.setValue(0); + cargoCapacity.setString(format.format(mass) + " kg"); + crewCapacity.setForeground(Color.WHITE); + crewCapacity.setValue(0); + crewCapacity.setString((int)crew + " crew"); + } + getEventDialog().setOkButtonEnabled(!hasErrors); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/MoveEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/MoveEventPanel.java new file mode 100644 index 0000000..8516990 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/MoveEventPanel.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Set; + +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.gui.component.CapacityPanel; +import edu.mit.spacenet.gui.component.CheckBoxTree; +import edu.mit.spacenet.gui.component.CheckBoxTreeModel; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.simulator.event.MoveEvent; + +/** + * A panel for viewing and editing a move event. + * + * @author Paul Grogan + */ +public class MoveEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private MoveEvent event; + + private JComboBox containerCombo; + private CapacityPanel capacityPanel; + + private CheckBoxTreeModel elementModel; + private CheckBoxTree elementTree; + + /** + * Instantiates a new move event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public MoveEventPanel(EventDialog eventDialog, MoveEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Move to: "), c); + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + containerCombo = new ContainerComboBox(); + add(containerCombo, c); + c.gridy++; + c.weightx = 0; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.HORIZONTAL; + capacityPanel = new CapacityPanel(); + add(capacityPanel, c); + c.gridy++; + c.gridx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Elements: "), c); + c.gridy++; + c.gridwidth = 2; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + elementModel = new CheckBoxTreeModel(); + elementTree = new CheckBoxTree(elementModel); + elementTree.setRootVisible(false); + elementTree.setShowsRootHandles(true); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,50)); + add(elementScroll, c); + } + private void initialize() { + containerCombo.addItem(event.getContainer()); + containerCombo.setSelectedItem(event.getContainer()); + + containerCombo.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + updateCapacities(); + } + }); + + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(event.getElements()); + elementModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + updateCapacities(); + } + public void treeNodesInserted(TreeModelEvent e) { } + public void treeNodesRemoved(TreeModelEvent e) { } + public void treeStructureChanged(TreeModelEvent e) { } + }); + elementTree.expandAll(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public MoveEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + if(containerCombo.getSelectedItem() instanceof I_Element) { + event.setContainer((I_Container)getEventDialog().getElement(((I_Element)containerCombo.getSelectedItem()).getUid())); + } else { + event.setContainer((I_Container)containerCombo.getSelectedItem()); + } + event.getElements().clear(); + for(I_Element element : elementModel.getTopCheckedElements()) { + event.getElements().add(getEventDialog().getElement(element.getUid())); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + I_Container container = (I_Container)containerCombo.getSelectedItem(); + containerCombo.removeAllItems(); + containerCombo.addItem(getEventDialog().getNode()); + if(getEventDialog().getNode().equals(container)) + containerCombo.setSelectedItem(container); + for(I_Element element: getEventDialog().getSimNode().getCompleteContents()) { + if(element instanceof I_Container) { + containerCombo.addItem(element); + if(element.equals(container)) { + containerCombo.setSelectedItem(element); + } + } + } + Set checkedElements = elementModel.getTopCheckedElements(); + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(checkedElements); + elementModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + updateCapacities(); + } + public void treeNodesInserted(TreeModelEvent e) { } + public void treeNodesRemoved(TreeModelEvent e) { } + public void treeStructureChanged(TreeModelEvent e) { } + }); + elementTree.expandAll(); + updateCapacities(); + } + + /** + * Update capacities. + */ + private void updateCapacities() { + double mass = 0; + double volume = 0; + int crew = 0; + for(I_Element e : elementModel.getTopCheckedElements()) { + if(!e.isInside((I_Container)containerCombo.getSelectedItem())) { + if(e instanceof I_Carrier) crew += ((I_Carrier)e).getCrewSize(); + + if(e instanceof CrewMember) crew++; + else { + mass += e.getTotalMass(); + volume += e.getTotalVolume(); + } + } + } + if(containerCombo.getSelectedItem() instanceof I_Carrier) { + I_Carrier v = (I_Carrier)containerCombo.getSelectedItem(); + mass += v.getCargoMass(); + volume += v.getCargoVolume(); + crew += v.getCrewSize(); + capacityPanel.updateCapacities(v, mass, volume, crew); + } else { + mass += getEventDialog().getSimNode().getCargoMass(); + volume += getEventDialog().getSimNode().getCargoVolume(); + crew += getEventDialog().getSimNode().getCrewSize(); + capacityPanel.updateCapacities(getEventDialog().getSimNode(), mass, volume, crew); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/ReconfigureEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/ReconfigureEventPanel.java new file mode 100644 index 0000000..e5da1d4 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/ReconfigureEventPanel.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.simulator.event.ReconfigureEvent; + +/** + * A panel for viewing and editing a reconfigure event. + * + * @author Paul Grogan + */ +public class ReconfigureEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private ReconfigureEvent event; + + private ElementTree elementTree; + private JComboBox ddlCurrentState, ddlNewState; + + /** + * Instantiates a new reconfigure event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public ReconfigureEventPanel(EventDialog eventDialog, ReconfigureEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Element: "), c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Current State: "), c); + c.gridy++; + add(new JLabel("New State: "), c); + + c.gridx = 1; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + elementTree = new ElementTree(); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,50)); + add(elementScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.HORIZONTAL; + ddlCurrentState = new JComboBox(); + ddlCurrentState.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof I_State) + label.setIcon((((I_State)value).getStateType()).getIcon()); + return label; + } + }); + ddlCurrentState.setEnabled(false); + add(ddlCurrentState, c); + c.gridy++; + ddlNewState = new JComboBox(); + ddlNewState.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof I_State) + label.setIcon((((I_State)value).getStateType()).getIcon()); + return label; + } + }); + ddlNewState.setEnabled(false); + add(ddlNewState, c); + } + private void initialize() { + elementTree.setRoot(getEventDialog().getSimNode()); + if(event.getElement()!=null && getEventDialog().getSimElement(event.getElement().getUid())!=null) { + elementTree.setSelection(getEventDialog().getSimElement(event.getElement().getUid())); + for(I_State simState : getEventDialog().getSimElement(event.getElement().getUid()).getStates()) { + ddlNewState.addItem(simState); + if(simState.equals(event.getState())) { + ddlNewState.setSelectedItem(simState); + } + } + } + elementTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + updateStates(); + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public ReconfigureEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setElement(null); + event.setState(null); + + if(elementTree.getElementSelection()!=null) { + event.setElement(getEventDialog().getElement(((I_Element)elementTree.getElementSelection()).getUid())); + if(ddlNewState.getSelectedItem()!=null&&event.getElement()!=null) { + for(I_State s : event.getElement().getStates()) { + if(s.equals(ddlNewState.getSelectedItem())) { + event.setState(s); + break; + } + } + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + I_Element selectedItem = elementTree.getElementSelection(); + TreeSelectionListener treeListener = elementTree.getTreeSelectionListeners()[0]; + elementTree.removeTreeSelectionListener(treeListener); + elementTree.setRoot(getEventDialog().getSimNode()); + elementTree.setSelection(selectedItem); + elementTree.addTreeSelectionListener(treeListener); + updateStates(); + } + private void updateStates() { + I_State state = (I_State)ddlNewState.getSelectedItem(); + + ddlCurrentState.removeAllItems(); + ddlNewState.removeAllItems(); + + if(elementTree.getSelectionCount()==0) { + ddlNewState.setEnabled(false); + getEventDialog().setOkButtonEnabled(false); + } else { + ddlNewState.setEnabled(true); + getEventDialog().setOkButtonEnabled(true); + + for(I_State s : elementTree.getElementSelection().getStates()) { + ddlCurrentState.addItem(s); + ddlNewState.addItem(s); + + if(elementTree.getElementSelection().getCurrentState().equals(s)) { + ddlCurrentState.setSelectedItem(s); + } + if(s.equals(state)) { + ddlNewState.setSelectedItem(s); + } + } + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/ReconfigureGroupEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/ReconfigureGroupEventPanel.java new file mode 100644 index 0000000..5642d25 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/ReconfigureGroupEventPanel.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.Set; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JScrollPane; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.StateType; +import edu.mit.spacenet.gui.component.CheckBoxTree; +import edu.mit.spacenet.gui.component.CheckBoxTreeModel; +import edu.mit.spacenet.simulator.event.ReconfigureGroupEvent; + +/** + * A panel for viewing and editing a reconfigure group event. + * + * @author Paul Grogan + */ +public class ReconfigureGroupEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private ReconfigureGroupEvent event; + + private CheckBoxTreeModel elementModel; + private CheckBoxTree elementTree; + private JComboBox ddlStateType; + + /** + * Instantiates a new reconfigure group event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public ReconfigureGroupEventPanel(EventDialog eventDialog, ReconfigureGroupEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + add(new JLabel("New State: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Elements: "), c); + + c.gridx = 1; + c.gridy = 0; + c.weighty = 0; + c.fill = GridBagConstraints.HORIZONTAL; + ddlStateType = new JComboBox(); + for(StateType t : StateType.values()) { + ddlStateType.addItem(t); + } + ddlStateType.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof StateType) + label.setIcon(((StateType)value).getIcon()); + return label; + } + }); + add(ddlStateType, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + elementModel = new CheckBoxTreeModel(); + elementModel.setChildrenChecked(false); + elementTree = new CheckBoxTree(elementModel); + elementTree.setRootVisible(false); + elementTree.setShowsRootHandles(true); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,50)); + add(elementScroll, c); + } + private void initialize() { + ddlStateType.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateView(); + } + }); + ddlStateType.setSelectedItem(event.getStateType()); + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementModel.setChildrenChecked(false); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(event.getElements()); + elementTree.expandAll(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public ReconfigureGroupEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setStateType((StateType)ddlStateType.getSelectedItem()); + event.getElements().clear(); + for(I_Element element : elementModel.getTopCheckedElements()) { + event.getElements().add(getEventDialog().getElement(element.getUid())); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + Set checkedElements = elementModel.getTopCheckedElements(); + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementModel.setChildrenChecked(false); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(checkedElements); + elementTree.expandAll(); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/RemoveEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/RemoveEventPanel.java new file mode 100644 index 0000000..1c2907b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/RemoveEventPanel.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.Set; + +import javax.swing.JLabel; +import javax.swing.JScrollPane; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.gui.component.CheckBoxTree; +import edu.mit.spacenet.gui.component.CheckBoxTreeModel; +import edu.mit.spacenet.simulator.event.RemoveEvent; + +/** + * A panel for viewing and editing a remove event. + * + * @author Paul Grogan + */ +public class RemoveEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private RemoveEvent event; + + private CheckBoxTreeModel elementModel; + private CheckBoxTree elementTree; + + /** + * Instantiates a new removes the event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public RemoveEventPanel(EventDialog eventDialog, RemoveEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Elements: "), c); + + c.gridx = 1; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + elementModel = new CheckBoxTreeModel(); + elementTree = new CheckBoxTree(elementModel); + elementTree.setRootVisible(false); + elementTree.setShowsRootHandles(true); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,50)); + add(elementScroll, c); + } + private void initialize() { + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(event.getElements()); + elementTree.expandAll(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public RemoveEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.getElements().clear(); + for(I_Element element : elementModel.getTopCheckedElements()) { + event.getElements().add(getEventDialog().getElement(element.getUid())); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + Set checkedElements = elementModel.getTopCheckedElements(); + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(checkedElements); + elementTree.expandAll(); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/SpaceTransportPanel.java b/src/main/java/edu/mit/spacenet/gui/event/SpaceTransportPanel.java new file mode 100644 index 0000000..ef4b923 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/SpaceTransportPanel.java @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Set; + +import javax.swing.BoxLayout; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.TreeSelectionModel; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.domain.network.edge.BurnType; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.CheckBoxNode; +import edu.mit.spacenet.gui.component.CheckBoxTree; +import edu.mit.spacenet.gui.component.CheckBoxTreeModel; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.simulator.event.BurnStageItem; +import edu.mit.spacenet.simulator.event.SpaceTransport; +import edu.mit.spacenet.util.Formulae; + +/** + * A panel for viewing and editing a space transport. + * + * @author Paul Grogan + */ +public class SpaceTransportPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private SpaceTransport event; + + private JLabel lblDestination, lblDuration; + private JComboBox ddlTrajectory; + private JButton btnAddBurn, btnAddStage; + private JTabbedPane tabbedBurnPane; + + private CheckBoxTreeModel elementModel; + private CheckBoxTree elementTree; + private DecimalFormat deltaVFormat = new DecimalFormat("0.0"); + + /** + * Instantiates a new space transport panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public SpaceTransportPanel(EventDialog eventDialog, SpaceTransport event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.weightx = 0; + c.weighty = 0; + c.gridy = 0; + c.gridx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Trajectory: "), c); + c.gridy+=2; + c.anchor = GridBagConstraints.LINE_START; + add(new JLabel("Elements: "), c); + + c.anchor = GridBagConstraints.LINE_START; + c.gridx = 1; + c.gridy = 0; + c.weightx = 1; + ddlTrajectory = new ContainerComboBox(); + add(ddlTrajectory, c); + c.gridy++; + JPanel trajectoryPanel = new JPanel(); + trajectoryPanel.setLayout(new BoxLayout(trajectoryPanel, BoxLayout.PAGE_AXIS)); + lblDestination = new JLabel(); + trajectoryPanel.add(lblDestination); + lblDuration = new JLabel(); + trajectoryPanel.add(lblDuration); + add(trajectoryPanel, c); + c.gridy+=2; + c.gridx = 0; + c.gridwidth = 2; + c.fill = GridBagConstraints.BOTH; + c.weighty = 1; + elementModel = new CheckBoxTreeModel(); + elementTree = new CheckBoxTree(elementModel); + elementTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + elementTree.setRootVisible(false); + elementTree.setShowsRootHandles(true); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,100)); + add(elementScroll, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + c.weighty = 0; + JPanel sequenceButtonPanel = new JPanel(); + sequenceButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + btnAddBurn = new JButton("Burn"); + btnAddBurn.setToolTipText("Burn the selected propulsive vehicles"); + btnAddBurn.setIcon(BurnStageItem.BURN_ICON); + btnAddBurn.setMargin(new Insets(3,3,3,3)); + btnAddBurn.setEnabled(false); + sequenceButtonPanel.add(btnAddBurn); + btnAddStage = new JButton("Stage"); + btnAddStage.setToolTipText("Stage the selected elements"); + btnAddStage.setIcon(BurnStageItem.STAGE_ICON); + btnAddStage.setMargin(new Insets(3,3,3,3)); + btnAddStage.setEnabled(false); + sequenceButtonPanel.add(btnAddStage); + add(sequenceButtonPanel, c); + c.weightx = 1; + c.weighty = 1; + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + tabbedBurnPane = new JTabbedPane(); + tabbedBurnPane.setTabPlacement(JTabbedPane.TOP); + add(tabbedBurnPane, c); + } + private void initialize() { + ddlTrajectory.addItem(event.getEdge()); + ddlTrajectory.setSelectedItem(event.getEdge()); + ddlTrajectory.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + // TODO: should probably give some kind of warning + createBurnPanels(); + } + } + }); + + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(event.getElements()); + elementModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + updateButtons(); + } + public void treeNodesInserted(TreeModelEvent e) { } + public void treeNodesRemoved(TreeModelEvent e) { } + public void treeStructureChanged(TreeModelEvent e) { } + }); + + if(event.getEdge() != null) { + createBurnPanels(); + for(int burn = 0; burn < event.getEdge().getBurns().size(); burn++) { + BurnPanel panel = (BurnPanel)tabbedBurnPane.getComponentAt(burn); + for(BurnStageItem i : event.getBurnStageSequence().get(burn)) { + BurnStageItem bs = new BurnStageItem(); + bs.setBurnStage(i.getBurnStage()); + bs.setElement(getEventDialog().getSimElement(i.getElement().getUid())); + panel.sequenceModel.addElement(bs); + } + } + } + elementTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + if(!elementTree.isSelectionEmpty()) { + ((BurnPanel)tabbedBurnPane.getSelectedComponent()).sequenceList.clearSelection(); + } + updateButtons(); + } + }); + btnAddBurn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ((BurnPanel)tabbedBurnPane.getSelectedComponent()).sequenceModel.addElement( + new BurnStageItem(BurnStageItem.BURN, + ((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement())); + updateView(); + } + }); + btnAddStage.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ((BurnPanel)tabbedBurnPane.getSelectedComponent()).sequenceModel.addElement( + new BurnStageItem(BurnStageItem.STAGE, + ((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement())); + updateView(); + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public SpaceTransport getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setEdge((SpaceEdge)ddlTrajectory.getSelectedItem()); + + event.getElements().clear(); + for(I_Element element : elementModel.getTopCheckedElements()) { + event.getElements().add(getEventDialog().getElement(element.getUid())); + } + + event.getBurnStageSequence().clear(); + for(Component c : tabbedBurnPane.getComponents()) { + ArrayList sequence = new ArrayList(); + for(Object o : ((BurnPanel)c).sequenceModel.toArray()) { + BurnStageItem i = new BurnStageItem(); + i.setBurnStage(((BurnStageItem)o).getBurnStage()); + i.setElement(getEventDialog().getElement(((BurnStageItem)o).getElement().getUid())); + sequence.add(i); + } + event.getBurnStageSequence().add(sequence); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + SpaceEdge trajectory = (SpaceEdge)ddlTrajectory.getSelectedItem(); + ItemListener trajectoryListener = ddlTrajectory.getItemListeners()[0]; + ddlTrajectory.removeItemListener(trajectoryListener); + ddlTrajectory.removeAllItems(); + for(Edge e : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getNetwork().getEdges()) { + if(e.getOrigin().equals(getEventDialog().getNode()) + && e instanceof SpaceEdge) { + ddlTrajectory.addItem(e); + if(e.equals(trajectory)) { + ddlTrajectory.setSelectedItem(e); + } + } + } + lblDestination.setText("Destination: " + + ((SpaceEdge)ddlTrajectory.getSelectedItem()).getDestination()); + lblDuration.setText("Duration: " + + ((SpaceEdge)ddlTrajectory.getSelectedItem()).getDuration() + " days"); + ddlTrajectory.addItemListener(trajectoryListener); + if(tabbedBurnPane.getComponentCount() != ((SpaceEdge)ddlTrajectory.getSelectedItem()).getBurns().size()) { + createBurnPanels(); + } + + Set checkedElements = elementModel.getTopCheckedElements(); + int[] selectionRows = elementTree.getSelectionRows(); + elementModel = new CheckBoxTreeModel(getEventDialog().getSimNode()); + elementTree.setModel(elementModel); + elementModel.setCheckedElements(checkedElements); + elementTree.setSelectionRows(selectionRows); + elementModel.addTreeModelListener(new TreeModelListener() { + public void treeNodesChanged(TreeModelEvent e) { + updateButtons(); + } + public void treeNodesInserted(TreeModelEvent e) { } + public void treeNodesRemoved(TreeModelEvent e) { } + public void treeStructureChanged(TreeModelEvent e) { } + }); + + for(int burn = 0; burn < ((SpaceEdge)ddlTrajectory.getSelectedItem()).getBurns().size(); burn++) { + BurnPanel burnPanel = (BurnPanel)tabbedBurnPane.getComponentAt(burn); + for(Object o : burnPanel.sequenceModel.toArray()) { + boolean isFound = false; + for(I_Element element : elementModel.getTopCheckedElements()) { + if(element.equals(((BurnStageItem)o).getElement())) isFound = true; + } + if(!isFound) burnPanel.sequenceModel.clear(); + } + } + updateDeltaV(); + } + private class BurnPanel extends JPanel { + private static final long serialVersionUID = -2491575968761743630L; + public JProgressBar deltaV; + public JLabel stackMassLabel; + public DefaultListModel sequenceModel; + public JList sequenceList; + public JScrollPane sequenceScroll; + public JButton btnClear; + + public BurnPanel() { + super(); + this.setLayout(new GridBagLayout()); + setOpaque(false); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.weightx = 0; + c.weighty = 0; + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Delta-V: "), c); + c.gridy++; + add(new JLabel("Stack Mass: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Sequence: "), c); + + c.gridx = 1; + c.gridy = 0; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + deltaV = new JProgressBar(0, 100); + deltaV.setStringPainted(true); + add(deltaV, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + stackMassLabel = new JLabel(); + add(new UnitsWrapper(stackMassLabel, "kg"), c); + + c.gridy++; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + sequenceModel = new DefaultListModel(); + sequenceList = new JList(sequenceModel); + sequenceList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + sequenceList.setCellRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(((BurnStageItem)value).getBurnStage().equals(BurnStageItem.BURN)) { + label.setIcon(BurnStageItem.BURN_ICON); + } else { + label.setIcon(BurnStageItem.STAGE_ICON); + } + + return label; + } + }); + sequenceScroll = new JScrollPane(sequenceList); + sequenceScroll.setPreferredSize(new Dimension(150,100)); + add(sequenceScroll, c); + + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + btnClear = new JButton("Clear"); + btnClear.setToolTipText("Clear the selected burns or stages"); + btnClear.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/cross.png"))); + btnClear.setMargin(new Insets(3,3,3,3)); + btnClear.setEnabled(false); + add(btnClear, c); + } + } + private void createBurnPanels() { + tabbedBurnPane.removeAll(); + SpaceEdge trajectory = ((SpaceEdge)ddlTrajectory.getSelectedItem()); + for(int burn = 0; burn < trajectory.getBurns().size(); burn++) { + BurnPanel panel = new BurnPanel(); + panel.btnClear.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for(Object o : ((BurnPanel)tabbedBurnPane.getSelectedComponent()).sequenceList.getSelectedValues()) + ((BurnPanel)tabbedBurnPane.getSelectedComponent()).sequenceModel.removeElement(o); + updateView(); + } + }); + panel.sequenceList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(!((BurnPanel)tabbedBurnPane.getSelectedComponent()).sequenceList.isSelectionEmpty()) { + elementTree.clearSelection(); + } + updateButtons(); + } + }); + tabbedBurnPane.add("Burn " + (burn+1), panel); + } + } + private void updateDeltaV() { + try { + HashMap massMap = new HashMap(); + HashMap omsFuelMap = new HashMap(); + HashMap rcsFuelMap = new HashMap(); + for(Object o : elementModel.getTopCheckedElements()) { + massMap.put((I_Element)o, ((I_Element)o).getTotalMass()); + if(o instanceof PropulsiveVehicle + && ((PropulsiveVehicle)o).getOmsIsp() > 0) { + omsFuelMap.put((PropulsiveVehicle)o, ((PropulsiveVehicle)o).getOmsFuelTank().getAmount()); + } + if(o instanceof PropulsiveVehicle + && ((PropulsiveVehicle)o).getRcsIsp() > 0) { + rcsFuelMap.put((PropulsiveVehicle)o, ((PropulsiveVehicle)o).getRcsFuelTank().getAmount()); + } + } + + for(int burn = 0; burn < ((SpaceEdge)ddlTrajectory.getSelectedItem()).getBurns().size(); burn++) { + BurnPanel burnPanel = (BurnPanel)tabbedBurnPane.getComponentAt(burn); + Burn b = ((SpaceEdge)ddlTrajectory.getSelectedItem()).getBurns().get(burn); + + double stackMass = 0; + for(I_Element e : massMap.keySet()) { + stackMass += massMap.get(e); + } + double deltaVReq = b.getDeltaV(); + + //System.out.println("deltaVReq: " + deltaVReq); + //System.out.println("stackMass: " + stackMass); + + for(Object o : burnPanel.sequenceModel.toArray()) { + BurnStageItem i = (BurnStageItem)o; + I_Element element = null; + for(I_Element e : massMap.keySet()) { + if(i.getElement().equals(e)) { + element = e; + break; + } + } + if(i.getBurnStage().equals(BurnStageItem.STAGE)) { + //System.out.println("stage: " + i.getElement().getName()); + stackMass -= massMap.get(element); + massMap.put(element, 0d); + } else if(i.getBurnStage().equals(BurnStageItem.BURN)) { + //System.out.println("burn: " + i.getElement().getName()); + PropulsiveVehicle v = (PropulsiveVehicle)element; + if(b.getBurnType().equals(BurnType.OMS)) { + if(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getOmsIsp()) > omsFuelMap.get(v)) { + double deltaVAchieved = Formulae.getAchievedDeltaV(stackMass, v.getOmsIsp(), omsFuelMap.get(v)); + //System.out.println("dv achieved: " + deltaVAchieved); + deltaVReq -= deltaVAchieved; + stackMass -= omsFuelMap.get(v); + massMap.put(v, massMap.get(v) - omsFuelMap.get(v)); + omsFuelMap.put(v, 0d); + } else { + //System.out.println("dv achieved: " + deltaVReq); + double fuelUsed = Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getOmsIsp()); + deltaVReq = 0; + stackMass -= fuelUsed; + massMap.put(v, massMap.get(v) - fuelUsed); + omsFuelMap.put(v, omsFuelMap.get(v) - fuelUsed); + } + } else { + if(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getRcsIsp()) > rcsFuelMap.get(v)) { + double deltaVAchieved = Formulae.getAchievedDeltaV(stackMass, v.getRcsIsp(), rcsFuelMap.get(v)); + //System.out.println("dv achieved: " + deltaVAchieved); + deltaVReq -= deltaVAchieved; + stackMass -= rcsFuelMap.get(v); + massMap.put(v, massMap.get(v) - rcsFuelMap.get(v)); + rcsFuelMap.put(v, 0d); + } else { + //System.out.println("dv achieved: " + deltaVReq); + double fuelUsed = Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getRcsIsp()); + deltaVReq = 0; + stackMass -= fuelUsed; + massMap.put(v, massMap.get(v) - fuelUsed); + rcsFuelMap.put(v, rcsFuelMap.get(v) - fuelUsed); + } + } + } + } + if(deltaVReq == 0) { + burnPanel.deltaV.setForeground(new Color(0, 153, 0)); + getEventDialog().setOkButtonEnabled(true); + } else { + burnPanel.deltaV.setForeground(new Color(153, 0, 0)); + //TODO annoying... getEventDialog().setOkButtonEnabled(false); + getEventDialog().setOkButtonEnabled(true); + } + burnPanel.stackMassLabel.setText(deltaVFormat.format(stackMass)); + burnPanel.deltaV.setValue((int)(100*((b.getDeltaV() - deltaVReq)/b.getDeltaV()))); + burnPanel.deltaV.setString(deltaVFormat.format((b.getDeltaV() - deltaVReq)) + " / " + b.getDeltaV() + " m/s (" + b.getBurnType().getName() + ")"); + } + } catch(Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, + "Sorry, an unhandled exception occurred.", + "Unhandled Exception in SpaceTransportGUI.updateDeltaV", + JOptionPane.WARNING_MESSAGE); + } + } + private void updateButtons() { + if(elementTree.getSelectionCount() > 0) { + if(elementTree.getSelectionCount() == 1 + && ((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).isChecked() + /* TODO: add check for previous stage */) { + btnAddStage.setEnabled(true); + if(((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement() instanceof PropulsiveVehicle) { + PropulsiveVehicle v = (PropulsiveVehicle)((CheckBoxNode)elementTree.getSelectionPath().getLastPathComponent()).getElement(); + if((((SpaceEdge)ddlTrajectory.getSelectedItem()).getBurns().get(tabbedBurnPane.getSelectedIndex()).getBurnType().equals(BurnType.OMS) && v.getOmsFuelTank() != null) + ||(((SpaceEdge)ddlTrajectory.getSelectedItem()).getBurns().get(tabbedBurnPane.getSelectedIndex()).getBurnType().equals(BurnType.RCS) && v.getRcsFuelTank() != null)) { + btnAddBurn.setEnabled(true); + } else { + btnAddBurn.setEnabled(false); + } + } else { + btnAddBurn.setEnabled(false); + } + } else { + btnAddStage.setEnabled(false); + btnAddBurn.setEnabled(false); + } + } else { + btnAddStage.setEnabled(false); + btnAddBurn.setEnabled(false); + } + BurnPanel panel = (BurnPanel)tabbedBurnPane.getSelectedComponent(); + if(panel.sequenceList.getSelectedIndices().length > 0) { + panel.btnClear.setEnabled(true); + } else { + panel.btnClear.setEnabled(false); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/SurfaceTransportPanel.java b/src/main/java/edu/mit/spacenet/gui/event/SurfaceTransportPanel.java new file mode 100644 index 0000000..027debf --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/SurfaceTransportPanel.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.text.DecimalFormat; + +import javax.swing.BoxLayout; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.element.SurfaceVehicle; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.simulator.event.SurfaceTransport; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A panel for viewing and editing a surface transport event. + * + * @author Paul Grogan + */ +public class SurfaceTransportPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private SurfaceTransport event; + + private JLabel lblDestination, lblDistance, lblDuration; + private JComboBox ddlEdge, ddlState; + private SpinnerNumberModel speedModel, dutyCycleModel; + private JSpinner speedSpinner, dutyCycleSpinner; + + private ElementTree elementTree; + + /** + * Instantiates a new surface transport panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public SurfaceTransportPanel(EventDialog eventDialog, SurfaceTransport event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridy = 0; + c.gridx = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Edge: "), c); + c.gridy+=2; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Vehicle: "), c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + add(new JLabel("Transport State: "), c); + c.gridy++; + add(new JLabel("Speed: "), c); + c.gridy++; + add(new JLabel("Duty Cycle: "), c); + + c.gridx = 1; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + ddlEdge = new ContainerComboBox(); + add(ddlEdge, c); + c.gridy++; + JPanel edgePanel = new JPanel(); + edgePanel.setLayout(new BoxLayout(edgePanel, BoxLayout.PAGE_AXIS)); + lblDestination = new JLabel(); + edgePanel.add(lblDestination); + lblDistance = new JLabel(); + edgePanel.add(lblDistance); + lblDuration = new JLabel(); + edgePanel.add(lblDuration); + add(edgePanel, c); + c.gridy++; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + elementTree = new ElementTree(); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(200,50)); + add(elementScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.HORIZONTAL; + ddlState = new JComboBox(); + ddlState.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof I_State) + label.setIcon((((I_State)value).getStateType()).getIcon()); + return label; + } + }); + ddlState.setEnabled(false); + add(ddlState, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + speedModel = new SpinnerNumberModel(0.0,0.0,100.0,1.0); + speedSpinner = new JSpinner(speedModel); + speedSpinner.setPreferredSize(new Dimension(75,20)); + speedSpinner.setEnabled(false); + add(new UnitsWrapper(speedSpinner, "km / hr"), c); + c.gridy++; + dutyCycleModel = new SpinnerNumberModel(1.0,0.0,1.0,0.05); + dutyCycleSpinner = new JSpinner(dutyCycleModel); + dutyCycleSpinner.setEnabled(false); + dutyCycleSpinner.setPreferredSize(new Dimension(75,20)); + add(dutyCycleSpinner, c); + } + private void initialize() { + if(event.getEdge()!=null) { + ddlEdge.addItem(event.getEdge()); + ddlEdge.setSelectedItem(event.getEdge()); + } + + elementTree.setRoot(getEventDialog().getSimNode()); + if(event.getVehicle()!=null) { + elementTree.setSelection(getEventDialog().getSimElement(event.getVehicle().getUid())); + for(I_State simState : getEventDialog().getSimElement(event.getVehicle().getUid()).getStates()) { + if(simState.equals(event.getTransportState())) { + ddlState.addItem(simState); + ddlState.setSelectedItem(simState); + } + } + } + + speedModel.setValue(event.getSpeed()); + dutyCycleModel.setValue(event.getDutyCycle()); + speedSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + updateDuration(); + } + }); + dutyCycleSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + updateDuration(); + } + }); + ddlEdge.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateView(); + } + }); + elementTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + if(elementTree.getSelectionCount() > 0 + && elementTree.getSelection() instanceof SurfaceVehicle) { + speedSpinner.setValue(((SurfaceVehicle)elementTree.getSelection()).getMaxSpeed()); + } + updateView(); + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public SurfaceTransport getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + event.setEdge((SurfaceEdge)ddlEdge.getSelectedItem()); + + event.setVehicle((SurfaceVehicle)getEventDialog().getElement(elementTree.getElementSelection().getUid())); + + if(ddlState.getSelectedItem() == null) { + event.setTransportState(null); + } else { + for(I_State s : getEventDialog().getElement(elementTree.getElementSelection().getUid()).getStates()) { + if(s.equals((I_State)ddlState.getSelectedItem())) { + event.setTransportState(s); + break; + } + } + } + event.setSpeed(speedModel.getNumber().doubleValue()); + event.setDutyCycle(dutyCycleModel.getNumber().doubleValue()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + SurfaceEdge edge = (SurfaceEdge)ddlEdge.getSelectedItem(); + ItemListener edgeListener = ddlEdge.getItemListeners()[0]; + ddlEdge.removeItemListener(edgeListener); + ddlEdge.removeAllItems(); + for(Edge e : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getNetwork().getEdges()) { + if(e instanceof SurfaceEdge && + (e.getOrigin().equals(getEventDialog().getNode()) + || e.getDestination().equals(getEventDialog().getNode()))) { + ddlEdge.addItem(e); + if(e.equals(edge)) { + ddlEdge.setSelectedItem(e); + } + } + } + if(ddlEdge.getSelectedItem()!=null) { + lblDestination.setText("Destination: " + + ((SurfaceEdge)ddlEdge.getSelectedItem()).getDestination()); + lblDistance.setText("Distance: " + + ((SurfaceEdge)ddlEdge.getSelectedItem()).getDistance() + " kilometers"); + } + ddlEdge.addItemListener(edgeListener); + + I_Element selectedItem = elementTree.getElementSelection(); + TreeSelectionListener treeListener = elementTree.getTreeSelectionListeners()[0]; + elementTree.removeTreeSelectionListener(treeListener); + elementTree.setRoot(getEventDialog().getSimNode()); + elementTree.setSelection(selectedItem); + elementTree.addTreeSelectionListener(treeListener); + + I_State state = (I_State)ddlState.getSelectedItem(); + + ddlState.removeAllItems(); + if(elementTree.getSelectionCount() > 0) { + for(I_State s : elementTree.getElementSelection().getStates()) { + ddlState.addItem(s); + + if(s.equals(state)) { + ddlState.setSelectedItem(s); + } + } + } + if(elementTree.getSelection() instanceof SurfaceVehicle) { + getEventDialog().setOkButtonEnabled(true); + ddlState.setEnabled(true); + + speedModel.setMaximum(((SurfaceVehicle)elementTree.getSelection()).getMaxSpeed()); + if(speedModel.getNumber().doubleValue() > ((SurfaceVehicle)elementTree.getSelection()).getMaxSpeed()) { + // TODO: should probably have a warning message + speedModel.setValue(speedModel.getMaximum()); + } + speedSpinner.setEnabled(true); + dutyCycleSpinner.setEnabled(true); + } else { + speedModel.setValue(0); + speedSpinner.setEnabled(false); + dutyCycleSpinner.setEnabled(false); + getEventDialog().setOkButtonEnabled(false); + ddlState.setEnabled(false); + } + + updateDuration(); + } + private void updateDuration() { + if(speedModel.getNumber().doubleValue() == 0 || dutyCycleModel.getNumber().doubleValue() == 0) { + lblDuration.setText("Duration: n/a"); + } else { + double duration = ((SurfaceEdge)ddlEdge.getSelectedItem()).getDistance()/(speedModel.getNumber().doubleValue()*dutyCycleModel.getNumber().doubleValue()*24); + DecimalFormat format = new DecimalFormat("0.00"); + lblDuration.setText("Duration: " + format.format(GlobalParameters.getRoundedTime(duration)) + " days"); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/event/TransferDemandsTable.java b/src/main/java/edu/mit/spacenet/gui/event/TransferDemandsTable.java new file mode 100644 index 0000000..c6a2e5d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/TransferDemandsTable.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.text.DecimalFormat; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.domain.resource.I_Resource; + +/** + * The Class TransferDemandsTable. + * + * @author Paul Grogan + */ +public class TransferDemandsTable extends JTable { + private static final long serialVersionUID = 2409986766964137963L; + + /** + * Instantiates a new transfer demands table. + */ + public TransferDemandsTable() { + setModel(new TransferDemandsModel()); + getColumnModel().getColumn(0).setHeaderValue("Resource"); + getColumnModel().getColumn(1).setHeaderValue("Amount"); + getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.000"); + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " " + ((TransferDemandsModel)getModel()).getContainerContents(row).getResource().getUnits()); + return this; + } + }); + getColumnModel().getColumn(2).setHeaderValue("Transferred"); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.000"); + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " " + ((TransferDemandsModel)getModel()).getContainerContents(row).getResource().getUnits()); + return this; + } + }); + setBackground(Color.WHITE); + getTableHeader().setReorderingAllowed(false); + getTableHeader().setBackground(Color.WHITE); + getTableHeader().setFont(getTableHeader().getFont().deriveFont(Font.BOLD)); + getTableHeader().setBorder(BorderFactory.createMatteBorder(0,0,1,0,Color.BLACK)); + getTableHeader().setOpaque(false); + } + + /** + * Gets the transfer demands. + * + * @return the transfer demands + */ + public DemandSet getTransferDemands() { + return ((TransferDemandsModel)getModel()).getTransferDemands(); + } + + /** + * Sets the data. + * + * @param container the container + * @param demands the demands + */ + public void setData(I_ResourceContainer container, DemandSet demands) { + ((TransferDemandsModel)getModel()).setData(container, demands); + } + private class TransferDemandsModel extends AbstractTableModel { + private static final long serialVersionUID = -8936343745298804353L; + private I_ResourceContainer container; + private DemandSet demands; + + public int getColumnCount() { + return 3; + } + public Class getColumnClass(int col) { + if(col==0) return Object.class; + else return Double.class; + } + public boolean isCellEditable(int row, int col) { + if(col==2) return true; + else return false; + } + public int getRowCount() { + if(container==null) return 0; + else return container.getContents().keySet().size(); + } + public Object getValueAt(int row, int col) { + if(col==0) return getContainerContents(row).getResource(); + else if(col==1) return getContainerContents(row).getAmount(); + else return getTransferDemand(row)==null?0:getTransferDemand(row).getAmount(); + } + public void setValueAt(Object value, int row, int col) { + if(col==2) { + double amount = Math.min((Double)value, getContainerContents(row).getAmount()); + if(getTransferDemand(row)==null) { + demands.add(new Demand(getContainerContents(row).getResource(), amount)); + } else { + getTransferDemand(row).setAmount(amount); + } + fireTableRowsUpdated(row, row); + } + } + public Demand getContainerContents(int row) { + int lastRowSeen = -1; + for(I_Resource resource : container.getContents().keySet()) { + lastRowSeen++; + if(lastRowSeen==row) return new Demand(resource, container.getContents().get(resource)); + } + return null; + } + public Demand getTransferDemand(int row) { + int lastRowSeen = -1; + for(I_Resource resource : container.getContents().keySet()) { + lastRowSeen++; + if(lastRowSeen==row) { + for(Demand demand : demands) { + if(resource.equals(demand.getResource())) return demand; + } + return null; + } + } + return null; + } + public void setData(I_ResourceContainer container, DemandSet demands) { + this.container = container; + this.demands = new DemandSet(); + for(Demand demand : demands) { + if(container.getContents().keySet().contains(demand.getResource())) { + this.demands.add(demand); + } + } + fireTableDataChanged(); + } + public DemandSet getTransferDemands() { + if(this.demands==null) return new DemandSet(); + DemandSet demands = new DemandSet(); + for(Demand demand : this.demands) { + if(container.getContents().keySet().contains(demand.getResource()) + && demand.getAmount()>0) { + demands.add(demand); + } + } + return demands; + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/event/TransferEventPanel.java b/src/main/java/edu/mit/spacenet/gui/event/TransferEventPanel.java new file mode 100644 index 0000000..13e514b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/event/TransferEventPanel.java @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.event; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.element.ResourceTank; +import edu.mit.spacenet.domain.element.SurfaceVehicle; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.gui.component.CapacityPanel; +import edu.mit.spacenet.simulator.event.TransferEvent; + +/** + * The Class TransferEventPanel. + * + * @author Paul Grogan + */ +public class TransferEventPanel extends AbstractEventPanel { + private static final long serialVersionUID = 769918023169742283L; + + private TransferEvent event; + + private JComboBox ddlDestinationContainer, ddlOriginContainer; + private CapacityPanel capacityPanel; + private TransferDemandsTable demandsTable; + + /** + * Instantiates a new transfer event panel. + * + * @param eventDialog the event dialog + * @param event the event + */ + public TransferEventPanel(EventDialog eventDialog, TransferEvent event) { + super(eventDialog, event); + this.event = event; + buildPanel(); + initialize(); + } + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Transfer from: "), c); + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + ddlOriginContainer = new JComboBox(); + add(ddlOriginContainer, c); + c.gridy++; + c.gridwidth = 1; + c.gridx = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Transfer to: "), c); + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + ddlDestinationContainer = new JComboBox(); + add(ddlDestinationContainer, c); + c.gridy++; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + capacityPanel = new CapacityPanel(); + add(capacityPanel, c); + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.FIRST_LINE_START; + add(new JLabel("Contents: "), c); + c.gridy++; + c.weighty = 1; + c.gridwidth = 2; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + demandsTable = new TransferDemandsTable(); + JScrollPane demandsScroll = new JScrollPane(demandsTable); + demandsScroll.setPreferredSize(new Dimension(250,50)); + demandsScroll.setBackground(Color.WHITE); + demandsScroll.getViewport().setBackground(Color.WHITE); + add(demandsScroll, c); + } + + /** + * Initialize. + */ + private void initialize() { + ddlOriginContainer.addItem(event.getOriginContainer()); + ddlOriginContainer.setSelectedItem(event.getOriginContainer()); + ddlOriginContainer.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + demandsTable.setData((I_ResourceContainer)ddlOriginContainer.getSelectedItem(), new DemandSet()); + updateView(); + } + } + }); + ddlDestinationContainer.addItem(event.getDestinationContainer()); + ddlDestinationContainer.setSelectedItem(event.getDestinationContainer()); + ddlDestinationContainer.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateCapacities(); + } + }); + if(event.getOriginContainer()!=null + && event.getOriginContainer() instanceof ResourceTank + && event.getOriginContainer().getContainer() instanceof PropulsiveVehicle) { + demandsTable.setData(((PropulsiveVehicle)getEventDialog().getSimElement(((PropulsiveVehicle)event.getOriginContainer().getContainer()).getUid())).getOmsFuelTank(), event.getTransferDemands()); + } else if(event.getOriginContainer()!=null + && event.getOriginContainer() instanceof ResourceTank + && event.getOriginContainer().getContainer() instanceof SurfaceVehicle) { + demandsTable.setData(((SurfaceVehicle)getEventDialog().getSimElement(((SurfaceVehicle)event.getOriginContainer().getContainer()).getUid())).getFuelTank(), event.getTransferDemands()); + } else if(event.getOriginContainer()!=null) { + demandsTable.setData((I_ResourceContainer)getEventDialog().getSimElement(event.getOriginContainer().getUid()), event.getTransferDemands()); + } + demandsTable.repaint(); + + demandsTable.getModel().addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + updateCapacities(); + } + }); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#getEvent() + */ + @Override + public TransferEvent getEvent() { + return event; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#saveEvent() + */ + @Override + public void saveEvent() { + if(demandsTable.isEditing()) demandsTable.getCellEditor().stopCellEditing(); + if(ddlDestinationContainer.getSelectedItem() instanceof ResourceTank + && ((ResourceTank)ddlDestinationContainer.getSelectedItem()).getContainer() instanceof PropulsiveVehicle) { + PropulsiveVehicle vehicle = (PropulsiveVehicle)((ResourceTank)ddlDestinationContainer.getSelectedItem()).getContainer(); + event.setDestinationContainer(((PropulsiveVehicle)getEventDialog().getElement(vehicle.getUid())).getOmsFuelTank()); + } else if(ddlDestinationContainer.getSelectedItem() instanceof ResourceTank && + ((ResourceTank)ddlDestinationContainer.getSelectedItem()).getContainer() instanceof SurfaceVehicle) { + SurfaceVehicle vehicle = (SurfaceVehicle)((ResourceTank)ddlDestinationContainer.getSelectedItem()).getContainer(); + event.setDestinationContainer(((SurfaceVehicle)getEventDialog().getElement(vehicle.getUid())).getFuelTank()); + } else if(ddlDestinationContainer.getSelectedItem() instanceof I_ResourceContainer) { + I_ResourceContainer container = (I_ResourceContainer)ddlDestinationContainer.getSelectedItem(); + event.setDestinationContainer((I_ResourceContainer)getEventDialog().getElement(container.getUid())); + } + if(ddlOriginContainer.getSelectedItem() instanceof ResourceTank + && ((ResourceTank)ddlOriginContainer.getSelectedItem()).getContainer() instanceof PropulsiveVehicle) { + PropulsiveVehicle vehicle = (PropulsiveVehicle)((ResourceTank)ddlOriginContainer.getSelectedItem()).getContainer(); + event.setOriginContainer(((PropulsiveVehicle)getEventDialog().getElement(vehicle.getUid())).getOmsFuelTank()); + event.setTransferDemands(demandsTable.getTransferDemands()); + } else if(ddlOriginContainer.getSelectedItem() instanceof ResourceTank + && ((ResourceTank)ddlOriginContainer.getSelectedItem()).getContainer() instanceof SurfaceVehicle) { + SurfaceVehicle vehicle = (SurfaceVehicle)((ResourceTank)ddlOriginContainer.getSelectedItem()).getContainer(); + event.setOriginContainer(((SurfaceVehicle)getEventDialog().getElement(vehicle.getUid())).getFuelTank()); + event.setTransferDemands(demandsTable.getTransferDemands()); + } else if(ddlOriginContainer.getSelectedItem() instanceof I_ResourceContainer) { + I_ResourceContainer container = (I_ResourceContainer)ddlOriginContainer.getSelectedItem(); + event.setOriginContainer((I_ResourceContainer)getEventDialog().getElement(container.getUid())); + event.setTransferDemands(demandsTable.getTransferDemands()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.event.AbstractEventPanel#updateView() + */ + @Override + public void updateView() { + I_ResourceContainer destinationContainer = (I_ResourceContainer)ddlDestinationContainer.getSelectedItem(); + ItemListener destinationListener = ddlDestinationContainer.getItemListeners()[0]; + ddlDestinationContainer.removeItemListener(destinationListener); + ddlDestinationContainer.removeAllItems(); + + I_ResourceContainer originContainer = (I_ResourceContainer)ddlOriginContainer.getSelectedItem(); + ItemListener originListener = ddlOriginContainer.getItemListeners()[0]; + ddlOriginContainer.removeItemListener(originListener); + ddlOriginContainer.removeAllItems(); + + DemandSet demands = demandsTable.getTransferDemands(); + + for(I_Element i : getEventDialog().getSimNode().getCompleteContents()) { + if(i instanceof I_ResourceContainer) { + ddlDestinationContainer.addItem(i); + ddlOriginContainer.addItem(i); + } else if(i instanceof PropulsiveVehicle) { + PropulsiveVehicle v = (PropulsiveVehicle)i; + if(v.getOmsFuelTank()!=null) { + ddlDestinationContainer.addItem(v.getOmsFuelTank()); + ddlOriginContainer.addItem(v.getOmsFuelTank()); + } + } else if(i instanceof SurfaceVehicle) { + SurfaceVehicle v = (SurfaceVehicle)i; + if(v.getFuelTank()!=null) { + ddlDestinationContainer.addItem(v.getFuelTank()); + ddlOriginContainer.addItem(v.getFuelTank()); + } + } + } + if(destinationContainer!=null + && destinationContainer instanceof ResourceTank + && destinationContainer.getContainer() instanceof PropulsiveVehicle) { + ddlDestinationContainer.setSelectedItem(((PropulsiveVehicle)getEventDialog().getSimElement(((PropulsiveVehicle)destinationContainer.getContainer()).getUid())).getOmsFuelTank()); + } else if(destinationContainer!=null + && destinationContainer instanceof ResourceTank + && destinationContainer.getContainer() instanceof SurfaceVehicle) { + ddlDestinationContainer.setSelectedItem(((SurfaceVehicle)getEventDialog().getSimElement(((SurfaceVehicle)destinationContainer.getContainer()).getUid())).getFuelTank()); + } else if(destinationContainer!=null + && getEventDialog().getSimElement(destinationContainer.getUid()) != null) { + ddlDestinationContainer.setSelectedItem(getEventDialog().getSimElement(destinationContainer.getUid())); + } + ddlDestinationContainer.addItemListener(destinationListener); + if(originContainer!=null + && originContainer instanceof ResourceTank + && originContainer.getContainer() instanceof PropulsiveVehicle) { + ddlOriginContainer.setSelectedItem(((PropulsiveVehicle)getEventDialog().getSimElement(((PropulsiveVehicle)originContainer.getContainer()).getUid())).getOmsFuelTank()); + demandsTable.setData(((PropulsiveVehicle)getEventDialog().getSimElement(((PropulsiveVehicle)originContainer.getContainer()).getUid())).getOmsFuelTank(), demands); + } else if(originContainer!=null + && originContainer instanceof ResourceTank + && originContainer.getContainer() instanceof SurfaceVehicle) { + ddlDestinationContainer.setSelectedItem(((SurfaceVehicle)getEventDialog().getSimElement(((SurfaceVehicle)originContainer.getContainer()).getUid())).getFuelTank()); + demandsTable.setData(((SurfaceVehicle)getEventDialog().getSimElement(((SurfaceVehicle)originContainer.getContainer()).getUid())).getFuelTank(), demands); + } else if(originContainer!=null + && getEventDialog().getSimElement(originContainer.getUid())!=null) { + ddlOriginContainer.setSelectedItem(getEventDialog().getSimElement(originContainer.getUid())); + demandsTable.setData((I_ResourceContainer)getEventDialog().getSimElement(originContainer.getUid()), demands); + } + ddlOriginContainer.addItemListener(originListener); + + updateCapacities(); + } + + /** + * Update capacities. + */ + private void updateCapacities() { + double mass = 0; + double volume = 0; + boolean hasErrors = false; + if(ddlDestinationContainer.getSelectedItem() instanceof I_ResourceContainer) { + I_ResourceContainer v = (I_ResourceContainer)ddlDestinationContainer.getSelectedItem(); + mass += v.getCargoMass(); + volume += v.getCargoVolume(); + if(!ddlDestinationContainer.getSelectedItem().equals(ddlOriginContainer.getSelectedItem())) { + for(Demand demand : demandsTable.getTransferDemands()) { + if(v.canAdd(demand.getResource(), demand.getAmount())) { + mass += demand.getMass(); + volume += demand.getVolume(); + } else { + mass += demand.getMass(); + volume += demand.getVolume(); + hasErrors = true; + } + } + } + hasErrors = capacityPanel.updateCapacities(v, mass, volume) || hasErrors; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/manifest/AddContainerButton.java b/src/main/java/edu/mit/spacenet/gui/manifest/AddContainerButton.java new file mode 100644 index 0000000..9fcfa17 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/manifest/AddContainerButton.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.manifest; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.ImageIcon; +import javax.swing.JMenuItem; + +import edu.mit.spacenet.domain.element.ElementType; +import edu.mit.spacenet.domain.element.ResourceContainerFactory; +import edu.mit.spacenet.gui.component.DropDownButton; + +/** + * A custom drop down button that allows the addition of new containers + * to the manifest tab. + */ +public class AddContainerButton extends DropDownButton { + private static final long serialVersionUID = 259141624873390794L; + + private ManifestTab manifestTab; + + /** + * Instantiates a new adds the container button. + * + * @param text the text + * @param icon the icon + */ + public AddContainerButton(ManifestTab manifestTab) { + super("Add", new ImageIcon(manifestTab.getClass().getClassLoader().getResource("icons/package_add.png"))); + this.manifestTab = manifestTab; + buildMenu(); + } + + /** + * Builds the menu. + */ + private void buildMenu() { + JMenuItem addCtb = new JMenuItem("Add Crew Transfer Bag (CTB)", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addCtb.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createCTB()); + manifestTab.updateView(); + } + }); + getMenu().add(addCtb); + JMenuItem addHalfCtb = new JMenuItem("Add Half Crew Transfer Bag (CTB)", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addHalfCtb.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createHCTB()); + manifestTab.updateView(); + } + }); + getMenu().add(addHalfCtb); + JMenuItem addDoubleCtb = new JMenuItem("Add Double Crew Transfer Bag (CTB)", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addDoubleCtb.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createDCTB()); + manifestTab.updateView(); + } + }); + getMenu().add(addDoubleCtb); + JMenuItem addLt = new JMenuItem("Add Liquid Tank", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addLt.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createLT()); + manifestTab.updateView(); + } + }); + getMenu().add(addLt); + JMenuItem addLtd = new JMenuItem("Add Liquid Tank Derivative", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addLtd.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createLTD()); + manifestTab.updateView(); + } + }); + getMenu().add(addLtd); + JMenuItem addGt = new JMenuItem("Add Gas Tank", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addGt.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createGT()); + manifestTab.updateView(); + } + }); + getMenu().add(addGt); + JMenuItem addGtd = new JMenuItem("Add Gas Tank Derivative", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addGtd.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createGTD()); + manifestTab.updateView(); + } + }); + getMenu().add(addGtd); + JMenuItem addShoss = new JMenuItem("Add Shoss Box", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addShoss.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createShoss()); + manifestTab.updateView(); + } + }); + getMenu().add(addShoss); + JMenuItem addPressShoss = new JMenuItem("Add Pressurized Shoss Box", ElementType.RESOURCE_CONTAINER.getIconType().getIcon()); + addPressShoss.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + manifestTab.getManifest().addContainer(ResourceContainerFactory.createPressShoss()); + manifestTab.updateView(); + } + }); + getMenu().add(addPressShoss); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/manifest/AggregatedDemandsTable.java b/src/main/java/edu/mit/spacenet/gui/manifest/AggregatedDemandsTable.java new file mode 100644 index 0000000..9b2380a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/manifest/AggregatedDemandsTable.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.manifest; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.text.DecimalFormat; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.scenario.Manifest; +import edu.mit.spacenet.scenario.SupplyEdge.SupplyPoint; + +/** + * A table for visualizing aggregated demands, and the portion of each demand + * that has been packed. + * + * @author Paul Grogan + */ +public class AggregatedDemandsTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + private ManifestTab manifestTab; + private AggregatedDemandsTableModel model; + + /** + * Instantiates a new aggregated demands table. + * + * @param m the manifest + */ + public AggregatedDemandsTable(ManifestTab manifestTab) { + this.manifestTab = manifestTab; + model = new AggregatedDemandsTableModel(); + setModel(model); + getColumnModel().getColumn(0).setHeaderValue("Supply Point"); + getColumnModel().getColumn(0).setMaxWidth(100); + getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 6799027210269525751L; + // custom renderer to highlight edge demands with an asterisk + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(getManifest().isEdgeDemand(getDemand(row))) setText(getText() + "*"); + return this; + } + }); + getColumnModel().getColumn(1).setHeaderValue("Resource"); + getColumnModel().getColumn(2).setHeaderValue("Amount"); + getColumnModel().getColumn(2).setMaxWidth(100); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format the decimals + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(JLabel.RIGHT); + setText(format.format(value) + " " + ((AggregatedDemandsTableModel)getModel()).getDemand(row).getResource().getUnits()); + return this; + } + }); + getColumnModel().getColumn(3).setHeaderValue("Packed"); + getColumnModel().getColumn(3).setMaxWidth(100); + getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 6799027210269525751L; + private DecimalFormat format = new DecimalFormat("0.00"); + // custom renderer to format the decimals + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setText(format.format(value) + " " + ((AggregatedDemandsTableModel)getModel()).getDemand(row).getResource().getUnits()); + setHorizontalAlignment(JLabel.RIGHT); + if(getValueAt(row, column).equals(getValueAt(row, column-1))&&!isSelected) { + setBackground(new Color(0xcc,0xff,0xcc)); + } else if(!isSelected) { + setBackground(new Color(0xff,0xcc,0xcc)); + } + return this; + } + }); + setBackground(Color.WHITE); + getTableHeader().setReorderingAllowed(false); + getTableHeader().setBackground(Color.WHITE); + getTableHeader().setFont(getTableHeader().getFont().deriveFont(Font.BOLD)); + getTableHeader().setBorder(BorderFactory.createMatteBorder(0,0,1,0,Color.BLACK)); + getTableHeader().setOpaque(false); + } + + /** + * Initialize. + */ + public void initialize() { + model.fireTableDataChanged(); + } + + /** + * Gets the manifest. + * + * @return the manifest + */ + private Manifest getManifest() { + return manifestTab.getManifest(); + } + + /** + * Gets the demand. + * + * @param row the row + * + * @return the demand + */ + public Demand getDemand(int row) { + return model.getDemand(row); + } + + /** + * Gets the selected demand. + * + * @return the selected demand + */ + public Demand getSelectedDemand() { + int row = getSelectedRow(); + if(row<0) return null; + else return getDemand(row); + } + + /** + * Gets the supply point. + * + * @param row the row + * + * @return the supply point + */ + public SupplyPoint getSupplyPoint(int row) { + return model.getSupplyPoint(row); + } + + /** + * Gets the selected supply point. + * + * @return the selected supply point + */ + public SupplyPoint getSelectedSupplyPoint() { + int row = getSelectedRow(); + if(row<0) return null; + else return getSupplyPoint(row); + } + + /** + * Updates the view. + */ + public void updateView() { + model.fireTableDataChanged(); + } + + /** + * The Class AggregatedDemandsTableModel. + */ + private class AggregatedDemandsTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 4; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + int i = 0; + for(SupplyPoint point : getManifest().getAggregatedNodeDemands().keySet()) { + i+=getManifest().getAggregatedNodeDemands().get(point).size(); + i+=getManifest().getAggregatedEdgeDemands().get(point.getEdge()).size(); + } + return i; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) return getSupplyPoint(row); + else if(col==1) return getDemand(row).getResource(); + else if(col==2) return getDemand(row).getAmount(); + else return getManifest().getPackedAmount(getDemand(row)); + } + + /** + * Gets the demand. + * + * @param row the row + * + * @return the demand + */ + private Demand getDemand(int row) { + int lastRowSeen = -1; + for(SupplyPoint point : getManifest().getAggregatedNodeDemands().keySet()) { + if(lastRowSeen + + getManifest().getAggregatedNodeDemands().get(point).size() + + getManifest().getAggregatedEdgeDemands().get(point.getEdge()).size() >= row) { + for(Demand d : getManifest().getAggregatedNodeDemands().get(point)) { + lastRowSeen++; + if(lastRowSeen==row) return d; + } + for(Demand d : getManifest().getAggregatedEdgeDemands().get(point.getEdge())) { + lastRowSeen++; + if(lastRowSeen==row) return d; + } + return null; + } + lastRowSeen+=getManifest().getAggregatedNodeDemands().get(point).size()+ + getManifest().getAggregatedEdgeDemands().get(point.getEdge()).size(); + } + return null; + } + + /** + * Gets the supply point. + * + * @param row the row + * + * @return the supply point + */ + private SupplyPoint getSupplyPoint(int row) { + return getManifest().getSupplyPoint(getDemand(row)); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/manifest/CarrierContentsTable.java b/src/main/java/edu/mit/spacenet/gui/manifest/CarrierContentsTable.java new file mode 100644 index 0000000..0439052 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/manifest/CarrierContentsTable.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.manifest; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.text.DecimalFormat; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.gui.renderer.ElementTableCellRenderer; +import edu.mit.spacenet.scenario.Manifest; +import edu.mit.spacenet.scenario.SupplyEdge; + +/** + * A table for viewing the manifested contents of a carrier. + * + * @author Paul Grogan + */ +public class CarrierContentsTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + private ManifestTab manifestTab; + private CarrierContentsTableModel model; + + /** + * Instantiates a new carrier contents table. + * + * @param m the manifest + */ + public CarrierContentsTable(ManifestTab manifestTab) { + this.manifestTab = manifestTab; + model = new CarrierContentsTableModel(); + setModel(model); + getColumnModel().getColumn(0).setHeaderValue("Container"); + getColumnModel().getColumn(0).setWidth(150); + getColumnModel().getColumn(0).setCellRenderer(new ElementTableCellRenderer()); + getColumnModel().getColumn(1).setHeaderValue("Mass"); + getColumnModel().getColumn(1).setMaxWidth(100); + getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 6799027210269525751L; + // custom renderer to format decimals and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + DecimalFormat format = new DecimalFormat("0.00"); + setText(format.format(value) + " kg"); + setHorizontalAlignment(JLabel.RIGHT); + return this; + } + }); + getColumnModel().getColumn(2).setHeaderValue("Volume"); + getColumnModel().getColumn(2).setMaxWidth(100); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 6799027210269525751L; + // custom renderer to format decimals and add units + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + DecimalFormat format = new DecimalFormat("0.000"); + setText(format.format(value) + " m^3"); + setHorizontalAlignment(JLabel.RIGHT); + return this; + } + }); + setBackground(Color.WHITE); + getTableHeader().setReorderingAllowed(false); + getTableHeader().setBackground(Color.WHITE); + getTableHeader().setFont(getTableHeader().getFont().deriveFont(Font.BOLD)); + getTableHeader().setBorder(BorderFactory.createMatteBorder(0,0,1,0,Color.BLACK)); + getTableHeader().setOpaque(false); + } + + /** + * Sets the carrier. + * + * @param edge the edge + * @param carrier the carrier + */ + public void setCarrier(SupplyEdge edge, I_Carrier carrier) { + model.setCarrier(edge, carrier); + model.fireTableDataChanged(); + } + + /** + * Gets the container. + * + * @param row the row + * + * @return the container + */ + public I_ResourceContainer getContainer(int row) { + return ((CarrierContentsTableModel)getModel()).getContainer(row); + } + + /** + * Gets the selected container. + * + * @return the selected container + */ + public I_ResourceContainer getSelectedContainer() { + int row = getSelectedRow(); + if(row<0) return null; + else return getContainer(row); + } + + /** + * Gets the manifest. + * + * @return the manifest + */ + private Manifest getManifest() { + return manifestTab.getManifest(); + } + + /** + * Initialize. + */ + public void initialize() { + model.fireTableDataChanged(); + } + + /** + * Update view. + */ + public void updateView() { + model.fireTableDataChanged(); + } + + /** + * The Class CarrierContentsTableModel. + */ + class CarrierContentsTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + + private SupplyEdge edge; + private I_Carrier carrier; + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 3; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + if(edge==null || carrier==null) return 0; + else return getManifest().getManifestedContainers().get(edge).get(carrier).size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) return getContainer(row); + else if(col==1) return getContainer(row).getMass() + getManifest().getCargoMass(getContainer(row), edge.getPoint()); + else return getContainer(row).getVolume(); + } + private I_ResourceContainer getContainer(int row) { + int lastRowSeen = -1; + for(I_ResourceContainer container : getManifest().getManifestedContainers().get(edge).get(carrier)) { + lastRowSeen++; + if(row==lastRowSeen) return container; + } + return null; + } + private void setCarrier(SupplyEdge edge, I_Carrier carrier) { + this.edge = edge; + this.carrier = carrier; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/manifest/ContainerContentsTable.java b/src/main/java/edu/mit/spacenet/gui/manifest/ContainerContentsTable.java new file mode 100644 index 0000000..5d62aaf --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/manifest/ContainerContentsTable.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.manifest; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.text.DecimalFormat; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.scenario.Manifest; +import edu.mit.spacenet.scenario.SupplyEdge.SupplyPoint; + +/** + * A table for viewing the packed contents of a container. + */ +public class ContainerContentsTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + private ManifestTab manifestTab; + private ContainerContentsTableModel model; + /** + * Instantiates a new container contents table. + * + * @param manifestTab the manifest tab + */ + public ContainerContentsTable(ManifestTab manifestTab) { + this.manifestTab = manifestTab; + model = new ContainerContentsTableModel(); + setModel(model); + getColumnModel().getColumn(0).setHeaderValue("Supply Point"); + getColumnModel().getColumn(0).setMaxWidth(100); + getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 6799027210269525751L; + + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(getManifest().isEdgeDemand(getManifest().getDemand(getDemand(row)))) setText(getText() + "*"); + return this; + } + }); + getColumnModel().getColumn(1).setHeaderValue("Resource"); + getColumnModel().getColumn(2).setHeaderValue("Amount"); + getColumnModel().getColumn(2).setMaxWidth(100); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 6799027210269525751L; + private DecimalFormat format = new DecimalFormat("0.00"); + + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setText(format.format(value) + " " + model.getDemand(row).getResource().getUnits()); + setHorizontalAlignment(JLabel.RIGHT); + return this; + } + }); + setBackground(Color.WHITE); + getTableHeader().setReorderingAllowed(false); + getTableHeader().setBackground(Color.WHITE); + getTableHeader().setFont(getTableHeader().getFont().deriveFont(Font.BOLD)); + getTableHeader().setBorder(BorderFactory.createMatteBorder(0,0,1,0,Color.BLACK)); + getTableHeader().setOpaque(false); + } + + /** + * Sets the container. + * + * @param container the container + * @param point the point + */ + public void setContainer(I_ResourceContainer container, SupplyPoint point) { + model.setContainer(container, point); + model.fireTableDataChanged(); + } + + /** + * Gets the demand. + * + * @param row the row + * + * @return the demand + */ + public Demand getDemand(int row) { + return model.getDemand(row); + } + + /** + * Gets the selected demand. + * + * @return the selected demand + */ + public Demand getSelectedDemand() { + int row = getSelectedRow(); + if(row<0) return null; + else return getDemand(row); + } + + /** + * Gets the manifest. + * + * @return the manifest + */ + private Manifest getManifest() { + return manifestTab.getManifest(); + } + + /** + * Initialize. + */ + public void initialize() { + model.fireTableDataChanged(); + } + + /** + * Update view. + */ + public void updateView() { + model.fireTableDataChanged(); + } + + /** + * The Class ContainerContentsTableModel. + */ + class ContainerContentsTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + + private I_ResourceContainer container; + private SupplyPoint point; + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 3; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + if(container==null) return 0; + else return getManifest().getPackedDemands(container, point).size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) return point; + else if(col==1) return getDemand(row).getResource(); + else return getDemand(row).getAmount(); + } + private Demand getDemand(int row) { + int lastRowSeen = -1; + for(Demand demand : getManifest().getPackedDemands(container, point)) { + lastRowSeen++; + if(row==lastRowSeen) return demand; + } + return null; + } + private void setContainer(I_ResourceContainer container, SupplyPoint point) { + this.container = container; + this.point = point; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/manifest/ManifestTab.java b/src/main/java/edu/mit/spacenet/gui/manifest/ManifestTab.java new file mode 100644 index 0000000..3b0688c --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/manifest/ManifestTab.java @@ -0,0 +1,880 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.manifest; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashSet; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JViewport; +import javax.swing.ListSelectionModel; +import javax.swing.SwingWorker; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.ScenarioPanel; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DropDownButton; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.scenario.Manifest; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.scenario.SupplyEdge; +import edu.mit.spacenet.scenario.SupplyEdge.SupplyPoint; +import edu.mit.spacenet.simulator.DemandSimulator; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * The tab component used to view and edit the scenario getManifest(). + * + * @author Paul Grogan + */ +public class ManifestTab extends JSplitPane { + private static final long serialVersionUID = 8829941616137676449L; + + private ScenarioPanel scenarioPanel; + private DemandSimulator simulator; + private SimWorker simWorker; + private ManifestWorker manifestWorker; + private AggregatedDemandsTable aggregatedDemandsTable; + private JButton clearButton, resetButton, autoManifestButton, unpackButton, autoPackButton; + + private PackedDemandsTable packedDemandsTable; + private JButton editContainerButton, removeContainerButton; + private JLabel containerNameLabel, containerMassLabel, containerVolumeLabel, containerEnvironmentLabel; + private ContainerContentsTable containerContentsTable; + private JButton unpackContentsButton; + private JProgressBar containerMassCapacity, containerVolumeCapacity; + private JButton packButton, unmanifestButton; + + private ElementTree carrierTree; + private CarrierContentsTable carrierContentsTable; + private JButton unmanifestContentsButton; + private JProgressBar carrierMassCapacity, carrierVolumeCapacity; + private JButton manifestButton; + + private ManifestedDemandsTable manifestedDemandsTable; + + /** + * Instantiates a new manifest tab. + * + * @param scenarioPanel the scenario panel + */ + public ManifestTab(ScenarioPanel scenarioPanel) { + this.scenarioPanel = scenarioPanel; + + setLeftComponent(buildDemandsPanel()); + JSplitPane rightPanel = new JSplitPane(); + rightPanel.setLeftComponent(buildPackingPanel()); + rightPanel.setRightComponent(buildManifestingPanel()); + setRightComponent(rightPanel); + + setResizeWeight(1/3D); + setDividerLocation(1/3D); + rightPanel.setResizeWeight(1/2D); + rightPanel.setDividerLocation(1/2D); + rightPanel.setBorder(BorderFactory.createEmptyBorder()); + setBorder(BorderFactory.createEmptyBorder()); + } + + /** + * Builds the demands panel. + * + * @return the demands panel + */ + private JPanel buildDemandsPanel() { + JPanel demandsPanel = new JPanel(); + demandsPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + demandsPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 5)); + clearButton = new JButton("Clear Manifest"); + clearButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/cross.png"))); + clearButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + getManifest().reset(); + updateView(); + } + }); + buttonPanel.add(clearButton); + resetButton = new JButton("Reset Manifest"); + resetButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/book_open_refresh.png"))); + resetButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + while(simWorker!=null && !simWorker.isDone()) { + // wait until previous reset is finished + } + getManifest().reset(); + simWorker = new SimWorker(); + simWorker.execute(); + } + }); + buttonPanel.add(resetButton); + autoManifestButton = new JButton("Auto-Manifest"); + autoManifestButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/book_open_lightning.png"))); + autoManifestButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + while(manifestWorker!=null && !manifestWorker.isDone()) { + // wait until previous auto-manifesting process is finished + } + manifestWorker = new ManifestWorker(); + manifestWorker.execute(); + } + }); + buttonPanel.add(autoManifestButton); + demandsPanel.add(buttonPanel, c); + + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + demandsPanel.add(new JLabel("Aggregated Demands"), c); + c.gridy++; + c.weighty = 1; + aggregatedDemandsTable = new AggregatedDemandsTable(this); + aggregatedDemandsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(aggregatedDemandsTable.getSelectedRow()>=0) { + //packedDemandsTable.clearSelection(); + //manifestedDemandsTable.clearSelection(); + } + updateButtons(); + } + }); + JScrollPane aggregatedDemandsScroll = new JScrollPane(aggregatedDemandsTable); + demandsPanel.add(aggregatedDemandsScroll, c); + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + + JPanel packButtonPanel = new JPanel(); + packButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + unpackButton = new JButton("Unpack"); + unpackButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/box_out.png"))); + unpackButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for(int row : aggregatedDemandsTable.getSelectedRows()) { + getManifest().unpackDemand(aggregatedDemandsTable.getDemand(row)); + } + updateView(); + } + }); + unpackButton.setEnabled(false); + packButtonPanel.add(unpackButton); + autoPackButton = new JButton("Auto-Pack"); + autoPackButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/box_lightning.png"))); + autoPackButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for(int row : aggregatedDemandsTable.getSelectedRows()) { + getManifest().autoPackDemand(aggregatedDemandsTable.getDemand(row)); + } + updateView(); + } + }); + autoPackButton.setEnabled(false); + packButtonPanel.add(autoPackButton); + demandsPanel.add(packButtonPanel, c); + return demandsPanel; + } + + /** + * Builds the packing panel. + * + * @return the packing panel + */ + private JPanel buildPackingPanel() { + JPanel packingPanel = new JPanel(); + packingPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + packingPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + packingPanel.add(new JLabel("Available Logistics Containers"), c); + c.gridy++; + c.weighty = 1; + packedDemandsTable = new PackedDemandsTable(this); + packedDemandsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(packedDemandsTable.getSelectedRow()>=0) { + //manifestedDemandsTable.clearSelection(); + } + updateContainer(); + updateButtons(); + } + }); + JScrollPane packedDemandsScroll = new JScrollPane(packedDemandsTable); + packingPanel.add(packedDemandsScroll, c); + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel containerButtonPanel = new JPanel(); + containerButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + DropDownButton addContainerButton = new AddContainerButton(this); + containerButtonPanel.add(addContainerButton); + editContainerButton = new JButton("Edit"); + editContainerButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/package_edit.png"))); + editContainerButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + // TODO add edit container dialog + } + }); + editContainerButton.setEnabled(false); + containerButtonPanel.add(editContainerButton); + removeContainerButton = new JButton("Remove"); + removeContainerButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/package_delete.png"))); + removeContainerButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + HashSet containers = new HashSet(); + for(int row : packedDemandsTable.getSelectedRows()) { + containers.add(packedDemandsTable.getContainer(row)); + } + for(I_ResourceContainer container : containers) getManifest().removeContainer(container); + updateView(); + } + }); + removeContainerButton.setEnabled(false); + containerButtonPanel.add(removeContainerButton); + packingPanel.add(containerButtonPanel, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + c.weightx = 0; + c.gridwidth = 1; + packingPanel.add(new JLabel("Name: "), c); + c.gridy++; + packingPanel.add(new JLabel("Total Mass: "), c); + c.gridy++; + packingPanel.add(new JLabel("Total Volume: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + packingPanel.add(new JLabel("Contents: "), c); + c.anchor = GridBagConstraints.LINE_END; + c.gridy+=2; + packingPanel.add(new JLabel("Environment: "), c); + c.gridy++; + packingPanel.add(new JLabel("Cargo Mass: "), c); + c.gridy++; + packingPanel.add(new JLabel("Cargo Volume: "), c); + c.gridx++; + c.weightx = 1; + c.gridy-=7; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + containerNameLabel = new JLabel(); + packingPanel.add(containerNameLabel, c); + c.gridy++; + containerMassLabel = new JLabel(); + packingPanel.add(containerMassLabel, c); + c.gridy++; + containerVolumeLabel = new JLabel(); + packingPanel.add(containerVolumeLabel, c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_START; + c.weighty = 0.4; + containerContentsTable = new ContainerContentsTable(this); + containerContentsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(containerContentsTable.getSelectedRowCount()==1) { + for(int row=0; row demands = new HashSet(); + for(int row : containerContentsTable.getSelectedRows()) { + demands.add(containerContentsTable.getDemand(row)); + } + for(Demand demand : demands) { + getManifest().unpackDemand(demand, + packedDemandsTable.getSelectedContainer()); + } + updateView(); + } + }); + unpackContentsButton.setEnabled(false); + packingPanel.add(unpackContentsButton, c); + c.gridy++; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + containerEnvironmentLabel = new JLabel(); + packingPanel.add(containerEnvironmentLabel, c); + c.gridy++; + containerMassCapacity = new JProgressBar(0,100); + containerMassCapacity.setStringPainted(true); + containerMassCapacity.setString(""); + packingPanel.add(containerMassCapacity, c); + c.gridy++; + containerVolumeCapacity = new JProgressBar(0,100); + containerVolumeCapacity.setStringPainted(true); + containerVolumeCapacity.setString(""); + packingPanel.add(containerVolumeCapacity, c); + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel packButtonPanel = new JPanel(); + packButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + packButton = new JButton("Pack"); + packButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/box_in.png"))); + packButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + for(int row : aggregatedDemandsTable.getSelectedRows()) { + getManifest().packDemand(aggregatedDemandsTable.getDemand(row), + packedDemandsTable.getSelectedContainer()); + } + updateView(); + } + }); + packButton.setEnabled(false); + packButtonPanel.add(packButton); + unmanifestButton = new JButton("Unmanifest"); + unmanifestButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/book_delete.png"))); + unmanifestButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList containers = new ArrayList(); + ArrayList edges = new ArrayList(); + for(int row : packedDemandsTable.getSelectedRows()) { + containers.add(packedDemandsTable.getContainer(row)); + edges.add(packedDemandsTable.getSupplyEdge(row)); + } + for(int i=0; i=0 + && aggregatedDemandsTable.getSelectedRow()>=0 + && packedDemandsTable.getSelectedRow()<0) { + //aggregatedDemandsTable.clearSelection(); + } + updateCarrier(); + updateButtons(); + } + }); + JScrollPane manifestedDemandsScroll = new JScrollPane(manifestedDemandsTable); + manifestingPanel.add(manifestedDemandsScroll, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + c.weightx = 0; + c.weighty = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.FIRST_LINE_END; + manifestingPanel.add(new JLabel("Carriers: "), c); + c.gridy++; + manifestingPanel.add(new JLabel("Containers: "), c); + c.anchor = GridBagConstraints.LINE_END; + c.gridy+=2; + manifestingPanel.add(new JLabel("Cargo Mass: "), c); + c.gridy++; + manifestingPanel.add(new JLabel("Cargo Volume: "), c); + c.gridx++; + c.weightx = 1; + c.gridy-=4; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.FIRST_LINE_START; + c.weighty = 0.4; + carrierTree = new ElementTree(); + carrierTree.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + carrierTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + updateElement(); + updateButtons(); + } + }); + JScrollPane carrierTreeScroll = new JScrollPane(carrierTree); + carrierTreeScroll.setPreferredSize(new Dimension(150,300)); + manifestingPanel.add(carrierTreeScroll, c); + c.gridy++; + carrierContentsTable = new CarrierContentsTable(this); + carrierContentsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(carrierContentsTable.getSelectedRowCount()==1) { + for(int row=0; row containers = new HashSet(); + for(int row : carrierContentsTable.getSelectedRows()) { + containers.add(carrierContentsTable.getContainer(row)); + } + for(I_ResourceContainer container : containers) { + getManifest().unmanifestContainer(container, + manifestedDemandsTable.getSelectedSupplyEdge()); + } + updateView(); + } + }); + unmanifestContentsButton.setEnabled(false); + manifestingPanel.add(unmanifestContentsButton, c); + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.gridy++; + carrierMassCapacity = new JProgressBar(0,100); + carrierMassCapacity.setStringPainted(true); + carrierMassCapacity.setString(""); + manifestingPanel.add(carrierMassCapacity, c); + c.gridy++; + carrierVolumeCapacity = new JProgressBar(0,100); + carrierVolumeCapacity.setStringPainted(true); + carrierVolumeCapacity.setString(""); + manifestingPanel.add(carrierVolumeCapacity, c); + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel manifestingButtonPanel = new JPanel(); + manifestingButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + manifestButton = new JButton("Manifest"); + manifestButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/book_add.png"))); + manifestButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList containers = new ArrayList(); + + for(int row : packedDemandsTable.getSelectedRows()) { + containers.add(packedDemandsTable.getContainer(row)); + } + for(int i=0; i0) { + for(int row : aggregatedDemandsTable.getSelectedRows()) { + unpackButton.setEnabled(getManifest().canUnpackDemand(aggregatedDemandsTable.getDemand(row))); + if(unpackButton.isEnabled()) break; + } + } + else unpackButton.setEnabled(false); + + if(aggregatedDemandsTable.getSelectedRowCount()>0) { + for(int row : aggregatedDemandsTable.getSelectedRows()) { + autoPackButton.setEnabled(getManifest().canAutoPackDemand(aggregatedDemandsTable.getDemand(row))); + if(autoPackButton.isEnabled()) break; + } + } + else autoPackButton.setEnabled(false); + + removeContainerButton.setEnabled(packedDemandsTable.getSelectedRowCount()>0); + + if(containerContentsTable.getSelectedRowCount()>0 + && packedDemandsTable.getSelectedRowCount()==1) { + for(int row : containerContentsTable.getSelectedRows()) { + unpackContentsButton.setEnabled(getManifest().canUnpackDemand( + containerContentsTable.getDemand(row), + packedDemandsTable.getSelectedContainer())); + if(unpackContentsButton.isEnabled()) break; + } + } + else unpackContentsButton.setEnabled(false); + + if(aggregatedDemandsTable.getSelectedRowCount()>0 + && packedDemandsTable.getSelectedRowCount()==1) { + for(int row : aggregatedDemandsTable.getSelectedRows()) { + packButton.setEnabled(getManifest().canPackDemand( + aggregatedDemandsTable.getDemand(row), + packedDemandsTable.getSelectedContainer())); + if(packButton.isEnabled()) break; + } + } + else packButton.setEnabled(false); + + if(packedDemandsTable.getSelectedRowCount()>0) { + for(int row : packedDemandsTable.getSelectedRows()) { + unmanifestButton.setEnabled(getManifest().canUnmanifestContainer( + packedDemandsTable.getContainer(row), + packedDemandsTable.getSupplyEdge(row))); + if(unmanifestButton.isEnabled()) break; + } + } + else unmanifestButton.setEnabled(false); + + if(carrierContentsTable.getSelectedRowCount()>0 + && manifestedDemandsTable.getSelectedRowCount()==1) + for(int row : carrierContentsTable.getSelectedRows()) { + unmanifestContentsButton.setEnabled(getManifest().canUnmanifestContainer( + carrierContentsTable.getContainer(row), + manifestedDemandsTable.getSelectedSupplyEdge())); + if(unmanifestContentsButton.isEnabled()) break; + } + else unmanifestContentsButton.setEnabled(false); + + if(packedDemandsTable.getSelectedRowCount()>0 + && manifestedDemandsTable.getSelectedRowCount()==1 + && carrierTree.getSelectionCount()==1 + && carrierTree.getSelection() instanceof I_Carrier) + for(int row : packedDemandsTable.getSelectedRows()) { + manifestButton.setEnabled(getManifest().canManifestContainer( + packedDemandsTable.getContainer(row), + manifestedDemandsTable.getSelectedSupplyEdge(), + (I_Carrier)carrierTree.getSelection())); + if(manifestButton.isEnabled()) break; + } + else manifestButton.setEnabled(false); + } + private void updateContainer() { + if(packedDemandsTable.getSelectedRowCount()==1) { + I_ResourceContainer container = packedDemandsTable.getContainer(packedDemandsTable.getSelectedRow()); + SupplyPoint point = packedDemandsTable.getSupplyPoint(packedDemandsTable.getSelectedRow()); + double cargoMass = getManifest().getCargoMass(container, point); + double cargoVolume = getManifest().getCargoVolume(container, point); + + DecimalFormat massFormat = new DecimalFormat("0.00"); + DecimalFormat volumeFormat = new DecimalFormat("0.000"); + containerNameLabel.setText(container.getName()); + containerMassLabel.setText(massFormat.format(container.getMass() + cargoMass) + " kg"); + containerVolumeLabel.setText(volumeFormat.format(container.getVolume()) + " m^3"); + containerContentsTable.setContainer(container, point); + containerEnvironmentLabel.setText(container.getCargoEnvironment().toString()); + + if(cargoMass - container.getMaxCargoMass() > GlobalParameters.getMassPrecision()/2d) + containerMassCapacity.setForeground(new Color(153, 0, 0)); + else containerMassCapacity.setForeground(new Color(0, 153, 0)); + if(container.getMaxCargoMass()==0) containerMassCapacity.setValue(100); + else containerMassCapacity.setValue((int)(100*cargoMass/container.getMaxCargoMass())); + containerMassCapacity.setString(massFormat.format(cargoMass) + " / " + massFormat.format(container.getMaxCargoMass()) + " kg"); + + if(cargoVolume - container.getMaxCargoVolume() > GlobalParameters.getVolumePrecision()/2d) + containerVolumeCapacity.setForeground(new Color(153, 0, 0)); + else containerVolumeCapacity.setForeground(new Color(0, 153, 0)); + if(container.getMaxCargoVolume()==0) containerVolumeCapacity.setValue(100); + else containerVolumeCapacity.setValue((int)(100*cargoVolume/container.getMaxCargoVolume())); + containerVolumeCapacity.setString(volumeFormat.format(cargoVolume) + " / " + volumeFormat.format(container.getMaxCargoVolume()) + " m^3"); + } else { + containerNameLabel.setText(null); + containerMassLabel.setText(null); + containerVolumeLabel.setText(null); + containerContentsTable.setContainer(null, null); + containerEnvironmentLabel.setText(null); + containerMassCapacity.setValue(0); + containerMassCapacity.setString(""); + containerVolumeCapacity.setValue(0); + containerVolumeCapacity.setString(""); + } + } + private void updateCarrier() { + if(manifestedDemandsTable.getSelectedRow()>=0) { + I_Carrier superCarrier = manifestedDemandsTable.getCarrier(manifestedDemandsTable.getSelectedRow()); + carrierTree.setRoot(superCarrier); + carrierTree.setRootVisible(true); + carrierTree.setSelection(superCarrier); + } else { + carrierTree.setRoot(null); + carrierTree.setRootVisible(false); + carrierMassCapacity.setValue(0); + carrierMassCapacity.setString(""); + carrierVolumeCapacity.setValue(0); + carrierVolumeCapacity.setString(""); + } + } + private void updateElement() { + if(carrierTree.getSelectionCount()>0 + && carrierTree.getSelection() instanceof I_Carrier) { + SupplyEdge edge = manifestedDemandsTable.getSupplyEdge(manifestedDemandsTable.getSelectedRow()); + I_Carrier carrier = (I_Carrier)carrierTree.getSelection(); + + carrierContentsTable.setCarrier(edge, carrier); + + double cargoMass = getManifest().getCargoMass(carrier, edge.getPoint()); + double cargoVolume = getManifest().getCargoVolume(carrier, edge.getPoint()); + + DecimalFormat massFormat = new DecimalFormat("0.00"); + if(cargoMass - carrier.getMaxCargoMass() > GlobalParameters.getMassPrecision()/2d) + carrierMassCapacity.setForeground(new Color(153, 0, 0)); + else carrierMassCapacity.setForeground(new Color(0, 153, 0)); + if(carrier.getMaxCargoMass()==0) carrierMassCapacity.setValue(100); + else carrierMassCapacity.setValue((int)(100*cargoMass/carrier.getMaxCargoMass())); + carrierMassCapacity.setString(massFormat.format(cargoMass) + " / " + massFormat.format(carrier.getMaxCargoMass()) + " kg"); + + DecimalFormat volumeFormat = new DecimalFormat("0.000"); + if(cargoVolume - carrier.getMaxCargoVolume() > GlobalParameters.getVolumePrecision()/2d) + carrierVolumeCapacity.setForeground(new Color(153, 0, 0)); + else carrierVolumeCapacity.setForeground(new Color(0, 153, 0)); + if(carrier.getMaxCargoVolume()==0) carrierVolumeCapacity.setValue(100); + else carrierVolumeCapacity.setValue((int)(100*cargoVolume/carrier.getMaxCargoVolume())); + carrierVolumeCapacity.setString(volumeFormat.format(cargoVolume) + " / " + volumeFormat.format(carrier.getMaxCargoVolume()) + " m^3"); + } else { + carrierMassCapacity.setValue(0); + carrierMassCapacity.setString(""); + + carrierVolumeCapacity.setValue(0); + carrierVolumeCapacity.setString(""); + + carrierContentsTable.setCarrier(null, null); + } + } + + /** + * A SwingWorker subclass that manages the time-intensive simulation in a + * separate thread. + */ + private class SimWorker extends SwingWorker { + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#doInBackground() + */ + public Void doInBackground() { + try { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Simulating Demands..."); + scenarioPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + simulator.simulate(); + getManifest().setSupplyEdges(simulator.getSupplyEdges()); + getManifest().setSupplyPoints(simulator.getSupplyPoints()); + getManifest().setAggregatedNodeDemands(simulator.getAggregatedNodeDemands()); + getManifest().setAggregatedEdgeDemands(simulator.getAggregatedEdgeDemands()); + scenarioPanel.setCursor(Cursor.getDefaultCursor()); + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#done() + */ + protected void done() { + // initialize demands panel components + aggregatedDemandsTable.initialize(); + // initialize packing panel components + packedDemandsTable.initialize(); + containerContentsTable.initialize(); + // initialize manifesting panel components + manifestedDemandsTable.initialize(); + carrierContentsTable.initialize(); + } + } + + /** + * A SwingWorker subclass that manages the time-intensive auto-manifesting + * in a separate thread. + */ + private class ManifestWorker extends SwingWorker { + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#doInBackground() + */ + public Void doInBackground() { + try { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Auto-Manifesting..."); + scenarioPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + getManifest().autoManifest(); + updateView(); + scenarioPanel.setCursor(Cursor.getDefaultCursor()); + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/manifest/ManifestedDemandsTable.java b/src/main/java/edu/mit/spacenet/gui/manifest/ManifestedDemandsTable.java new file mode 100644 index 0000000..2dd4889 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/manifest/ManifestedDemandsTable.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.manifest; + +import java.awt.Color; +import java.awt.Font; + +import javax.swing.BorderFactory; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.scenario.Manifest; +import edu.mit.spacenet.scenario.SupplyEdge; + +/** + * A table for viewing the available carriers for manifesting. + * + * @author Paul Grogan + */ +public class ManifestedDemandsTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + private ManifestTab manifestTab; + private ManifestedDemandsTableModel model; + /** + * Instantiates a new manifested demands table. + * + * @param manifest the manifest + */ + public ManifestedDemandsTable(ManifestTab manifestTab) { + this.manifestTab = manifestTab; + model = new ManifestedDemandsTableModel(); + setModel(model); + getColumnModel().getColumn(0).setHeaderValue("Supply Edge"); + getColumnModel().getColumn(0).setWidth(150); + getColumnModel().getColumn(1).setHeaderValue("Carrier"); + + setBackground(Color.WHITE); + getTableHeader().setReorderingAllowed(false); + getTableHeader().setBackground(Color.WHITE); + getTableHeader().setFont(getTableHeader().getFont().deriveFont(Font.BOLD)); + getTableHeader().setBorder(BorderFactory.createMatteBorder(0,0,1,0,Color.BLACK)); + getTableHeader().setOpaque(false); + } + + /** + * Gets the supply edge. + * + * @param row the row + * + * @return the supply edge + */ + public SupplyEdge getSupplyEdge(int row) { + return model.getEdge(row); + } + + /** + * Gets the selected supply edge. + * + * @return the selected supply edge + */ + public SupplyEdge getSelectedSupplyEdge() { + int row = getSelectedRow(); + if(row<0) return null; + else return getSupplyEdge(row); + } + + /** + * Gets the carrier. + * + * @param row the row + * + * @return the carrier + */ + public I_Carrier getCarrier(int row) { + return model.getCarrier(row); + } + + /** + * Gets the selected carrier. + * + * @return the selected carrier + */ + public I_Carrier getSelectedCarrier() { + int row = getSelectedRow(); + if(row<0) return null; + else return getCarrier(row); + } + + /** + * Gets the manifest. + * + * @return the manifest + */ + private Manifest getManifest() { + return manifestTab.getManifest(); + } + + /** + * Initialize. + */ + public void initialize() { + model.fireTableDataChanged(); + } + + /** + * Update view. + */ + public void updateView() { + model.fireTableDataChanged(); + } + + /** + * The Class ManifestedDemandsTableModel. + */ + class ManifestedDemandsTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 2; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + int i = 0; + for(SupplyEdge edge : getManifest().getSupplyEdges()) { + i+=edge.getCarriers().size(); + } + return i; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) return getEdge(row); + else return getCarrier(row); + } + private SupplyEdge getEdge(int row) { + int lastRowSeen = -1; + for(SupplyEdge edge : getManifest().getSupplyEdges()) { + if(lastRowSeen + edge.getCarriers().size() >= row) { + return edge; + } + lastRowSeen+=edge.getCarriers().size(); + } + return null; + } + private I_Carrier getCarrier(int row) { + int lastRowSeen = -1; + for(SupplyEdge edge : getManifest().getSupplyEdges()) { + if(lastRowSeen + edge.getCarriers().size() >= row) { + for(I_Carrier carrier : edge.getCarriers()) { + lastRowSeen++; + if(lastRowSeen==row) return carrier; + } + return null; + } + lastRowSeen+=edge.getCarriers().size(); + } + return null; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/manifest/PackedDemandsTable.java b/src/main/java/edu/mit/spacenet/gui/manifest/PackedDemandsTable.java new file mode 100644 index 0000000..6ba221e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/manifest/PackedDemandsTable.java @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.manifest; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; + +import javax.swing.BorderFactory; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.gui.renderer.ElementTableCellRenderer; +import edu.mit.spacenet.scenario.Manifest; +import edu.mit.spacenet.scenario.SupplyEdge; +import edu.mit.spacenet.scenario.SupplyEdge.SupplyPoint; + +/** + * The table used to view the available resource containers for demand packing. + * + * @author Paul Grogan + */ +public class PackedDemandsTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + private ManifestTab manifestTab; + private PackedDemandsTableModel model; + /** + * Instantiates a new packed demands table. + * + * @param manifestTab the manifest tab + */ + public PackedDemandsTable(ManifestTab manifestTab) { + this.manifestTab = manifestTab; + model = new PackedDemandsTableModel(); + setModel(model); + getColumnModel().getColumn(0).setHeaderValue("Supply Point"); + getColumnModel().getColumn(0).setMaxWidth(100); + getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 6799027210269525751L; + // custom renderer to show edge demands with an asterisk + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(getManifest().isEdgeDemand(getContainer(row))) setText(getText() + "*"); + return this; + } + }); + getColumnModel().getColumn(1).setHeaderValue("Container"); + getColumnModel().getColumn(1).setCellRenderer(new ElementTableCellRenderer()); + getColumnModel().getColumn(2).setHeaderValue("Supply Edge"); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = 6799027210269525751L; + // custom renderer to highlight selection + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value!=null&&!isSelected) { + setBackground(new Color(0xcc,0xff,0xcc)); + } else if(!isSelected) { + setBackground(new Color(0xff,0xcc,0xcc)); + } + return this; + } + }); + setBackground(Color.WHITE); + getTableHeader().setReorderingAllowed(false); + getTableHeader().setBackground(Color.WHITE); + getTableHeader().setFont(getTableHeader().getFont().deriveFont(Font.BOLD)); + getTableHeader().setBorder(BorderFactory.createMatteBorder(0,0,1,0,Color.BLACK)); + getTableHeader().setOpaque(false); + } + + /** + * Gets the manifest. + * + * @return the manifest + */ + private Manifest getManifest() { + return manifestTab.getManifest(); + } + + /** + * Gets the container. + * + * @param row the row + * + * @return the container + */ + public I_ResourceContainer getContainer(int row) { + return ((PackedDemandsTableModel)getModel()).getContainer(row); + } + + /** + * Gets the selected container. + * + * @return the selected container + */ + public I_ResourceContainer getSelectedContainer() { + int row = getSelectedRow(); + if(row<0) return null; + else return getContainer(row); + } + + /** + * Gets the supply point. + * + * @param row the row + * + * @return the supply point + */ + public SupplyPoint getSupplyPoint(int row) { + return model.getSupplyPoint(row); + } + + /** + * Gets the selected supply point. + * + * @return the selected supply point + */ + public SupplyPoint getSelectedSupplyPoint() { + int row = getSelectedRow(); + if(row<0) return null; + else return getSupplyPoint(row); + } + + /** + * Gets the supply edge. + * + * @param row the row + * + * @return the supply edge + */ + public SupplyEdge getSupplyEdge(int row) { + return model.getSupplyEdge(row); + } + + /** + * Gets the selected supply edge. + * + * @return the selected supply edge + */ + public SupplyEdge getSelectedSupplyEdge() { + int row = getSelectedRow(); + if(row<0) return null; + else return getSupplyEdge(row); + } + + /** + * Initialize. + */ + public void initialize() { + model.fireTableDataChanged(); + } + + /** + * Update view. + */ + public void updateView() { + model.fireTableDataChanged(); + } + + /** + * The Class PackedDemandsTableModel. + */ + class PackedDemandsTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 3; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + int rows = getManifest().getEmptyContainers().size(); + for(SupplyPoint point : getManifest().getSupplyPoints()) { + rows+=getManifest().getCachedContainerDemands().get(point).size(); + } + return rows; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) return getSupplyPoint(row); + else if(col==1) return getContainer(row); + else return getSupplyEdge(row); + } + + /** + * Gets the container. + * + * @param row the row + * + * @return the container + */ + private I_ResourceContainer getContainer(int row) { + int lastRowSeen = -1; + for(I_ResourceContainer container : getManifest().getEmptyContainers()) { + lastRowSeen++; + if(lastRowSeen==row) return container; + } + for(SupplyPoint point : getManifest().getSupplyPoints()) { + for(I_ResourceContainer container : getManifest().getCachedContainerDemands().get(point)) { + lastRowSeen++; + if(lastRowSeen==row) return container; + } + } + return null; + } + + /** + * Gets the supply point. + * + * @param row the row + * + * @return the supply point + */ + private SupplyPoint getSupplyPoint(int row) { + int lastRowSeen = getManifest().getEmptyContainers().size()-1; + if(row<=lastRowSeen) return null; + for(SupplyPoint point : getManifest().getSupplyPoints()) { + lastRowSeen+=getManifest().getCachedContainerDemands().get(point).size(); + if(row<=lastRowSeen) return point; + } + return null; + } + + /** + * Gets the supply edge. + * + * @param row the row + * + * @return the supply edge + */ + private SupplyEdge getSupplyEdge(int row) { + SupplyPoint point = getSupplyPoint(row); + I_ResourceContainer container = getContainer(row); + + if(point==null) return null; + for(SupplyEdge edge : getManifest().getSupplyEdges()) { + if(edge.getDestination().equals(point.getNode()) + && edge.getEndTime()<=point.getTime()) { + for(I_Carrier carrier : edge.getCarriers()) { + if(getManifest().getManifestedContainers().get(edge).get(carrier).contains(container)) + return edge; + } + } + } + return null; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/manifest/RawDemandsTable.java b/src/main/java/edu/mit/spacenet/gui/manifest/RawDemandsTable.java new file mode 100644 index 0000000..8080ec2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/manifest/RawDemandsTable.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.manifest; + +import java.text.DecimalFormat; + +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.simulator.DemandSimulator; +import edu.mit.spacenet.simulator.SimDemand; + +/** + * A table to view the raw demands. + * + * @author Paul Grogan + */ +public class RawDemandsTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + + private DemandSimulator simulator; + + /** + * Instantiates a new raw demands table. + * + * @param simulator the simulator + */ + public RawDemandsTable(DemandSimulator simulator, boolean test) { + this.simulator = simulator; + setModel(new RawDemandsTableModel(simulator)); + getColumnModel().getColumn(0).setHeaderValue("Time"); + getColumnModel().getColumn(0).setMaxWidth(50); + DefaultTableCellRenderer tRenderer = new DefaultTableCellRenderer(); + tRenderer.setHorizontalAlignment(DefaultTableCellRenderer.CENTER); + getColumnModel().getColumn(0).setCellRenderer(tRenderer); + getColumnModel().getColumn(1).setHeaderValue("Element"); + getColumnModel().getColumn(1).setWidth(250); + getColumnModel().getColumn(2).setHeaderValue("Location"); + getColumnModel().getColumn(2).setWidth(150); + getColumnModel().getColumn(3).setHeaderValue("Demand"); + } + + /** + * Update view. + */ + public void updateView() { + for(SimDemand demand : simulator.getUnsatisfiedDemands()){ + demand.getDemands().clean(); + } + + ((RawDemandsTableModel)getModel()).fireTableDataChanged(); + } + + /** + * The Class RawDemandsTableModel. + */ + class RawDemandsTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + + private DemandSimulator simulator; + + /** + * Instantiates a new raw demands table model. + * + * @param simulator the simulator + */ + public RawDemandsTableModel(DemandSimulator simulator) { + super(); + this.simulator = simulator; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 4; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + int i = 0; + for(SimDemand demand : simulator.getUnsatisfiedDemands()) { + i+=demand.getDemands().size(); + } + return i; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) { + DecimalFormat format = new DecimalFormat("0.00"); + return format.format(getSimDemand(row).getTime()); + } else if(col==1) { + return getSimDemand(row).getElement(); + } else if(col==2) { + return getSimDemand(row).getLocation(); + } else { + return getDemand(row); + } + } + private SimDemand getSimDemand(int row) { + int lastRowSeen = -1; + for(SimDemand demand : simulator.getUnsatisfiedDemands()) { + if(lastRowSeen + demand.getDemands().size() >= row) { + return demand; + } + lastRowSeen+=demand.getDemands().size(); + } + return null; + } + private Demand getDemand(int row) { + int lastRowSeen = -1; + for(SimDemand demand : simulator.getUnsatisfiedDemands()) { + if(lastRowSeen + demand.getDemands().size() >= row) { + for(Demand d : demand.getDemands()) { + lastRowSeen++; + if(lastRowSeen==row) return d; + } + return null; + } + lastRowSeen+=demand.getDemands().size(); + } + return null; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/mission/AddEventButton.java b/src/main/java/edu/mit/spacenet/gui/mission/AddEventButton.java new file mode 100644 index 0000000..e56603b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/AddEventButton.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.ImageIcon; +import javax.swing.JMenuItem; + +import edu.mit.spacenet.gui.component.DropDownButton; +import edu.mit.spacenet.gui.event.EventDialog; +import edu.mit.spacenet.simulator.event.EventFactory; +import edu.mit.spacenet.simulator.event.EventType; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.I_Process; +import edu.mit.spacenet.simulator.event.I_Transport; + +/** + * A custom drop down button that contains the menu items for adding all of the + * different kinds of events to a mission. + */ +public class AddEventButton extends DropDownButton { + private static final long serialVersionUID = 8336153141415104568L; + private MissionPanel missionPanel; + + /** + * Instantiates a new adds the event button. + * + * @param missionPanel the mission panel + */ + public AddEventButton(MissionPanel missionPanel) { + super("Add Event", new ImageIcon(missionPanel.getClass().getClassLoader().getResource("icons/cog_add.png"))); + this.missionPanel = missionPanel; + getButton().setMargin(new Insets(3,3,3,3)); + setToolTipText("Add Event"); + addMenuItems(); + } + + /** + * Adds the event menu items. + */ + private void addMenuItems() { + JMenuItem addCreateEvent = new JMenuItem(EventType.CREATE.getName(), EventType.CREATE.getIcon()); + addCreateEvent.setToolTipText("Instantiate elements at a node or nested within a carrier element"); + addCreateEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.CREATE); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addCreateEvent); + JMenuItem addAddEvent = new JMenuItem(EventType.ADD.getName(), EventType.ADD.getIcon()); + addAddEvent.setToolTipText("Add resources to a container element"); + addAddEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.ADD); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addAddEvent); + JMenuItem addMoveEvent = new JMenuItem(EventType.MOVE.getName(), EventType.MOVE.getIcon()); + addMoveEvent.setToolTipText("Move elements to a node or to a carrier element"); + addMoveEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.MOVE); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addMoveEvent); + JMenuItem addTransferEvent = new JMenuItem(EventType.TRANSFER.getName(), EventType.TRANSFER.getIcon()); + addTransferEvent.setToolTipText("Transfer resources from one container to another"); + addTransferEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.TRANSFER); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addTransferEvent); + JMenuItem addRemoveEvent = new JMenuItem(EventType.REMOVE.getName(), EventType.REMOVE.getIcon()); + addRemoveEvent.setToolTipText("Remove elements from the simulation."); + addRemoveEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.REMOVE); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addRemoveEvent); + JMenuItem addReconfigureEvent = new JMenuItem(EventType.RECONFIGURE.getName(), EventType.RECONFIGURE.getIcon()); + addReconfigureEvent.setToolTipText("Reconfigure an element to a new state"); + addReconfigureEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.RECONFIGURE); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addReconfigureEvent); + JMenuItem addReconfigureGroupEvent = new JMenuItem(EventType.RECONFIGURE_GROUP.getName(), EventType.RECONFIGURE_GROUP.getIcon()); + addReconfigureGroupEvent.setToolTipText("Reconfigure a set of elements to a new state type"); + addReconfigureGroupEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.RECONFIGURE_GROUP); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addReconfigureGroupEvent); + JMenuItem addDemandEvent = new JMenuItem(EventType.DEMAND.getName(), EventType.DEMAND.getIcon()); + addDemandEvent.setToolTipText("Demand for resources by an element"); + addDemandEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.DEMAND); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addDemandEvent); + JMenuItem addBurnEvent = new JMenuItem(EventType.BURN.getName(), EventType.BURN.getIcon()); + addBurnEvent.setToolTipText("Impulsive OMS or RCS burn"); + addBurnEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.BURN); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addBurnEvent); + JMenuItem addEvaEvent = new JMenuItem(EventType.EVA.getName(), EventType.EVA.getIcon()); + addEvaEvent.setToolTipText("Extra-vehicular activity"); + addEvaEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.EVA); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addEvaEvent); + JMenuItem addSpaceTransport = new JMenuItem(EventType.SPACE_TRANSPORT.getName(), EventType.SPACE_TRANSPORT.getIcon()); + addSpaceTransport.setToolTipText("Transports a stack from node to node along a trajectory of impulsive burns"); + addSpaceTransport.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.SPACE_TRANSPORT); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addSpaceTransport); + JMenuItem addSurfaceTransport = new JMenuItem(EventType.SURFACE_TRANSPORT.getName(), EventType.SURFACE_TRANSPORT.getIcon()); + addSurfaceTransport.setToolTipText("Transports a surface vehicle from surface node to surface node"); + addSurfaceTransport.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.SURFACE_TRANSPORT); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addSurfaceTransport); + JMenuItem addFlightProcess = new JMenuItem(EventType.FLIGHT_TRANSPORT.getName(), EventType.FLIGHT_TRANSPORT.getIcon()); + addFlightProcess.setToolTipText("Transports a stack from node to node under pre-specified flight constraints"); + addFlightProcess.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.FLIGHT_TRANSPORT); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addFlightProcess); + JMenuItem addExplorationProcess = new JMenuItem(EventType.EXPLORATION.getName(), EventType.EXPLORATION.getIcon()); + addExplorationProcess.setToolTipText("Schedules EVAs at a specified frequency"); + addExplorationProcess.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + I_Event event = EventFactory.createEvent(EventType.EXPLORATION); + prefill(event); + EventDialog.createAndShowGUI(missionPanel, event); + } + }); + getMenu().add(addExplorationProcess); + } + + /** + * Prefills the events based on the currently-selected event. If another + * event is selected, the new event is assigned the same time, one higher + * priority, and same location. If another process is selected, the new + * event is assigned the time after duration, priority 1, and same location. + * If a transport is selected, the new event is assigned the time after + * duration, priority 1, and destination location. The new event is also + * prefixed with up to 5 characters of the name of the mission. + * + * @param event the event + */ + private void prefill(I_Event event) { + if(missionPanel.getEventsTable().getRowCount() > 0) { + I_Event prevEvent; + if(missionPanel.getEventsTable().getSelectedRowCount()>0 + && missionPanel.getEventsTable().getSelectedRow(). + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.ImageIcon; +import javax.swing.JMenuItem; + +import edu.mit.spacenet.domain.model.CrewConsumablesDemandModel; +import edu.mit.spacenet.domain.model.DemandModelFactory; +import edu.mit.spacenet.domain.model.DemandModelType; +import edu.mit.spacenet.gui.component.DropDownButton; +import edu.mit.spacenet.gui.model.DemandModelDialog; + +/** + * A custom drop down button containing the options to add the different kinds + * of mission-level demand models to a mission. + */ +public class AddMissionDemandModelButton extends DropDownButton { + private static final long serialVersionUID = -3212156860465231812L; + + private MissionPanel missionPanel; + + /** + * Instantiates a new adds the mission demand model button. + * + * @param missionPanel the mission panel + */ + public AddMissionDemandModelButton(MissionPanel missionPanel) { + super("Add Model", new ImageIcon(missionPanel.getClass().getClassLoader().getResource("icons/comment_add.png"))); + this.missionPanel = missionPanel; + getButton().setMargin(new Insets(3,3,3,3)); + setToolTipText("Add Demand Model"); + addMenuItems(); + } + + /** + * Adds the menu items. + */ + private void addMenuItems() { + JMenuItem addImpulseDemandModel = new JMenuItem(DemandModelType.TIMED_IMPULSE.getName(), DemandModelType.TIMED_IMPULSE.getIcon()); + addImpulseDemandModel.setToolTipText("Add a one-time demand for resources"); + addImpulseDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DemandModelDialog.createAndShowGUI(missionPanel, DemandModelFactory.createDemandModel(missionPanel.getMissionSplitPane().getMission(), DemandModelType.TIMED_IMPULSE)); + } + }); + getMenu().add(addImpulseDemandModel); + JMenuItem addRatedDemandModel = new JMenuItem(DemandModelType.RATED.getName(), DemandModelType.RATED.getIcon()); + addRatedDemandModel.setToolTipText("Add a recurring demand for resources based on a demand rate"); + addRatedDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DemandModelDialog.createAndShowGUI(missionPanel, DemandModelFactory.createDemandModel(missionPanel.getMissionSplitPane().getMission(), DemandModelType.RATED)); + } + }); + getMenu().add(addRatedDemandModel); + JMenuItem addCrewConsumablesDemandModel = new JMenuItem(DemandModelType.CREW_CONSUMABLES.getName(), DemandModelType.CREW_CONSUMABLES.getIcon()); + addCrewConsumablesDemandModel.setToolTipText("Use the crew consumables model"); + addCrewConsumablesDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + CrewConsumablesDemandModel model = new CrewConsumablesDemandModel(missionPanel.getMissionSplitPane().getMission()); + DemandModelDialog.createAndShowGUI(missionPanel, model); + } + }); + getMenu().add(addCrewConsumablesDemandModel); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/mission/ElementBatChart.java b/src/main/java/edu/mit/spacenet/gui/mission/ElementBatChart.java new file mode 100644 index 0000000..d68011e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/ElementBatChart.java @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.Ellipse2D; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Date; +import java.util.List; +import java.util.Vector; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.SymbolAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import com.toedter.calendar.JDateChooser; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.MiniSimulator; +import edu.mit.spacenet.simulator.SimState; +import edu.mit.spacenet.util.DateFunctions; + +/** + * A bat-style chart to display the element location history with associated + * control panel. + * + * @author Paul Grogan + */ +public class ElementBatChart extends JSplitPane { + private static final long serialVersionUID = -6405124067606236705L; + private MissionsSplitPane missionsSplitPane; + private JDateChooser startDate, endDate; + private CheckBoxTableModel elementsModel; + private ChartPanel batChartPanel; + private JButton refreshButton; + + /** + * Instantiates a new element bat chart. + * + * @param tab the missions tab + */ + public ElementBatChart(MissionsSplitPane missionsSplitPane) { + this.missionsSplitPane = missionsSplitPane; + + batChartPanel = new SNChartPanel(); + batChartPanel.setPreferredSize(new Dimension(600,400)); + setLeftComponent(batChartPanel); + + JPanel controlPanel = new JPanel(); + controlPanel.setLayout(new GridBagLayout()); + controlPanel.setBorder(BorderFactory.createTitledBorder("Chart Options")); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.BOTH; + controlPanel.add(new JLabel("Start Date: "), c); + c.gridy++; + controlPanel.add(new JLabel("End Date: "), c); + c.gridy--; + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + startDate = new JDateChooser(); + startDate.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + if(e.getPropertyName().equals("date") && isAutoRefresh()) updateChart(); + } + }); + controlPanel.add(startDate, c); + c.gridy++; + endDate = new JDateChooser(); + endDate.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + if(e.getPropertyName().equals("date") && isAutoRefresh()) updateChart(); + } + }); + controlPanel.add(endDate, c); + c.gridx--; + c.gridy++; + c.gridwidth = 2; + c.weightx = 0; + c.weighty = 1; + elementsModel = new CheckBoxTableModel(); + elementsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE && isAutoRefresh()) updateChart(); + } + }); + JTable elementsTable = new JTable(elementsModel); + elementsTable.getColumnModel().getColumn(0).setHeaderRenderer(new DefaultTableCellRenderer() { + // custom renderer to display the eye header icon + private static final long serialVersionUID = 1L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/eye.png"))); + setHorizontalAlignment(JLabel.CENTER); + return this; + } + }); + elementsTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + // custom renderer to display the element icons + private static final long serialVersionUID = 1L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof I_Element) setIcon(((I_Element)value).getIcon()); + return this; + } + }); + elementsTable.getTableHeader().setReorderingAllowed(false); + elementsTable.getColumnModel().getColumn(0).setMaxWidth(25); + elementsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Elements"); + elementsTable.setShowGrid(false); + JScrollPane elementsScroll = new JScrollPane(elementsTable); + elementsScroll.setPreferredSize(new Dimension(150,200)); + controlPanel.add(elementsScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(); + buttonPanel.setOpaque(false); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllElementsButton = new JButton("Select All"); + selectAllElementsButton.setToolTipText("Select All Elements"); + selectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + elementsModel.selectAll(); + } + }); + buttonPanel.add(selectAllElementsButton); + JButton deselectAllElementsButton = new JButton("Deselect All"); + deselectAllElementsButton.setToolTipText("Deselect All Elements"); + deselectAllElementsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + elementsModel.deselectAll(); + } + }); + buttonPanel.add(deselectAllElementsButton); + controlPanel.add(buttonPanel, c); + c.gridy++; + JPanel prop = new JPanel(); + prop.setOpaque(false); + prop.setPreferredSize(new Dimension(1,15)); + controlPanel.add(prop, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + refreshButton = new JButton("Refresh", new ImageIcon(getClass().getClassLoader().getResource("icons/arrow_refresh.png"))); + refreshButton.setVisible(false); + refreshButton.setMargin(new Insets(3,3,3,3)); + refreshButton.setToolTipText("Refresh Chart"); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + refreshChart(); + } + }); + controlPanel.add(refreshButton, c); + + setRightComponent(controlPanel); + + setName("Element Bat Chart"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(490); + } + + /** + * Initializes the chart for a new scenario. + */ + public void initialize() { + startDate.setEnabled(getScenario()!=null); + endDate.setEnabled(getScenario()!=null); + + if(getScenario()!=null) { + startDate.setSelectableDateRange(getScenario().getStartDate(), null); + endDate.setSelectableDateRange(getScenario().getStartDate(), null); + refreshChart(); + } + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + private Scenario getScenario() { + return missionsSplitPane.getMissionsTab().getScenarioPanel().getScenario(); + } + + /** + * Gets the simulator. + * + * @return the simulator + */ + private MiniSimulator getSimulator() { + return missionsSplitPane.getMissionsTab().getSimulator(); + } + + /** + * Checks if auto refresh is enabled. + * + * @return true, if auto refresh is enabled + */ + private boolean isAutoRefresh() { + return SpaceNetSettings.getInstance().isAutoRefresh(); + } + + /** + * Updates the view. + */ + public void updateView() { + if(isAutoRefresh()) { + refreshButton.setVisible(false); + refreshChart(); + } else { + refreshButton.setVisible(true); + } + } + private boolean isUpdating = false; + + /** + * Refreshes the chart. Uses a swing worker to run the process in a separate + * thread so the GUI does not freeze. + */ + private void refreshChart() { + if(isUpdating) return; + isUpdating = true; + SwingWorker worker = new SwingWorker() { + public Void doInBackground() throws Exception { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Refreshing Chart..."); + List selectedElements = elementsModel.getSelectedObjects(); + elementsModel.clear(); + for(I_Element element : getScenario().getElements()) { + elementsModel.addObject(element, selectedElements.contains(element)); + } + try { + updateChart(); + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + public void done() { + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + isUpdating = false; + } + }; + worker.execute(); + } + + /** + * Updates the chart (time-intensive for large campaigns or for many + * elements. + */ + private void updateChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, + "Date", + "Node", + dataset, + true, + true, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + SymbolAxis rangeAxis = createRangeAxis(); + plot.setRangeAxis(rangeAxis); + plot.setBackgroundPaint(Color.lightGray); + plot.setDomainGridlinePaint(Color.white); + plot.setRangeGridlinePaint(Color.white); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + + plot.setRangeGridlinesVisible(false); + plot.setDomainGridlinesVisible(false); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + double delta = -0.5; + for(I_Element element : elementsModel.getSelectedObjects()) { + delta += 1d/(elementsModel.getSelectedObjects().size()+1); + TimeSeries s = new TimeSeries(element.getName(), Hour.class); + for(SimState state : getSimulator().getLocationHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), state.getTime()); + if(state.getLocation(element) != null + && state.getLocation(element) instanceof Node + && (startDate.getDate()==null || date.after(startDate.getDate())) + && (endDate.getDate()==null || date.before(endDate.getDate()))) { + s.addOrUpdate(new Hour(date), delta + node2Number((Node)state.getLocation(element), rangeAxis)); + } + } + /* TODO: this section may attempt at removing "unnecessary" points, + * i.e. the points where the element is at the same nodeboth before + * and after. + for(int i=1; i < s.getItemCount()-1; i++) { + if(s.getDataItem(i).getValue().equals(s.getDataItem(i+1).getValue()) + && s.getDataItem(i).getValue().equals(s.getDataItem(i-1).getValue())) { + s.delete(s.getTimePeriod(i)); + i=1; + } + } + */ + if(s.getItemCount()>0) { + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(0,0,0,0)); + } + } + + batChartPanel.setChart(chart); + } + + /** + * Creates the range axis (list of nodes on the vertical axis). + * + * @return the symbol axis + */ + private SymbolAxis createRangeAxis() { + Vector nodeLabels = new Vector(); + for (Node n : getScenario().getNetwork().getNodes()) { + nodeLabels.add(n.getName()); + } + String[] array = {}; + return new SymbolAxis(null, nodeLabels.toArray(array)); + } + + /** + * Converts a node to its numeric value used in plotting. + * + * @param node the node + * @param axis the axis + * + * @return the number + */ + private int node2Number(Node node, SymbolAxis axis) { + for (int i = 0; i < axis.getSymbols().length; i++) { + if (axis.getSymbols()[i].equals(node.getName())) { + return i; + } + } + return -1; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/mission/EventsTable.java b/src/main/java/edu/mit/spacenet/gui/mission/EventsTable.java new file mode 100644 index 0000000..871e7be --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/EventsTable.java @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.Component; +import java.awt.event.MouseEvent; +import java.text.DecimalFormat; +import java.util.Collections; +import java.util.List; + +import javax.swing.DefaultCellEditor; +import javax.swing.ImageIcon; +import javax.swing.JComboBox; +import javax.swing.JTable; +import javax.swing.UIManager; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableCellEditor; + +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.simulator.MiniSimulator; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.event.I_Event; + +/** + * A table used to display and edit the events for a mission. + * + * @author Paul Grogan + */ +public class EventsTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + + private CustomTableModel model; + private MissionPanel eventsPanel; + private String[] columnToolTips = {"", + "Days after mission start", + "Relative priority of concurrent events", + null}; + + /** + * Instantiates a new event table. + * + * @param tab the missions tab + */ + public EventsTable(MissionPanel eventsPanel) { + super(); + this.eventsPanel = eventsPanel; + + model = new CustomTableModel(); + setModel(model); + + getColumnModel().getColumn(0).setHeaderValue(""); + getColumnModel().getColumn(0).setMaxWidth(20); + getColumnModel().getColumn(1).setHeaderRenderer(new DefaultTableCellRenderer() { + // custom renderer to show a clock header icon + private static final long serialVersionUID = 1L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/time.png"))); + setBorder(UIManager.getBorder("TableHeader.cellBorder")); + setBackground(UIManager.getColor("TableHeader.cellBackground")); + setHorizontalAlignment(CENTER); + return this; + } + }); + getColumnModel().getColumn(1).setMaxWidth(40); + DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); + renderer.setHorizontalAlignment(DefaultTableCellRenderer.CENTER); + getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + // custom renderer to show "0.00" format for time + private static final long serialVersionUID = 7793722593255866883L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof Double) { + DecimalFormat format = new DecimalFormat("0.00"); + setText(format.format(value)); + setHorizontalAlignment(CENTER); + } + return this; + } + }); + getColumnModel().getColumn(2).setHeaderRenderer(new DefaultTableCellRenderer() { + // custom renderer to show priority header icon + private static final long serialVersionUID = 1L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/priority.png"))); + setBorder(UIManager.getBorder("TableHeader.cellBorder")); + setBackground(UIManager.getColor("TableHeader.cellBackground")); + setHorizontalAlignment(CENTER); + return this; + } + }); + getColumnModel().getColumn(2).setMaxWidth(20); + getColumnModel().getColumn(2).setCellRenderer(renderer); + getColumnModel().getColumn(3).setHeaderValue("Event Name"); + getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer() { + // custom renderer to show error icons and messages (if necessary) + private static final long serialVersionUID = 7793722593255866883L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setIcon(null); + setIconTextGap(0); + setToolTipText(null); + for(SimSpatialError error : getSimulator().getSpatialErrors()) { + if(error.getEvent().getRoot().equals(getEvent(row))) { + setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/bullet_error.png"))); + setToolTipText("Error: " + error.getMessage()); + return this; + } + } + return this; + } + }); + + getTableHeader().setReorderingAllowed(false); + } + + /** + * Initializes the table for a new mission. + */ + public void initialize() { + model.setMission(eventsPanel.getMissionSplitPane().getMission()); + } + + /** + * Gets the simulator. + * + * @return the simulator + */ + private MiniSimulator getSimulator() { + return eventsPanel.getMissionSplitPane().getMissionsTab().getSimulator(); + } + + /* (non-Javadoc) + * @see javax.swing.JTable#createDefaultTableHeader() + */ + protected JTableHeader createDefaultTableHeader() { + return new JTableHeader(columnModel) { + private static final long serialVersionUID = 5017703878414116560L; + + public String getToolTipText(MouseEvent e) { + java.awt.Point p = e.getPoint(); + int index = columnModel.getColumnIndexAtX(p.x); + int realIndex = + columnModel.getColumn(index).getModelIndex(); + return columnToolTips[realIndex]; + } + }; + } + + /* (non-Javadoc) + * @see javax.swing.JTable#getCellEditor(int, int) + */ + public TableCellEditor getCellEditor(int row, int col) { + if(col==2) { + JComboBox comboBox = new JComboBox(); + for(int i = 1; i <= 5; i++) { + comboBox.addItem(new Integer(i).toString()); + } + comboBox.setSelectedIndex((Integer)getValueAt(row,col)-1); + return new DefaultCellEditor(comboBox); + } else { + return super.getCellEditor(row, col); + } + } + + /** + * A custom table model to handle event data for missions. + */ + class CustomTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + private List data; + + /** + * Sets the mission. + * + * @param mission the new mission + */ + public void setMission(Mission mission) { + if(mission==null) data = null; + else data = mission.getEventList(); + fireTableDataChanged(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 4; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + return data==null?0:data.size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int col) { + if(col==0) return false; + else return true; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnClass(int) + */ + public Class getColumnClass(int col) { + if(col==0) { + return ImageIcon.class; + } else if(col==1) { + return Double.class; + } else if(col==2) { + return Integer.class; + } else { + return String.class; + } + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) { + return data.get(row).getEventType().getIcon(); + } else if(col==1) { + return data.get(row).getTime(); + } else if(col==2) { + return data.get(row).getPriority(); + } else { + return data.get(row).getName(); + } + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int) + */ + public void setValueAt(Object value, int row, int col) { + if(col==1) { + data.get(row).setTime((Double)value); + } else if(col==2) { + data.get(row).setPriority(Integer.parseInt((String)value)); + } else if(col==3) { + data.get(row).setName((String)value); + } + Collections.sort(data); + fireTableDataChanged(); + eventsPanel.getMissionSplitPane().getMissionsTab().updateView(); + } + + /** + * Gets the event. + * + * @param row the row + * + * @return the event + */ + public I_Event getEvent(int row) { + return data.get(row); + } + + /** + * Removes the event. + * + * @param event the event + */ + public void removeEvent(I_Event event) { + data.remove(event); + fireTableDataChanged(); + } + + /** + * Adds the event. + * + * @param event the event + */ + public void add(I_Event event) { + data.add(event); + fireTableDataChanged(); + } + } + + /** + * Updates the view. + */ + public void updateView() { + int selectedRow = getSelectedRow(); + model.fireTableDataChanged(); + if(getSelectedRow(). + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.Color; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.util.Vector; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.SymbolAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.event.BurnEvent; +import edu.mit.spacenet.simulator.event.CreateEvent; +import edu.mit.spacenet.simulator.event.DemandEvent; +import edu.mit.spacenet.simulator.event.EvaEvent; +import edu.mit.spacenet.simulator.event.ExplorationProcess; +import edu.mit.spacenet.simulator.event.FlightTransport; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.MoveEvent; +import edu.mit.spacenet.simulator.event.ReconfigureEvent; +import edu.mit.spacenet.simulator.event.ReconfigureGroupEvent; +import edu.mit.spacenet.simulator.event.RemoveEvent; +import edu.mit.spacenet.simulator.event.SpaceTransport; +import edu.mit.spacenet.simulator.event.SurfaceTransport; +import edu.mit.spacenet.simulator.event.TransferEvent; +import edu.mit.spacenet.util.DateFunctions; + +/** + * A bat-style chart that displays mission events. + * + * @author Paul Grogan + */ +public class MissionBatChart extends SNChartPanel { + private static final long serialVersionUID = -6405124067606236705L; + + private MissionSplitPane missionSplitPane; + + /** + * Instantiates a new process bat chart within a mission split pane. + * + * @param missionSplitPane the mission split pane + */ + public MissionBatChart(MissionSplitPane missionSplitPane) { + this.missionSplitPane = missionSplitPane; + } + + /** + * Initializes the component for a new mission. + */ + public void initialize() { + updateView(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + private Scenario getScenario() { + return missionSplitPane.getMissionsTab().getScenarioPanel().getScenario(); + } + + /** + * Gets the mission. + * + * @return the mission + */ + private Mission getMission() { + return missionSplitPane.getMission(); + } + + /** + * Updates the view. + */ + public void updateView() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, + "Date", + "Node", + dataset, + false, + true, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + SymbolAxis rangeAxis = createRangeAxis(); + plot.setRangeAxis(rangeAxis); + plot.setBackgroundPaint(Color.lightGray); + plot.setDomainGridlinePaint(Color.white); + plot.setRangeGridlinePaint(Color.white); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + + plot.setRangeGridlinesVisible(false); + plot.setDomainGridlinesVisible(false); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + for(I_Event event : getMission().getEventList()) { + if(event.getLocation() instanceof Node) { + if(event instanceof SpaceTransport + && ((SpaceTransport)event).getEdge() != null) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number(((SpaceTransport) event).getEdge().getOrigin(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime() + ((SpaceTransport)event).getEdge().getDuration())), + node2Number(((SpaceTransport) event).getEdge().getDestination(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.RED); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0)); + } else if(event instanceof SurfaceTransport + && ((SurfaceTransport)event).getEdge() != null) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + if(((SurfaceTransport)event).isReversed()) { + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number(((SurfaceTransport) event).getEdge().getDestination(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime() + ((SurfaceTransport)event).getDuration())), + node2Number(((SurfaceTransport) event).getEdge().getOrigin(), rangeAxis)); + } else { + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number(((SurfaceTransport) event).getEdge().getOrigin(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime() + ((SurfaceTransport)event).getDuration())), + node2Number(((SurfaceTransport) event).getEdge().getDestination(), rangeAxis)); + } + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.GREEN); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0)); + } else if(event instanceof FlightTransport + && ((FlightTransport)event).getEdge() != null) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number(((FlightTransport) event).getEdge().getOrigin(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime() + ((FlightTransport)event).getEdge().getDuration())), + node2Number(((FlightTransport) event).getEdge().getDestination(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.YELLOW); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0)); + } else if(event instanceof ExplorationProcess + && event.getLocation() != null) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime() + ((ExplorationProcess)event).getDuration())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.CYAN); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0)); + } else if(event.getLocation() != null){ + if(event instanceof CreateEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.GREEN); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof MoveEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.ORANGE); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof TransferEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.ORANGE); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof RemoveEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.BLACK); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof DemandEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.BLUE); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof ReconfigureEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.PINK); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof ReconfigureGroupEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.PINK); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof BurnEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.RED); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof EvaEvent) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), getMission().getStartDate()) + event.getTime() + ((EvaEvent)event).getEvaDuration()/24)), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.CYAN); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } + } + } + } + setChart(chart); + } + + /** + * Creates the range axis (list of nodes on the vertical axis). + * + * @return the symbol axis + */ + private SymbolAxis createRangeAxis() { + Vector nodeLabels = new Vector(); + for (Node n : getScenario().getNetwork().getNodes()) { + nodeLabels.add(n.getName()); + } + String[] array = {}; + return new SymbolAxis(null, nodeLabels.toArray(array)); + } + + /** + * Converts a node to its numeric representation for the symbol axis. + * + * @param node the node + * @param axis the axis + * + * @return the number + */ + private int node2Number(Node node, SymbolAxis axis) { + for (int i = 0; i < axis.getSymbols().length; i++) { + if (axis.getSymbols()[i].equals(node.getName())) { + return i; + } + } + return -1; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/mission/MissionPanel.java b/src/main/java/edu/mit/spacenet/gui/mission/MissionPanel.java new file mode 100644 index 0000000..ec7a428 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/MissionPanel.java @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Collections; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import com.toedter.calendar.JDateChooser; + +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.gui.event.EventDialog; +import edu.mit.spacenet.gui.model.DemandModelDialog; +import edu.mit.spacenet.simulator.event.I_Event; + +/** + * A panel used to display and edit mission-specific information. + */ +public class MissionPanel extends JPanel { + private static final long serialVersionUID = -1544896538049800449L; + + private MissionSplitPane missionSplitPane; + + private JComboBox ddlOrigin, ddlDestination, ddlReturnOrigin, ddlReturnDestination; + private JTextField txtName; + private JDateChooser calStartDate; + private DefaultListModel demandModelsModel; + private JList demandModelsList; + private EventsTable eventsTable; + private JButton btnEditDemandModel, btnRemoveDemandModel, btnEditEvent, btnRemoveEvent; + + /** + * Instantiates a new mission panel. + * + * @param missionSplitPane the mission split pane + */ + public MissionPanel(MissionSplitPane missionSplitPane) { + this.missionSplitPane = missionSplitPane; + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + c.weighty = 0; + c.weightx = 0; + c.gridy = 0; + c.gridx = 0; + add(new JLabel("Name: "), c); + c.gridy++; + add(new JLabel("Start Date: "), c); + c.gridy++; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + JPanel departurePanel = new JPanel(); + departurePanel.setBorder(BorderFactory.createTitledBorder("Departure Trip")); + departurePanel.setLayout(new GridBagLayout()); + GridBagConstraints g = new GridBagConstraints(); + g.gridx = 0; + g.gridy = 0; + g.insets = new Insets(2,2,2,2); + g.anchor = GridBagConstraints.LINE_END; + departurePanel.add(new JLabel("From: "), g); + g.gridy++; + departurePanel.add(new JLabel("To: "), g); + g.gridy--; + g.gridx++; + g.anchor = GridBagConstraints.LINE_START; + g.fill = GridBagConstraints.BOTH; + g.weightx = 1; + ddlOrigin = new ContainerComboBox(); + ddlOrigin.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + missionSplitPane.getMission().setOrigin((Node)ddlOrigin.getSelectedItem()); + } + } + }); + departurePanel.add(ddlOrigin, g); + g.gridy++; + ddlDestination = new ContainerComboBox(); + ddlDestination.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + missionSplitPane.getMission().setDestination((Node)ddlDestination.getSelectedItem()); + } + } + }); + departurePanel.add(ddlDestination, g); + JPanel returnPanel = new JPanel(); + returnPanel.setBorder(BorderFactory.createTitledBorder("Return Trip")); + returnPanel.setLayout(new GridBagLayout()); + g = new GridBagConstraints(); + g.gridx = 0; + g.gridy = 0; + g.insets = new Insets(2,2,2,2); + g.anchor = GridBagConstraints.LINE_END; + returnPanel.add(new JLabel("From: "), g); + g.gridy++; + returnPanel.add(new JLabel("To: "), g); + g.gridy--; + g.gridx++; + g.anchor = GridBagConstraints.LINE_START; + g.fill = GridBagConstraints.BOTH; + g.weightx = 1; + ddlReturnOrigin = new ContainerComboBox(); + ddlReturnOrigin.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + missionSplitPane.getMission().setReturnOrigin((Node)ddlReturnOrigin.getSelectedItem()); + } + }); + returnPanel.add(ddlReturnOrigin, g); + g.gridy++; + ddlReturnDestination = new ContainerComboBox(); + ddlReturnDestination.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + missionSplitPane.getMission().setReturnDestination((Node)ddlReturnDestination.getSelectedItem()); + } + }); + returnPanel.add(ddlReturnDestination, g); + + JPanel nodePanel = new JPanel(); + nodePanel.setBorder(BorderFactory.createEmptyBorder()); + nodePanel.setLayout(new BoxLayout(nodePanel, BoxLayout.LINE_AXIS)); + nodePanel.add(departurePanel); + nodePanel.add(returnPanel); + add(nodePanel, c); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.FIRST_LINE_START; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Demand Models: "), c); + c.gridy+=3; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_START; + add(new JLabel("Events: "), c); + + c.gridx = 1; + c.gridy = 0; + c.fill = GridBagConstraints.BOTH; + txtName = new JTextField(20); + txtName.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent e) { + missionSplitPane.getMission().setName(txtName.getText()); + eventsTable.updateView(); + } + }); + add(txtName, c); + c.gridy++; + calStartDate = new JDateChooser(); + calStartDate.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + if(e.getPropertyName().equals("date")) { + missionSplitPane.getMission().setStartDate(calStartDate.getDate()); + updateView(); + } + } + }); + add(calStartDate, c); + c.gridy+=3; + c.gridwidth = 2; + c.gridx = 0; + c.weighty = 0.1; + c.weightx = 1; + demandModelsModel = new DefaultListModel(); + demandModelsList = new JList(demandModelsModel); + demandModelsList.setCellRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1271331296677711150L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + label.setIcon(((I_DemandModel)value).getDemandModelType().getIcon()); + return label; + } + }); + demandModelsList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2 && demandModelsList.getSelectedIndex()>=0) { + DemandModelDialog.createAndShowGUI(getThis(), (I_DemandModel)demandModelsList.getSelectedValue()); + } + } + }); + demandModelsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + demandModelsList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + updateButtons(); + } + }); + JScrollPane demandModelsScroll = new JScrollPane(demandModelsList); + demandModelsScroll.setPreferredSize(new Dimension(125,20)); + add(demandModelsScroll, c); + c.gridy++; + c.gridx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel demandsButtonPanel = new JPanel(); + demandsButtonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 3, 0)); + demandsButtonPanel.add(new AddMissionDemandModelButton(this)); + + btnEditDemandModel = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/comment_edit.png"))); + btnEditDemandModel.setMargin(new Insets(3,3,3,3)); + btnEditDemandModel.setToolTipText("Edit Demand Model"); + btnEditDemandModel.setEnabled(false); + btnEditDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + DemandModelDialog.createAndShowGUI(getThis(), (I_DemandModel)demandModelsList.getSelectedValue()); + } + }); + demandsButtonPanel.add(btnEditDemandModel); + + btnRemoveDemandModel = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/comment_delete.png"))); + btnRemoveDemandModel.setMargin(new Insets(3,3,3,3)); + btnRemoveDemandModel.setToolTipText("Remove Demand Model"); + btnRemoveDemandModel.setEnabled(false); + btnRemoveDemandModel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + missionSplitPane.getMission().getDemandModels().remove(demandModelsList.getSelectedValue()); + updateView(); + } + }); + demandsButtonPanel.add(btnRemoveDemandModel); + add(demandsButtonPanel, c); + + c.gridy+=2; + c.weighty = 0.9; + c.fill = GridBagConstraints.BOTH; + eventsTable = new EventsTable(this); + eventsTable.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount()==2 && eventsTable.getSelectedRow()>=0) { + if(eventsTable.isEditing()) eventsTable.getCellEditor().stopCellEditing(); + EventDialog.createAndShowGUI(getThis(), eventsTable.getEvent(eventsTable.getSelectedRow())); + } + } + }); + eventsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + updateButtons(); + } + }); + JScrollPane eventScroll = new JScrollPane(eventsTable); + eventScroll.setBackground(Color.WHITE); + eventScroll.getViewport().setBackground(Color.WHITE); + eventScroll.setPreferredSize(new Dimension(150,150)); + add(eventScroll, c); + + JPanel eventButtonPanel = new JPanel(); + eventButtonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 3, 0)); + eventButtonPanel.add(new AddEventButton(this)); + + btnEditEvent = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/cog_edit.png"))); + btnEditEvent.setMargin(new Insets(3,3,3,3)); + btnEditEvent.setToolTipText("Edit Event"); + btnEditEvent.setEnabled(false); + btnEditEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(eventsTable.isEditing()) eventsTable.getCellEditor().stopCellEditing(); + EventDialog.createAndShowGUI(getThis(), eventsTable.getEvent(eventsTable.getSelectedRow())); + } + }); + eventButtonPanel.add(btnEditEvent); + + btnRemoveEvent = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/cog_delete.png"))); + btnRemoveEvent.setMargin(new Insets(3,3,3,3)); + btnRemoveEvent.setToolTipText("Remove Event"); + btnRemoveEvent.setEnabled(false); + btnRemoveEvent.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(eventsTable.isEditing()) eventsTable.getCellEditor().stopCellEditing(); + ArrayList events = new ArrayList(); + for(int row : eventsTable.getSelectedRows()) { + events.add(eventsTable.getEvent(row)); + } + JPanel warningPanel = new JPanel(); + warningPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + warningPanel.add(new JLabel("Permanently delete the following events?"), c); + c.gridy++; + c.weighty = 1; + DefaultListModel eventsList = new DefaultListModel(); + for(I_Event v : events) { + eventsList.addElement(v); + } + warningPanel.add(new JScrollPane(new JList(eventsList)), c); + int answer = JOptionPane.showOptionDialog(missionSplitPane, + warningPanel, + "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); + if (answer == JOptionPane.YES_OPTION) { + for(I_Event event : events) { + missionSplitPane.getMission().getEventList().remove(event); + } + + } + missionSplitPane.getMissionsTab().updateView(); + } + }); + eventButtonPanel.add(btnRemoveEvent); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + add(eventButtonPanel, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + JButton btnOk = new JButton("Save", new ImageIcon(getClass().getClassLoader().getResource("icons/application_go.png"))); + btnOk.setMargin(new Insets(3,3,3,3)); + btnOk.setToolTipText("Save Mission"); + btnOk.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + missionSplitPane.getMissionsTab().editMissions(); + } + }); + add(btnOk, c); + } + + /** + * Gets this. + * + * @return this + */ + private MissionPanel getThis() { return this; } + + /** + * Initializes the panel for a new mission. + */ + public void initialize() { + txtName.setEnabled(missionSplitPane.getMission()!=null); + calStartDate.setEnabled(missionSplitPane.getMission()!=null); + ddlOrigin.setEnabled(missionSplitPane.getMission()!=null); + ddlDestination.setEnabled(missionSplitPane.getMission()!=null); + ddlReturnOrigin.setEnabled(missionSplitPane.getMission()!=null); + ddlReturnDestination.setEnabled(missionSplitPane.getMission()!=null); + demandModelsList.setEnabled(missionSplitPane.getMission()!=null); + eventsTable.setEnabled(missionSplitPane.getMission()!=null); + if(missionSplitPane.getMission()!=null) { + txtName.setText(missionSplitPane.getMission().getName()); + calStartDate.setDate(missionSplitPane.getMission().getStartDate()); + Node origin = missionSplitPane.getMission().getOrigin(); + Node destination = missionSplitPane.getMission().getDestination(); + Node returnOrigin = missionSplitPane.getMission().getReturnOrigin(); + Node returnDestination = missionSplitPane.getMission().getReturnDestination(); + ddlOrigin.removeAllItems(); + ddlDestination.removeAllItems(); + ddlReturnOrigin.removeAllItems(); + ddlReturnDestination.removeAllItems(); + ddlReturnOrigin.addItem(null); + ddlReturnDestination.addItem(null); + for(Node n : SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getNetwork().getNodes()) { + ddlOrigin.addItem(n); + ddlDestination.addItem(n); + ddlReturnOrigin.addItem(n); + ddlReturnDestination.addItem(n); + } + ddlOrigin.setSelectedItem(origin); + ddlDestination.setSelectedItem(destination); + ddlReturnOrigin.setSelectedItem(returnOrigin); + ddlReturnDestination.setSelectedItem(returnDestination); + + demandModelsModel.clear(); + for(I_DemandModel m : missionSplitPane.getMission().getDemandModels()) { + demandModelsModel.addElement(m); + } + } + eventsTable.initialize(); + updateButtons(); + } + + /** + * Updates the demand model and event-related buttons. + */ + private void updateButtons() { + if(demandModelsList.getSelectedIndices().length == 1) { + btnEditDemandModel.setEnabled(true); + btnRemoveDemandModel.setEnabled(true); + } else if(demandModelsList.getSelectedIndices().length > 1) { + btnEditDemandModel.setEnabled(false); + btnRemoveDemandModel.setEnabled(true); + } else { + btnEditDemandModel.setEnabled(false); + btnRemoveDemandModel.setEnabled(false); + } + if(eventsTable.getSelectedRowCount() == 1) { + btnEditEvent.setEnabled(true); + btnRemoveEvent.setEnabled(true); + } else if(eventsTable.getSelectedRowCount() > 1) { + btnEditEvent.setEnabled(false); + btnRemoveEvent.setEnabled(true); + } else { + btnEditEvent.setEnabled(false); + btnRemoveEvent.setEnabled(false); + } + } + + /** + * Updates the view. + */ + public void updateView() { + Collections.sort(missionSplitPane.getMission().getEventList()); + eventsTable.updateView(); + demandModelsModel.clear(); + for(I_DemandModel m : missionSplitPane.getMission().getDemandModels()) { + demandModelsModel.addElement(m); + } + updateButtons(); + } + + /** + * Gets the mission split pane. + * + * @return the mission split pane + */ + public MissionSplitPane getMissionSplitPane() { + return missionSplitPane; + } + + /** + * Gets the events table. + * + * @return the events table + */ + public EventsTable getEventsTable() { + return eventsTable; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/mission/MissionSplitPane.java b/src/main/java/edu/mit/spacenet/gui/mission/MissionSplitPane.java new file mode 100644 index 0000000..63eb560 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/MissionSplitPane.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import javax.swing.JSplitPane; + +import edu.mit.spacenet.scenario.Mission; + +/** + * A split panel used to display mission details and a bat chart visualization. + */ +public class MissionSplitPane extends JSplitPane { + private static final long serialVersionUID = -1544896538049800449L; + + private MissionsTab missionsTab; + private Mission mission; + + private MissionPanel missionPanel; + private MissionBatChart missionBatChart; + + /** + * Instantiates a new mission split pane. + * + * @param missionsTab the missions tab + */ + public MissionSplitPane(MissionsTab missionsTab) { + super(JSplitPane.HORIZONTAL_SPLIT); + this.missionsTab = missionsTab; + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + missionPanel = new MissionPanel(this); + setLeftComponent(missionPanel); + missionBatChart = new MissionBatChart(this); + setRightComponent(missionBatChart); + } + + /** + * Initializes the panel for a new mission. + */ + public void initialize() { + missionPanel.initialize(); + missionBatChart.initialize(); + } + + /** + * Updates the view. + */ + public void updateView() { + missionPanel.updateView(); + missionBatChart.updateView(); + } + + /** + * Gets the missions tab. + * + * @return the missions tab + */ + public MissionsTab getMissionsTab() { + return missionsTab; + } + + /** + * Gets the mission. + * + * @return the mission + */ + public Mission getMission() { + return mission; + } + + /** + * Sets the mission and initializes the components. + * + * @param mission the new mission + */ + public void setMission(Mission mission) { + this.mission = mission; + if(mission!=null) initialize(); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/mission/MissionsPanel.java b/src/main/java/edu/mit/spacenet/gui/mission/MissionsPanel.java new file mode 100644 index 0000000..dd8477b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/MissionsPanel.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.gui.command.AddMissionCommand; +import edu.mit.spacenet.gui.command.CopyMissionCommand; +import edu.mit.spacenet.gui.command.RemoveMissionCommand; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.Scenario; + +/** + * A panel used to display and edit the campaign missions. + */ +public class MissionsPanel extends JPanel { + private static final long serialVersionUID = -227481087996502271L; + + private MissionsSplitPane missionsSplitPane; + private MissionsTable missionsTable; + + private JButton addMissionButton, editMissionButton, copyMissionButton, + removeMissionButton; + + /** + * Instantiates a new missions panel. + * + * @param missionsSplitPane the missions split pane + */ + public MissionsPanel(MissionsSplitPane missionsSplitPane) { + this.missionsSplitPane = missionsSplitPane; + buildPanel(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new BorderLayout()); + missionsTable = new MissionsTable(this); + missionsTable.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if(e.getClickCount() == 2 && missionsTable.getSelectedRow() >=0) { + if(missionsTable.isEditing()) missionsTable.getCellEditor().stopCellEditing(); + missionsSplitPane.getMissionsTab().editMission(missionsTable.getSelectedMission()); + } + } + }); + missionsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + updateButtons(); + } + }); + JScrollPane missionScroll = new JScrollPane(missionsTable); + missionScroll.setPreferredSize(new Dimension(150,250)); + add(missionScroll, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + addMissionButton = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/application_add.png"))); + addMissionButton.setMargin(new Insets(3,3,3,3)); + addMissionButton.setToolTipText("Add New Mission"); + addMissionButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(missionsTable.isEditing()) missionsTable.getCellEditor().stopCellEditing(); + AddMissionCommand command = new AddMissionCommand(getMissionsSplitPane().getMissionsTab(), new Mission(getScenario())); + command.execute(); + } + }); + buttonPanel.add(addMissionButton); + editMissionButton = new JButton("Edit", new ImageIcon(getClass().getClassLoader().getResource("icons/application_edit.png"))); + editMissionButton.setMargin(new Insets(3,3,3,3)); + editMissionButton.setToolTipText("Edit Mission"); + editMissionButton.setEnabled(false); + editMissionButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(missionsTable.isEditing()) missionsTable.getCellEditor().stopCellEditing(); + missionsSplitPane.getMissionsTab().editMission(missionsTable.getSelectedMission()); + } + }); + buttonPanel.add(editMissionButton); + copyMissionButton = new JButton("Copy", new ImageIcon(getClass().getClassLoader().getResource("icons/application_double.png"))); + copyMissionButton.setMargin(new Insets(3,3,3,3)); + copyMissionButton.setToolTipText("Copy Mission"); + copyMissionButton.setEnabled(false); + copyMissionButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(missionsTable.isEditing()) missionsTable.getCellEditor().stopCellEditing(); + CopyMissionCommand command = new CopyMissionCommand(missionsSplitPane.getMissionsTab(), missionsTable.getSelectedMission()); + command.execute(); + } + }); + buttonPanel.add(copyMissionButton); + removeMissionButton = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/application_delete.png"))); + removeMissionButton.setMargin(new Insets(3,3,3,3)); + removeMissionButton.setToolTipText("Remove Mission"); + removeMissionButton.setEnabled(false); + removeMissionButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(missionsTable.isEditing()) missionsTable.getCellEditor().stopCellEditing(); + ArrayList missions = new ArrayList(); + for(int row : missionsTable.getSelectedRows()) { + missions.add(missionsTable.getMission(row)); + } + RemoveMissionCommand command = new RemoveMissionCommand(getMissionsSplitPane().getMissionsTab(), missions); + command.execute(); + } + }); + buttonPanel.add(removeMissionButton); + add(buttonPanel, BorderLayout.SOUTH); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + private Scenario getScenario() { + return missionsSplitPane.getMissionsTab().getScenarioPanel().getScenario(); + } + + /** + * Updates the copy/edit/remove buttons. + */ + private void updateButtons() { + if(missionsTable.getSelectedRowCount() == 1) { + copyMissionButton.setEnabled(true); + editMissionButton.setEnabled(true); + removeMissionButton.setEnabled(true); + } else if(missionsTable.getSelectedRowCount() > 1) { + copyMissionButton.setEnabled(false); + editMissionButton.setEnabled(false); + removeMissionButton.setEnabled(true); + } else { + copyMissionButton.setEnabled(false); + editMissionButton.setEnabled(false); + removeMissionButton.setEnabled(false); + } + } + + /** + * Initializes the components for a new campaign. + */ + public void initialize() { + missionsTable.initialize(); + updateButtons(); + } + + /** + * Updates the view. + */ + public void updateView() { + missionsTable.updateView(); + updateButtons(); + } + + /** + * Gets the missions split pane. + * + * @return the missions split pane + */ + public MissionsSplitPane getMissionsSplitPane() { + return missionsSplitPane; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/mission/MissionsSplitPane.java b/src/main/java/edu/mit/spacenet/gui/mission/MissionsSplitPane.java new file mode 100644 index 0000000..ae0fedd --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/MissionsSplitPane.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; + +/** + * A panel to display the campaign missions and useful visualizations. + */ +public class MissionsSplitPane extends JSplitPane { + private static final long serialVersionUID = -5912020298671757298L; + + private MissionsTab missionsTab; + + private MissionsPanel missionsPanel; + private JTabbedPane chartTabs; + private ProcessBatChart processBatChart; + private ElementBatChart elementBatChart; + + /** + * Instantiates a new missions split pane. + * + * @param missionsTab the missions tab + */ + public MissionsSplitPane(MissionsTab missionsTab) { + super(JSplitPane.HORIZONTAL_SPLIT); + this.missionsTab = missionsTab; + + missionsPanel = new MissionsPanel(this); + setLeftComponent(missionsPanel); + chartTabs = new JTabbedPane(); + processBatChart = new ProcessBatChart(this); + chartTabs.add(processBatChart); + elementBatChart = new ElementBatChart(this); + chartTabs.add(elementBatChart); + setRightComponent(chartTabs); + } + + /** + * Initializes the components for a new campaign. + */ + public void initialize() { + missionsPanel.initialize(); + processBatChart.initialize(); + elementBatChart.initialize(); + } + + /** + * Updates the view. + */ + public void updateView() { + missionsPanel.updateView(); + if(chartTabs.getSelectedComponent().equals(processBatChart)) { + processBatChart.updateView(); + } else if(chartTabs.getSelectedComponent().equals(elementBatChart)) { + elementBatChart.updateView(); + } + } + + /** + * Gets the missions tab. + * + * @return the missions tab + */ + public MissionsTab getMissionsTab() { + return missionsTab; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/mission/MissionsTab.java b/src/main/java/edu/mit/spacenet/gui/mission/MissionsTab.java new file mode 100644 index 0000000..59ee789 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/MissionsTab.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.CardLayout; +import java.awt.Cursor; + +import javax.swing.JPanel; +import javax.swing.SwingWorker; + +import edu.mit.spacenet.gui.ScenarioPanel; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.simulator.MiniSimulator; + +/** + * The tab used to define the campaign missions. + */ +public class MissionsTab extends JPanel { + private static final long serialVersionUID = -1914358227873959747L; + private static String MISSIONS = "Missions Panel"; + private static String MISSION = "Mission Panel"; + + private ScenarioPanel scenarioPanel; + + private MissionsSplitPane missionsSplitPane; + private MissionSplitPane missionSplitPane; + private MiniSimulator simulator; + private SimWorker simWorker; + + /** + * Instantiates a new missions tab. + * + * @param scenarioPanel the scenario panel + */ + public MissionsTab(ScenarioPanel scenarioPanel) { + this.scenarioPanel = scenarioPanel; + setLayout(new CardLayout()); + missionsSplitPane = new MissionsSplitPane(this); + add(missionsSplitPane, MISSIONS); + missionSplitPane = new MissionSplitPane(this); + add(missionSplitPane, MISSION); + } + + /** + * Initializes the missions tab. + */ + public void initialize() { + simulator = new MiniSimulator(scenarioPanel.getScenario()); + missionsSplitPane.initialize(); + editMissions(); + } + + /** + * Updates the view. Uses a swing worker to run the spatial simulation in a + * separate thread so the GUI doesn't freeze up. + */ + public void updateView() { + while(simWorker != null && !simWorker.isDone()) { + // lock UI while previous simulation is running + } + simWorker = new SimWorker(); + simWorker.execute(); + } + + /** + * Gets the mission split pane. + * + * @return the mission split pane + */ + public MissionSplitPane getMissionSplitPane() { + return missionSplitPane; + } + + /** + * Gets the simulator. + * + * @return the simulator + */ + public MiniSimulator getSimulator() { + return simulator; + } + + /** + * Gives control to the mission split pane to edit the mission. + * + * @param mission the mission + */ + public void editMission(Mission mission) { + missionSplitPane.setMission(mission); + ((CardLayout)getLayout()).show(this, MISSION); + } + + /** + * Gives control to the missions split pane to edit the missions. + */ + public void editMissions() { + if(missionSplitPane.getMission()!=null) missionSplitPane.setMission(null); + ((CardLayout)getLayout()).show(this, MISSIONS); + updateView(); + } + + /** + * Gets the scenario panel. + * + * @return the scenario panel + */ + public ScenarioPanel getScenarioPanel() { + return scenarioPanel; + } + + /** + * A SwingWorker subclass that manages the time-intensive simulation in a + * separate thread. + */ + private class SimWorker extends SwingWorker { + private boolean isInitialization; + + /** + * Instantiates a new sim worker. + * + * @param isInitialization the is initialization + */ + public SimWorker(boolean isInitialization) { + this.isInitialization = isInitialization; + } + + /** + * Instantiates a new sim worker. + */ + public SimWorker() { + this(false); + } + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#doInBackground() + */ + public Void doInBackground() { + try { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Simulating Missions..."); + scenarioPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + simulator.simulate(); + scenarioPanel.setCursor(Cursor.getDefaultCursor()); + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + public void done() { + if(missionSplitPane.getMission()==null) { + if(isInitialization) { + missionsSplitPane.initialize(); + } else { + missionsSplitPane.updateView(); + } + } else { + if(isInitialization) { + missionSplitPane.initialize(); + } else { + missionSplitPane.updateView(); + } + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/mission/MissionsTable.java b/src/main/java/edu/mit/spacenet/gui/mission/MissionsTable.java new file mode 100644 index 0000000..b890a8b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/mission/MissionsTable.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.Component; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import javax.swing.ImageIcon; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.MiniSimulator; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.event.I_Event; + +/** + * A table to display and edit missions. + * + * @author Paul Grogan + */ +public class MissionsTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + + private CustomTableModel model; + private MissionsPanel missionListPanel; + + /** + * Instantiates a new mission table. + * + * @param missionListPanel the mission list panel + */ + public MissionsTable(MissionsPanel missionListPanel) { + super(); + this.missionListPanel = missionListPanel; + + model = new CustomTableModel(); + setModel(model); + + DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); + renderer.setHorizontalAlignment(DefaultTableCellRenderer.CENTER); + + getColumnModel().getColumn(0).setHeaderValue("#"); + getColumnModel().getColumn(0).setCellRenderer(renderer); + getColumnModel().getColumn(0).setMaxWidth(25); + getColumnModel().getColumn(1).setHeaderValue("Start Date"); + getColumnModel().getColumn(1).setMaxWidth(100); + getColumnModel().getColumn(2).setHeaderValue("Mission Name"); + getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() { + // a custom renderer to display simulation error icons and messages + private static final long serialVersionUID = 7793722593255866883L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setIcon(null); + setIconTextGap(0); + setToolTipText(null); + for(SimSpatialError error : getSimulator().getSpatialErrors()) { + for(I_Event event : getMission(row).getEventList()) { + if(error.getEvent().getRoot().equals(event)) { + setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/bullet_error.png"))); + setToolTipText("This mission has errors."); + return this; + } + } + } + return this; + } + }); + + getTableHeader().setReorderingAllowed(false); + } + + /** + * Initializes the table for a new scenario. + */ + public void initialize() { + model.setScenario(getScenario()); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + private Scenario getScenario() { + return missionListPanel.getMissionsSplitPane().getMissionsTab().getScenarioPanel().getScenario(); + } + + /** + * Gets the simulator. + * + * @return the simulator + */ + private MiniSimulator getSimulator() { + return missionListPanel.getMissionsSplitPane().getMissionsTab().getSimulator(); + } + + /** + * A custom table model to manage the mission data in a campaign. + */ + class CustomTableModel extends AbstractTableModel { + private static final long serialVersionUID = -678300273079091701L; + private List data; + + /** + * Sets the scenario. + * + * @param scenario the new scenario + */ + public void setScenario(Scenario scenario) { + if(scenario==null) data = null; + else data = scenario.getMissionList(); + fireTableDataChanged(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 3; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + return data==null?0:data.size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int col) { + if(col==0) return false; + else return true; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnClass(int) + */ + public Class getColumnClass(int col) { + if(col==0) { + return Integer.class; + } else if(col==1) { + return Date.class; + } else { + return String.class; + } + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + if(col==0) { + return new Integer(row+1); + } else if(col==1) { + return data.get(row).getStartDate(); + } else { + return data.get(row).getName(); + } + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int) + */ + public void setValueAt(Object value, int row, int col) { + if(col==1) { + data.get(row).setStartDate((Date)value); + } else if(col==2) { + data.get(row).setName((String)value); + } + sortMissions(); + missionListPanel.getMissionsSplitPane().getMissionsTab().updateView(); + } + + /** + * Gets the mission in a particular row. + * + * @param row the row + * + * @return the mission + */ + public Mission getMission(int row) { + return data.get(row); + } + + /** + * Sorts the missions. + */ + public void sortMissions() { + Collections.sort(data); + fireTableDataChanged(); + } + } + + /** + * Updates the view. + */ + public void updateView() { + int selectedRow = getSelectedRow(); + model.sortMissions(); + if(selectedRow. + */ +package edu.mit.spacenet.gui.mission; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.SymbolAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import com.toedter.calendar.JDateChooser; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.SpaceNetSettings; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.SimState; +import edu.mit.spacenet.simulator.event.BurnEvent; +import edu.mit.spacenet.simulator.event.CreateEvent; +import edu.mit.spacenet.simulator.event.DemandEvent; +import edu.mit.spacenet.simulator.event.EvaEvent; +import edu.mit.spacenet.simulator.event.EventType; +import edu.mit.spacenet.simulator.event.ExplorationProcess; +import edu.mit.spacenet.simulator.event.FlightTransport; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.MoveEvent; +import edu.mit.spacenet.simulator.event.ReconfigureEvent; +import edu.mit.spacenet.simulator.event.ReconfigureGroupEvent; +import edu.mit.spacenet.simulator.event.RemoveEvent; +import edu.mit.spacenet.simulator.event.SpaceTransport; +import edu.mit.spacenet.simulator.event.SurfaceTransport; +import edu.mit.spacenet.simulator.event.TransferEvent; +import edu.mit.spacenet.util.DateFunctions; + +/** + * A bat-style chart that displays scenario events. If used from a missions + * split pane, the control panel is visible, if used from a mission split pane + * (while editing one mission), it will be hidden. + * + * @author Paul Grogan + */ +public class ProcessBatChart extends JSplitPane { + private static final long serialVersionUID = -6405124067606236705L; + private MissionsSplitPane missionsSplitPane; + private JDateChooser startDate, endDate; + private CheckBoxTableModel missionsModel; + private CheckBoxTableModel eventsModel; + private ChartPanel batChartPanel; + private JCheckBox waitCheck; + private JButton refreshButton; + + private ChartUpdater chartUpdater; + + /** + * Instantiates a new process bat chart within a mission split pane. + * + * @param missionsSplitPane the missions split pane + */ + public ProcessBatChart(MissionsSplitPane missionsSplitPane) { + this.missionsSplitPane = missionsSplitPane; + buildChart(); + } + + /** + * Builds the chart. + */ + private void buildChart() { + batChartPanel = new SNChartPanel(); + batChartPanel.setPreferredSize(new Dimension(500,300)); + setLeftComponent(batChartPanel); + + JPanel controlPanel = new JPanel(); + controlPanel.setLayout(new GridBagLayout()); + controlPanel.setBorder(BorderFactory.createTitledBorder("Chart Options")); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.BOTH; + controlPanel.add(new JLabel("Start Date: "), c); + c.gridy++; + controlPanel.add(new JLabel("End Date: "), c); + c.gridy--; + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + startDate = new JDateChooser(); + startDate.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + if(e.getPropertyName().equals("date") && isAutoRefresh()) updateChart(); + } + }); + controlPanel.add(startDate, c); + c.gridy++; + endDate = new JDateChooser(); + endDate.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + if(e.getPropertyName().equals("date") && isAutoRefresh()) updateChart(); + } + }); + controlPanel.add(endDate, c); + c.gridx--; + c.gridwidth = 2; + c.gridy++; + c.weighty = 1; + missionsModel = new CheckBoxTableModel(); + missionsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE && isAutoRefresh()) updateChart(); + } + }); + JTable missionsTable = new JTable(missionsModel); + missionsTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + missionsTable.getTableHeader().setReorderingAllowed(false); + missionsTable.getColumnModel().getColumn(0).setMaxWidth(25); + missionsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Missions"); + missionsTable.setShowGrid(false); + JScrollPane missionsScroll = new JScrollPane(missionsTable); + missionsScroll.setPreferredSize(new Dimension(150,100)); + controlPanel.add(missionsScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel missionsButtonPanel = new JPanel(); + missionsButtonPanel.setOpaque(false); + missionsButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllMissionsButton = new JButton("Select All"); + selectAllMissionsButton.setToolTipText("Select All Missions"); + selectAllMissionsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + missionsModel.selectAll(); + } + }); + missionsButtonPanel.add(selectAllMissionsButton); + JButton deselectAllMissionsButton = new JButton("Deselect All"); + deselectAllMissionsButton.setToolTipText("Deselect All Missions"); + deselectAllMissionsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + missionsModel.deselectAll(); + } + }); + missionsButtonPanel.add(deselectAllMissionsButton); + controlPanel.add(missionsButtonPanel, c); + c.weightx = 0; + c.fill = GridBagConstraints.BOTH; + c.gridy++; + JPanel prop1 = new JPanel(); + prop1.setOpaque(false); + prop1.setPreferredSize(new Dimension(1,15)); + controlPanel.add(prop1, c); + c.gridy++; + c.weighty = 1; + eventsModel = new CheckBoxTableModel(); + for(EventType t : EventType.values()) { + eventsModel.addObject(t); + } + eventsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + if(e.getType()==TableModelEvent.UPDATE && isAutoRefresh()) updateChart(); + } + }); + JTable eventsTable = new JTable(eventsModel); + eventsTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + eventsTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { + // custom renderer to show the event type icon + private static final long serialVersionUID = 1L; + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof EventType) setIcon(((EventType)value).getIcon()); + return this; + } + }); + eventsTable.getTableHeader().setReorderingAllowed(false); + eventsTable.getColumnModel().getColumn(0).setMaxWidth(25); + eventsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Event Types"); + eventsTable.setShowGrid(false); + JScrollPane eventsScroll = new JScrollPane(eventsTable); + eventsScroll.setPreferredSize(new Dimension(150,100)); + controlPanel.add(eventsScroll, c); + c.gridy++; + c.weighty = 0; + waitCheck = new JCheckBox("Draw Elements Waiting (Null Process)"); + waitCheck.setOpaque(false); + waitCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(isAutoRefresh()) updateChart(); + } + }); + controlPanel.add(waitCheck, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + JPanel eventsButtonPanel = new JPanel(); + eventsButtonPanel.setOpaque(false); + eventsButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllEventsButton = new JButton("Select All"); + selectAllEventsButton.setToolTipText("Select All Events"); + selectAllEventsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + eventsModel.selectAll(); + waitCheck.setSelected(true); + } + }); + eventsButtonPanel.add(selectAllEventsButton); + JButton deselectAllEventsButton = new JButton("Deselect All"); + deselectAllEventsButton.setToolTipText("Deselect All Events"); + deselectAllEventsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + eventsModel.deselectAll(); + waitCheck.setSelected(false); + } + }); + eventsButtonPanel.add(deselectAllEventsButton); + controlPanel.add(eventsButtonPanel, c); + c.gridy++; + JPanel prop2 = new JPanel(); + prop2.setOpaque(false); + prop2.setPreferredSize(new Dimension(1,15)); + controlPanel.add(prop2, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_END; + refreshButton = new JButton("Refresh", new ImageIcon(getClass().getClassLoader().getResource("icons/arrow_refresh.png"))); + refreshButton.setVisible(false); + refreshButton.setMargin(new Insets(3,3,3,3)); + refreshButton.setToolTipText("Refresh Chart"); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + updateChart(); + } + }); + controlPanel.add(refreshButton, c); + + setRightComponent(controlPanel); + + setName("Process Bat Chart"); + setOneTouchExpandable(true); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + + setDividerSize(10); + setDividerLocation(490); + } + + /** + * Initializes the component for a new scenario. + */ + public void initialize() { + startDate.setEnabled(getScenario()!=null); + endDate.setEnabled(getScenario()!=null); + if(getScenario()!=null) { + startDate.setSelectableDateRange(getScenario().getStartDate(), null); + endDate.setSelectableDateRange(getScenario().getStartDate(), null); + } + missionsModel.clear(); + updateView(); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + private Scenario getScenario() { + return missionsSplitPane.getMissionsTab().getScenarioPanel().getScenario(); + } + + /** + * Checks if auto refresh is enabled. + * + * @return true, if auto refresh is enabled + */ + private boolean isAutoRefresh() { + return SpaceNetSettings.getInstance().isAutoRefresh(); + } + + /** + * Updates the view. (Refreshes the chart if auto-refresh is enabled, + * ensures manual refresh button is visible otherwise). + */ + public void updateView() { + // update mission list + List deselectedMissions = missionsModel.getDeselectedObjects(); + TableModelListener[] modelListeners = missionsModel.getTableModelListeners(); + for(TableModelListener l : modelListeners) { + missionsModel.removeTableModelListener(l); + } + missionsModel.clear(); + for(Mission mission : getScenario().getMissionList()) { + missionsModel.addObject(mission, !deselectedMissions.contains(mission)); + } + for(TableModelListener l : modelListeners) { + missionsModel.addTableModelListener(l); + } + missionsModel.fireTableDataChanged(); + + // update auto refresh button + if(isAutoRefresh()) { + refreshButton.setVisible(false); + } else { + refreshButton.setVisible(true); + } + + // update chart + if(isAutoRefresh()) updateChart(); + } + + /** + * Refreshes the chart (time-intensive for large campaigns). Uses a swing + * worker to run the update process in a separate thread so the GUI does + * not freeze. + */ + public void updateChart() { + while(chartUpdater != null && !chartUpdater.isDone()) { + // wait until current update is complete + } + chartUpdater = new ChartUpdater(); + chartUpdater.execute(); + } + + /** + * Updates the chart (Time-intensive for large campaigns). + */ + private void rebuildChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, + "Date", + "Node", + dataset, + false, + true, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + SymbolAxis rangeAxis = createRangeAxis(); + plot.setRangeAxis(rangeAxis); + plot.setBackgroundPaint(Color.lightGray); + plot.setDomainGridlinePaint(Color.white); + plot.setRangeGridlinePaint(Color.white); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + + plot.setRangeGridlinesVisible(false); + plot.setDomainGridlinesVisible(false); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + for(Mission mission : missionsModel.getSelectedObjects()) { + for(I_Event event : mission.getEventList()) { + if((startDate.getDate()==null||DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime()).compareTo(startDate.getDate())>=0) + && (endDate.getDate()==null||DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime()).compareTo(endDate.getDate())<=0) + && event.getLocation() instanceof Node) { + if(event instanceof SpaceTransport + && ((SpaceTransport)event).getEdge() != null + && eventsModel.getSelectedObjects().contains(EventType.SPACE_TRANSPORT)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number(((SpaceTransport) event).getEdge().getOrigin(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime() + ((SpaceTransport)event).getEdge().getDuration())), + node2Number(((SpaceTransport) event).getEdge().getDestination(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.RED); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0)); + } else if(event instanceof SurfaceTransport + && ((SurfaceTransport)event).getEdge() != null + && eventsModel.getSelectedObjects().contains(EventType.SURFACE_TRANSPORT)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + if(((SurfaceTransport)event).isReversed()) { + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number(((SurfaceTransport) event).getEdge().getDestination(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime() + ((SurfaceTransport)event).getDuration())), + node2Number(((SurfaceTransport) event).getEdge().getOrigin(), rangeAxis)); + } else { + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number(((SurfaceTransport) event).getEdge().getOrigin(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime() + ((SurfaceTransport)event).getDuration())), + node2Number(((SurfaceTransport) event).getEdge().getDestination(), rangeAxis)); + } + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.GREEN); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0)); + } else if(event instanceof FlightTransport + && ((FlightTransport)event).getEdge() != null + && eventsModel.getSelectedObjects().contains(EventType.FLIGHT_TRANSPORT)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number(((FlightTransport) event).getEdge().getOrigin(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime() + ((FlightTransport)event).getEdge().getDuration())), + node2Number(((FlightTransport) event).getEdge().getDestination(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.YELLOW); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0)); + } else if(event instanceof ExplorationProcess + && event.getLocation() != null + && eventsModel.getSelectedObjects().contains(EventType.EXPLORATION)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime() + ((ExplorationProcess)event).getDuration())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.CYAN); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(-2.0, -2.0, 4.0, 4.0)); + } else if(event.getLocation() != null){ + if(event instanceof CreateEvent + && eventsModel.getSelectedObjects().contains(EventType.CREATE)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.GREEN); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof MoveEvent + && eventsModel.getSelectedObjects().contains(EventType.MOVE)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.ORANGE); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof TransferEvent + && eventsModel.getSelectedObjects().contains(EventType.TRANSFER)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.ORANGE); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof RemoveEvent + && eventsModel.getSelectedObjects().contains(EventType.REMOVE)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.BLACK); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof DemandEvent + && eventsModel.getSelectedObjects().contains(EventType.DEMAND)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.BLUE); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof ReconfigureEvent + && eventsModel.getSelectedObjects().contains(EventType.RECONFIGURE)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.PINK); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof ReconfigureGroupEvent + && eventsModel.getSelectedObjects().contains(EventType.RECONFIGURE_GROUP)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.PINK); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof BurnEvent + && eventsModel.getSelectedObjects().contains(EventType.BURN)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.RED); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } else if(event instanceof EvaEvent + && eventsModel.getSelectedObjects().contains(EventType.EVA)) { + TimeSeries s = new TimeSeries(event.getName(), Hour.class); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime())), + node2Number((Node)event.getLocation(), rangeAxis)); + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + event.getTime() + ((EvaEvent)event).getEvaDuration()/24)), + node2Number((Node)event.getLocation(), rangeAxis)); + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.CYAN); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0)); + } + } + } + } + } + if(waitCheck.isSelected()) { + // this section uses the simulator data to plot the time-history + // of element locations + Mission firstMission = missionsModel.getSelectedObjects().size()>0?missionsModel.getSelectedObjects().get(0):null; + double minTime1 = firstMission==null?Double.MAX_VALUE:DateFunctions.getDaysBetween(getScenario().getStartDate(), firstMission.getStartDate()); + Mission lastMission = missionsModel.getSelectedObjects().size()>0?missionsModel.getSelectedObjects().get(missionsModel.getSelectedObjects().size()-1):null; + double maxTime1 = lastMission==null?0:DateFunctions.getDaysBetween(getScenario().getStartDate(), DateFunctions.getDate(lastMission.getStartDate(), lastMission.getDuration())); + + double minTime2 = startDate.getDate()==null?0:DateFunctions.getDaysBetween(getScenario().getStartDate(), startDate.getDate()); + double maxTime2 = endDate.getDate()==null?Double.MAX_VALUE:DateFunctions.getDaysBetween(getScenario().getStartDate(), endDate.getDate()); + + double minTime = Math.max(minTime1, minTime2); + double maxTime = Math.min(maxTime1, maxTime2); + + for(I_Element element : getScenario().getElements()) { + Node prevNode = null; + List series = new ArrayList(); + int i = -1; + for(SimState state : missionsSplitPane.getMissionsTab().getSimulator().getLocationHistory()) { + if(prevNode!=null && prevNode.equals(state.getLocation(element))) { + series.get(i).addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), Math.min(Math.max(minTime, state.getTime()), maxTime))), + node2Number((Node)state.getLocation(element), rangeAxis)); + } else if(state.getLocation(element) instanceof Node) { + prevNode = (Node)state.getLocation(element); + series.add(new TimeSeries(element + "waiting at " + prevNode + " (" + i + ")")); + i++; + series.get(i).addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), Math.min(Math.max(minTime, state.getTime()), maxTime))), + node2Number((Node)state.getLocation(element), rangeAxis)); + } else { + prevNode = null; + } + } + for(TimeSeries s : series) { + ((TimeSeriesCollection)dataset).addSeries(s); + r.setSeriesPaint(dataset.getSeriesCount() - 1, Color.GRAY); + r.setSeriesShape(dataset.getSeriesCount() - 1, + new Ellipse2D.Double(0, 0, 0, 0)); + } + } + } + + batChartPanel.setChart(chart); + } + + /** + * Creates the range axis (list of nodes on the vertical axis). + * + * @return the symbol axis + */ + private SymbolAxis createRangeAxis() { + Vector nodeLabels = new Vector(); + for (Node n : getScenario().getNetwork().getNodes()) { + nodeLabels.add(n.getName()); + } + String[] array = {}; + return new SymbolAxis(null, nodeLabels.toArray(array)); + } + + /** + * Converts a node to its numeric representation for the symbol axis. + * + * @param node the node + * @param axis the axis + * + * @return the number + */ + private int node2Number(Node node, SymbolAxis axis) { + for (int i = 0; i < axis.getSymbols().length; i++) { + if (axis.getSymbols()[i].equals(node.getName())) { + return i; + } + } + return -1; + } + + + /** + * An updater to process the charts in a separate thread. + */ + private class ChartUpdater extends SwingWorker { + + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#doInBackground() + */ + protected Void doInBackground() { + try { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Refreshing Charts..."); + missionsSplitPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + rebuildChart(); + missionsSplitPane.setCursor(Cursor.getDefaultCursor()); + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/model/AbstractDemandModelPanel.java b/src/main/java/edu/mit/spacenet/gui/model/AbstractDemandModelPanel.java new file mode 100644 index 0000000..2044288 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/model/AbstractDemandModelPanel.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.model; + +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.model.I_DemandModel; + +/** + * An abstract class that serves as an interface to the demand model panels. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class AbstractDemandModelPanel extends JPanel { + private static final long serialVersionUID = -4507539878695833125L; + + private DemandModelDialog demandModelDialog; + + /** + * Instantiates a new abstract demand model panel. + * + * @param demandModelDialog the demand model dialog + * @param demandModel the demand model + */ + public AbstractDemandModelPanel(DemandModelDialog demandModelDialog, + I_DemandModel demandModel) { + this.demandModelDialog = demandModelDialog; + } + + /** + * Save demand model. + */ + public abstract void saveDemandModel(); + + /** + * Gets the demand model dialog. + * + * @return the demand model dialog + */ + public DemandModelDialog getDemandModelDialog() { + return demandModelDialog; + } + + /** + * Checks if is demand model valid. + * + * @return true, if is demand model valid + */ + public abstract boolean isDemandModelValid(); + + /** + * Gets the demand model. + * + * @return the demand model + */ + public abstract I_DemandModel getDemandModel(); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/model/CrewConsumablesDemandModelPanel.java b/src/main/java/edu/mit/spacenet/gui/model/CrewConsumablesDemandModelPanel.java new file mode 100644 index 0000000..f9a57ee --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/model/CrewConsumablesDemandModelPanel.java @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.model; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTabbedPane; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import edu.mit.spacenet.domain.model.CrewConsumablesDemandModel; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * The panel for viewing and editing crew consumables mission-level demand + * models. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class CrewConsumablesDemandModelPanel extends AbstractDemandModelPanel { + private static final long serialVersionUID = -966209133130231178L; + + private CrewConsumablesDemandModel demandModel; + + private SpinnerNumberModel crewSizeModel, crewTimeModel, + explorationDurationModel, transitDurationModel, reservesDurationModel, + waterRecoveryModel, clothingLifetimeModel; + private JSpinner crewSizeSpinner, crewTimeSpinner, + explorationDurationSpinner, transitDurationSpinner, reservesDurationSpinner, + waterRecoverySpinner, clothingLifetimeSpinner; + private JCheckBox transitDemandsCheck; + private SpinnerNumberModel waterRateModel, evaWaterRateModel, foodSupportRateModel, + ambientFoodRateModel, rfFoodRateModel, oxygenRateModel, evaOxygenRateModel, + nitrogenRateModel, hygieneRateModel, hygieneKitModel, clothingRateModel, + personalItemsModel, officeEquipmentModel, evaSuitModel, evaLithiumHydroxideModel, + healthEquipmentModel, healthConsumablesModel, safetyEquipmentModel, + commEquipmentModel, computerEquipmentModel, trashBagRateModel, wasteContainmentRateModel; + private JSpinner waterRateSpinner, evaWaterRateSpinner, foodSupportRateSpinner, + ambientFoodRateSpinner, rfFoodRateSpinner, oxygenRateSpinner, evaOxygenRateSpinner, + nitrogenRateSpinner, hygieneRateSpinner, hygieneKitSpinner, clothingRateSpinner, + personalItemsSpinner, officeEquipmentSpinner, evaSuitSpinner, evaLithiumHydroxideSpinner, + healthEquipmentSpinner, healthConsumablesSpinner, safetyEquipmentSpinner, + commEquipmentSpinner, computerEquipmentSpinner, trashBagRateSpinner, wasteContainmentRateSpinner; + private DemandTable demandTable; + + /** + * Instantiates a new crew consumables demand model panel. + * + * @param demandModelDialog the demand model dialog + * @param demandModel the demand model + */ + public CrewConsumablesDemandModelPanel(DemandModelDialog demandModelDialog, + CrewConsumablesDemandModel demandModel) { + super(demandModelDialog, demandModel); + this.demandModel = demandModel; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + JTabbedPane tabbedPane = new JTabbedPane(); + tabbedPane.add(buildInputsPanel(), "Inputs"); + tabbedPane.add(buildRatesPanel(), "Rates"); + tabbedPane.add(buildDemandsPanel(), "Demands"); + tabbedPane.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + updateDemands(); + } + }); + setLayout(new BorderLayout()); + add(tabbedPane, BorderLayout.CENTER); + } + + /** + * Builds the inputs panel. + * + * @return the inputs panel + */ + private JPanel buildInputsPanel() { + JPanel inputsPanel = new JPanel(); + inputsPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + inputsPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + inputsPanel.add(new JLabel("Crew Size: "), c); + c.gridy++; + inputsPanel.add(new JLabel("EVA Crew Time: "), c); + c.gridy++; + inputsPanel.add(new JLabel("Exploration Duration: "), c); + c.gridy++; + c.gridy++; + inputsPanel.add(new JLabel("Transit Duration: "), c); + c.gridy++; + inputsPanel.add(new JLabel("Reserves Duration: "), c); + c.gridy++; + inputsPanel.add(new JLabel("Water Recovery Rate: "), c); + c.gridy++; + inputsPanel.add(new JLabel("Clothing Lifetime"), c); + c.gridy = 0; + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.weightx = 1; + crewSizeModel = new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1); + crewSizeSpinner = new JSpinner(crewSizeModel); + crewSizeSpinner.setEnabled(false); + crewSizeSpinner.setPreferredSize(new Dimension(50,20)); + inputsPanel.add(new UnitsWrapper(crewSizeSpinner, "crew"), c); + c.gridy++; + crewTimeModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, 0.25); + crewTimeSpinner = new JSpinner(crewTimeModel); + crewTimeSpinner.setEnabled(false); + crewTimeSpinner.setPreferredSize(new Dimension(50,20)); + inputsPanel.add(new UnitsWrapper(crewTimeSpinner, "crew-hours"), c); + c.gridy++; + explorationDurationModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getTimePrecision()); + explorationDurationSpinner = new JSpinner(explorationDurationModel); + explorationDurationSpinner.setEnabled(false); + explorationDurationSpinner.setPreferredSize(new Dimension(50,20)); + inputsPanel.add(new UnitsWrapper(explorationDurationSpinner, "days"), c); + c.gridy++; + transitDemandsCheck = new JCheckBox("Omit Transit Demands"); + transitDemandsCheck.setOpaque(false); + inputsPanel.add(transitDemandsCheck, c); + c.gridy++; + transitDurationModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getTimePrecision()); + transitDurationSpinner = new JSpinner(transitDurationModel); + transitDurationSpinner.setEnabled(false); + transitDurationSpinner.setPreferredSize(new Dimension(50,20)); + inputsPanel.add(new UnitsWrapper(transitDurationSpinner, "days"), c); + c.gridy++; + reservesDurationModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getTimePrecision()); + reservesDurationSpinner = new JSpinner(reservesDurationModel); + reservesDurationSpinner.setPreferredSize(new Dimension(50,20)); + inputsPanel.add(new UnitsWrapper(reservesDurationSpinner, "days"), c); + c.gridy++; + waterRecoveryModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getTimePrecision()); + waterRecoverySpinner = new JSpinner(waterRecoveryModel); + waterRecoverySpinner.setPreferredSize(new Dimension(50,20)); + inputsPanel.add(new UnitsWrapper(waterRecoverySpinner, "%"), c); + c.gridy++; + clothingLifetimeModel = new SpinnerNumberModel(1, 1, Double.MAX_VALUE, GlobalParameters.getTimePrecision()); + clothingLifetimeSpinner = new JSpinner(clothingLifetimeModel); + clothingLifetimeSpinner.setPreferredSize(new Dimension(50,20)); + inputsPanel.add(new UnitsWrapper(clothingLifetimeSpinner, "days"), c); + c.gridy++; + c.weighty = 1; + inputsPanel.add(new JLabel(), c); + return inputsPanel; + } + + /** + * Builds the rates panel. + * + * @return the rates panel + */ + private JPanel buildRatesPanel() { + JPanel ratesPanel = new JPanel(); + ratesPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + ratesPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + ratesPanel.add(new JLabel("Water: "), c); + c.gridy++; + ratesPanel.add(new JLabel("EVA Water: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Food Support: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Ambient Food: "), c); + c.gridy++; + ratesPanel.add(new JLabel("R/F Food: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Oxygen: "), c); + c.gridy++; + ratesPanel.add(new JLabel("EVA Oxygen: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Nitrogen: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Hygiene Items: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Hygiene Kits: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Clothing: "), c); + c.gridx+=2; + c.gridy = 0; + ratesPanel.add(new JLabel("Personal Items: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Office Equipment: "), c); + c.gridy++; + ratesPanel.add(new JLabel("EVA Suits: "), c); + c.gridy++; + ratesPanel.add(new JLabel("EVA LiOH: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Health Equipment: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Health Consumables: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Safety Equipment: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Comm Equipment: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Computer Equipment: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Trash Bags: "), c); + c.gridy++; + ratesPanel.add(new JLabel("Waste Containment: "), c); + c.gridy = 0; + c.gridx = 1; + c.anchor = GridBagConstraints.LINE_START; + waterRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + waterRateSpinner = new JSpinner(waterRateModel); + waterRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(waterRateSpinner, "kg/crew/day"), c); + c.gridy++; + evaWaterRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + evaWaterRateSpinner = new JSpinner(evaWaterRateModel); + evaWaterRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(evaWaterRateSpinner, "kg/crew/hour"), c); + c.gridy++; + foodSupportRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + foodSupportRateSpinner = new JSpinner(foodSupportRateModel); + foodSupportRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(foodSupportRateSpinner, "kg/crew/day"), c); + c.gridy++; + ambientFoodRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + ambientFoodRateSpinner = new JSpinner(ambientFoodRateModel); + ambientFoodRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(ambientFoodRateSpinner, "kg/crew/day"), c); + c.gridy++; + rfFoodRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + rfFoodRateSpinner = new JSpinner(rfFoodRateModel); + rfFoodRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(rfFoodRateSpinner, "kg/crew/day"), c); + c.gridy++; + oxygenRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + oxygenRateSpinner = new JSpinner(oxygenRateModel); + oxygenRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(oxygenRateSpinner, "kg/crew/day"), c); + c.gridy++; + evaOxygenRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + evaOxygenRateSpinner = new JSpinner(evaOxygenRateModel); + evaOxygenRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(evaOxygenRateSpinner, "kg/crew/hour"), c); + c.gridy++; + nitrogenRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + nitrogenRateSpinner = new JSpinner(nitrogenRateModel); + nitrogenRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(nitrogenRateSpinner, "kg/crew/day"), c); + c.gridy++; + hygieneRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + hygieneRateSpinner = new JSpinner(hygieneRateModel); + hygieneRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(hygieneRateSpinner, "kg/crew/day"), c); + c.gridy++; + hygieneKitModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + hygieneKitSpinner = new JSpinner(hygieneKitModel); + hygieneKitSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(hygieneKitSpinner, "kg/crew"), c); + c.gridy++; + clothingRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + clothingRateSpinner = new JSpinner(clothingRateModel); + clothingRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(clothingRateSpinner, "kg/crew/change"), c); + c.gridy = 0; + c.gridx+=2; + personalItemsModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + personalItemsSpinner = new JSpinner(personalItemsModel); + personalItemsSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(personalItemsSpinner, "kg/crew"), c); + c.gridy++; + officeEquipmentModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + officeEquipmentSpinner = new JSpinner(officeEquipmentModel); + officeEquipmentSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(officeEquipmentSpinner, "kg/crew"), c); + c.gridy++; + evaSuitModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + evaSuitSpinner = new JSpinner(evaSuitModel); + evaSuitSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(evaSuitSpinner, "kg/crew"), c); + c.gridy++; + evaLithiumHydroxideModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + evaLithiumHydroxideSpinner = new JSpinner(evaLithiumHydroxideModel); + evaLithiumHydroxideSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(evaLithiumHydroxideSpinner, "kg/crew/hour"), c); + c.gridy++; + healthEquipmentModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + healthEquipmentSpinner = new JSpinner(healthEquipmentModel); + healthEquipmentSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(healthEquipmentSpinner, "kg"), c); + c.gridy++; + healthConsumablesModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + healthConsumablesSpinner = new JSpinner(healthConsumablesModel); + healthConsumablesSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(healthConsumablesSpinner, "kg/crew/day"), c); + c.gridy++; + safetyEquipmentModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + safetyEquipmentSpinner = new JSpinner(safetyEquipmentModel); + safetyEquipmentSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(safetyEquipmentSpinner, "kg"), c); + c.gridy++; + commEquipmentModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + commEquipmentSpinner = new JSpinner(commEquipmentModel); + commEquipmentSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(commEquipmentSpinner, "kg"), c); + c.gridy++; + computerEquipmentModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + computerEquipmentSpinner = new JSpinner(computerEquipmentModel); + computerEquipmentSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(computerEquipmentSpinner, "kg/crew"), c); + c.gridy++; + trashBagRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + trashBagRateSpinner = new JSpinner(trashBagRateModel); + trashBagRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(trashBagRateSpinner, "kg/crew/day"), c); + c.gridy++; + wasteContainmentRateModel = new SpinnerNumberModel(0, 0, Double.MAX_VALUE, GlobalParameters.getDemandPrecision()); + wasteContainmentRateSpinner = new JSpinner(wasteContainmentRateModel); + wasteContainmentRateSpinner.setPreferredSize(new Dimension(50,20)); + ratesPanel.add(new UnitsWrapper(wasteContainmentRateSpinner, "kg/crew/day"), c); + c.gridy++; + c.gridx = 0; + c.gridwidth = 4; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JButton resetButton = new JButton("Reset Default Rates"); + resetButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + demandModel.resetDefaultRates(); + initialize(); + } + }); + ratesPanel.add(resetButton, c); + return ratesPanel; + } + + /** + * Initializes the panel for a new demand model. + */ + private void initialize() { + crewSizeModel.setValue(demandModel.getMissionCrewSize()); + crewTimeModel.setValue(demandModel.getMissionEvaCrewTime()); + explorationDurationModel.setValue(demandModel.getMissionExplorationDuration()); + transitDemandsCheck.setSelected(demandModel.isTransitDemandsOmitted()); + transitDurationModel.setValue(demandModel.getMissionTransitDuration()); + reservesDurationModel.setValue(demandModel.getReservesDuration()); + waterRecoveryModel.setValue(100*demandModel.getWaterRecoveryRate()); + clothingLifetimeModel.setValue(demandModel.getClothingLifetime()); + + waterRateModel.setValue(demandModel.getWaterRate()); + evaWaterRateModel.setValue(demandModel.getEvaWaterRate()); + foodSupportRateModel.setValue(demandModel.getFoodSupportRate()); + ambientFoodRateModel.setValue(demandModel.getAmbientFoodRate()); + rfFoodRateModel.setValue(demandModel.getRfFoodRate()); + oxygenRateModel.setValue(demandModel.getOxygenRate()); + evaOxygenRateModel.setValue(demandModel.getEvaOxygenRate()); + nitrogenRateModel.setValue(demandModel.getNitrogenRate()); + hygieneRateModel.setValue(demandModel.getHygieneRate()); + hygieneKitModel.setValue(demandModel.getHygieneKit()); + clothingRateModel.setValue(demandModel.getClothingRate()); + personalItemsModel.setValue(demandModel.getPersonalItems()); + officeEquipmentModel.setValue(demandModel.getOfficeEquipment()); + evaSuitModel.setValue(demandModel.getEvaSuit()); + evaLithiumHydroxideModel.setValue(demandModel.getEvaLithiumHydroxide()); + healthEquipmentModel.setValue(demandModel.getHealthEquipment()); + healthConsumablesModel.setValue(demandModel.getHealthConsumables()); + safetyEquipmentModel.setValue(demandModel.getSafetyEquipment()); + commEquipmentModel.setValue(demandModel.getCommEquipment()); + computerEquipmentModel.setValue(demandModel.getComputerEquipment()); + trashBagRateModel.setValue(demandModel.getTrashBagRate()); + wasteContainmentRateModel.setValue(demandModel.getWasteContainmentRate()); + } + + /** + * Builds the demands panel. + * + * @return the demands panel + */ + private JPanel buildDemandsPanel() { + JPanel demandsPanel = new JPanel(); + demandsPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + c.weighty = 1; + c.weightx = 1; + demandTable = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + demandTable.setEnabled(false); + JScrollPane demandScroll = new JScrollPane(demandTable); + demandScroll.setPreferredSize(new Dimension(300,200)); + demandsPanel.add(demandScroll, c); + return demandsPanel; + } + + /** + * Updates the demands. + */ + private void updateDemands() { + saveDemandModel(); + demandTable.removeAllDemands(); + for(Demand demand : demandModel.generateDemands(0, null)) { + demandTable.addDemand(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#getDemandModel() + */ + public CrewConsumablesDemandModel getDemandModel() { + return demandModel; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#saveDemandModel() + */ + public void saveDemandModel() { + demandModel.setTransitDemandsOmitted(transitDemandsCheck.isSelected()); + demandModel.setReservesDuration(reservesDurationModel.getNumber().doubleValue()); + demandModel.setWaterRecoveryRate(waterRecoveryModel.getNumber().doubleValue()/100d); + demandModel.setClothingLifetime(clothingLifetimeModel.getNumber().doubleValue()); + + demandModel.setWaterRate(waterRateModel.getNumber().doubleValue()); + demandModel.setEvaWaterRate(evaWaterRateModel.getNumber().doubleValue()); + demandModel.setFoodSupportRate(foodSupportRateModel.getNumber().doubleValue()); + demandModel.setAmbientFoodRate(ambientFoodRateModel.getNumber().doubleValue()); + demandModel.setRfFoodRate(rfFoodRateModel.getNumber().doubleValue()); + demandModel.setOxygenRate(oxygenRateModel.getNumber().doubleValue()); + demandModel.setEvaOxygenRate(evaOxygenRateModel.getNumber().doubleValue()); + demandModel.setNitrogenRate(nitrogenRateModel.getNumber().doubleValue()); + demandModel.setHygieneRate(hygieneRateModel.getNumber().doubleValue()); + demandModel.setHygieneKit(hygieneKitModel.getNumber().doubleValue()); + demandModel.setClothingRate(clothingRateModel.getNumber().doubleValue()); + demandModel.setPersonalItems(personalItemsModel.getNumber().doubleValue()); + demandModel.setOfficeEquipment(officeEquipmentModel.getNumber().doubleValue()); + demandModel.setEvaSuit(evaSuitModel.getNumber().doubleValue()); + demandModel.setEvaLithiumHydroxide(evaLithiumHydroxideModel.getNumber().doubleValue()); + demandModel.setHealthEquipment(healthEquipmentModel.getNumber().doubleValue()); + demandModel.setHealthConsumables(healthConsumablesModel.getNumber().doubleValue()); + demandModel.setSafetyEquipment(safetyEquipmentModel.getNumber().doubleValue()); + demandModel.setCommEquipment(commEquipmentModel.getNumber().doubleValue()); + demandModel.setComputerEquipment(computerEquipmentModel.getNumber().doubleValue()); + demandModel.setTrashBagRate(trashBagRateModel.getNumber().doubleValue()); + demandModel.setWasteContainmentRate(wasteContainmentRateModel.getNumber().doubleValue()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#isDemandModelValid() + */ + @Override + public boolean isDemandModelValid() { + return true; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/model/DemandModelDialog.java b/src/main/java/edu/mit/spacenet/gui/model/DemandModelDialog.java new file mode 100644 index 0000000..cf499e9 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/model/DemandModelDialog.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.model; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.element.StateDialog; +import edu.mit.spacenet.gui.mission.MissionPanel; + +/** + * The dialog for viewing and editing demand models. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class DemandModelDialog extends JDialog { + private static final long serialVersionUID = 5836025162293791120L; + + private StateDialog stateDialog; + private MissionPanel missionPanel; + private I_DemandModel demandModel; + + private JTextField nameText; + private AbstractDemandModelPanel demandModelPanel; + private JButton okButton; + + /** + * Instantiates a new demand model dialog. + * + * @param stateDialog the state dialog + * @param demandModel the demand model + */ + public DemandModelDialog(StateDialog stateDialog, I_DemandModel demandModel) { + super(stateDialog, "Edit Demand Model", true); + this.stateDialog = stateDialog; + this.demandModel = demandModel; + buildDialog(); + initialize(); + setMinimumSize(new Dimension(300,150)); + } + + /** + * Instantiates a new demand model dialog. + * + * @param missionPanel the missions panel + * @param demandModel the demand model + */ + public DemandModelDialog(MissionPanel missionPanel, I_DemandModel demandModel) { + super(SpaceNetFrame.getInstance(), "Edit Demand Model", true); + this.missionPanel = missionPanel; + this.demandModel = demandModel; + buildDialog(); + initialize(); + } + + /** + * Builds the dialog. + */ + private void buildDialog() { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Name: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText = new JTextField(20); + contentPanel.add(nameText, c); + + c.gridy++; + c.gridx = 0; + c.weighty = 1; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + demandModelPanel = DemandModelPanelFactory.createDemandModelPanel(this, demandModel); + contentPanel.add(demandModelPanel, c); + + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + contentPanel.add(buttonPanel, c); + + okButton = new JButton("OK", new ImageIcon(getClass().getClassLoader().getResource("icons/comment_go.png"))); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveDemandModel(); + } + }); + buttonPanel.add(okButton); + JButton cancelButton = new JButton("Cancel", new ImageIcon(getClass().getClassLoader().getResource("icons/comment_delete.png"))); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPanel.add(cancelButton); + + getRootPane().setDefaultButton(okButton); + setContentPane(contentPanel); + } + + /** + * Initializes the dialog for a new demand model. + */ + private void initialize() { + nameText.setText(demandModel.getName()); + } + + /** + * Checks if is demand model valid. + * + * @return true, if is demand model valid + */ + private boolean isDemandModelValid() { + if(nameText.getText().length()==0) { + JOptionPane.showMessageDialog(this, + "Please enter a demand model name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(!demandModelPanel.isDemandModelValid()) return false; + return true; + } + + /** + * Saves the demand model. + */ + private void saveDemandModel() { + if(isDemandModelValid()) { + demandModel.setName(nameText.getText()); + demandModelPanel.saveDemandModel(); + if(missionPanel != null) { + if(!missionPanel.getMissionSplitPane().getMission().getDemandModels().contains(demandModel)) { + missionPanel.getMissionSplitPane().getMission().getDemandModels().add(demandModel); + } + } else if(stateDialog != null) { + if(!stateDialog.containsDemandModel(demandModel)) { + stateDialog.addDemandModel(demandModel); + } + } + if(missionPanel != null) { + missionPanel.updateView(); + } else if(stateDialog != null) { + stateDialog.repaint(); + } + dispose(); + } + } + + /** + * Gets the mission panel. + * + * @return the mission panel + */ + public MissionPanel getMissionPanel() { + return missionPanel; + } + + /** + * Gets the state dialog. + * + * @return the state dialog + */ + public StateDialog getStateDialog() { + return stateDialog; + } + + /** + * Creates and shows the dialog. + * + * @param missionsTab the missions tab + * @param demandModel the demand model + */ + public static void createAndShowGUI(MissionPanel missionPanel, I_DemandModel demandModel) { + DemandModelDialog d = new DemandModelDialog(missionPanel, demandModel); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } + + /** + * Creates and shows the dialog. + * + * @param stateDialog the state dialog + * @param demandModel the demand model + */ + public static void createAndShowGUI(StateDialog stateDialog, I_DemandModel demandModel) { + DemandModelDialog d = new DemandModelDialog(stateDialog, demandModel); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/model/DemandModelPanelFactory.java b/src/main/java/edu/mit/spacenet/gui/model/DemandModelPanelFactory.java new file mode 100644 index 0000000..4232a03 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/model/DemandModelPanelFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.model; + +import edu.mit.spacenet.domain.model.CrewConsumablesDemandModel; +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.domain.model.RatedDemandModel; +import edu.mit.spacenet.domain.model.SparingByMassDemandModel; +import edu.mit.spacenet.domain.model.TimedImpulseDemandModel; + +/** + * A factory for creating demand model panels. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class DemandModelPanelFactory { + + /** + * Creates a new DemandModelPanel object. + * + * @param demandModelDialog the demand model dialog + * @param demandModel the demand model + * + * @return the abstract demand model panel + */ + public static AbstractDemandModelPanel createDemandModelPanel(DemandModelDialog demandModelDialog, I_DemandModel demandModel) { + switch(demandModel.getDemandModelType()) { + case CREW_CONSUMABLES: + return new CrewConsumablesDemandModelPanel(demandModelDialog, (CrewConsumablesDemandModel)demandModel); + case TIMED_IMPULSE: + return new TimedImpulseDemandModelPanel(demandModelDialog, (TimedImpulseDemandModel)demandModel); + case RATED: + return new RatedDemandModelPanel(demandModelDialog, (RatedDemandModel)demandModel); + case SPARING_BY_MASS: + return new SparingByMassDemandModelPanel(demandModelDialog, (SparingByMassDemandModel)demandModel); + default: throw new RuntimeException("Unsupported Demand Model"); + } + } + +} diff --git a/src/main/java/edu/mit/spacenet/gui/model/RatedDemandModelPanel.java b/src/main/java/edu/mit/spacenet/gui/model/RatedDemandModelPanel.java new file mode 100644 index 0000000..12bf8fb --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/model/RatedDemandModelPanel.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.model; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.domain.model.RatedDemandModel; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; + +/** + * The panel for viewing and editing rated demand models. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class RatedDemandModelPanel extends AbstractDemandModelPanel { + private static final long serialVersionUID = -966209133130231178L; + + private RatedDemandModel demandModel; + + private DemandTable demandsList; + private JScrollPane demandsScroll; + private JButton btnRemoveDemand; + + /** + * Instantiates a new rated demand model panel. + * + * @param demandModelDialog the demand model dialog + * @param demandModel the demand model + */ + public RatedDemandModelPanel(DemandModelDialog demandModelDialog, + RatedDemandModel demandModel) { + super(demandModelDialog, demandModel); + this.demandModel = demandModel; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Demands: "), c); + + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.gridx = 1; + c.weightx = 1; + c.weighty = 1; + demandsList = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + demandsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + demandsList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(demandsList.getSelectedRows().length >= 1) { + btnRemoveDemand.setEnabled(true); + } else { + btnRemoveDemand.setEnabled(false); + } + } + }); + demandsList.getColumnModel().getColumn(2).setHeaderValue("Amt/Day"); + demandsScroll = new JScrollPane(demandsList); + demandsScroll.setPreferredSize(new Dimension(400,150)); + add(demandsScroll, c); + + c.gridy++; + c.fill = GridBagConstraints.NONE; + c.weighty = 0; + JPanel demandButtonPanel = new JPanel(); + demandButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + add(demandButtonPanel, c); + + JButton btnAddDemand = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_put.png"))); + btnAddDemand.setMargin(new Insets(3,3,3,3)); + btnAddDemand.setToolTipText("Add a Demand"); + btnAddDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + demandsList.addDemand(new Demand()); + } + }); + demandButtonPanel.add(btnAddDemand); + btnRemoveDemand = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_remove.png"))); + btnRemoveDemand.setMargin(new Insets(3,3,3,3)); + btnRemoveDemand.setToolTipText("Remove Demand"); + btnRemoveDemand.setEnabled(false); + btnRemoveDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList demands = new ArrayList(); + for(int row : demandsList.getSelectedRows()) { + demands.add(demandsList.getDemand(row)); + } + for(Demand demand : demands) { + demandsList.remove(demand); + } + } + }); + demandButtonPanel.add(btnRemoveDemand); + } + + /** + * Initializes the panel for a new demand model. + */ + private void initialize() { + demandsList.removeAllDemands(); + for(Demand demand : demandModel.getDemandRates()) { + demandsList.addDemand(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#getDemandModel() + */ + @Override + public RatedDemandModel getDemandModel() { + return demandModel; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#saveDemandModel() + */ + public void saveDemandModel() { + if(demandsList.isEditing()) demandsList.getCellEditor().stopCellEditing(); + demandModel.getDemandRates().clear(); + for(Demand demand : demandsList.getDemands()) { + if(demand.getResource()!=null) + demandModel.getDemandRates().add(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#isDemandModelValid() + */ + @Override + public boolean isDemandModelValid() { + return true; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/model/SparingByMassDemandModelPanel.java b/src/main/java/edu/mit/spacenet/gui/model/SparingByMassDemandModelPanel.java new file mode 100644 index 0000000..722b706 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/model/SparingByMassDemandModelPanel.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.model; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import edu.mit.spacenet.domain.model.SparingByMassDemandModel; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; +import edu.mit.spacenet.gui.component.UnitsWrapper; + +/** + * The panel for viewing and editing sparing by mass demand models. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class SparingByMassDemandModelPanel extends AbstractDemandModelPanel { + private static final long serialVersionUID = -966209133130231178L; + + private SparingByMassDemandModel demandModel; + + private JCheckBox partsListEnabledCheck; + private SpinnerNumberModel unpressRateModel, pressRateModel; + private JSpinner unpressRateSpinner, pressRateSpinner; + private DemandTable demandsTable; + + /** + * Instantiates a new sparing by mass demand model panel. + * + * @param demandModelDialog the demand model dialog + * @param demandModel the demand model + */ + public SparingByMassDemandModelPanel(DemandModelDialog demandModelDialog, + SparingByMassDemandModel demandModel) { + super(demandModelDialog, demandModel); + this.demandModel = demandModel; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.gridwidth = 2; + c.fill = GridBagConstraints.HORIZONTAL; + partsListEnabledCheck = new JCheckBox("Use element parts to generate spares resource types"); + partsListEnabledCheck.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + updateDemands(); + } + }); + add(partsListEnabledCheck, c); + partsListEnabledCheck.setToolTipText("Use part applications to guide the resource types of demanded spares"); + + c.gridy++; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Unpress. Rate: "), c); + c.gridy++; + add(new JLabel("Press. Rate: "), c); + c.gridy++; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Annual Demands: "), c); + + c.gridx++; + c.gridy = 1; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + unpressRateModel = new SpinnerNumberModel(0.00,0.00,1000,.5); + unpressRateSpinner = new JSpinner(unpressRateModel); + unpressRateSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + updateDemands(); + } + }); + add(new UnitsWrapper(unpressRateSpinner, "% mass / year"), c); + unpressRateSpinner.setToolTipText("Unpressurized spares demands per year [percent]"); + + c.gridy++; + pressRateModel = new SpinnerNumberModel(0.00,0.00,1000,.5); + pressRateSpinner = new JSpinner(pressRateModel); + pressRateSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + updateDemands(); + } + }); + add(new UnitsWrapper(pressRateSpinner, "% mass / year"), c); + pressRateSpinner.setToolTipText("Pressurized spares demands per year [percent]"); + + c.gridy++; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + demandsTable = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + demandsTable.setEnabled(false); + JScrollPane demandsScroll = new JScrollPane(demandsTable); + demandsScroll.setPreferredSize(new Dimension(400,100)); + add(demandsScroll, c); + } + + /** + * Update demands. + */ + private void updateDemands() { + demandsTable.removeAllDemands(); + for(Demand demand : demandModel.generateDemands(365.25, + pressRateModel.getNumber().doubleValue()/100d, + unpressRateModel.getNumber().doubleValue()/100d, + partsListEnabledCheck.isSelected())) { + demandsTable.addDemand(demand); + } + repaint(); + } + + /** + * Initializes the panel for a new demand model. + */ + private void initialize() { + demandModel.setElement(getDemandModelDialog().getStateDialog().getElementDialog().getElement()); + unpressRateModel.setValue(demandModel.getUnpressurizedSparesRate()*100); + pressRateModel.setValue(demandModel.getPressurizedSparesRate()*100); + partsListEnabledCheck.setSelected(demandModel.isPartsListEnabled()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#getDemandModel() + */ + public SparingByMassDemandModel getDemandModel() { + return demandModel; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#saveDemandModel() + */ + public void saveDemandModel() { + demandModel.setElement(getDemandModelDialog().getStateDialog().getElementDialog().getElement()); + demandModel.setUnpressurizedSparesRate(unpressRateModel.getNumber().doubleValue()/100d); + demandModel.setPressurizedSparesRate(pressRateModel.getNumber().doubleValue()/100d); + demandModel.setPartsListEnabled(partsListEnabledCheck.isSelected()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#isDemandModelValid() + */ + @Override + public boolean isDemandModelValid() { + return true; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/model/TimedImpulseDemandModelPanel.java b/src/main/java/edu/mit/spacenet/gui/model/TimedImpulseDemandModelPanel.java new file mode 100644 index 0000000..6a77aa2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/model/TimedImpulseDemandModelPanel.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.model; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.domain.model.TimedImpulseDemandModel; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.gui.component.DemandTable; + +/** + * The panel for viewing and editing timed impulse demand models. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class TimedImpulseDemandModelPanel extends AbstractDemandModelPanel { + private static final long serialVersionUID = -966209133130231178L; + + private TimedImpulseDemandModel demandModel; + + private DemandTable demandsList; + private JScrollPane demandsScroll; + private JButton btnRemoveDemand; + + /** + * Instantiates a new timed impulse demand model panel. + * + * @param demandModelDialog the demand model dialog + * @param demandModel the demand model + */ + public TimedImpulseDemandModelPanel(DemandModelDialog demandModelDialog, + TimedImpulseDemandModel demandModel) { + super(demandModelDialog, demandModel); + this.demandModel = demandModel; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel() { + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 1; + c.anchor = GridBagConstraints.FIRST_LINE_END; + add(new JLabel("Demands: "), c); + + c.gridx = 1; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.weighty = 1; + demandsList = new DemandTable(SpaceNetFrame.getInstance().getScenarioPanel().getScenario().getDataSource().getResourceLibrary()); + demandsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + demandsList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(demandsList.getSelectedRows().length >= 1) { + btnRemoveDemand.setEnabled(true); + } else { + btnRemoveDemand.setEnabled(false); + } + } + }); + demandsScroll = new JScrollPane(demandsList); + demandsScroll.setPreferredSize(new Dimension(400,150)); + add(demandsScroll, c); + + c.gridy++; + c.fill = GridBagConstraints.NONE; + c.weighty = 0; + JPanel demandButtonPanel = new JPanel(); + demandButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + add(demandButtonPanel, c); + + JButton btnAddDemand = new JButton("Add", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_put.png"))); + btnAddDemand.setToolTipText("Add a Demand"); + btnAddDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + demandsList.addDemand(new Demand()); + } + }); + demandButtonPanel.add(btnAddDemand); + btnRemoveDemand = new JButton("Remove", new ImageIcon(getClass().getClassLoader().getResource("icons/basket_remove.png"))); + btnRemoveDemand.setToolTipText("Remove Demand"); + btnRemoveDemand.setEnabled(false); + btnRemoveDemand.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ArrayList demands = new ArrayList(); + for(int row : demandsList.getSelectedRows()) { + demands.add(demandsList.getDemand(row)); + } + for(Demand demand : demands) { + demandsList.remove(demand); + } + } + }); + demandButtonPanel.add(btnRemoveDemand); + } + + /** + * Initializes the panel for a new demand model. + */ + private void initialize() { + demandsList.removeAllDemands(); + for(Demand demand : demandModel.getDemands()) { + demandsList.addDemand(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#getDemandModel() + */ + public TimedImpulseDemandModel getDemandModel() { + return demandModel; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#saveDemandModel() + */ + public void saveDemandModel() { + if(demandsList.isEditing()) demandsList.getCellEditor().stopCellEditing(); + demandModel.getDemands().clear(); + for(Demand demand : demandsList.getDemands()) { + if(demand.getResource()!=null) + demandModel.getDemands().add(demand); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.gui.model.AbstractDemandModelPanel#isDemandModelValid() + */ + @Override + public boolean isDemandModelValid() { + return true; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/network/EdgeDetailsPanel.java b/src/main/java/edu/mit/spacenet/gui/network/EdgeDetailsPanel.java new file mode 100644 index 0000000..e456737 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/network/EdgeDetailsPanel.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.network; + +import java.awt.CardLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.gui.component.UnitsWrapper; + +/** + * A custom JPanel that displays the details (both generic and class-specific) + * for an edge. + * + * @author Paul Grogan + */ +public class EdgeDetailsPanel extends JPanel { + private static final long serialVersionUID = 5485329322200614498L; + private static String NO_EDGE = "No Edge Panel"; + private static String SURFACE_EDGE = "Surface Edge Panel"; + private static String SPACE_EDGE = "Space Edge Panel"; + private static String FLIGHT_EDGE = "Flight Edge Panel"; + + private JLabel titleLabel, nodesLabel, descriptionLabel, distanceLabel, + spaceDurationLabel, flightDurationLabel, maxCrewLabel, maxCargoLabel; + private JPanel edgeDetailsPanel, surfaceEdgeDetailsPanel, + spaceEdgeDetailsPanel, flightEdgeDetailsPanel; + + /** + * Instantiates a new edge details panel. + */ + public EdgeDetailsPanel() { + setBorder(BorderFactory.createTitledBorder("Edge Details")); + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; + titleLabel = new JLabel(); + add(titleLabel, c); + c.gridy++; + nodesLabel = new JLabel(); + add(nodesLabel, c); + c.gridy++; + descriptionLabel = new JLabel(); + add(descriptionLabel, c); + c.gridy++; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + edgeDetailsPanel = new JPanel(); + edgeDetailsPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + edgeDetailsPanel.setLayout(new CardLayout()); + edgeDetailsPanel.add(new JPanel(), NO_EDGE); + surfaceEdgeDetailsPanel = new JPanel(); + surfaceEdgeDetailsPanel.setLayout(new GridBagLayout()); + { + GridBagConstraints g = new GridBagConstraints(); + g.gridx = 0; + g.gridy = 0; + g.fill = GridBagConstraints.NONE; + g.anchor = GridBagConstraints.LINE_END; + surfaceEdgeDetailsPanel.add(new JLabel("Distance: "), g); + g.gridy = 0; + g.gridx++; + g.weightx = 1; + g.anchor = GridBagConstraints.LINE_START; + distanceLabel = new JLabel(); + surfaceEdgeDetailsPanel.add(new UnitsWrapper(distanceLabel, "km"), g); + g.gridy++; + g.weighty = 1; + surfaceEdgeDetailsPanel.add(new JPanel(), g); + } + edgeDetailsPanel.add(surfaceEdgeDetailsPanel, SURFACE_EDGE); + spaceEdgeDetailsPanel = new JPanel(); + spaceEdgeDetailsPanel.setLayout(new GridBagLayout()); + { + GridBagConstraints g = new GridBagConstraints(); + g.gridx = 0; + g.gridy = 0; + g.fill = GridBagConstraints.NONE; + g.anchor = GridBagConstraints.LINE_END; + spaceEdgeDetailsPanel.add(new JLabel("Duration: "), g); + g.gridy++; + //TODO add burns label + g.gridy = 0; + g.gridx++; + g.weightx = 1; + g.anchor = GridBagConstraints.LINE_START; + spaceDurationLabel = new JLabel(); + spaceEdgeDetailsPanel.add(new UnitsWrapper(spaceDurationLabel, "days"), g); + g.gridy++; + //TODO: add list of burns label + g.gridy++; + g.weighty = 1; + spaceEdgeDetailsPanel.add(new JPanel(), g); + } + edgeDetailsPanel.add(spaceEdgeDetailsPanel, SPACE_EDGE); + flightEdgeDetailsPanel = new JPanel(); + flightEdgeDetailsPanel.setLayout(new GridBagLayout()); + { + GridBagConstraints g = new GridBagConstraints(); + g.gridx = 0; + g.gridy = 0; + g.fill = GridBagConstraints.NONE; + g.anchor = GridBagConstraints.LINE_END; + flightEdgeDetailsPanel.add(new JLabel("Duration: "), g); + g.gridy++; + flightEdgeDetailsPanel.add(new JLabel("Max Crew: "), g); + g.gridy++; + flightEdgeDetailsPanel.add(new JLabel("Max Cargo: "), g); + g.gridy = 0; + g.gridx++; + g.weightx = 1; + g.anchor = GridBagConstraints.LINE_START; + flightDurationLabel = new JLabel(); + flightEdgeDetailsPanel.add(new UnitsWrapper(flightDurationLabel, "days"), g); + g.gridy++; + maxCrewLabel = new JLabel(); + flightEdgeDetailsPanel.add(maxCrewLabel, g); + g.gridy++; + maxCargoLabel = new JLabel(); + flightEdgeDetailsPanel.add(new UnitsWrapper(maxCargoLabel, "kg"), g); + g.gridy++; + g.weighty = 1; + flightEdgeDetailsPanel.add(new JPanel(), g); + } + edgeDetailsPanel.add(flightEdgeDetailsPanel, FLIGHT_EDGE); + add(edgeDetailsPanel, c); + } + + /** + * Updates the display for a new edge, clears if null is passed. + * + * @param edge the new edge + */ + public void setEdge(Edge edge) { + if(edge==null) { + titleLabel.setText(""); + nodesLabel.setText(""); + descriptionLabel.setText(""); + } else { + titleLabel.setText(edge.getName() + " (" + edge.getEdgeType() + " Edge)"); + nodesLabel.setText(edge.getOrigin() + " to " + edge.getDestination()); + descriptionLabel.setText(edge.getDescription()); + switch(edge.getEdgeType()) { + case SURFACE: + ((CardLayout)edgeDetailsPanel.getLayout()).show(edgeDetailsPanel, SURFACE_EDGE); + distanceLabel.setText("" + ((SurfaceEdge)edge).getDistance()); + break; + case SPACE: + ((CardLayout)edgeDetailsPanel.getLayout()).show(edgeDetailsPanel, SPACE_EDGE); + spaceDurationLabel.setText("" + ((SpaceEdge)edge).getDuration()); + //TODO: add burns list + break; + case FLIGHT: + ((CardLayout)edgeDetailsPanel.getLayout()).show(edgeDetailsPanel, FLIGHT_EDGE); + flightDurationLabel.setText("" + ((FlightEdge)edge).getDuration()); + maxCrewLabel.setText("" + ((FlightEdge)edge).getMaxCrewSize()); + maxCargoLabel.setText("" + ((FlightEdge)edge).getMaxCargoMass()); + break; + default: + ((CardLayout)edgeDetailsPanel.getLayout()).show(edgeDetailsPanel, NO_EDGE); + } + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/network/EdgeTable.java b/src/main/java/edu/mit/spacenet/gui/network/EdgeTable.java new file mode 100644 index 0000000..52189c2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/network/EdgeTable.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.network; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.List; + +import javax.swing.DefaultListModel; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.renderer.EdgeTableCellRenderer; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; + +/** + * A table to view and toggle the inclusion of edges in the scenario network. + * + * @author Paul Grogan + */ +public class EdgeTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + + private CustomTableModel model; + private NetworkTab networkTab; + + /** + * Instantiates a new edge table. + * + * @param networkTab the network tab + */ + public EdgeTable(NetworkTab networkTab) { + super(); + this.networkTab = networkTab; + + model = new CustomTableModel(); + setModel(model); + DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); + renderer.setHorizontalAlignment(DefaultTableCellRenderer.CENTER); + getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + getColumnModel().getColumn(0).setMaxWidth(25); + getColumnModel().getColumn(1).setHeaderValue("Name"); + getColumnModel().getColumn(1).setCellRenderer(new EdgeTableCellRenderer()); + getColumnModel().getColumn(2).setHeaderValue("Orig."); + getColumnModel().getColumn(2).setCellRenderer(renderer); + getColumnModel().getColumn(2).setMaxWidth(45); + getColumnModel().getColumn(3).setHeaderValue("Dest."); + getColumnModel().getColumn(3).setCellRenderer(renderer); + getColumnModel().getColumn(3).setMaxWidth(45); + + getTableHeader().setReorderingAllowed(false); + } + + /** + * Initializes the edge table to a new scenario. + */ + public void initialize() { + ((CustomTableModel)getModel()).setScenario(networkTab.getScenario()); + } + + /** + * Update view. + */ + public void updateView() { + model.fireTableDataChanged(); + } + + /** + * Check all edges. + */ + public void checkAll() { + for(int i=0; i getColumnClass(int col) { + if(col==0) return Boolean.class; + else if(col==2||col==3) return Node.class; + else return Edge.class; + } + public Object getValueAt(int row, int col) { + if(col==0) { + Edge edge = (Edge)getValueAt(row, 1); + for(Edge e : scenario.getNetwork().getEdges()) { + if(e.equals(edge)) return true; + } + return false; + } + else if(col==2) return ((Edge)getValueAt(row, 1)).getOrigin(); + else if(col==3) return ((Edge)getValueAt(row, 1)).getDestination(); + else { + int count = 0; + for(Edge edge : scenario.getDataSource().getEdgeLibrary()) { + if((networkTab.getEdgeTypeFilter()==null||edge.getEdgeType()==networkTab.getEdgeTypeFilter()) + && edge.getName().toLowerCase().contains(networkTab.getEdgeSearchText().toLowerCase())) { + if(count==row) return edge; + count++; + } + } + return null; + } + } + public void setValueAt(Object value, int row, int col) { + if(col==0) { + Edge edge = (Edge)getValueAt(row,1); + if(value.equals(Boolean.TRUE)) { + scenario.getNetwork().getEdges().add(edge); + for(Node node : scenario.getDataSource().getNodeLibrary()) { + if(!scenario.getNetwork().getNodes().contains(node) + && (edge.getOrigin().equals(node) + || edge.getDestination().equals(node))) { + scenario.getNetwork().getNodes().add(node); + } + } + } else { + List uses = networkTab.getScenario().getEdgeUses(edge); + if(uses.size() > 0) { + JPanel warningPanel = new JPanel(); + warningPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + warningPanel.add(new JLabel("The following use " + edge + " and must be changed before removal:"), c); + c.gridy++; + c.weighty = 1; + DefaultListModel usagesList = new DefaultListModel(); + for(Object o : uses) { + usagesList.addElement(o); + } + warningPanel.add(new JScrollPane(new JList(usagesList)), c); + JOptionPane.showMessageDialog(networkTab.getScenarioPanel(), warningPanel, "SpaceNet Warning", JOptionPane.WARNING_MESSAGE); + } else { + scenario.getNetwork().remove(edge); + } + } + } + fireTableRowsUpdated(row, row); + networkTab.getNetworkPanel().repaint(); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/network/NetworkTab.java b/src/main/java/edu/mit/spacenet/gui/network/NetworkTab.java new file mode 100644 index 0000000..89c2910 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/network/NetworkTab.java @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.network; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.EdgeType; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.NodeType; +import edu.mit.spacenet.gui.ScenarioPanel; +import edu.mit.spacenet.gui.command.FilterNetworkCommand; +import edu.mit.spacenet.gui.component.SearchTextField; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.gui.visualization.NetworkPanel; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.scenario.ScenarioType; + +/** + * The tab component to view and edit the scenario network. + * + * @author Paul Grogan + */ +public class NetworkTab extends JSplitPane { + private static final long serialVersionUID = 5930409573819745343L; + private static String NODE_DETAILS = "Node Details Panel"; + private static String EDGE_DETAILS = "Edge Details Panel"; + + private JComboBox scenarioTypeCombo, nodeTypeCombo, edgeTypeCombo; + private JTabbedPane locationSelectionTabbedPane; + private JPanel nodeSelectionPanel, edgeSelectionPanel; + private SearchTextField nodeSearchText, edgeSearchText; + private NodeTable nodeTable; + private EdgeTable edgeTable; + private JPanel detailsPanel; + private NodeDetailsPanel nodeDetailsPanel; + private EdgeDetailsPanel edgeDetailsPanel; + + private NetworkPanel networkPanel; + + private JCheckBox drawOrbitalLimitsCheck, simpleModeCheck, + displaySunCheck, blackBackgroundCheck; + + private ScenarioPanel scenarioPanel; + + /** + * Instantiates a new network tab. + * + * @param scenarioPanel the scenario panel + */ + public NetworkTab(ScenarioPanel scenarioPanel) { + this.scenarioPanel = scenarioPanel; + + buildControlPanel(); + buildDisplayPanel(); + + setResizeWeight(0); + setDividerLocation(250); + setBorder(BorderFactory.createEmptyBorder()); + + initialize(); + } + private void buildControlPanel() { + JPanel controlPanel = new JPanel(); + controlPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + controlPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + controlPanel.add(new JLabel("Scenario Type: "), c); + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + scenarioTypeCombo = new JComboBox(); + for(ScenarioType type : ScenarioType.values()) { + scenarioTypeCombo.addItem(type); + } + scenarioTypeCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -2255885956722142642L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setIcon(((ScenarioType)value).getIcon()); + return this; + } + }); + scenarioTypeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(getScenario().getScenarioType()!=scenarioTypeCombo.getSelectedItem()) { + getScenario().setScenarioType((ScenarioType)scenarioTypeCombo.getSelectedItem()); + FilterNetworkCommand command = new FilterNetworkCommand(getScenario()); + command.execute(); + updateView(); + } + } + }); + controlPanel.add(scenarioTypeCombo, c); + c.gridx = 0; + c.gridy++; + c.gridwidth = 2; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + locationSelectionTabbedPane = new JTabbedPane(); + + nodeSelectionPanel = new JPanel(); + nodeSelectionPanel.setLayout(new BorderLayout()); + JPanel nodeSearchPanel = new JPanel(); + nodeSearchPanel.setLayout(new BoxLayout(nodeSearchPanel, BoxLayout.LINE_AXIS)); + nodeSearchText = new SearchTextField("Enter Search Term"); + nodeSearchText.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent e) { + nodeTable.updateView(); + } + }); + nodeSearchPanel.add(nodeSearchText); + nodeTypeCombo = new JComboBox(); + nodeTypeCombo.addItem("All"); + for(NodeType type : NodeType.values()) { + nodeTypeCombo.addItem(type); + } + nodeTypeCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -2255885956722142642L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof NodeType) setIcon(((NodeType)value).getIcon()); + return this; + } + }); + nodeTypeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + nodeTable.updateView(); + } + }); + nodeSearchPanel.add(nodeTypeCombo); + nodeSelectionPanel.add(nodeSearchPanel, BorderLayout.NORTH); + nodeTable = new NodeTable(this); + nodeTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(nodeTable.getSelectedRow()>=0) { + networkPanel.getNetworkLayer().getSelectedEdges().clear(); + networkPanel.getNetworkLayer().getSelectedNodes().clear(); + for(int row : nodeTable.getSelectedRows()) { + networkPanel.getNetworkLayer().getSelectedNodes().add(((Node)nodeTable.getModel().getValueAt(row, 1)).getTid()); + } + networkPanel.repaint(); + } + if(nodeTable.getSelectedRows().length == 1) { + nodeDetailsPanel.setNode((Node)nodeTable.getModel().getValueAt(nodeTable.getSelectedRow(), 1)); + } else { + nodeDetailsPanel.setNode(null); + } + } + }); + JScrollPane nodeScroll = new JScrollPane(nodeTable); + nodeScroll.setPreferredSize(new Dimension(150,300)); + nodeSelectionPanel.add(nodeScroll, BorderLayout.CENTER); + JPanel nodeButtonPanel = new JPanel(); + nodeButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllNodesButton = new JButton("Select All"); + selectAllNodesButton.setToolTipText("Select All Nodes"); + selectAllNodesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + nodeTable.checkAll(); + } + }); + nodeButtonPanel.add(selectAllNodesButton); + JButton deselectAllNodesButton = new JButton("Deselect All"); + deselectAllNodesButton.setToolTipText("Deselect All Nodes"); + deselectAllNodesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + nodeTable.uncheckAll(); + } + }); + nodeButtonPanel.add(deselectAllNodesButton); + nodeSelectionPanel.add(nodeButtonPanel, BorderLayout.SOUTH); + locationSelectionTabbedPane.add(nodeSelectionPanel, "Nodes"); + + edgeSelectionPanel = new JPanel(); + edgeSelectionPanel.setLayout(new BorderLayout()); + JPanel edgeSearchPanel = new JPanel(); + edgeSearchPanel.setLayout(new BoxLayout(edgeSearchPanel, BoxLayout.LINE_AXIS)); + edgeSearchText = new SearchTextField("Enter Search Term"); + edgeSearchText.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent e) { + edgeTable.updateView(); + } + }); + edgeSearchPanel.add(edgeSearchText); + edgeTypeCombo = new JComboBox(); + edgeTypeCombo.addItem("All"); + for(EdgeType type : EdgeType.values()) { + if(type!=EdgeType.TIME_DEPENDENT) + edgeTypeCombo.addItem(type); + } + edgeTypeCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -2255885956722142642L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof EdgeType) setIcon(((EdgeType)value).getIcon()); + return this; + } + }); + edgeTypeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + edgeTable.updateView(); + } + }); + edgeSearchPanel.add(edgeTypeCombo); + edgeSelectionPanel.add(edgeSearchPanel, BorderLayout.NORTH); + edgeTable = new EdgeTable(this); + edgeTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + if(edgeTable.getSelectedRow()>=0) { + networkPanel.getNetworkLayer().getSelectedEdges().clear(); + networkPanel.getNetworkLayer().getSelectedNodes().clear(); + for(int row : edgeTable.getSelectedRows()) { + networkPanel.getNetworkLayer().getSelectedEdges().add(((Edge)edgeTable.getModel().getValueAt(row, 1)).getTid()); + } + networkPanel.repaint(); + } + if(edgeTable.getSelectedRows().length == 1) { + edgeDetailsPanel.setEdge((Edge)edgeTable.getModel().getValueAt(edgeTable.getSelectedRow(), 1)); + } else { + edgeDetailsPanel.setEdge(null); + } + } + }); + JScrollPane edgeScroll = new JScrollPane(edgeTable); + edgeScroll.setPreferredSize(new Dimension(150,300)); + edgeSelectionPanel.add(edgeScroll, BorderLayout.CENTER); + JPanel edgeButtonPanel = new JPanel(); + edgeButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllEdgesButton = new JButton("Select All"); + selectAllEdgesButton.setToolTipText("Select All Edges"); + selectAllEdgesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + edgeTable.checkAll(); + } + }); + edgeButtonPanel.add(selectAllEdgesButton); + JButton deselectAllEdgesButton = new JButton("Deselect All"); + deselectAllEdgesButton.setToolTipText("Deselect All Edges"); + deselectAllEdgesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + edgeTable.uncheckAll(); + } + }); + edgeButtonPanel.add(deselectAllEdgesButton); + edgeSelectionPanel.add(edgeButtonPanel, BorderLayout.SOUTH); + locationSelectionTabbedPane.add(edgeSelectionPanel, "Edges"); + controlPanel.add(locationSelectionTabbedPane, c); + + c.gridy++; + detailsPanel = new JPanel(); + detailsPanel.setLayout(new CardLayout()); + nodeDetailsPanel = new NodeDetailsPanel(); + detailsPanel.add(nodeDetailsPanel, NODE_DETAILS); + edgeDetailsPanel = new EdgeDetailsPanel(); + detailsPanel.add(edgeDetailsPanel, EDGE_DETAILS); + + locationSelectionTabbedPane.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + if(locationSelectionTabbedPane.getSelectedIndex()==0) { + ((CardLayout)detailsPanel.getLayout()).show(detailsPanel, NODE_DETAILS); + edgeTable.clearSelection(); + } else { + ((CardLayout)detailsPanel.getLayout()).show(detailsPanel, EDGE_DETAILS); + nodeTable.clearSelection(); + } + } + }); + + controlPanel.add(detailsPanel, c); + + setLeftComponent(new JScrollPane(controlPanel)); + } + + /** + * Builds the display panel. + */ + private void buildDisplayPanel() { + JSplitPane displayPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + networkPanel = new NetworkPanel(); + networkPanel.setPreferredSize(new Dimension(600,400)); + displayPanel.setTopComponent(new JScrollPane(networkPanel)); + displayPanel.setResizeWeight(1); + + JPanel displayOptionsPanel = new JPanel(); + displayOptionsPanel.setLayout(new BoxLayout(displayOptionsPanel, BoxLayout.LINE_AXIS)); + JPanel bodyOptionsPanel = new JPanel(); + bodyOptionsPanel.setBorder(BorderFactory.createTitledBorder("Body Display Options")); + bodyOptionsPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.insets = new Insets(2,2,2,2); + c.anchor = GridBagConstraints.LINE_END; + bodyOptionsPanel.add(new JLabel("Size Scaling:"), c); + c.gridy++; + bodyOptionsPanel.add(new JLabel("Size Basis:"), c); + c.gridy++; + bodyOptionsPanel.add(new JLabel("Size Disparity:"), c); + c.gridx+=2; + c.gridy = 0; + bodyOptionsPanel.add(new JLabel("Position Scaling:"), c); + c.gridy++; + bodyOptionsPanel.add(new JLabel("Position Basis:"), c); + c.gridy++; + bodyOptionsPanel.add(new JLabel("Position Disparity:"), c); + c.gridy = 0; + c.gridx = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + final SpinnerNumberModel sizeScalingModel = new SpinnerNumberModel(networkPanel.getBodyLayer().getSizeScale(), 0, Double.MAX_VALUE, 0.1); + final JSpinner sizeScalingSpinner = new JSpinner(sizeScalingModel); + sizeScalingSpinner.setPreferredSize(new Dimension(60,20)); + sizeScalingSpinner.setToolTipText("A parameter that controls the rate of size increase."); + sizeScalingSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getBodyLayer().setSizeScale(sizeScalingModel.getNumber().doubleValue()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(sizeScalingSpinner, c); + c.gridy++; + final SpinnerNumberModel sizeBasisModel = new SpinnerNumberModel(networkPanel.getBodyLayer().getSizeBasis(), 0, Double.MAX_VALUE, 0.1); + final JSpinner sizeBasisSpinner = new JSpinner(sizeBasisModel); + sizeBasisSpinner.setPreferredSize(new Dimension(60,20)); + sizeBasisSpinner.setToolTipText("A parameter that sets the median size (units of Earth diameters)."); + sizeBasisSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getBodyLayer().setSizeBasis(sizeBasisModel.getNumber().doubleValue()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(sizeBasisSpinner, c); + c.gridy++; + final SpinnerNumberModel sizeDisparityModel = new SpinnerNumberModel(networkPanel.getBodyLayer().getSizeDisparity(), 1.0, Double.MAX_VALUE, 0.1); + final JSpinner sizeDisparitySpinner = new JSpinner(sizeDisparityModel); + sizeDisparitySpinner.setPreferredSize(new Dimension(60,20)); + sizeDisparitySpinner.setToolTipText("A parameter that sets the maximum difference between the largest and smallest sizes."); + sizeDisparitySpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getBodyLayer().setSizeDisparity(sizeDisparityModel.getNumber().doubleValue()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(sizeDisparitySpinner, c); + c.gridy=0; + c.gridx+=2; + final SpinnerNumberModel locationScalingModel = new SpinnerNumberModel(networkPanel.getBodyLayer().getLocationScale(), 0, Double.MAX_VALUE, 0.1); + final JSpinner locationScalingSpinner = new JSpinner(locationScalingModel); + locationScalingSpinner.setPreferredSize(new Dimension(60,20)); + locationScalingSpinner.setToolTipText("A parameter that controls the rate of distance increase."); + locationScalingSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getBodyLayer().setLocationScale(locationScalingModel.getNumber().doubleValue()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(locationScalingSpinner, c); + c.gridy++; + final SpinnerNumberModel locationBasisModel = new SpinnerNumberModel(networkPanel.getBodyLayer().getLocationBasis(), 0, Double.MAX_VALUE, 0.1); + final JSpinner locationBasisSpinner = new JSpinner(locationBasisModel); + locationBasisSpinner.setPreferredSize(new Dimension(60,20)); + locationBasisSpinner.setToolTipText("A parameter that sets the median distance (units of AU)."); + locationBasisSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getBodyLayer().setLocationBasis(locationBasisModel.getNumber().doubleValue()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(locationBasisSpinner, c); + c.gridy++; + final SpinnerNumberModel locationDisparityModel = new SpinnerNumberModel(networkPanel.getBodyLayer().getLocationDisparity(), 1.0, Double.MAX_VALUE, 0.1); + final JSpinner locationDisparitySpinner = new JSpinner(locationDisparityModel); + locationDisparitySpinner.setPreferredSize(new Dimension(60,20)); + locationDisparitySpinner.setToolTipText("A parameter that sets the maximum difference between the largest and smallest distances."); + locationDisparitySpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getBodyLayer().setLocationDisparity(locationDisparityModel.getNumber().doubleValue()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(locationDisparitySpinner, c); + c.gridy=0; + c.gridx++; + drawOrbitalLimitsCheck = new JCheckBox("Draw Orbital Limits"); + drawOrbitalLimitsCheck.setSelected(networkPanel.getBodyLayer().isDrawOrbitalLimits()); + drawOrbitalLimitsCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + networkPanel.getBodyLayer().setDrawOrbitalLimits(drawOrbitalLimitsCheck.isSelected()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(drawOrbitalLimitsCheck, c); + c.gridy++; + simpleModeCheck = new JCheckBox("Inline Moon Mode"); + simpleModeCheck.setSelected(networkPanel.getBodyLayer().isSimpleMode()); + simpleModeCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + displaySunCheck.setEnabled(!simpleModeCheck.isSelected()); + if(simpleModeCheck.isSelected() && displaySunCheck.isSelected()) { + displaySunCheck.setSelected(false); + } + networkPanel.getBodyLayer().setSimpleMode(simpleModeCheck.isSelected()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(simpleModeCheck, c); + c.gridy++; + displaySunCheck = new JCheckBox("Display Sun"); + displaySunCheck.setEnabled(!networkPanel.getBodyLayer().isSimpleMode()); + displaySunCheck.setSelected(!networkPanel.getBodyLayer().isSimpleMode() + && networkPanel.getBodyLayer().isDisplaySun()); + displaySunCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + networkPanel.getBodyLayer().setDisplaySun(displaySunCheck.isSelected()); + networkPanel.repaint(); + } + }); + bodyOptionsPanel.add(displaySunCheck, c); + displayOptionsPanel.add(bodyOptionsPanel); + + JPanel networkOptionsPanel = new JPanel(); + networkOptionsPanel.setBorder(BorderFactory.createTitledBorder("Network Display Options")); + networkOptionsPanel.setLayout(new GridBagLayout()); + c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + networkOptionsPanel.add(new JLabel("Altitude Scaling:"), c); + c.gridy++; + networkOptionsPanel.add(new JLabel("Altitude Basis:"), c); + c.gridy=0; + c.gridx+=2; + networkOptionsPanel.add(new JLabel("Node Size:"), c); + c.gridy++; + networkOptionsPanel.add(new JLabel("Edge Width:"), c); + c.gridy = 0; + c.gridx = 1;; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; + c.weightx = 1; + final SpinnerNumberModel altitudeScalingModel = new SpinnerNumberModel(1/networkPanel.getNetworkLayer().getAltitudeScale(), 0.5, Double.MAX_VALUE, 0.5); + final JSpinner altitudeScalingSpinner = new JSpinner(altitudeScalingModel); + altitudeScalingSpinner.setPreferredSize(new Dimension(60,20)); + altitudeScalingSpinner.setToolTipText("A parameter that controls the rate of distance increase for orbital altitude."); + altitudeScalingSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getNetworkLayer().setAltitudeScale(1/altitudeScalingModel.getNumber().doubleValue()); + networkPanel.repaint(); + } + }); + networkOptionsPanel.add(altitudeScalingSpinner, c); + c.gridy++; + final SpinnerNumberModel altitudeBasisModel = new SpinnerNumberModel(networkPanel.getNetworkLayer().getAltitudeBasis(), 0, Double.MAX_VALUE, 0.5); + final JSpinner altitudeBasisSpinner = new JSpinner(altitudeBasisModel); + altitudeBasisSpinner.setPreferredSize(new Dimension(60,20)); + altitudeBasisSpinner.setToolTipText("A parameter that sets the median altitude (units of kilometers)."); + altitudeBasisSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getNetworkLayer().setAltitudeBasis(altitudeBasisModel.getNumber().doubleValue()); + networkPanel.repaint(); + } + }); + networkOptionsPanel.add(altitudeBasisSpinner, c); + c.gridy=0; + c.gridx+=2; + final SpinnerNumberModel nodeSizeModel = new SpinnerNumberModel(networkPanel.getNetworkLayer().getNodeSize(), 0, 32, 4); + final JSpinner nodeSizeSpinner = new JSpinner(nodeSizeModel); + nodeSizeSpinner.setPreferredSize(new Dimension(60,20)); + nodeSizeSpinner.setToolTipText("A parameter that sets the node size (pixels)."); + nodeSizeSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getNetworkLayer().setNodeSize(nodeSizeModel.getNumber().intValue()); + networkPanel.repaint(); + } + }); + networkOptionsPanel.add(new UnitsWrapper(nodeSizeSpinner, "px"), c); + c.gridy++; + final SpinnerNumberModel edgeWidthModel = new SpinnerNumberModel(networkPanel.getNetworkLayer().getEdgeWidth(), 1, 5, 1); + final JSpinner edgeWidthSpinner = new JSpinner(edgeWidthModel); + edgeWidthSpinner.setPreferredSize(new Dimension(60,20)); + edgeWidthSpinner.setToolTipText("A parameter that sets the edge width (pixels)."); + edgeWidthSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + networkPanel.getNetworkLayer().setEdgeWidth(edgeWidthModel.getNumber().intValue()); + networkPanel.repaint(); + } + }); + networkOptionsPanel.add(new UnitsWrapper(edgeWidthSpinner, "px"), c); + c.gridy++; + c.gridx = 0; + c.gridwidth = 4; + blackBackgroundCheck = new JCheckBox("Draw Black Background"); + blackBackgroundCheck.setSelected(networkPanel.isBlackBackground()); + blackBackgroundCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + networkPanel.setBlackBackground(blackBackgroundCheck.isSelected()); + networkPanel.repaint(); + } + }); + networkOptionsPanel.add(blackBackgroundCheck, c); + displayOptionsPanel.add(networkOptionsPanel); + + + displayPanel.setBottomComponent(displayOptionsPanel); + displayPanel.setBorder(BorderFactory.createEmptyBorder()); + displayPanel.setDividerSize(5); + displayPanel.setLastDividerLocation(425); + displayPanel.setDividerLocation(1000); + displayPanel.setOneTouchExpandable(true); + displayPanel.setResizeWeight(1); + setRightComponent(displayPanel); + } + + /** + * Initializes the network tab by enabling/disabling components and setting + * initial values. + */ + public void initialize() { + scenarioTypeCombo.setEnabled(getScenario()!=null); + nodeSearchText.setEnabled(getScenario()!=null); + nodeTypeCombo.setEnabled(getScenario()!=null); + nodeTable.setEnabled(getScenario()!=null); + edgeSearchText.setEnabled(getScenario()!=null); + edgeTypeCombo.setEnabled(getScenario()!=null); + edgeTable.setEnabled(getScenario()!=null); + if(getScenario()!=null) { + scenarioTypeCombo.setSelectedItem(getScenario().getScenarioType()); + nodeTable.initialize(); + edgeTable.initialize(); + networkPanel.setNetwork(getScenario().getNetwork()); + } + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return scenarioPanel.getScenario(); + } + + /** + * Gets the scenario panel. + * + * @return the scenario panel + */ + public ScenarioPanel getScenarioPanel() { + return scenarioPanel; + } + + /** + * Gets the network panel. + * + * @return the network panel + */ + public NetworkPanel getNetworkPanel() { + return networkPanel; + } + + /** + * Update view. + */ + public void updateView() { + nodeTable.updateView(); + edgeTable.updateView(); + networkPanel.repaint(); + } + + /** + * Gets the node search text. + * + * @return the node search text + */ + public String getNodeSearchText() { + if(nodeSearchText.getText().equals(nodeSearchText.getDefaultText())) + return ""; + else return nodeSearchText.getText(); + } + + /** + * Gets the node type filter. + * + * @return the node type filter + */ + public NodeType getNodeTypeFilter() { + if(nodeTypeCombo.getSelectedItem() instanceof NodeType) { + return (NodeType)nodeTypeCombo.getSelectedItem(); + } else return null; + } + + /** + * Gets the edge search text. + * + * @return the edge search text + */ + public String getEdgeSearchText() { + if(edgeSearchText.getText().equals(edgeSearchText.getDefaultText())) + return ""; + else return edgeSearchText.getText(); + } + + /** + * Gets the edge type filter. + * + * @return the edge type filter + */ + public EdgeType getEdgeTypeFilter() { + if(edgeTypeCombo.getSelectedItem() instanceof EdgeType) { + return (EdgeType)edgeTypeCombo.getSelectedItem(); + } else return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/network/NodeDetailsPanel.java b/src/main/java/edu/mit/spacenet/gui/network/NodeDetailsPanel.java new file mode 100644 index 0000000..c6721b3 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/network/NodeDetailsPanel.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.network; + +import java.awt.CardLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.network.node.LagrangeNode; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.gui.component.UnitsWrapper; + +/** + * A custom JPanel that displays the details (both generic and class-specific) + * for a node. + * + * @author Paul Grogan + */ +public class NodeDetailsPanel extends JPanel { + private static final long serialVersionUID = -3620939764968978036L; + private static String NO_NODE = "No Node Panel"; + private static String SURFACE_NODE = "Surface Node Panel"; + private static String ORBITAL_NODE = "Orbital Node Panel"; + private static String LAGRANGE_NODE = "Lagrange Node Panel"; + + private JLabel titleLabel, descriptionLabel, surfaceBodyLabel, + latitudeLabel, longitudeLabel, orbitalBodyLabel, periapsisLabel, + apoapsisLabel, inclinationLabel, majorBodyLabel, minorBodyLabel, + lagrangeNumberLabel; + private JPanel nodeDetailsPanel, surfaceNodeDetailsPanel, + orbitalNodeDetailsPanel, lagrangeNodeDetailsPanel; + + /** + * Instantiates a new node details panel. + */ + public NodeDetailsPanel() { + setBorder(BorderFactory.createTitledBorder("Node Details")); + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; + titleLabel = new JLabel(); + add(titleLabel, c); + c.gridy++; + descriptionLabel = new JLabel(); + add(descriptionLabel, c); + c.gridy++; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + nodeDetailsPanel = new JPanel(); + nodeDetailsPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + nodeDetailsPanel.setLayout(new CardLayout()); + nodeDetailsPanel.add(new JPanel(), NO_NODE); + surfaceNodeDetailsPanel = new JPanel(); + surfaceNodeDetailsPanel.setLayout(new GridBagLayout()); + { + GridBagConstraints g = new GridBagConstraints(); + g.gridx = 0; + g.gridy = 0; + g.fill = GridBagConstraints.NONE; + g.anchor = GridBagConstraints.LINE_END; + surfaceNodeDetailsPanel.add(new JLabel("Body: "), g); + g.gridy++; + surfaceNodeDetailsPanel.add(new JLabel("Latitude: "), g); + g.gridy++; + surfaceNodeDetailsPanel.add(new JLabel("Longitude: "), g); + g.gridy = 0; + g.gridx++; + g.weightx = 1; + g.anchor = GridBagConstraints.LINE_START; + surfaceBodyLabel = new JLabel(); + surfaceNodeDetailsPanel.add(surfaceBodyLabel, g); + g.gridy++; + latitudeLabel = new JLabel(); + surfaceNodeDetailsPanel.add(new UnitsWrapper(latitudeLabel, "deg"), g); + g.gridy++; + longitudeLabel = new JLabel(); + surfaceNodeDetailsPanel.add(new UnitsWrapper(longitudeLabel, "deg"), g); + g.gridy++; + g.weighty = 1; + surfaceNodeDetailsPanel.add(new JPanel(), g); + } + nodeDetailsPanel.add(surfaceNodeDetailsPanel, SURFACE_NODE); + orbitalNodeDetailsPanel = new JPanel(); + orbitalNodeDetailsPanel.setLayout(new GridBagLayout()); + { + GridBagConstraints g = new GridBagConstraints(); + g.gridx = 0; + g.gridy = 0; + g.fill = GridBagConstraints.NONE; + g.anchor = GridBagConstraints.LINE_END; + orbitalNodeDetailsPanel.add(new JLabel("Body: "), g); + g.gridy++; + orbitalNodeDetailsPanel.add(new JLabel("Periapsis: "), g); + g.gridy++; + orbitalNodeDetailsPanel.add(new JLabel("Apoapsis: "), g); + g.gridy++; + orbitalNodeDetailsPanel.add(new JLabel("Inclination: "), g); + g.gridy = 0; + g.gridx++; + g.weightx = 1; + g.anchor = GridBagConstraints.LINE_START; + orbitalBodyLabel = new JLabel(); + orbitalNodeDetailsPanel.add(orbitalBodyLabel, g); + g.gridy++; + apoapsisLabel = new JLabel(); + orbitalNodeDetailsPanel.add(new UnitsWrapper(apoapsisLabel, "km"), g); + g.gridy++; + periapsisLabel = new JLabel(); + orbitalNodeDetailsPanel.add(new UnitsWrapper(periapsisLabel, "km"), g); + g.gridy++; + inclinationLabel = new JLabel(); + orbitalNodeDetailsPanel.add(new UnitsWrapper(inclinationLabel, "deg"), g); + g.gridy++; + g.weighty = 1; + orbitalNodeDetailsPanel.add(new JPanel(), g); + } + nodeDetailsPanel.add(orbitalNodeDetailsPanel, ORBITAL_NODE); + lagrangeNodeDetailsPanel = new JPanel(); + lagrangeNodeDetailsPanel.setLayout(new GridBagLayout()); + { + GridBagConstraints g = new GridBagConstraints(); + g.gridx = 0; + g.gridy = 0; + g.fill = GridBagConstraints.NONE; + g.anchor = GridBagConstraints.LINE_END; + lagrangeNodeDetailsPanel.add(new JLabel("Major Body: "), g); + g.gridy++; + lagrangeNodeDetailsPanel.add(new JLabel("Minor Body: "), g); + g.gridy++; + lagrangeNodeDetailsPanel.add(new JLabel("Lagrange Number: "), g); + g.gridy = 0; + g.gridx++; + g.weightx = 1; + g.anchor = GridBagConstraints.LINE_START; + majorBodyLabel = new JLabel(); + lagrangeNodeDetailsPanel.add(majorBodyLabel, g); + g.gridy++; + minorBodyLabel = new JLabel(); + lagrangeNodeDetailsPanel.add(minorBodyLabel, g); + g.gridy++; + lagrangeNumberLabel = new JLabel(); + lagrangeNodeDetailsPanel.add(lagrangeNumberLabel, g); + g.gridy++; + g.weighty = 1; + lagrangeNodeDetailsPanel.add(new JPanel(), g); + } + nodeDetailsPanel.add(lagrangeNodeDetailsPanel, LAGRANGE_NODE); + add(nodeDetailsPanel, c); + } + + /** + * Updates the display for a new node, clears if null is passed. + * + * @param node the new node + */ + public void setNode(Node node) { + if(node==null) { + titleLabel.setText(""); + descriptionLabel.setText(""); + ((CardLayout)nodeDetailsPanel.getLayout()).show(nodeDetailsPanel, NO_NODE); + } else { + titleLabel.setText(node.getName() + " (" + node.getNodeType() + " Node)"); + descriptionLabel.setText(node.getDescription()); + switch(node.getNodeType()) { + case SURFACE: + ((CardLayout)nodeDetailsPanel.getLayout()).show(nodeDetailsPanel, SURFACE_NODE); + surfaceBodyLabel.setText(((SurfaceNode)node).getBody().toString()); + latitudeLabel.setText("" + ((SurfaceNode)node).getLatitude()); + longitudeLabel.setText("" + ((SurfaceNode)node).getLongitude()); + break; + case ORBITAL: + ((CardLayout)nodeDetailsPanel.getLayout()).show(nodeDetailsPanel, ORBITAL_NODE); + orbitalBodyLabel.setText(((OrbitalNode)node).getBody().toString()); + apoapsisLabel.setText("" + ((OrbitalNode)node).getApoapsis()); + periapsisLabel.setText("" + ((OrbitalNode)node).getPeriapsis()); + inclinationLabel.setText("" + ((OrbitalNode)node).getInclination()); + break; + case LAGRANGE: + ((CardLayout)nodeDetailsPanel.getLayout()).show(nodeDetailsPanel, LAGRANGE_NODE); + majorBodyLabel.setText(((LagrangeNode)node).getBody().toString()); + minorBodyLabel.setText(((LagrangeNode)node).getMinorBody().toString()); + lagrangeNumberLabel.setText("" + ((LagrangeNode)node).getNumber()); + break; + default: + ((CardLayout)nodeDetailsPanel.getLayout()).show(nodeDetailsPanel, NO_NODE); + } + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/network/NodeTable.java b/src/main/java/edu/mit/spacenet/gui/network/NodeTable.java new file mode 100644 index 0000000..ba8ad0f --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/network/NodeTable.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.network; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.List; + +import javax.swing.DefaultListModel; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.renderer.NodeTableCellRenderer; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; + +/** + * A table to view and toggle the inclusion of nodes in the scenario network. + */ +public class NodeTable extends JTable { + private static final long serialVersionUID = -5960985748957372743L; + + private CustomTableModel model; + private NetworkTab networkTab; + + /** + * Instantiates a new node table. + * + * @param networkTab the network tab + */ + public NodeTable(NetworkTab networkTab) { + super(); + this.networkTab = networkTab; + + model = new CustomTableModel(); + setModel(model); + DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); + renderer.setHorizontalAlignment(DefaultTableCellRenderer.CENTER); + getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + getColumnModel().getColumn(0).setMaxWidth(25); + getColumnModel().getColumn(1).setHeaderValue("Name"); + getColumnModel().getColumn(1).setCellRenderer(new NodeTableCellRenderer()); + + getTableHeader().setReorderingAllowed(false); + } + + /** + * Initializes the node table to a new scenario. + */ + public void initialize() { + ((CustomTableModel)getModel()).setScenario(networkTab.getScenario()); + } + + /** + * Update view. + */ + public void updateView() { + model.fireTableDataChanged(); + } + + /** + * Check all nodes. + */ + public void checkAll() { + for(int i=0; i getColumnClass(int col) { + if(col==0) return Boolean.class; + else if(col==1) return Node.class; + else return Integer.class; + } + public Object getValueAt(int row, int col) { + if(col==0) { + Node node = (Node)getValueAt(row, 1); + for(Node n : scenario.getNetwork().getNodes()) { + if(n.equals(node)) return true; + } + return false; + } else { + int count = 0; + for(Node node : scenario.getDataSource().getNodeLibrary()) { + if((networkTab.getNodeTypeFilter()==null||node.getNodeType()==networkTab.getNodeTypeFilter()) + && node.getName().toLowerCase().contains(networkTab.getNodeSearchText().toLowerCase())) { + if(count==row) return node; + count++; + } + } + return null; + } + } + public void setValueAt(Object value, int row, int col) { + if(col==0) { + Node node = (Node)getValueAt(row,1); + if(value.equals(Boolean.TRUE)) { + scenario.getNetwork().getNodes().add(node); + for(Edge edge : scenario.getDataSource().getEdgeLibrary()) { + if(!scenario.getNetwork().getEdges().contains(edge) + && scenario.getNetwork().getNodes().contains(edge.getOrigin()) + && scenario.getNetwork().getNodes().contains(edge.getDestination())) { + scenario.getNetwork().getEdges().add(edge); + } + } + } else { + List uses = networkTab.getScenario().getNodeUses(node); + if(uses.size() > 0) { + JPanel warningPanel = new JPanel(); + warningPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + warningPanel.add(new JLabel("The following use " + node + " and must be changed before removal:"), c); + c.gridy++; + c.weighty = 1; + DefaultListModel usagesList = new DefaultListModel(); + for(Object o : uses) { + usagesList.addElement(o); + } + warningPanel.add(new JScrollPane(new JList(usagesList)), c); + JOptionPane.showMessageDialog(networkTab.getScenarioPanel(), warningPanel, "SpaceNet Warning", JOptionPane.WARNING_MESSAGE); + } else { + scenario.getNetwork().remove(node); + } + } + } + fireTableRowsUpdated(row, row); + networkTab.getNetworkPanel().repaint(); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/node/AbstractNodeEditorPanel.java b/src/main/java/edu/mit/spacenet/gui/node/AbstractNodeEditorPanel.java new file mode 100644 index 0000000..4a52999 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/node/AbstractNodeEditorPanel.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.node; + +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.network.node.Node; + +/** + * Abstract component that serves as an interface to the various node panels on the editor. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class AbstractNodeEditorPanel extends JPanel { + private static final long serialVersionUID = -7771843429615660661L; + + private NodeEditorDialog dialog; + + /** + * Instantiates a new abstract node editor panel. + * + * @param dialog the dialog + */ + public AbstractNodeEditorPanel(NodeEditorDialog dialog) { + this.dialog = dialog; + } + + /** + * Gets the dialog. + * + * @return the dialog + */ + public NodeEditorDialog getDialog() { + return dialog; + } + + /** + * Checks if is node valid. + * + * @return true, if is node valid + */ + public abstract boolean isNodeValid(); + + /** + * Gets the node. + * + * @return the node + */ + public abstract Node getNode(); + + /** + * Saves the node. + */ + public abstract void saveNode(); +} diff --git a/src/main/java/edu/mit/spacenet/gui/node/LagrangeNodeEditorPanel.java b/src/main/java/edu/mit/spacenet/gui/node/LagrangeNodeEditorPanel.java new file mode 100644 index 0000000..2242101 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/node/LagrangeNodeEditorPanel.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.node; + +import java.awt.Component; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; + +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.LagrangeNode; + +/** + * A panel to edit Lagrange nodes. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class LagrangeNodeEditorPanel extends AbstractNodeEditorPanel { + private static final long serialVersionUID = -7968181121519566546L; + + private LagrangeNode node; + private JTextField nameText; + private JComboBox majorBodyCombo, minorBodyCombo, numberCombo; + private JTextArea descriptionText; + + /** + * Instantiates a new lagrange node editor panel. + * + * @param node the node + */ + public LagrangeNodeEditorPanel(NodeEditorDialog dialog, LagrangeNode node) { + super(dialog); + this.node = node; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel(){ + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Name: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText= new JTextField(); + add(nameText, c); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Major Body: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + majorBodyCombo= new JComboBox(); + for(Body t : Body.values()) majorBodyCombo.addItem(t); + majorBodyCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -1061418828847174455L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value!=null) setIcon(((Body)value).getIcon()); + return this; + } + }); + add(majorBodyCombo, c); + majorBodyCombo.setToolTipText("The more massive body in the orbital equilibrium"); + + c.gridx++; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Minor Body: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + minorBodyCombo= new JComboBox(); + for(Body t : Body.values()) minorBodyCombo.addItem(t); + minorBodyCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -1061418828847174455L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value!=null) setIcon(((Body)value).getIcon()); + return this; + } + }); + add(minorBodyCombo, c); + minorBodyCombo.setToolTipText("The less massive body in the orbital equilibrium"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("L.P. Number: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + numberCombo= new JComboBox(new Integer[]{1,2,3,4,5}); + add(numberCombo, c); + numberCombo.setToolTipText("1: between bodies; 2: outside minor body; 3: outside major body; 4: leading triangular; 5: lagging triangular"); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Description: "), c); + + c.gridx++; + c.weighty = 1; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(5,10); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + add(new JScrollPane(descriptionText), c); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(node!= null){ + nameText.setText(node.getName()); + majorBodyCombo.setSelectedItem(node.getBody()); + minorBodyCombo.setSelectedItem(node.getMinorBody()); + numberCombo.setSelectedItem(node.getNumber()); + descriptionText.setText(node.getDescription()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.node.AbstractNodePanelEditor#getNode() + */ + public LagrangeNode getNode() { + return node; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.node.AbstractNodePanelEditor#isNodeValid() + */ + public boolean isNodeValid() { + if(nameText.getText().length()==0){ + JOptionPane.showMessageDialog(getDialog(), + "Please enter a node name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(majorBodyCombo.getSelectedItem()==null) { + JOptionPane.showMessageDialog(getDialog(), + "Please select a major celestial body.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(minorBodyCombo.getSelectedItem()==null) { + JOptionPane.showMessageDialog(getDialog(), + "Please select a minor celestial body.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.node.AbstractNodePanelEditor#saveNode() + */ + public void saveNode(){ + node.setName(nameText.getText()); + node.setBody((Body)majorBodyCombo.getSelectedItem()); + node.setMinorBody((Body)minorBodyCombo.getSelectedItem()); + node.setNumber((Integer)numberCombo.getSelectedItem()); + node.setDescription(descriptionText.getText()); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/node/NodeEditorDialog.java b/src/main/java/edu/mit/spacenet/gui/node/NodeEditorDialog.java new file mode 100644 index 0000000..4f81e9b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/node/NodeEditorDialog.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.node; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.network.node.LagrangeNode; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.NodeType; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.gui.data.DataSourceDialog; +import edu.mit.spacenet.gui.renderer.NodeTypeListCellRenderer; + +/** + * A dialog box used to edit nodes. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class NodeEditorDialog extends JDialog { + private static final long serialVersionUID = 8072239734759253813L; + + private Node node; + private JComboBox nodeTypeCombo; + private AbstractNodeEditorPanel nodePanel; + private DataSourceDialog dialog; + private JButton okButton; + private JButton cancelButton; + + /** + * Instantiates a new node editor dialog. + * + * @param editorFrame the editor frame + * @param node the node1 + */ + private NodeEditorDialog(DataSourceDialog dialog, Node node) { + super(dialog, "Edit Node", true); + this.dialog = dialog; + this.node = node; + buildDialog(); + } + + + /** + * Builds the dialog. + */ + public void buildDialog(){ + + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Type: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + nodeTypeCombo = new JComboBox(); + for(NodeType t : NodeType.values()) nodeTypeCombo.addItem(t); + if(node!=null){ + nodeTypeCombo.setSelectedItem(node.getNodeType()); + } + nodeTypeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED + && (node==null || node.getNodeType()!=e.getItem())) { + switch((NodeType)e.getItem()) { + case SURFACE: + node = new SurfaceNode(); + reset(); + break; + case ORBITAL: + node = new OrbitalNode(); + reset(); + break; + case LAGRANGE: + node = new LagrangeNode(); + reset(); + break; + } + } + } + }); + nodeTypeCombo.setRenderer(new NodeTypeListCellRenderer()); + if(node.getTid()>0){ + nodeTypeCombo.setEnabled(false); + } + contentPanel.add(nodeTypeCombo, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + nodePanel = NodeEditorPanelFactory.createNodePanel(this, node); + contentPanel.add(nodePanel, c); + + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + okButton = new JButton(node.getTid()<0?"Add":"Save", new ImageIcon(getClass().getClassLoader().getResource("icons/database_go.png"))); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveNode(); + } + }); + buttonPanel.add(okButton); + + cancelButton = new JButton("Cancel", new ImageIcon(getClass().getClassLoader().getResource("icons/database.png"))); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPanel.add(cancelButton); + contentPanel.add(buttonPanel, c); + setContentPane(contentPanel); + } + + /** + * Gets the node. + * + * @return the node + */ + public Node getNode(){ + return this.node; + } + + /** + * Resets the components for changing to a different type of node. + */ + private void reset() { + getContentPane().remove(nodePanel); + nodePanel = NodeEditorPanelFactory.createNodePanel(this, node); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 1; + c.weightx = 1; + c.weighty = 1; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + getContentPane().add(nodePanel, c); + validate(); + pack(); + repaint(); + } + + /** + * Saves the node. + */ + public void saveNode() { + if(nodePanel.isNodeValid()) { + nodePanel.saveNode(); + try { + dialog.getDataSource().saveNode(getNode()); + dialog.loadDataSource(); + dispose(); + } catch (Exception e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(dialog, + "SpaceNet Errror", + "An error occurred while saving the node.", + JOptionPane.ERROR_MESSAGE); + } + } + } + + /** + * Gets the dialog. + * + * @return the dialog + */ + public DataSourceDialog getDialog() { + return dialog; + } + + /** + * Creates and shows the GUI. + * + * @param DataSourcePanel the data source panel + * @param node1 the node1 + */ + public static void createAndShowGUI (DataSourceDialog dialog, Node node1){ + NodeEditorDialog d = new NodeEditorDialog(dialog, node1); + d.setMinimumSize(new Dimension(300,150)); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/node/NodeEditorPanelFactory.java b/src/main/java/edu/mit/spacenet/gui/node/NodeEditorPanelFactory.java new file mode 100644 index 0000000..a5a5147 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/node/NodeEditorPanelFactory.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.node; + +import edu.mit.spacenet.domain.network.node.LagrangeNode; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.NodeType; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.domain.network.node.SurfaceNode; + +/** + * A factory for creating NodeEditorPanel objects. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class NodeEditorPanelFactory { + + /** + * Creates a new NodeEditorPanel object. + * + * @param node the node + * + * @return the abstract node editor panel + */ + public static AbstractNodeEditorPanel createNodePanel(NodeEditorDialog dialog, Node node) { + if(node.getNodeType()==NodeType.SURFACE){ + return new SurfaceNodeEditorPanel(dialog, (SurfaceNode)node);} + else if(node.getNodeType()==NodeType.ORBITAL){ + return new OrbitalNodeEditorPanel(dialog, (OrbitalNode)node);} + else if(node.getNodeType()==NodeType.LAGRANGE){ + return new LagrangeNodeEditorPanel(dialog, (LagrangeNode)node);} + else + return null; // check for other types of nodes + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/node/OrbitalNodeEditorPanel.java b/src/main/java/edu/mit/spacenet/gui/node/OrbitalNodeEditorPanel.java new file mode 100644 index 0000000..6e541b7 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/node/OrbitalNodeEditorPanel.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.node; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.gui.component.UnitsWrapper; + +/** + * A panel used to edit orbital nodes. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class OrbitalNodeEditorPanel extends AbstractNodeEditorPanel { + private static final long serialVersionUID = -7968181121519566546L; + + private OrbitalNode node; + + private JTextField nameText; + private JComboBox bodyCombo; + private SpinnerNumberModel inclinationModel, apoapsisModel, periapsisModel; + private JSpinner inclinationSpinner, apoapsisSpinner, periapsisSpinner; + private JTextArea descriptionText; + + /** + * Instantiates a new orbital node panel editor. + * + * @param node the node + */ + public OrbitalNodeEditorPanel(NodeEditorDialog dialog, OrbitalNode node) { + super(dialog); + this.node = node; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + public void buildPanel(){ + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Name: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText= new JTextField(); + add(nameText, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Body: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.gridwidth = 3; + bodyCombo= new JComboBox(); + for(Body t : Body.values()) bodyCombo.addItem(t); + bodyCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -1061418828847174455L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value!=null) setIcon(((Body)value).getIcon()); + return this; + } + }); + add(bodyCombo, c); + bodyCombo.setToolTipText("Body about which orbit circles"); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Apoapsis: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + apoapsisModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, 0.01); + apoapsisSpinner = new JSpinner(apoapsisModel); + apoapsisSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(apoapsisSpinner, "km"), c); + apoapsisSpinner.setToolTipText("Farthest distance in the orbit [kilometers]"); + + c.gridx++; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Periapsis: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + periapsisModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, 0.01); + periapsisSpinner = new JSpinner(periapsisModel); + periapsisSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(periapsisSpinner, "km"), c); + periapsisSpinner.setToolTipText("Closest distance in the orbit [kilometers]"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Inclination: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + c.gridwidth = 3; + inclinationModel = new SpinnerNumberModel(0,-90,270,0.01); + inclinationSpinner = new JSpinner(inclinationModel); + inclinationSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(inclinationSpinner, "\u00B0"), c); + inclinationSpinner.setToolTipText("Inclination of orbit [degrees]"); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Description: "), c); + + c.gridx++; + c.weighty = 1; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(5,10); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + add(new JScrollPane(descriptionText), c); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(node!= null){ + nameText.setText(node.getName()); + bodyCombo.setSelectedItem(node.getBody()); + inclinationModel.setValue(node.getInclination()); + apoapsisModel.setValue(node.getApoapsis()); + periapsisModel.setValue(node.getPeriapsis()); + descriptionText.setText(node.getDescription()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.node.gui.AbstractNodePanelEditor#getNode() + */ + public OrbitalNode getNode() { + return node; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.node.gui.AbstractNodePanelEditor#isNodeValid() + */ + public boolean isNodeValid() { + if(nameText.getText().length()==0){ + JOptionPane.showMessageDialog(getDialog(), + "Please enter a node name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(apoapsisModel.getNumber().doubleValue(). + */ +package edu.mit.spacenet.gui.node; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.gui.component.UnitsWrapper; + +/** + * A panel that is used for editing surface nodes. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class SurfaceNodeEditorPanel extends AbstractNodeEditorPanel { + private static final long serialVersionUID = -7968181121519566546L; + private static final String N="N",S="S",E="E",W="W"; + + private SurfaceNode node; + + private JTextField nameText; + private JComboBox bodyCombo, latitudeCombo, longitudeCombo; + private SpinnerNumberModel latitudeModel, longitudeModel; + private JSpinner latitudeSpinner, longitudeSpinner; + private JTextArea descriptionText; + + /** + * Instantiates a new surface node panel editor. + * + * @param node the node + */ + public SurfaceNodeEditorPanel(NodeEditorDialog dialog, SurfaceNode node) { + super(dialog); + this.node = node; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + public void buildPanel(){ + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Name: "), c); + + c.gridx++; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText= new JTextField(); + add(nameText, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Body: "), c); + + c.gridx++; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + bodyCombo= new JComboBox(); + for(Body t : Body.values()) bodyCombo.addItem(t); + bodyCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = -1061418828847174455L; + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value!=null) setIcon(((Body)value).getIcon()); + return this; + } + }); + add(bodyCombo, c); + bodyCombo.setToolTipText("Body on which location resides"); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Latitude: "), c); + + c.gridx++; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + latitudeModel = new SpinnerNumberModel(0,0,90,0.01); + latitudeSpinner = new JSpinner(latitudeModel); + latitudeSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(latitudeSpinner, "\u00B0"), c); + latitudeSpinner.setToolTipText("Latitude of location [degrees]"); + c.gridx++; + c.weightx = 1; + latitudeCombo = new JComboBox(new String[]{N,S}); + add(latitudeCombo, c); + latitudeCombo.setToolTipText("N: North; S: South"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Longitude: "), c); + + c.gridx++; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + longitudeModel = new SpinnerNumberModel(0,0,180,0.01); + longitudeSpinner = new JSpinner(longitudeModel); + longitudeSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(longitudeSpinner, "\u00B0"), c); + longitudeSpinner.setToolTipText("Longitude of location [degrees]"); + c.gridx++; + c.weightx = 1; + longitudeCombo = new JComboBox(new String[]{E,W}); + add(longitudeCombo, c); + longitudeCombo.setToolTipText("E: East; W: West"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Description: "), c); + + c.gridx++; + c.weighty = 1; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(5,10); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + add(new JScrollPane(descriptionText), c); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(node!= null){ + nameText.setText(node.getName()); + bodyCombo.setSelectedItem(node.getBody()); + latitudeModel.setValue(Math.abs(node.getLatitude())); + if(node.getLatitude()<0) latitudeCombo.setSelectedItem(S); + else latitudeCombo.setSelectedItem(N); + longitudeModel.setValue(Math.abs(node.getLongitude())); + if(node.getLatitude()<0) longitudeCombo.setSelectedItem(W); + else longitudeCombo.setSelectedItem(E); + descriptionText.setText(node.getDescription()); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.node.gui.AbstractNodePanelEditor#getNode() + */ + public SurfaceNode getNode() { + return node; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.node.gui.AbstractNodePanelEditor#isNodeValid() + */ + public boolean isNodeValid() { + if(nameText.getText().length()==0){ + JOptionPane.showMessageDialog(getDialog(), + "Please enter a node name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + if(bodyCombo.getSelectedItem()==null) { + JOptionPane.showMessageDialog(getDialog(), + "Please select a celestial body.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + return true; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.editor.gui.node.AbstractNodePanelEditor#saveNode() + */ + public void saveNode(){ + node.setName(nameText.getText()); + node.setBody((Body)bodyCombo.getSelectedItem()); + node.setLatitude((latitudeCombo.getSelectedItem()==S?-1:1)*latitudeModel.getNumber().doubleValue()); + node.setLongitude((longitudeCombo.getSelectedItem()==W?-1:1)*longitudeModel.getNumber().doubleValue()); + node.setDescription(descriptionText.getText()); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/BurnListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/BurnListCellRenderer.java new file mode 100644 index 0000000..ca24e97 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/BurnListCellRenderer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.simulator.event.BurnStageItem; + +/** + * Renders the burn label as its burn type icon, time, delta-v and type. + */ +public class BurnListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof Burn) { + Burn burn = (Burn)value; + setIcon(BurnStageItem.BURN_ICON); + setText("(" + burn.getTime() + ") " + burn.getDeltaV() + + " m/s " + burn.getBurnType()); + } + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/DemandModelListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/DemandModelListCellRenderer.java new file mode 100644 index 0000000..f0a0dff --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/DemandModelListCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.model.I_DemandModel; + +/** + * Renders the demand model label as its name and icon. + */ +public class DemandModelListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof I_DemandModel) setIcon(((I_DemandModel)value).getDemandModelType().getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/EdgeTableCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/EdgeTableCellRenderer.java new file mode 100644 index 0000000..ec1f95e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/EdgeTableCellRenderer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.network.edge.Edge; + +/** + * Renders a node icon with name. + */ +public class EdgeTableCellRenderer extends DefaultTableCellRenderer { + private static final long serialVersionUID = 325292919910855476L; + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) + */ + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setIcon(((Edge)value).getEdgeType().getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/EdgeTypeListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/EdgeTypeListCellRenderer.java new file mode 100644 index 0000000..11a6421 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/EdgeTypeListCellRenderer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.EdgeType; + +/** + * Renders the edge type label with its icon and name. + */ +public class EdgeTypeListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof Edge) setIcon(((EdgeType)value).getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/ElementPreviewListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/ElementPreviewListCellRenderer.java new file mode 100644 index 0000000..f0fe6a3 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/ElementPreviewListCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.data.ElementPreview; + +/** + * Renders the element preview label with its icon and name. + */ +public class ElementPreviewListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof ElementPreview) setIcon(((ElementPreview)value).getIconType().getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/ElementTableCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/ElementTableCellRenderer.java new file mode 100644 index 0000000..4b1b031 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/ElementTableCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.element.I_Element; + +/** + * Renders an element icon with name. + */ +public class ElementTableCellRenderer extends DefaultTableCellRenderer { + private static final long serialVersionUID = 325292919910855476L; + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof I_Element) setIcon(((I_Element)value).getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/ElementTypeListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/ElementTypeListCellRenderer.java new file mode 100644 index 0000000..a86a4b0 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/ElementTypeListCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.element.ElementType; + +/** + * Renders the element type label with its icon and name. + */ +public class ElementTypeListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof ElementType) setIcon(((ElementType)value).getIconType().getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/NodeListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/NodeListCellRenderer.java new file mode 100644 index 0000000..b11c9e8 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/NodeListCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.network.node.Node; + +/** + * Renders the node label as its node type icon and node name. + */ +public class NodeListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof Node) setIcon(((Node)value).getNodeType().getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/NodeTableCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/NodeTableCellRenderer.java new file mode 100644 index 0000000..194b5a7 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/NodeTableCellRenderer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.network.node.Node; + +/** + * Renders a node icon with name. + */ +public class NodeTableCellRenderer extends DefaultTableCellRenderer { + private static final long serialVersionUID = 325292919910855476L; + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) + */ + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setIcon(((Node)value).getNodeType().getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/NodeTypeListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/NodeTypeListCellRenderer.java new file mode 100644 index 0000000..8e0c97c --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/NodeTypeListCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.network.node.NodeType; + +/** + * Renders the node type label with its icon and name. + */ +public class NodeTypeListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setIcon(((NodeType)value).getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/ResourceListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/ResourceListCellRenderer.java new file mode 100644 index 0000000..733d22b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/ResourceListCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.resource.I_Resource; + +/** + * Renders the resource label as its name and icon. + */ +public class ResourceListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof I_Resource) setIcon(((I_Resource)value).getResourceType().getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/ResourceTypeListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/ResourceTypeListCellRenderer.java new file mode 100644 index 0000000..115a861 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/ResourceTypeListCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.resource.ResourceType; + +/** + * Renders the resource type label with its icon and name. + */ +public class ResourceTypeListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof ResourceType) setIcon(((ResourceType)value).getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/ResourceTypeTableCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/ResourceTypeTableCellRenderer.java new file mode 100644 index 0000000..224305a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/ResourceTypeTableCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +import edu.mit.spacenet.domain.resource.ResourceType; + +/** + * Renders an resource type icon with name. + */ +public class ResourceTypeTableCellRenderer extends DefaultTableCellRenderer { + private static final long serialVersionUID = 325292919910855476L; + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(value instanceof ResourceType) setIcon(((ResourceType)value).getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/StateTypeListCellRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/StateTypeListCellRenderer.java new file mode 100644 index 0000000..e291882 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/StateTypeListCellRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; + +import edu.mit.spacenet.domain.element.StateType; + +/** + * Renders the state type label with its icon and name. + */ +public class StateTypeListCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 2481135321054790586L; + + /* (non-Javadoc) + * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof StateType) setIcon(((StateType)value).getIcon()); + return this; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/renderer/VisibilityTableCellHeaderRenderer.java b/src/main/java/edu/mit/spacenet/gui/renderer/VisibilityTableCellHeaderRenderer.java new file mode 100644 index 0000000..acf7b0b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/renderer/VisibilityTableCellHeaderRenderer.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.renderer; + +import java.awt.Component; + +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.UIManager; +import javax.swing.table.DefaultTableCellRenderer; + +/** + * Renders a centered visibility icon. + */ +public class VisibilityTableCellHeaderRenderer extends DefaultTableCellRenderer { + private static final long serialVersionUID = 325292919910855476L; + + /* (non-Javadoc) + * @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/eye.png"))); + setBorder(UIManager.getBorder("TableHeader.cellBorder")); + setBackground(UIManager.getColor("TableHeader.cellBackground")); + setHorizontalAlignment(JLabel.CENTER); + return this; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorDialog.java b/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorDialog.java new file mode 100644 index 0000000..edabd5c --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorDialog.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.resource; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.domain.resource.Resource; +import edu.mit.spacenet.domain.resource.ResourceType; +import edu.mit.spacenet.gui.data.DataSourceDialog; +import edu.mit.spacenet.gui.renderer.ResourceTypeListCellRenderer; + +/** + * A dialog box for editing resources. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class ResourceEditorDialog extends JDialog { + private static final long serialVersionUID = -8753859556068289559L; + private I_Resource resource; + private ResourceEditorPanel resourcePanel; + private DataSourceDialog dialog; + + private JComboBox resourceTypeCombo; + private JButton okButton; + private JButton cancelButton; + + /** + * Instantiates a new resource editor dialog. + * + * @param editorFrame the editor frame + * @param resource the resource + */ + private ResourceEditorDialog(DataSourceDialog editorFrame, I_Resource resource) { + super(editorFrame, "Edit Resource", true); + this.resource = resource; + this.dialog = editorFrame; + buildDialog(); + initialize(); + } + + /** + * Builds the dialog. + */ + private void buildDialog(){ + JPanel contentPanel = new JPanel(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + contentPanel.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + contentPanel.add(new JLabel("Type: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + resourceTypeCombo = new JComboBox(); + resourceTypeCombo.setRenderer(new ResourceTypeListCellRenderer()); + for(ResourceType t : ResourceType.values()) + if(t!=ResourceType.GENERIC) resourceTypeCombo.addItem(t); + resourceTypeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED + && (resource.getResourceType()!=e.getItem())) { + switch((ResourceType)e.getItem()) { + case RESOURCE: + resource = new Resource(); + reset(); + break; + case ITEM: + resource = new Item(); + reset(); + break; + } + } + } + }); + + resourceTypeCombo.setRenderer(new ResourceTypeListCellRenderer()); + + resourceTypeCombo.setEnabled(resource.getTid()<0); + + contentPanel.add(resourceTypeCombo, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.weightx = 1; + c.weighty = 1; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + resourcePanel = ResourceEditorPanelFactory.createResourceEditorPanel(this, resource); + contentPanel.add(resourcePanel, c); + + c.gridy++; + c.weighty = 0; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0)); + okButton = new JButton(resource.getTid()<0?"Add":"Save", new ImageIcon(getClass().getClassLoader().getResource("icons/database_go.png"))); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveResource(); + } + }); + buttonPanel.add(okButton); + + cancelButton = new JButton("Cancel", new ImageIcon(getClass().getClassLoader().getResource("icons/database.png"))); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPanel.add(cancelButton); + contentPanel.add(buttonPanel, c); + + setContentPane(contentPanel); + } + + /** + * Initializes the components. + */ + private void initialize() { + resourceTypeCombo.setSelectedItem(resource.getResourceType()); + } + + /** + * Gets the resource. + * + * @return the resource + */ + public I_Resource getResource(){ + return this.resource; + } + + /** + * Resets the component for when the type of resource is changed. + */ + private void reset() { + getContentPane().remove(resourcePanel); + resourcePanel = ResourceEditorPanelFactory.createResourceEditorPanel(this, resource); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 1; + c.weightx = 1; + c.weighty = 1; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + getContentPane().add(resourcePanel, c); + validate(); + repaint(); + } + + /** + * Saves the resource. + */ + public void saveResource() { + if(resourcePanel.isResourceValid()) { + try { + resourcePanel.saveResource(); + dialog.getDataSource().saveResource(getResource()); + dialog.loadDataSource(); + dispose(); + } catch (Exception e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(dialog, + "SpaceNet Errror", + "An error occurred while saving the resource.", + JOptionPane.ERROR_MESSAGE); + } + } + } + + /** + * Creates and shows the GUI. + * + * @param dialog the editor frame + * @param resource the resource + */ + public static void createAndShowGUI(DataSourceDialog dialog, I_Resource resource) { + ResourceEditorDialog d = new ResourceEditorDialog(dialog, resource); + d.setMinimumSize(new Dimension(300,150)); + d.pack(); + d.setLocationRelativeTo(d.getParent()); + d.setVisible(true); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorPanel.java b/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorPanel.java new file mode 100644 index 0000000..7599f02 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorPanel.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.resource; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.domain.resource.ResourceType; +import edu.mit.spacenet.gui.component.UnitsWrapper; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A panel for editing resources. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public class ResourceEditorPanel extends JPanel { + private static final long serialVersionUID = 4522726218623374399L; + private I_Resource resource; + private ResourceEditorDialog dialog; + + private JTextField nameText, unitsText; + private JComboBox classOfSupplyCombo, environmentCombo; + private SpinnerNumberModel unitMassModel, unitVolumeModel, packingFactorModel; + private JSpinner unitMassSpinner, unitVolumeSpinner, packingFactorSpinner; + private JTextArea descriptionText; + + /** + * Instantiates a new resource panel editor. + * + * @param resourcePanel1 the resource panel1 + * @param resource the resource + */ + public ResourceEditorPanel(ResourceEditorDialog dialog, I_Resource resource) { + this.resource = resource; + this.dialog = dialog; + buildPanel(); + initialize(); + } + + /** + * Builds the panel. + */ + private void buildPanel(){ + setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Name: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + nameText= new JTextField(); + add(nameText, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Class of Supply: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + classOfSupplyCombo= new JComboBox(); + for(ClassOfSupply t : ClassOfSupply.values()) classOfSupplyCombo.addItem(t); + add(classOfSupplyCombo, c); + + c.gridy++; + c.gridx = 0; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Environment: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + environmentCombo= new JComboBox(); + for(Environment t : Environment.values()) environmentCombo.addItem(t); + add(environmentCombo, c); + environmentCombo.setToolTipText("Required environment for storage"); + + c.gridx++; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Packing Factor: "), c); + + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + packingFactorModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, 0.01); + packingFactorSpinner = new JSpinner(packingFactorModel); + packingFactorSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(packingFactorSpinner,"-"), c); + packingFactorSpinner.setToolTipText("Fraction of additional COS 5 required to pack resource in a container [unitless]"); + + c.gridy++; + c.gridx = 0; + c.weightx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Units: "), c); + + c.gridx++; + c.gridwidth = 3; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + unitsText = new JTextField(5); + add(unitsText, c); + unitsText.setToolTipText("Units in which resource is measured"); + + c.gridy++; + c.gridwidth = 1; + c.gridx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Unit Mass: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + unitMassModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, GlobalParameters.getMassPrecision()); + unitMassSpinner = new JSpinner(unitMassModel); + unitMassSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(unitMassSpinner, "kg"), c); + unitMassSpinner.setToolTipText("Mass of one unit of resource [kilograms]"); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Unit Volume: "), c); + + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.NONE; + unitVolumeModel = new SpinnerNumberModel(0,0,Double.MAX_VALUE, GlobalParameters.getVolumePrecision()); + unitVolumeSpinner = new JSpinner(unitVolumeModel); + unitVolumeSpinner.setPreferredSize(new Dimension(75,20)); + add(new UnitsWrapper(unitVolumeSpinner, "m^3"), c); + unitVolumeSpinner.setToolTipText("Volume of one unit of resource [cubic meters]"); + + c.gridy++; + c.gridx = 0; + c.anchor = GridBagConstraints.FIRST_LINE_END; + c.fill = GridBagConstraints.NONE; + add(new JLabel("Description: "), c); + + c.gridx++; + c.weighty = 1; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + descriptionText = new JTextArea(5,10); + descriptionText.setLineWrap(true); + descriptionText.setWrapStyleWord(true); + descriptionText.setFont(new Font("Sans-Serif", Font.PLAIN, 11)); + add(new JScrollPane(descriptionText), c); + } + + /** + * Initializes the components. + */ + private void initialize() { + if(resource!= null){ + nameText.setText(resource.getName()); + classOfSupplyCombo.setSelectedItem(resource.getClassOfSupply()); + environmentCombo.setSelectedItem(resource.getEnvironment()); + unitsText.setText(resource.getUnits()); + unitMassModel.setValue(resource.getUnitMass()); + unitVolumeModel.setValue(resource.getUnitVolume()); + packingFactorModel.setValue(resource.getPackingFactor()); + descriptionText.setText(resource.getDescription()); + + unitsText.setEnabled(resource.getResourceType()!=ResourceType.ITEM); + } + } + + /** + * Gets the resource. + * + * @return the resource + */ + public I_Resource getResource() { + return resource; + } + + /** + * Checks if the resource is valid. + * + * @return true, if resource is valid + */ + public boolean isResourceValid() { + if(nameText.getText().length()==0){ + JOptionPane.showMessageDialog(dialog, + "Please enter a resource name.", + "SpaceNet Warning", + JOptionPane.WARNING_MESSAGE); + return false; + } + return true; + } + + /** + * Saves changes to the resource. + */ + public void saveResource() { + resource.setName(nameText.getText()); + resource.setClassOfSupply((ClassOfSupply)classOfSupplyCombo.getSelectedItem()); + resource.setEnvironment((Environment)environmentCombo.getSelectedItem()); + resource.setUnits(unitsText.getText()); + resource.setPackingFactor(packingFactorModel.getNumber().doubleValue()); + resource.setUnitMass(unitMassModel.getNumber().doubleValue()); + resource.setUnitVolume(unitVolumeModel.getNumber().doubleValue()); + resource.setDescription(descriptionText.getText()); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorPanelFactory.java b/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorPanelFactory.java new file mode 100644 index 0000000..287d70e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/resource/ResourceEditorPanelFactory.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.resource; + +import edu.mit.spacenet.domain.resource.I_Resource; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.domain.resource.Resource; +import edu.mit.spacenet.domain.resource.ResourceType; + +/** + * A factory for creating ResourcePanelEditor objects. + * + * @author Paul Grogan, ptgrogan@mit.edu + * @author Ivo Ferreira + */ +public abstract class ResourceEditorPanelFactory { + public static ResourceEditorPanel createResourceEditorPanel(ResourceEditorDialog dialog, I_Resource resource) { + if(resource.getResourceType()==ResourceType.RESOURCE) + return new ResourceEditorPanel(dialog,(Resource)resource); + else if (resource.getResourceType()==ResourceType.ITEM){ + return new ResourceEditorPanel(dialog,(Item)resource); + } + else return null; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/simulation/ElementCosHistoryChart.java b/src/main/java/edu/mit/spacenet/gui/simulation/ElementCosHistoryChart.java new file mode 100644 index 0000000..8d0aac5 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/simulation/ElementCosHistoryChart.java @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.simulation; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.SimNetwork; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Chart for displaying the history of elements' contents broken down by class + * of supply. + * + * @author Paul Grogan + */ +public class ElementCosHistoryChart extends JSplitPane { + private static final long serialVersionUID = -6405124067606236705L; + private SimulationTab tab; + private JComboBox elementCombo; + private CheckBoxTableModel cosModel; + private ChartPanel chartPanel; + private JCheckBox linearizeDataCheck; + + /** + * Instantiates a new element cos history chart. + * + * @param tab the simulation tab + */ + public ElementCosHistoryChart(SimulationTab tab) { + this.tab = tab; + + chartPanel = new SNChartPanel(); + chartPanel.setPreferredSize(new Dimension(600,400)); + setLeftComponent(chartPanel); + + JPanel controlPanel = new JPanel(); + controlPanel.setLayout(new GridBagLayout()); + controlPanel.setBorder(BorderFactory.createTitledBorder("Chart Options")); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + controlPanel.add(new JLabel("Element: "), c); + c.gridy = 0; + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + elementCombo = new ContainerComboBox(); + elementCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + updateView(); + } + } + }); + controlPanel.add(elementCombo, c); + c.gridx--; + c.gridy++; + c.gridwidth = 2; + c.weightx = 0; + c.weighty = 1; + cosModel = new CheckBoxTableModel(); + for(int i=1; i<=10; i++) { + cosModel.addObject(ClassOfSupply.getInstance(i)); + } + cosModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + updateChart(); + } + }); + JTable cosTable = new JTable(cosModel); + cosTable.getTableHeader().setReorderingAllowed(false); + cosTable.getColumnModel().getColumn(0).setHeaderValue(""); + cosTable.getColumnModel().getColumn(0).setMaxWidth(25); + cosTable.getColumnModel().getColumn(1).setHeaderValue("Filter Classes of Supply"); + cosTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + cosTable.setShowGrid(false); + JScrollPane cosScroll = new JScrollPane(cosTable); + cosScroll.setPreferredSize(new Dimension(150,200)); + controlPanel.add(cosScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllButton = new JButton("Select All"); + selectAllButton.setToolTipText("Select All COS"); + selectAllButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.selectAll(); + } + }); + buttonPanel.add(selectAllButton); + JButton deselectAllButton = new JButton("Deselect All"); + deselectAllButton.setToolTipText("Deselect All COS"); + deselectAllButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.deselectAll(); + } + }); + buttonPanel.add(deselectAllButton); + controlPanel.add(buttonPanel, c); + c.gridy++; + JPanel prop = new JPanel(); + prop.setPreferredSize(new Dimension(1,15)); + controlPanel.add(prop, c); + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + linearizeDataCheck = new JCheckBox("Linearize Data", true); + linearizeDataCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateChart(); + } + }); + controlPanel.add(linearizeDataCheck, c); + + controlPanel.setMinimumSize(new Dimension(150,50)); + setRightComponent(controlPanel); + + setName("Element History"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(700); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return tab.getScenario(); + } + + /** + * Initialize. + */ + public void initialize() { + elementCombo.removeAllItems(); + updateChart(); + } + + + /** + * Update view. + */ + public void updateView() { + tab.getScenarioPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + I_Element selectedElement = (I_Element)elementCombo.getSelectedItem(); + ItemListener elementListener = elementCombo.getItemListeners()[0]; + elementCombo.removeItemListener(elementListener); + elementCombo.removeAllItems(); + for(I_Element element : getScenario().getElements()) { + elementCombo.addItem(element); + } + if(selectedElement!=null) elementCombo.setSelectedItem(selectedElement); + elementCombo.addItemListener(elementListener); + updateChart(); + tab.getScenarioPanel().setCursor(Cursor.getDefaultCursor()); + } + + /** + * Update chart. + */ + private void updateChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, + "Date", + "Mass (kg)", + dataset, + true, + true, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + if(elementCombo.getSelectedItem()!=null) { + for(ClassOfSupply cos : cosModel.getSelectedObjects()) { + TimeSeries s = new TimeSeries("COS " + cos.getId(), Hour.class); + double amount = 0; + boolean firstPoint = true; + for(SimNetwork network : tab.getSimulator().getNetworkHistory()) { + I_Element element = network.getNetwork().getRegistrar().get(((I_Element)elementCombo.getSelectedItem()).getUid()); + if(element == null) + element = network.getNetwork().getRemovedRegistrar().get(((I_Element)elementCombo.getSelectedItem()).getUid()); + if(element != null) { + Hour hour = new Hour(DateFunctions.getDate(getScenario().getStartDate(), network.getTime())); + if(!firstPoint + && !linearizeDataCheck.isSelected()) + s.addOrUpdate(hour.previous(), amount); + amount = element.getTotalMass(cos); + s.addOrUpdate(hour, amount); + firstPoint = false; + } + } + + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + r.setSeriesPaint(dataset.getSeriesCount() - 1, cos.getColor()); + } + } + chartPanel.setChart(chart); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/simulation/LocationCosHistoryChart.java b/src/main/java/edu/mit/spacenet/gui/simulation/LocationCosHistoryChart.java new file mode 100644 index 0000000..461811a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/simulation/LocationCosHistoryChart.java @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.simulation; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.util.Date; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.ContainerComboBox; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.SimNetwork; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Chart for displaying the aggregate resources broken down by class of supply + * at various locations. + * + * @author Paul Grogan + */ +public class LocationCosHistoryChart extends JSplitPane { + private static final long serialVersionUID = -6405124067606236705L; + private SimulationTab tab; + private JComboBox locationCombo; + private CheckBoxTableModel cosModel; + private ChartPanel chartPanel; + private JCheckBox linearizeDataCheck; + + /** + * Instantiates a new location cos history chart. + * + * @param tab the simulation tab + */ + public LocationCosHistoryChart(SimulationTab tab) { + this.tab = tab; + + chartPanel = new SNChartPanel(); + chartPanel.setPreferredSize(new Dimension(600,400)); + setLeftComponent(chartPanel); + + JPanel controlPanel = new JPanel(); + controlPanel.setLayout(new GridBagLayout()); + controlPanel.setBorder(BorderFactory.createTitledBorder("Chart Options")); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + controlPanel.add(new JLabel("Location: "), c); + c.gridy = 0; + c.gridx++; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + locationCombo = new ContainerComboBox(); + locationCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + updateView(); + } + } + }); + controlPanel.add(locationCombo, c); + c.gridx--; + c.gridy++; + c.gridwidth = 2; + c.weightx = 0; + c.weighty = 1; + cosModel = new CheckBoxTableModel(); + for(int i=1; i<=10; i++) { + cosModel.addObject(ClassOfSupply.getInstance(i)); + } + cosModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + updateChart(); + } + }); + JTable cosTable = new JTable(cosModel); + cosTable.getTableHeader().setReorderingAllowed(false); + cosTable.getColumnModel().getColumn(0).setHeaderValue(""); + cosTable.getColumnModel().getColumn(0).setMaxWidth(25); + cosTable.getColumnModel().getColumn(1).setHeaderValue("Filter Classes of Supply"); + cosTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + cosTable.setShowGrid(false); + JScrollPane cosScroll = new JScrollPane(cosTable); + cosScroll.setPreferredSize(new Dimension(150,200)); + controlPanel.add(cosScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(); + buttonPanel.setOpaque(false); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllButton = new JButton("Select All"); + selectAllButton.setToolTipText("Select All COS"); + selectAllButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.selectAll(); + } + }); + buttonPanel.add(selectAllButton); + JButton deselectAllButton = new JButton("Deselect All"); + deselectAllButton.setToolTipText("Deselect All COS"); + deselectAllButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + cosModel.deselectAll(); + } + }); + buttonPanel.add(deselectAllButton); + controlPanel.add(buttonPanel, c); + c.gridy++; + JPanel prop = new JPanel(); + prop.setOpaque(false); + prop.setPreferredSize(new Dimension(1,15)); + controlPanel.add(prop, c); + + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + linearizeDataCheck = new JCheckBox("Linearize Data", true); + linearizeDataCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateChart(); + } + }); + controlPanel.add(linearizeDataCheck, c); + + controlPanel.setMinimumSize(new Dimension(150,50)); + setRightComponent(controlPanel); + + setName("Location History"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(700); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return tab.getScenario(); + } + + /** + * Initialize. + */ + public void initialize() { + locationCombo.removeAllItems(); + updateChart(); + } + + /** + * Update view. + */ + public void updateView() { + tab.getScenarioPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + Location selectedLocation = (Location)locationCombo.getSelectedItem(); + ItemListener locationListener = locationCombo.getItemListeners()[0]; + locationCombo.removeItemListener(locationListener); + locationCombo.removeAllItems(); + for(Location location : getScenario().getNetwork().getLocations()) { + locationCombo.addItem(location); + } + if(selectedLocation!=null) locationCombo.setSelectedItem(selectedLocation); + locationCombo.addItemListener(locationListener); + updateChart(); + tab.getScenarioPanel().setCursor(Cursor.getDefaultCursor()); + } + private void updateChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, + "Date", + "Mass (kg)", + dataset, + true, + true, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + if(locationCombo.getSelectedItem()!=null) { + for(ClassOfSupply cos : cosModel.getSelectedObjects()) { + TimeSeries s = new TimeSeries("COS " + cos.getId(), Hour.class); + double amount = 0; + for(SimNetwork network : tab.getSimulator().getNetworkHistory()) { + Location location; + if(locationCombo.getSelectedItem() instanceof Node) { + location = network.getNetwork().getNodeByTid(((Node)locationCombo.getSelectedItem()).getTid()); + } else { + location = network.getNetwork().getEdgeByTid(((Edge)locationCombo.getSelectedItem()).getTid()); + } + Date date = DateFunctions.getDate(getScenario().getStartDate(), network.getTime()); + if(!linearizeDataCheck.isSelected() && amount>0) s.addOrUpdate(new Hour(date).previous(), amount); + amount = location.getTotalMass(cos, tab.getSimulator()); + s.addOrUpdate(new Hour(date), amount); + } + dataset.addSeries(s); + + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + r.setSeriesPaint(dataset.getSeriesCount() - 1, cos.getColor()); + } + } + + chartPanel.setChart(chart); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/simulation/MoeHistoryChart.java b/src/main/java/edu/mit/spacenet/gui/simulation/MoeHistoryChart.java new file mode 100644 index 0000000..ee94823 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/simulation/MoeHistoryChart.java @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.simulation; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.geom.Ellipse2D; +import java.text.DecimalFormat; +import java.util.Date; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.time.Hour; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.ui.RectangleInsets; + +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.gui.component.CheckBoxTableModel; +import edu.mit.spacenet.gui.component.SNChartPanel; +import edu.mit.spacenet.gui.renderer.VisibilityTableCellHeaderRenderer; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.FullSimulator; +import edu.mit.spacenet.simulator.moe.MoeCrewSurfaceDays; +import edu.mit.spacenet.simulator.moe.MoeCrewTime; +import edu.mit.spacenet.simulator.moe.MoeExplorationCapability; +import edu.mit.spacenet.simulator.moe.MoeExplorationMassDelivered; +import edu.mit.spacenet.simulator.moe.MoeLaunchMass; +import edu.mit.spacenet.simulator.moe.MoeMassCapacityUtilization; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Chart for visualizing the evolution of the various measures of effectiveness + * over the course of the simulation. + * + * @author Paul Grogan + */ +public class MoeHistoryChart extends JSplitPane { + private static final long serialVersionUID = -6405124067606236705L; + private SimulationTab tab; + private JComboBox moeCombo; + private CheckBoxTableModel locationsModel; + private JLabel totalValueLabel, valueLabel; + private ChartPanel chartPanel; + private JCheckBox linearizeDataCheck; + + /** + * Instantiates a new MOE history chart. + * + * @param tab the simulation tab + */ + public MoeHistoryChart(SimulationTab tab) { + this.tab = tab; + + chartPanel = new SNChartPanel(); + chartPanel.setPreferredSize(new Dimension(600,400)); + setLeftComponent(chartPanel); + + JPanel controlPanel = new JPanel(); + controlPanel.setLayout(new GridBagLayout()); + controlPanel.setBorder(BorderFactory.createTitledBorder("Chart Options")); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + c.gridwidth = 2; + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + moeCombo = new JComboBox(); + for(MoeType t : MoeType.values()) { + moeCombo.addItem(t); + } + moeCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + updateView(); + } + } + }); + controlPanel.add(moeCombo, c); + c.gridx--; + c.gridy++; + c.gridwidth = 1; + c.weighty = 0; + c.weightx = 0; + c.gridx = 0; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JLabel totalMetricLabel = new JLabel("Total: "); + controlPanel.add(totalMetricLabel, c); + c.gridy++; + JLabel metricLabel = new JLabel("Filtered: "); + controlPanel.add(metricLabel, c); + c.gridx++; + c.gridy--; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + totalValueLabel = new JLabel(""); + controlPanel.add(totalValueLabel, c); + c.gridy++; + valueLabel = new JLabel(""); + controlPanel.add(valueLabel, c); + c.gridx--; + c.gridy++; + c.gridwidth = 2; + c.weightx = 1; + c.weighty = 1; + locationsModel = new CheckBoxTableModel(); + locationsModel.addTableModelListener(new TableModelListener() { + public void tableChanged(TableModelEvent e) { + updateChart(); + } + }); + JTable locationsTable = new JTable(locationsModel); + locationsTable.getTableHeader().setReorderingAllowed(false); + locationsTable.getColumnModel().getColumn(0).setHeaderValue(""); + locationsTable.getColumnModel().getColumn(0).setMaxWidth(25); + locationsTable.getColumnModel().getColumn(1).setHeaderValue("Filter Locations"); + locationsTable.getColumnModel().getColumn(0).setHeaderRenderer(new VisibilityTableCellHeaderRenderer()); + locationsTable.setShowGrid(false); + JScrollPane locationsScroll = new JScrollPane(locationsTable); + locationsScroll.setPreferredSize(new Dimension(150,200)); + controlPanel.add(locationsScroll, c); + c.gridy++; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + JButton selectAllButton = new JButton("Select All"); + selectAllButton.setToolTipText("Select All Locations"); + selectAllButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + locationsModel.selectAll(); + } + }); + buttonPanel.add(selectAllButton); + JButton deselectAllButton = new JButton("Deselect All"); + deselectAllButton.setToolTipText("Deselect All Locations"); + deselectAllButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + locationsModel.deselectAll(); + } + }); + buttonPanel.add(deselectAllButton); + controlPanel.add(buttonPanel, c); + c.gridy++; + JPanel prop = new JPanel(); + prop.setPreferredSize(new Dimension(1,15)); + controlPanel.add(prop, c); + + c.gridy++; + c.anchor = GridBagConstraints.LINE_START; + linearizeDataCheck = new JCheckBox("Linearize Data", true); + linearizeDataCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateChart(); + } + }); + controlPanel.add(linearizeDataCheck, c); + + controlPanel.setMinimumSize(new Dimension(150,50)); + setRightComponent(controlPanel); + + setName("Measures History"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(700); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return tab.getScenario(); + } + + /** + * Initialize. + */ + public void initialize() { + locationsModel.clear(); + totalValueLabel.setText(""); + valueLabel.setText(""); + updateChart(); + } + + /** + * Update view. + */ + public void updateView() { + tab.getScenarioPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + List deselectedLocations = locationsModel.getDeselectedObjects(); + locationsModel.clear(); + DecimalFormat format; + switch((MoeType)moeCombo.getSelectedItem()) { + case CREW_SURFACE_DAYS: + for(MoeCrewSurfaceDays moe : tab.getSimulator().getCrewSurfaceDaysHistory()) { + locationsModel.addObject(moe.getLocation(), !deselectedLocations.contains(moe.getLocation())); + } + format = new DecimalFormat("0.0"); + totalValueLabel.setText(format.format(tab.getSimulator().getTotalCrewSurfaceDays())); + break; + case CREW_TIME: + for(MoeCrewTime moe : tab.getSimulator().getCrewTimeHistory()) { + locationsModel.addObject(moe.getLocation(), !deselectedLocations.contains(moe.getLocation())); + } + format = new DecimalFormat("0.0"); + totalValueLabel.setText(format.format(tab.getSimulator().getTotalCrewTime()) + " hours"); + break; + case LAUNCH_MASS: + for(MoeLaunchMass moe : tab.getSimulator().getLaunchMassHistory()) { + locationsModel.addObject(moe.getLocation(), !deselectedLocations.contains(moe.getLocation())); + } + format = new DecimalFormat("0.0"); + totalValueLabel.setText(format.format(tab.getSimulator().getTotalLaunchMass()/1000d) + " mT"); + break; + case EXPLORATION_MASS_DELIVERED: + for(MoeExplorationMassDelivered moe : tab.getSimulator().getExplorationMassDeliveredHistory()) { + locationsModel.addObject(moe.getLocation(), !deselectedLocations.contains(moe.getLocation())); + } + format = new DecimalFormat("0"); + totalValueLabel.setText(format.format(tab.getSimulator().getTotalExplorationMassDelivered()) + " kg"); + break; + case UP_MASS_CAPACITY_UTILIZATION: + for(MoeMassCapacityUtilization moe : tab.getSimulator().getUpMassCapacityUtilizationHistory()) { + locationsModel.addObject(moe.getLocation(), !deselectedLocations.contains(moe.getLocation())); + } + format = new DecimalFormat("0.000"); + totalValueLabel.setText(format.format(tab.getSimulator().getTotalUpMassCapacityUtilization())); + break; + case RETURN_MASS_CAPACITY_UTILIZATION: + for(MoeMassCapacityUtilization moe : tab.getSimulator().getDownMassCapacityUtilizationHistory()) { + locationsModel.addObject(moe.getLocation(), !deselectedLocations.contains(moe.getLocation())); + } + format = new DecimalFormat("0.000"); + totalValueLabel.setText(format.format(tab.getSimulator().getTotalDownMassCapacityUtilization())); + break; + case EXPLORATION_CAPABILITY: + for(MoeExplorationCapability moe : tab.getSimulator().getExplorationCapabilityHistory()) { + locationsModel.addObject(moe.getLocation(), !deselectedLocations.contains(moe.getLocation())); + } + format = new DecimalFormat("0"); + totalValueLabel.setText(format.format(tab.getSimulator().getTotalExplorationCapability())); + break; + case RELATIVE_EXPLORATION_CAPABILITY: + for(MoeExplorationCapability moe : tab.getSimulator().getExplorationCapabilityHistory()) { + locationsModel.addObject(moe.getLocation(), !deselectedLocations.contains(moe.getLocation())); + } + format = new DecimalFormat("0.00"); + totalValueLabel.setText(format.format(tab.getSimulator().getTotalRelativeExplorationCapability())); + break; + } + updateChart(); + tab.getScenarioPanel().setCursor(Cursor.getDefaultCursor()); + } + private void updateChart() { + TimeSeriesCollection dataset = new TimeSeriesCollection(); + + JFreeChart chart = ChartFactory.createTimeSeriesChart( + null, + "Date", + "Value", + dataset, + true, + true, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.GRAY); + plot.setRangeGridlinePaint(Color.GRAY); + plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); + + XYItemRenderer r = chart.getXYPlot().getRenderer(); + + if (r instanceof XYLineAndShapeRenderer) { + XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; + renderer.setBaseShapesVisible(true); + renderer.setBaseShapesFilled(true); + } + + DecimalFormat format; + if(((MoeType)moeCombo.getSelectedItem()).equals(MoeType.CREW_SURFACE_DAYS)) { + TimeSeries s = new TimeSeries("Total", Hour.class); + plot.getRangeAxis().setLabel("Crew Surface Days"); + double amount = 0; + s.addOrUpdate(new Hour(getScenario().getStartDate()), amount); + for(MoeCrewSurfaceDays moe : tab.getSimulator().getCrewSurfaceDaysHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), moe.getTime()); + if(locationsModel.getSelectedObjects().contains(moe.getLocation())) { + if(!linearizeDataCheck.isSelected() && amount>0) s.addOrUpdate(new Hour(date).previous(), amount); + amount += moe.getAmount(); + s.addOrUpdate(new Hour(date), amount); + } + } + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount); + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + format = new DecimalFormat("0.0"); + valueLabel.setText(format.format(amount)); + } else if(((MoeType)moeCombo.getSelectedItem()).equals(MoeType.CREW_TIME)) { + TimeSeries s1 = new TimeSeries(MoeCrewTime.UNAVAILABLE, Hour.class); + TimeSeries s2 = new TimeSeries(MoeCrewTime.EXPLORATION, Hour.class); + TimeSeries s3 = new TimeSeries(MoeCrewTime.CORRECTIVE_MAINTENANCE, Hour.class); + TimeSeries s4 = new TimeSeries(MoeCrewTime.PREVENTATIVE_MAINTENANCE, Hour.class); + plot.getRangeAxis().setLabel("Hours"); + double amount1=0,amount2=0,amount3=0,amount4=0; + s1.addOrUpdate(new Hour(getScenario().getStartDate()), amount1); + s2.addOrUpdate(new Hour(getScenario().getStartDate()), amount2); + s3.addOrUpdate(new Hour(getScenario().getStartDate()), amount3); + s4.addOrUpdate(new Hour(getScenario().getStartDate()), amount4); + for(MoeCrewTime moe : tab.getSimulator().getCrewTimeHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), moe.getTime()); + if(locationsModel.getSelectedObjects().contains(moe.getLocation())) { + if(!linearizeDataCheck.isSelected() && amount1>0) s1.addOrUpdate(new Hour(date).previous(), amount1); + if(!linearizeDataCheck.isSelected() && amount2>0) s2.addOrUpdate(new Hour(date).previous(), amount2); + if(!linearizeDataCheck.isSelected() && amount3>0) s3.addOrUpdate(new Hour(date).previous(), amount3); + if(!linearizeDataCheck.isSelected() && amount4>0) s4.addOrUpdate(new Hour(date).previous(), amount4); + if(moe.getType().equals(MoeCrewTime.UNAVAILABLE)) { + amount1 += moe.getAmount(); + } else if(moe.getType().equals(MoeCrewTime.EXPLORATION)) { + amount2 += moe.getAmount(); + } else if(moe.getType().equals(MoeCrewTime.CORRECTIVE_MAINTENANCE)) { + amount3 += moe.getAmount(); + } else if(moe.getType().equals(MoeCrewTime.PREVENTATIVE_MAINTENANCE)) { + amount4 += moe.getAmount(); + } + s1.addOrUpdate(new Hour(date), amount1); + s2.addOrUpdate(new Hour(date), amount2); + s3.addOrUpdate(new Hour(date), amount3); + s4.addOrUpdate(new Hour(date), amount4); + } + } + s1.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount1); + s2.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount2); + s3.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount3); + s4.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount4); + dataset.addSeries(s1); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + dataset.addSeries(s2); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + dataset.addSeries(s3); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + dataset.addSeries(s4); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + format = new DecimalFormat("0.0"); + valueLabel.setText(format.format(amount1+amount2+amount3+amount4)); + } else if(((MoeType)moeCombo.getSelectedItem()).equals(MoeType.LAUNCH_MASS)) { + TimeSeries s = new TimeSeries("Total", Hour.class); + plot.getRangeAxis().setLabel("Launch Mass (mT)"); + double amount = 0; + s.addOrUpdate(new Hour(getScenario().getStartDate()), amount); + for(MoeLaunchMass moe : tab.getSimulator().getLaunchMassHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), moe.getTime()); + if(locationsModel.getSelectedObjects().contains(moe.getLocation())) { + if(!linearizeDataCheck.isSelected() && amount>0) s.addOrUpdate(new Hour(date).previous(), amount); + amount += moe.getAmount()/1000d; + s.addOrUpdate(new Hour(date), amount); + } + } + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount); + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + format = new DecimalFormat("0.0"); + valueLabel.setText(format.format(amount) + " mT"); + } else if(((MoeType)moeCombo.getSelectedItem()).equals(MoeType.EXPLORATION_MASS_DELIVERED)) { + TimeSeries s = new TimeSeries("Total", Hour.class); + plot.getRangeAxis().setLabel("Exploration Mass Delivered (kg)"); + double amount = 0; + s.addOrUpdate(new Hour(getScenario().getStartDate()), amount); + for(MoeExplorationMassDelivered moe : tab.getSimulator().getExplorationMassDeliveredHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), moe.getTime()); + if(locationsModel.getSelectedObjects().contains(moe.getLocation())) { + if(!linearizeDataCheck.isSelected() && amount>0) s.addOrUpdate(new Hour(date).previous(), amount); + amount += moe.getAmount(); + s.addOrUpdate(new Hour(date), amount); + } + } + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount); + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + format = new DecimalFormat("0"); + valueLabel.setText(format.format(amount) + " kg"); + } else if(((MoeType)moeCombo.getSelectedItem()).equals(MoeType.UP_MASS_CAPACITY_UTILIZATION)) { + TimeSeries s1 = new TimeSeries("Capacity", Hour.class); + TimeSeries s2 = new TimeSeries("Utilization", Hour.class); + plot.getRangeAxis().setLabel("Up-Mass Utilization (kg)"); + double capacity = 0; + double amount = 0; + s1.addOrUpdate(new Hour(getScenario().getStartDate()), capacity); + s2.addOrUpdate(new Hour(getScenario().getStartDate()), amount); + for(MoeMassCapacityUtilization moe : tab.getSimulator().getUpMassCapacityUtilizationHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), moe.getTime()); + if(locationsModel.getSelectedObjects().contains(moe.getLocation())) { + if(!linearizeDataCheck.isSelected() && capacity>0) s1.addOrUpdate(new Hour(date).previous(), capacity); + if(!linearizeDataCheck.isSelected() && amount>0) s2.addOrUpdate(new Hour(date).previous(), amount); + capacity += moe.getCapacity(); + amount += moe.getAmount(); + s1.addOrUpdate(new Hour(date), capacity); + s2.addOrUpdate(new Hour(date), amount); + } + } + s1.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), capacity); + s2.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount); + dataset.addSeries(s1); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + dataset.addSeries(s2); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + format = new DecimalFormat("0.000"); + valueLabel.setText(capacity==0?"n/a":format.format(amount/capacity)); + } else if(((MoeType)moeCombo.getSelectedItem()).equals(MoeType.RETURN_MASS_CAPACITY_UTILIZATION)) { + TimeSeries s1 = new TimeSeries("Capacity", Hour.class); + TimeSeries s2 = new TimeSeries("Utilization", Hour.class); + plot.getRangeAxis().setLabel("Return-Mass Utilization (kg)"); + double capacity = 0; + double amount = 0; + s1.addOrUpdate(new Hour(getScenario().getStartDate()), capacity); + s2.addOrUpdate(new Hour(getScenario().getStartDate()), amount); + for(MoeMassCapacityUtilization moe : tab.getSimulator().getDownMassCapacityUtilizationHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), moe.getTime()); + if(locationsModel.getSelectedObjects().contains(moe.getLocation())) { + if(!linearizeDataCheck.isSelected() && capacity>0) s1.addOrUpdate(new Hour(date).previous(), capacity); + if(!linearizeDataCheck.isSelected() && amount>0) s2.addOrUpdate(new Hour(date).previous(), amount); + capacity += moe.getCapacity(); + amount += moe.getAmount(); + s1.addOrUpdate(new Hour(date), capacity); + s2.addOrUpdate(new Hour(date), amount); + } + } + s1.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), capacity); + s2.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount); + dataset.addSeries(s1); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + dataset.addSeries(s2); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + format = new DecimalFormat("0.000"); + valueLabel.setText(capacity==0?"n/a":format.format(amount/capacity)); + } else if(((MoeType)moeCombo.getSelectedItem()).equals(MoeType.EXPLORATION_CAPABILITY)) { + TimeSeries s = new TimeSeries("Total", Hour.class); + plot.getRangeAxis().setLabel("Exploration Capability"); + double amount = 0; + s.addOrUpdate(new Hour(getScenario().getStartDate()), amount); + for(MoeExplorationCapability moe : tab.getSimulator().getExplorationCapabilityHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), moe.getTime()); + if(locationsModel.getSelectedObjects().contains(moe.getLocation())) { + if(!linearizeDataCheck.isSelected() && amount>0) s.addOrUpdate(new Hour(date).previous(), amount); + amount += moe.getMass()*moe.getDuration(); + s.addOrUpdate(new Hour(date), amount); + } + } + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), amount); + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + format = new DecimalFormat("0"); + valueLabel.setText(format.format(amount)); + } else if(((MoeType)moeCombo.getSelectedItem()).equals(MoeType.RELATIVE_EXPLORATION_CAPABILITY)) { + TimeSeries s = new TimeSeries("Total", Hour.class); + plot.getRangeAxis().setLabel("Relative Exploration Capability"); + double amount = 0; + double value = 0; + s.addOrUpdate(new Hour(getScenario().getStartDate()), value); + for(MoeExplorationCapability moe : tab.getSimulator().getExplorationCapabilityHistory()) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), moe.getTime()); + + if(locationsModel.getSelectedObjects().contains(moe.getLocation())) { + amount += moe.getMass()*moe.getDuration(); + + double mass = 0; + for(MoeLaunchMass moeMass : tab.getSimulator().getLaunchMassHistory()) { + if(moeMass.getTime()<=moe.getTime()) + mass += moeMass.getAmount(); + else break; + } + if(!linearizeDataCheck.isSelected() && value>0) s.addOrUpdate(new Hour(date).previous(), value); + value = (amount/FullSimulator.APOLLO_17_EXPLORATION_CAPABILITY)/(mass/FullSimulator.APOLLO_17_LAUNCH_MASS); + s.addOrUpdate(new Hour(date), value); + } + } + s.addOrUpdate(new Hour(DateFunctions.getDate(getScenario().getStartDate(), + tab.getSimulator().getTime())), value); + dataset.addSeries(s); + r.setSeriesShape(dataset.getSeriesCount() - 1, new Ellipse2D.Double(-1,-1,2,2)); + format = new DecimalFormat("0.00"); + valueLabel.setText(format.format(value)); + } + + chartPanel.setChart(chart); + } + + /** + * The Enum MoeType. + */ + enum MoeType { + + /** The crew surface days. */ + CREW_SURFACE_DAYS("Crew Surface Days"), + + /** The crew time. */ + CREW_TIME("Crew Time"), + + /** The launch mass. */ + LAUNCH_MASS("Launch Mass"), + + /** The exploration mass delivered. */ + EXPLORATION_MASS_DELIVERED("Exploration Mass Delivered"), + + /** The up mass capacity utilization. */ + UP_MASS_CAPACITY_UTILIZATION("Up-Mass Capacity Utilization"), + + /** The return mass capacity utilization. */ + RETURN_MASS_CAPACITY_UTILIZATION("Return-Mass Capacity Utilization"), + + /** The exploration capability. */ + EXPLORATION_CAPABILITY("Exploration Capability"), + + /** The relative exploration capability. */ + RELATIVE_EXPLORATION_CAPABILITY("Relative Exploration Capability"); + + private String name; + private MoeType(String name) { + this.name = name; + } + + /** + * Gets the name. + * + * @return the name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/simulation/NetworkHistoryVisualization.java b/src/main/java/edu/mit/spacenet/gui/simulation/NetworkHistoryVisualization.java new file mode 100644 index 0000000..1c61e10 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/simulation/NetworkHistoryVisualization.java @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.simulation; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Hashtable; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSlider; +import javax.swing.JSpinner; +import javax.swing.JSplitPane; +import javax.swing.JToggleButton; +import javax.swing.SpinnerNumberModel; +import javax.swing.SwingWorker; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.element.SurfaceVehicle; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.gui.component.CapacityPanel; +import edu.mit.spacenet.gui.component.ElementTree; +import edu.mit.spacenet.gui.component.FuelPanel; +import edu.mit.spacenet.gui.visualization.NetworkPanel; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.util.DateFunctions; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Visualization of the network with options to run animation over the course + * of the simulation. + * + * @author Paul Grogan + */ +public class NetworkHistoryVisualization extends JSplitPane { + private static final long serialVersionUID = -6405124067606236705L; + private static int numLabels = 5; + private static double stepsPerDay = 1/GlobalParameters.getTimePrecision(); + + private SimulationTab tab; + private DecimalFormat decimalFormat = new DecimalFormat("0.0"); + + private JSlider timeSlider; + private JToggleButton playButton; + private Animation animation; + private JButton startButton, rewindButton, stopButton, + fastforwardButton, endButton; + private JSpinner rateSpinner; + private JCheckBox constantTimeCheck; + + private NetworkPanel networkPanel; + private JLabel dateLabel, relativeTimeLabel; + private ElementTree elementTree; + private CapacityPanel capacityPanel; + private FuelPanel fuelPanel; + private JLabel stateLabel, stateValueLabel, massLabel, massValueLabel, + volumeLabel, volumeValueLabel; + + /** + * Instantiates a new network history visualization. + * + * @param tab the simulation tab + */ + public NetworkHistoryVisualization(SimulationTab tab) { + this.tab = tab; + + JSplitPane visualizationPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + JPanel sliderPanel = new JPanel(); + sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS)); + timeSlider = new JSlider(); + timeSlider.setEnabled(false); + timeSlider.setFocusable(false); + timeSlider.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + updateElements(); + } + }); + sliderPanel.add(timeSlider); + visualizationPanel.setTopComponent(sliderPanel); + + networkPanel = new NetworkPanel(); + networkPanel.setBackground(Color.BLACK); + networkPanel.setPreferredSize(new Dimension(600,400)); + visualizationPanel.setBottomComponent(networkPanel); + + visualizationPanel.setDividerSize(0); + visualizationPanel.setDividerLocation(75); + visualizationPanel.setBorder(BorderFactory.createEmptyBorder()); + setLeftComponent(visualizationPanel); + + JPanel controlPanel = new JPanel(); + controlPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + controlPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.gridwidth = 2; + + JPanel buttonPanel = new JPanel(); + startButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/control_start.png"))); + startButton.setMargin(new Insets(0,0,0,0)); + startButton.setEnabled(false); + startButton.setFocusable(false); + startButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(playButton.isSelected()) { + playButton.setSelected(false); + } + timeSlider.setValue(timeSlider.getMinimum()); + } + }); + buttonPanel.add(startButton); + rewindButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/control_rewind.png"))); + rewindButton.setMargin(new Insets(0,0,0,0)); + rewindButton.setEnabled(false); + rewindButton.setFocusable(false); + rewindButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(playButton.isSelected()) { + playButton.setSelected(false); + } + timeSlider.setValue(Math.max(timeSlider.getMinimum(), timeSlider.getValue()-1)); + } + }); + buttonPanel.add(rewindButton); + stopButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/control_stop.png"))); + stopButton.setMargin(new Insets(0,0,0,0)); + stopButton.setEnabled(false); + stopButton.setFocusable(false); + stopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(playButton.isSelected()) { + playButton.setSelected(false); + } + } + }); + buttonPanel.add(stopButton); + playButton = new JToggleButton(new ImageIcon(getClass().getClassLoader().getResource("icons/control_play.png"))); + playButton.setSelectedIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_pause.png"))); + playButton.setMargin(new Insets(0,0,0,0)); + playButton.setEnabled(false); + playButton.setFocusable(false); + playButton.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange()==ItemEvent.SELECTED) { + if(timeSlider.getValue()==timeSlider.getMaximum()) + timeSlider.setValue(timeSlider.getMinimum()); + animation = new Animation(); + animation.execute(); + } else if(e.getStateChange()==ItemEvent.DESELECTED) { + animation.cancel(true); + } + } + }); + buttonPanel.add(playButton); + fastforwardButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/control_fastforward.png"))); + fastforwardButton.setMargin(new Insets(0,0,0,0)); + fastforwardButton.setEnabled(false); + fastforwardButton.setFocusable(false); + fastforwardButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(playButton.isSelected()) { + playButton.setSelected(false); + } + timeSlider.setValue(Math.min(timeSlider.getMaximum(), timeSlider.getValue()+1)); + } + }); + buttonPanel.add(fastforwardButton); + endButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/control_end.png"))); + endButton.setMargin(new Insets(0,0,0,0)); + endButton.setEnabled(false); + endButton.setFocusable(false); + endButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(playButton.isSelected()) { + playButton.setSelected(false); + } + timeSlider.setValue(timeSlider.getMaximum()); + } + }); + buttonPanel.add(endButton); + controlPanel.add(buttonPanel, c); + c.gridy++; + c.gridwidth = 1; + c.anchor = GridBagConstraints.LINE_END; + c.fill = GridBagConstraints.NONE; + JLabel rateLabel = new JLabel("Frames per second: "); + controlPanel.add(rateLabel, c); + c.gridx++; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + rateSpinner = new JSpinner(new SpinnerNumberModel(10, 1, 50, 1)); + controlPanel.add(rateSpinner, c); + c.gridx--; + c.gridy++; + c.gridwidth = 2; + constantTimeCheck = new JCheckBox("Constant Time per Frame"); + controlPanel.add(constantTimeCheck, c); + c.gridy++; + c.weighty = 1; + JPanel detailsPanel = new JPanel(); + controlPanel.add(detailsPanel, c); + detailsPanel.setLayout(new GridBagLayout()); + detailsPanel.setBorder(BorderFactory.createTitledBorder("Element Details")); + c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.gridwidth = 2; + c.weightx = 1; + dateLabel = new JLabel(); + detailsPanel.add(dateLabel, c); + c.gridy++; + relativeTimeLabel = new JLabel(); + detailsPanel.add(relativeTimeLabel, c); + c.gridy++; + detailsPanel.add(new JLabel("Elements: "), c); + c.gridy++; + c.weighty = 1; + elementTree = new ElementTree(); + elementTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + updateCapacities(); + } + }); + JScrollPane elementScroll = new JScrollPane(elementTree); + elementScroll.setPreferredSize(new Dimension(150,200)); + detailsPanel.add(elementScroll, c); + c.gridy++; + c.weighty = 0; + c.weightx = 0; + c.gridwidth = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + stateLabel = new JLabel("State: "); + stateLabel.setVisible(false); + detailsPanel.add(stateLabel, c); + c.gridx++; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + stateValueLabel = new JLabel(); + stateValueLabel.setVisible(false); + detailsPanel.add(stateValueLabel, c); + c.gridy++; + c.gridx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + massLabel = new JLabel("Mass: "); + massLabel.setVisible(false); + detailsPanel.add(massLabel, c); + c.gridx++; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + massValueLabel = new JLabel(); + massValueLabel.setVisible(false); + detailsPanel.add(massValueLabel, c); + c.gridy++; + c.gridx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + volumeLabel = new JLabel("Volume: "); + volumeLabel.setVisible(false); + detailsPanel.add(volumeLabel, c); + c.gridx++; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + volumeValueLabel = new JLabel(); + volumeValueLabel.setVisible(false); + detailsPanel.add(volumeValueLabel, c); + c.gridy++; + c.gridx = 0; + c.gridwidth = 2; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + capacityPanel = new CapacityPanel(); + capacityPanel.setVisible(false); + detailsPanel.add(capacityPanel, c); + c.gridy++; + fuelPanel = new FuelPanel(); + fuelPanel.setVisible(false); + detailsPanel.add(fuelPanel, c); + + controlPanel.setMinimumSize(new Dimension(150,50)); + setRightComponent(controlPanel); + setName("Network History"); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + setResizeWeight(1); + setDividerLocation(700); + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return tab.getScenario(); + } + + /** + * Initialize. + */ + public void initialize() { + networkPanel.setNetwork(getScenario().getNetwork()); + updateView(); + } + + /** + * Update view. + */ + public void updateView() { + tab.getScenarioPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + if(tab.getSimulator().getNetworkHistory().size() > 0) { + timeSlider.setEnabled(true); + timeSlider.setMinimum(0); + double maxTime = tab.getSimulator().getTime(); + int maxVal = (int)Math.ceil(maxTime*stepsPerDay); + while(maxVal%numLabels!=0) maxVal++; + timeSlider.setMaximum(maxVal); + Hashtable labelDictionary = new Hashtable(); + SimpleDateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy"); + for(int i=0; i<=numLabels; i++) { + Date date = DateFunctions.getDate(getScenario().getStartDate(), maxVal*i/numLabels/stepsPerDay); + labelDictionary.put(maxVal*i/numLabels, new JLabel(dateFormat.format(date))); + } + timeSlider.setLabelTable(labelDictionary); + timeSlider.setMajorTickSpacing(maxVal/numLabels); + timeSlider.setMinorTickSpacing(0); + timeSlider.setPaintTicks(true); + timeSlider.setPaintLabels(true); + timeSlider.setValue(timeSlider.getMinimum()); + + startButton.setEnabled(true); + rewindButton.setEnabled(true); + playButton.setEnabled(true); + stopButton.setEnabled(true); + fastforwardButton.setEnabled(true); + endButton.setEnabled(true); + updateElements(); + } else { + timeSlider.setMinimum(0); + timeSlider.setMaximum(0); + timeSlider.setLabelTable(null); + timeSlider.setMajorTickSpacing(0); + timeSlider.setValue(0); + timeSlider.setEnabled(false); + startButton.setEnabled(false); + rewindButton.setEnabled(false); + playButton.setEnabled(false); + stopButton.setEnabled(false); + fastforwardButton.setEnabled(false); + endButton.setEnabled(false); + updateElements(); + updateCapacities(); + } + tab.getScenarioPanel().setCursor(Cursor.getDefaultCursor()); + } + private void updateElements() { + if(tab.getSimulator().getNetworkHistory().size()>0) { + Network network; + double time; + if(timeSlider.getValue()==timeSlider.getMaximum()) { + network = tab.getSimulator().getScenario().getNetwork(); + time = tab.getSimulator().getTime(); + } else { + int i=0; + while(tab.getSimulator().getNetworkHistory().get(i+1).getTime()*stepsPerDay <= timeSlider.getValue() + && i < tab.getSimulator().getNetworkHistory().size() - 2) { + i++; + } + network = tab.getSimulator().getNetworkHistory().get(i).getNetwork(); + time = timeSlider.getValue()/stepsPerDay; + } + SimpleDateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy kk:mm"); + dateLabel.setText("Date: " + dateFormat.format(DateFunctions.getDate(getScenario().getStartDate(), time))); + relativeTimeLabel.setText("Relative Time: " + GlobalParameters.getRoundedTime(time)); + elementTree.setRoot(network); + networkPanel.setNetwork(network); + } else { + dateLabel.setText("Date: "); + relativeTimeLabel.setText("Relative Time: "); + elementTree.setRoot(null); + networkPanel.setNetwork(tab.getScenario().getNetwork()); + } + networkPanel.repaint(); + } + + /** + * Update capacities. + */ + private void updateCapacities() { + if(elementTree.getSelection() instanceof I_Element) { + I_Element element = (I_Element)elementTree.getSelection(); + if(element.getCurrentState()==null) { + stateValueLabel.setText(null); + stateValueLabel.setIcon(null); + stateValueLabel.setVisible(false); + stateLabel.setVisible(false); + } else { + stateValueLabel.setText(element.getCurrentState().toString()); + stateValueLabel.setIcon(element.getCurrentState().getStateType().getIcon()); + stateValueLabel.setVisible(true); + stateLabel.setVisible(true); + } + massValueLabel.setText(decimalFormat.format(element.getMass()) + " kg"); + volumeValueLabel.setText(decimalFormat.format(element.getVolume()) + " m^3"); + massLabel.setVisible(true); + massValueLabel.setVisible(true); + if(GlobalParameters.isVolumeConstrained()) { + volumeLabel.setVisible(true); + volumeValueLabel.setVisible(true); + } else { + volumeLabel.setVisible(false); + volumeValueLabel.setVisible(false); + } + } else { + stateValueLabel.setText(null); + stateValueLabel.setIcon(null); + stateValueLabel.setVisible(false); + massValueLabel.setVisible(false); + massLabel.setVisible(false); + volumeValueLabel.setVisible(false); + volumeLabel.setVisible(false); + } + + if(elementTree.getSelection() instanceof I_Carrier) { + I_Carrier carrier = (I_Carrier)elementTree.getSelection(); + capacityPanel.setVisible(true); + capacityPanel.updateCapacities(carrier, carrier.getCargoMass(), + carrier.getCargoVolume(), carrier.getCrewSize()); + } else if(elementTree.getSelection() instanceof I_ResourceContainer) { + I_ResourceContainer container = (I_ResourceContainer)elementTree.getSelection(); + capacityPanel.setVisible(true); + capacityPanel.updateCapacities(container, container.getCargoMass(), + container.getCargoVolume()); + } else if(elementTree.getSelection() instanceof Location) { + Location location = (Location)elementTree.getSelection(); + capacityPanel.setVisible(true); + capacityPanel.updateCapacities(location, location.getCargoMass(), + location.getCargoVolume(), location.getCrewSize()); + } else { + capacityPanel.setVisible(false); + } + if(elementTree.getSelection() instanceof PropulsiveVehicle) { + PropulsiveVehicle vehicle = (PropulsiveVehicle)elementTree.getSelection(); + fuelPanel.setVisible(true); + fuelPanel.updateFuel(vehicle); + } else if(elementTree.getSelection() instanceof SurfaceVehicle) { + SurfaceVehicle vehicle = (SurfaceVehicle)elementTree.getSelection(); + fuelPanel.setVisible(true); + fuelPanel.updateFuel(vehicle); + } else { + fuelPanel.setVisible(false); + } + } + + /** + * The Class Animation. + */ + class Animation extends SwingWorker { + + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#doInBackground() + */ + @Override + public Void doInBackground() { + if(constantTimeCheck.isSelected()) { + while(timeSlider.getValue() < timeSlider.getMaximum() + && !isCancelled()) { + timeSlider.setValue(timeSlider.getValue() + 1); + try { + Thread.sleep((1000/(Integer)rateSpinner.getValue())); + } catch (InterruptedException e) { } + } + } else { + int i = 0; + while(i < tab.getSimulator().getNetworkHistory().size() + && timeSlider.getValue()/stepsPerDay > tab.getSimulator().getNetworkHistory().get(i).getTime()) { + i++; + } + while(i < tab.getSimulator().getNetworkHistory().size() + && !isCancelled()) { + timeSlider.setValue((int)(tab.getSimulator().getNetworkHistory().get(i).getTime()*stepsPerDay)); + i++; + try { + Thread.sleep((1000/(Integer)rateSpinner.getValue())); + } catch (InterruptedException e) { } + } + } + return null; + } + + /* (non-Javadoc) + * @see org.jdesktop.swingworker.SwingWorker#done() + */ + public void done() { + playButton.setSelected(false); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/simulation/SimulationTab.java b/src/main/java/edu/mit/spacenet/gui/simulation/SimulationTab.java new file mode 100644 index 0000000..927e515 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/simulation/SimulationTab.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.simulation; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.text.DecimalFormat; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.SwingWorker; + +import edu.mit.spacenet.gui.ScenarioPanel; +import edu.mit.spacenet.gui.SpaceNetFrame; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.FullSimulator; +import edu.mit.spacenet.simulator.SimError; + +/** + * Tab component for running the full simulation, analyzing errors, and + * visualizing the outputs. + * + * @author Paul Grogan + */ +public class SimulationTab extends JSplitPane { + private static final long serialVersionUID = 6299975123289250302L; + + private JPanel controlPanel; + private JCheckBox detailedExplorationsCheck, detailedEvasCheck; + private JButton simulateButton; + private DefaultListModel errorsModel; + private JList errorsList; + private JTabbedPane tabs; + + private NetworkHistoryVisualization networkVisualization; + private MoeHistoryChart moeChart; + private LocationCosHistoryChart locationChart; + private ElementCosHistoryChart elementChart; + + private FullSimulator simulator; + + private ScenarioPanel scenarioPanel; + private boolean isSimulating = false; + + /** + * Instantiates a new simulation tab. + * + * @param scenarioPanel the scenario panel + */ + public SimulationTab(ScenarioPanel scenarioPanel) { + this.scenarioPanel = scenarioPanel; + + controlPanel = new JPanel(); + controlPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + controlPanel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2,2,2,2); + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.BOTH; + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + detailedExplorationsCheck = new JCheckBox("Detailed Explorations"); + detailedExplorationsCheck.setToolTipText("Detailed explorations are not necessary if using mission-level demand models to capture EVA demands."); + detailedExplorationsCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + getScenario().setDetailedExploration(detailedExplorationsCheck.isSelected()); + } + }); + controlPanel.add(detailedExplorationsCheck, c); + c.gridy++; + detailedEvasCheck = new JCheckBox("Detailed EVAs"); + detailedEvasCheck.setToolTipText("Detailed EVAs are not necessary if using mission-level demand models to capture EVA demands."); + detailedEvasCheck.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + getScenario().setDetailedEva(detailedEvasCheck.isSelected()); + } + }); + controlPanel.add(detailedEvasCheck, c); + c.gridy++; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + simulateButton = new JButton("Simulate", new ImageIcon(getClass().getClassLoader().getResource("icons/lightning_go.png"))); + simulateButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if(isSimulating) return; + isSimulating = true; + SwingWorker worker = new SwingWorker() { + public Void doInBackground() { + SpaceNetFrame.getInstance().getStatusBar().setStatusMessage("Running Simulation..."); + getScenarioPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + simulator.simulate(); + if(simulator.getErrors().size()>0) { + JOptionPane.showMessageDialog(tabs, + "The simulation completed with " + simulator.getErrors().size() + + " error" + (simulator.getErrors().size()==1?"":"s") + ".", + "SpaceNet Simulation Errors", + JOptionPane.WARNING_MESSAGE); + } + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + public void done() { + updateView(); + SpaceNetFrame.getInstance().getStatusBar().clearStatusMessage(); + getScenarioPanel().setCursor(Cursor.getDefaultCursor()); + isSimulating = false; + } + }; + worker.execute(); + } + }); + controlPanel.add(simulateButton, c); + c.gridy++; + c.gridwidth = 2; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; + controlPanel.add(new JLabel("Simulation Errors: "), c); + c.gridy++; + c.weighty = .5; + c.fill = GridBagConstraints.BOTH; + errorsModel = new DefaultListModel(); + errorsList = new JList(errorsModel); + errorsList.setCellRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 635852745823206059L; + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(value instanceof SimError) { + SimError error = (SimError)value; + DecimalFormat format = new DecimalFormat("0.00"); + setText(format.format(error.getTime()) + ": " + error.getMessage()); + setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/bullet_error.png"))); + } + return this; + } + }); + JScrollPane errorsScroll = new JScrollPane(errorsList); + errorsScroll.setPreferredSize(new Dimension(50,50)); + controlPanel.add(errorsScroll, c); + + c.gridy++; + c.weighty = .5; + c.anchor = GridBagConstraints.FIRST_LINE_START; + c.fill = GridBagConstraints.NONE; + + setLeftComponent(new JScrollPane(controlPanel)); + + tabs = new JTabbedPane(); + networkVisualization = new NetworkHistoryVisualization(this); + tabs.add(networkVisualization); + moeChart = new MoeHistoryChart(this); + tabs.add(moeChart); + locationChart = new LocationCosHistoryChart(this); + tabs.add(locationChart); + elementChart = new ElementCosHistoryChart(this); + tabs.add(elementChart); + + setRightComponent(tabs); + + setResizeWeight(.1); + setDividerLocation(150); + setOneTouchExpandable(true); + setDividerSize(10); + setBorder(BorderFactory.createEmptyBorder()); + } + + /** + * Initialize. + */ + public void initialize() { + simulator = new FullSimulator(getScenario()); + errorsModel.clear(); + detailedExplorationsCheck.setSelected(getScenario().isDetailedExploration()); + detailedEvasCheck.setSelected(getScenario().isDetailedEva()); + networkVisualization.initialize(); + moeChart.initialize(); + locationChart.initialize(); + elementChart.initialize(); + } + + /** + * Gets the scenario panel. + * + * @return the scenario panel + */ + public ScenarioPanel getScenarioPanel() { + return scenarioPanel; + } + + /** + * Gets the this. + * + * @return the this + */ + public SimulationTab getThis() { + return this; + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return scenarioPanel.getScenario(); + } + + /** + * Gets the simulator. + * + * @return the simulator + */ + public FullSimulator getSimulator() { + return simulator; + } + + /** + * Update view. + */ + public void updateView() { + errorsModel.clear(); + detailedExplorationsCheck.setSelected(getScenario().isDetailedExploration()); + detailedEvasCheck.setSelected(getScenario().isDetailedEva()); + for(SimError error : simulator.getErrors()) { + errorsModel.addElement(error); + } + networkVisualization.updateView(); + moeChart.updateView(); + locationChart.updateView(); + elementChart.updateView(); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/visualization/BodyLayer.java b/src/main/java/edu/mit/spacenet/gui/visualization/BodyLayer.java new file mode 100644 index 0000000..04f6bd3 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/visualization/BodyLayer.java @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.visualization; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.LagrangeNode; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * The layer that represents celestrial bodies in the network visualization. + * + * @author Nii Armar, Paul Grogan + */ +public class BodyLayer extends JPanel { + private static final long serialVersionUID = -7130437870888000639L; + + private NetworkPanel networkPanel; + + private double horizontalScale = 1; + private double verticalScale = 1; + + private double sizeDisparity = 10.0; + private double sizeScale = 2.0; + private double sizeBasis = 1.0; + private double locationDisparity = 30.0; + private double locationScale = 1.5; + private double locationBasis = 1.0; + private boolean drawOrbitalLimits = false; + private boolean simpleMode = true; + private boolean displaySun = false; + + private Map bodyLocationMap; + private Map bodySizeMap; + + /** + * Instantiates a new body layer. + * + * @param networkPanel the network panel + */ + public BodyLayer(NetworkPanel networkPanel) { + this.networkPanel = networkPanel; + setOpaque(false); + setLayout(null); + bodyLocationMap = new HashMap(); + bodySizeMap = new HashMap(); + } + + /* (non-Javadoc) + * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) + */ + public void paintComponent(Graphics g) { + super.paintComponent(g); + int planetCount = 0; + + Set bodies = new HashSet(); + for(Node node : getNetwork().getNodes()) { + Body body = null; + if(node instanceof LagrangeNode && ((LagrangeNode)node).getNumber() <= 2) { + body = ((LagrangeNode)node).getMinorBody(); + } else { + body = node.getBody(); + } + if(body.getParent()==Body.SUN && !bodies.contains(body)) planetCount++; + bodies.add(body); + } + + if(bodies.size()==0) { + // display nothing + } else if((bodies.size()==1 || planetCount==1) && !bodies.contains(Body.SUN) && simpleMode) { + // lay out moons to the right of planet + double width = 0; + double height = 0; + + for(Body planet : Body.values()) { + double planetSize = 0; + if((planet.getParent()==Body.SUN||bodies.size()==1) && bodies.contains(planet)) { + planetSize = getRawSize(planet.getPlanetaryRadius()); + height = planetSize*1.5; + width = planetSize*1.5; + + for(Body moon : Body.values()) { + double moonSize = 0; + double moonLocation = 0; + if(moon.getParent()==planet && bodies.contains(moon)) { + moonSize = getRawSize(moon.getPlanetaryRadius()); + moonLocation = getRawLocation(moon.getOrbitalRadius()); + + height = Math.max(height, moonSize*1.5); + width = Math.max(width, planetSize*3/4d + moonLocation + moonSize*3/4d); + } + } + } + } + horizontalScale = (getBounds().width)/width; + verticalScale = (getBounds().height)/height; + + bodyLocationMap.clear(); + bodySizeMap.clear(); + for(Body planet : Body.values()) { + int planetSize = 0; + if((planet.getParent()==Body.SUN||bodies.size()==1) && bodies.contains(planet)) { + planetSize = getScaledNumber(getRawSize(planet.getPlanetaryRadius())); + int h_space = getBounds().width - (int)Math.round(width*Math.min(horizontalScale, verticalScale)); + int v_space = getBounds().height - (int)Math.round(height*Math.min(horizontalScale, verticalScale)); + bodyLocationMap.put(planet, new Point(h_space/2 + planetSize*3/4, v_space/2 + planetSize*3/4)); + bodySizeMap.put(planet, planetSize); + + drawBody(planet, g); + + for(Body moon : Body.values()) { + int moonSize = 0; + int moonLocation = 0; + if(moon.getParent()==planet && bodies.contains(moon)) { + moonSize = getScaledNumber(getRawSize(moon.getPlanetaryRadius())); + moonLocation = getScaledNumber(getRawLocation(moon.getOrbitalRadius())); + + bodyLocationMap.put(moon, + new Point(bodyLocationMap.get(planet).x+moonLocation, + bodyLocationMap.get(planet).y)); + bodySizeMap.put(moon, moonSize); + + drawBody(moon, g); + } + } + } + } + } else if(displaySun||bodies.contains(Body.SUN)) { + // lay out planets to the right, moons below each planet + double width = 0; + double height = 0; + + double sunSize = getRawSize(Body.SUN.getPlanetaryRadius()); + width = sunSize/2d; + height = sunSize; + + for(Body planet : Body.values()) { + double planetSize = 0; + double planetLocation = 0; + + if(planet.getParent()==Body.SUN && bodies.contains(planet)) { + planetSize = getRawSize(planet.getPlanetaryRadius()); + planetLocation = getRawLocation(planet.getOrbitalRadius()); + + height = Math.max(height, planetSize*3/2d); + width = Math.max(width, planetLocation + planetSize*3/4d); + + for(Body moon : Body.values()) { + double moonSize = 0; + double moonLocation = 0; + if(moon.getParent()==planet && bodies.contains(moon)) { + moonSize = getRawSize(moon.getPlanetaryRadius()); + moonLocation = getRawLocation(moon.getOrbitalRadius()); + + height = Math.max(height, sunSize/2d + moonLocation + moonSize*3/4d); + } + } + } + } + + horizontalScale = (getBounds().width)/width; + verticalScale = (getBounds().height)/height; + + bodyLocationMap.clear(); + bodySizeMap.clear(); + + int v_space = getBounds().height - (int)Math.round(height*Math.min(horizontalScale, verticalScale)); + + bodyLocationMap.put(Body.SUN, new Point(0, v_space/2+getScaledNumber(sunSize)/2)); + bodySizeMap.put(Body.SUN, getScaledNumber(sunSize)); + + if(Body.SUN.getImage()==null) { + g.setColor(Body.SUN.getColor()); + g.fillOval(-bodySizeMap.get(Body.SUN)/2, bodyLocationMap.get(Body.SUN).y-bodySizeMap.get(Body.SUN)/2, + bodySizeMap.get(Body.SUN), bodySizeMap.get(Body.SUN)); + } else { + g.drawImage(Body.SUN.getImage(), bodyLocationMap.get(Body.SUN).x, bodyLocationMap.get(Body.SUN).y-bodySizeMap.get(Body.SUN)/2, + bodySizeMap.get(Body.SUN)/2, bodySizeMap.get(Body.SUN), null); + } + + for(Body planet : Body.values()) { + int planetSize = 0; + int planetLocation = 0; + if(planet.getParent()==Body.SUN && bodies.contains(planet)) { + planetSize = getScaledNumber(getRawSize(planet.getPlanetaryRadius())); + planetLocation = getScaledNumber(getRawLocation(planet.getOrbitalRadius())); + bodyLocationMap.put(planet, new Point(planetLocation, bodyLocationMap.get(Body.SUN).y)); + bodySizeMap.put(planet, planetSize); + + drawBody(planet, g); + + for(Body moon : Body.values()) { + int moonSize = 0; + int moonLocation = 0; + if(moon.getParent()==planet && bodies.contains(moon)) { + moonSize = getScaledNumber(getRawSize(moon.getPlanetaryRadius())); + moonLocation = getScaledNumber(getRawLocation(moon.getOrbitalRadius())); + + bodyLocationMap.put(moon, new Point(bodyLocationMap.get(planet).x, + bodyLocationMap.get(planet).y + moonLocation)); + bodySizeMap.put(moon, moonSize); + + drawBody(moon, g); + } + } + } + } + } else { + // lay out planets to the right, moons below each planet + double width = 0; + double height = 0; + + Body firstPlanet = null; + Body largestPlanet = null; + { + double firstPlanetLocation = Double.MAX_VALUE; + double largestPlanetSize = 0; + for(Body planet : Body.values()) { + if(planet.getParent()==Body.SUN && bodies.contains(planet)) { + if(getRawLocation(planet.getOrbitalRadius()) < firstPlanetLocation) { + firstPlanetLocation = getRawLocation(planet.getOrbitalRadius()); + firstPlanet = planet; + } + if(getRawSize(planet.getPlanetaryRadius()) > largestPlanetSize) { + largestPlanetSize = getRawSize(planet.getPlanetaryRadius()); + largestPlanet = planet; + } + } + } + } + + double rawFirstPlanetLocation = getRawSize(firstPlanet.getPlanetaryRadius())*3/4d; + double rawLargestPlanetSize = getRawSize(largestPlanet.getPlanetaryRadius()); + + for(Body planet : Body.values()) { + double planetSize = 0; + double planetLocation = 0; + + if(planet.getParent()==Body.SUN && bodies.contains(planet)) { + planetSize = getRawSize(planet.getPlanetaryRadius()); + planetLocation = planet==firstPlanet?rawFirstPlanetLocation: + rawFirstPlanetLocation + getRawLocation(planet.getOrbitalRadius()-firstPlanet.getOrbitalRadius()); + + height = Math.max(height, planetSize*3/2d); + width = Math.max(width, planetLocation + planetSize*3/4d); + + for(Body moon : Body.values()) { + double moonSize = 0; + double moonLocation = 0; + if(moon.getParent()==planet && bodies.contains(moon)) { + moonSize = getRawSize(moon.getPlanetaryRadius()); + moonLocation = getRawLocation(moon.getOrbitalRadius()); + + height = Math.max(height, rawLargestPlanetSize*3/4d + moonLocation + moonSize*3/4d); + } + } + } + } + + horizontalScale = (getBounds().width)/width; + verticalScale = (getBounds().height)/height; + + bodyLocationMap.clear(); + bodySizeMap.clear(); + + int v_space = getBounds().height - (int)Math.round(height*Math.min(horizontalScale, verticalScale)); + int h_space = getBounds().width - (int)Math.round(width*Math.min(horizontalScale, verticalScale)); + + int firstPlanetLocation = getScaledNumber(getRawSize(firstPlanet.getPlanetaryRadius()))*3/4; + int largestPlanetSize = getScaledNumber(getRawSize(largestPlanet.getPlanetaryRadius())); + + for(Body planet : Body.values()) { + int planetSize = 0; + int planetLocation = 0; + if(planet.getParent()==Body.SUN && bodies.contains(planet)) { + planetSize = getScaledNumber(getRawSize(planet.getPlanetaryRadius())); + planetLocation = planet==firstPlanet?firstPlanetLocation: + firstPlanetLocation + getScaledNumber(getRawLocation(planet.getOrbitalRadius()-firstPlanet.getOrbitalRadius())); + bodyLocationMap.put(planet, new Point(h_space/2 + planetLocation, v_space/2 + largestPlanetSize*3/4)); + bodySizeMap.put(planet, planetSize); + + drawBody(planet, g); + + for(Body moon : Body.values()) { + int moonSize = 0; + int moonLocation = 0; + if(moon.getParent()==planet && bodies.contains(moon)) { + moonSize = getScaledNumber(getRawSize(moon.getPlanetaryRadius())); + moonLocation = getScaledNumber(getRawLocation(moon.getOrbitalRadius())); + + bodyLocationMap.put(moon, new Point(bodyLocationMap.get(planet).x, + bodyLocationMap.get(planet).y + moonLocation)); + bodySizeMap.put(moon, moonSize); + + drawBody(moon, g); + } + } + } + } + } + } + private void drawBody(Body body, Graphics g) { + if(body.getImage()==null) { + g.setColor(body.getColor()); + g.fillOval(bodyLocationMap.get(body).x - bodySizeMap.get(body)/2, + bodyLocationMap.get(body).y - bodySizeMap.get(body)/2, + bodySizeMap.get(body), bodySizeMap.get(body)); + } else { + g.drawImage(body.getImage(), + bodyLocationMap.get(body).x - bodySizeMap.get(body)/2, + bodyLocationMap.get(body).y - bodySizeMap.get(body)/2, + bodySizeMap.get(body), bodySizeMap.get(body), null); + } + if(drawOrbitalLimits) { + Graphics2D g2 = (Graphics2D)g; + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[]{10.0f}, 0.0f)); + g.setColor(Color.LIGHT_GRAY); + g.drawOval(bodyLocationMap.get(body).x - bodySizeMap.get(body)*3/4, + bodyLocationMap.get(body).y - bodySizeMap.get(body)*3/4, + bodySizeMap.get(body)*3/2, + bodySizeMap.get(body)*3/2); + } + } + + /** + * Gets the scaled number. + * + * @param number the number + * + * @return the scaled number + */ + public int getScaledNumber(double number) { + return (int)Math.round(number*Math.min(horizontalScale, verticalScale)); + } + private double getRawSize(double size) { + return (sizeDisparity - 1)/(Math.PI)*Math.atan(sizeScale*(size-sizeBasis))+(sizeDisparity + 1)/2d; + } + private double getRawLocation(double location) { + return (locationDisparity - 1)/(Math.PI)*Math.atan(locationScale*(location-locationBasis))+(locationDisparity + 1)/2d; + } + private Network getNetwork() { + return networkPanel.getNetwork(); + } + + /** + * Gets the size scale. + * + * @return the size scale + */ + public double getSizeScale() { + return sizeScale; + } + + /** + * Sets the size scale. + * + * @param sizeScale the new size scale + */ + public void setSizeScale(double sizeScale) { + this.sizeScale = sizeScale; + } + + /** + * Gets the size basis. + * + * @return the size basis + */ + public double getSizeBasis() { + return sizeBasis; + } + + /** + * Sets the size basis. + * + * @param sizeBasis the new size basis + */ + public void setSizeBasis(double sizeBasis) { + this.sizeBasis = sizeBasis; + } + + /** + * Gets the location scale. + * + * @return the location scale + */ + public double getLocationScale() { + return locationScale; + } + + /** + * Sets the location scale. + * + * @param locationScale the new location scale + */ + public void setLocationScale(double locationScale) { + this.locationScale = locationScale; + } + + /** + * Gets the location basis. + * + * @return the location basis + */ + public double getLocationBasis() { + return locationBasis; + } + + /** + * Sets the location basis. + * + * @param locationBasis the new location basis + */ + public void setLocationBasis(double locationBasis) { + this.locationBasis = locationBasis; + } + + /** + * Gets the size disparity. + * + * @return the size disparity + */ + public double getSizeDisparity() { + return sizeDisparity; + } + + /** + * Sets the size disparity. + * + * @param sizeDisparity the new size disparity + */ + public void setSizeDisparity(double sizeDisparity) { + this.sizeDisparity = sizeDisparity; + } + + /** + * Gets the location disparity. + * + * @return the location disparity + */ + public double getLocationDisparity() { + return locationDisparity; + } + + /** + * Sets the location disparity. + * + * @param locationDisparity the new location disparity + */ + public void setLocationDisparity(double locationDisparity) { + this.locationDisparity = locationDisparity; + } + + /** + * Gets the body location. + * + * @param body the body + * + * @return the body location + */ + public Point getBodyLocation(Body body) { + if(bodyLocationMap.keySet().contains(body)) return bodyLocationMap.get(body); + else return new Point(); + } + + /** + * Gets the body size. + * + * @param body the body + * + * @return the body size + */ + public Integer getBodySize(Body body) { + if(bodySizeMap.keySet().contains(body)) return bodySizeMap.get(body); + else return new Integer(0); + } + + /** + * Checks if is draw orbital limits. + * + * @return true, if is draw orbital limits + */ + public boolean isDrawOrbitalLimits() { + return drawOrbitalLimits; + } + + /** + * Sets the draw orbital limits. + * + * @param drawOrbitalLimits the new draw orbital limits + */ + public void setDrawOrbitalLimits(boolean drawOrbitalLimits) { + this.drawOrbitalLimits = drawOrbitalLimits; + } + + /** + * Checks if is simple mode. + * + * @return true, if is simple mode + */ + public boolean isSimpleMode() { + return simpleMode; + } + + /** + * Sets the simple mode. + * + * @param simpleMode the new simple mode + */ + public void setSimpleMode(boolean simpleMode) { + this.simpleMode = simpleMode; + } + + /** + * Checks if is display sun. + * + * @return true, if is display sun + */ + public boolean isDisplaySun() { + return displaySun; + } + + /** + * Sets the display sun. + * + * @param displaySun the new display sun + */ + public void setDisplaySun(boolean displaySun) { + this.displaySun = displaySun; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/visualization/ElementLayer.java b/src/main/java/edu/mit/spacenet/gui/visualization/ElementLayer.java new file mode 100644 index 0000000..e4867a7 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/visualization/ElementLayer.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.visualization; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Point; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * The layer that represents elements in the network visualization. + * + * @author Paul Grogan + */ +public class ElementLayer extends JPanel { + private static final long serialVersionUID = -2339880151125938146L; + private NetworkPanel networkPanel; + private Map elementLocationMap; + + private Set selectedElements; + + /** + * Instantiates a new element layer. + * + * @param networkPanel the network panel + */ + public ElementLayer(NetworkPanel networkPanel) { + this.networkPanel = networkPanel; + elementLocationMap = new HashMap(); + selectedElements = new HashSet(); + setOpaque(false); + setLayout(null); + } + + /* (non-Javadoc) + * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) + */ + public void paintComponent(Graphics g) { + super.paintComponent(g); + + for(Location location : getNetwork().getLocations()) { + Point center = new Point(); + if(location instanceof Node) { + center = networkPanel.getNetworkLayer().getLocation((Node)location); + } else if(location instanceof SurfaceEdge) { + Point origin = networkPanel.getNetworkLayer().getLocation(((Edge)location).getOrigin()); + Point destination = networkPanel.getNetworkLayer().getLocation(((Edge)location).getDestination()); + center = new Point((origin.x + destination.x)/2,(origin.y + destination.y)/2); + } else if(location instanceof Edge) { + Point origin = networkPanel.getNetworkLayer().getLocation(((Edge)location).getOrigin()); + Point destination = networkPanel.getNetworkLayer().getLocation(((Edge)location).getDestination()); + int w = Math.abs(origin.x-destination.x); + int h = Math.abs(origin.y-destination.y); + double angle = 0; + Point ovalCenter = new Point(destination.x,origin.y); + if(origin.x <= destination.x && origin.y <= destination.y) { + angle = 5*Math.PI/4; + } else if(origin.x <= destination.x && origin.y > destination.y) { + angle = 3*Math.PI/4; + } else if(origin.x > destination.x && origin.y <= destination.y) { + angle = 7*Math.PI/4; + } else if(origin.x > destination.x && origin.y > destination.y) { + angle = 1*Math.PI/4; + } + center = new Point(ovalCenter.x + (int)(Math.cos(angle)*w), + ovalCenter.y - (int)(Math.sin(angle)*h)); + } + + int sideCount = (int)Math.ceil(Math.sqrt(location.getContents().size())); + int col = 0; + int row = 0; + for(I_Element element : location.getContents()) { + ImageIcon icon = element.getIcon(); + int x = (int)Math.round(center.x - sideCount*icon.getIconWidth()/2d + (col+0.5)*icon.getIconWidth()); + int y = (int)Math.round(center.y - sideCount*icon.getIconHeight()/2d + (row+0.5)*icon.getIconHeight()); + Point point = new Point(x,y); + elementLocationMap.put(element.getUid(), point); + g.drawImage(icon.getImage(), + point.x-icon.getIconWidth()/2, + point.y-icon.getIconHeight()/2, + icon.getIconWidth(), + icon.getIconHeight(), + null); + if(selectedElements.contains(element.getUid())) { + g.setColor(Color.WHITE); + g.setFont(getFont().deriveFont(Font.BOLD).deriveFont(10)); + g.drawString(element.getName(), point.x+icon.getIconWidth()/2, point.y+icon.getIconHeight()/2); + } + col++; + if(col >= sideCount) { + col = 0; + row++; + } + } + + } + } + private Network getNetwork() { + return networkPanel.getNetwork(); + } + + /** + * Gets the location. + * + * @param element the element + * + * @return the location + */ + public Point getLocation(I_Element element) { + return new Point(); + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/visualization/NetworkLayer.java b/src/main/java/edu/mit/spacenet/gui/visualization/NetworkLayer.java new file mode 100644 index 0000000..9b17d55 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/visualization/NetworkLayer.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.visualization; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; + +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.LagrangeNode; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.domain.network.node.SurfaceNode; + +/** + * The layer that represents nodes and edges in the network visualization. + * + * @author Nii Armar, Paul Grogan + * + */ +public class NetworkLayer extends JPanel { + private static final long serialVersionUID = 4415070504799243431L; + private NetworkPanel networkPanel; + + private double altitudeScale = 0.01; + private double altitudeBasis = 150; + + private int edgeWidth = 1; + private int nodeSize = 16; + + private Map nodeLocationMap; + private Set selectedEdges, selectedNodes; + + /** + * Instantiates a new network layer. + * + * @param networkPanel the network panel + */ + public NetworkLayer(NetworkPanel networkPanel) { + this.networkPanel = networkPanel; + nodeLocationMap = new HashMap(); + selectedEdges = new HashSet(); + selectedNodes = new HashSet(); + setOpaque(false); + setLayout(null); + /* + for(Node node : getScenario().getNetwork().getNodes()) { + NodeLabel n = new NodeLabel(node, this); + add(n); + }*/ + } + + /* (non-Javadoc) + * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) + */ + public void paintComponent(Graphics g) { + super.paintComponent(g); + nodeLocationMap.clear(); + for(Node node : getNetwork().getNodes()) { + nodeLocationMap.put(node.getTid(),getLocation(node)); + } + for(Edge edge : getNetwork().getEdges()) { + Point origin = nodeLocationMap.get(edge.getOrigin().getTid()); + Point destination = nodeLocationMap.get(edge.getDestination().getTid()); + g.setColor(edge.getEdgeType().getColor()); + Graphics2D g2 = (Graphics2D)g; + if(selectedEdges.contains(edge.getTid())) { + g2.setStroke(new BasicStroke(3*edgeWidth)); + } else { + g2.setStroke(new BasicStroke(edgeWidth)); + } + if(edge instanceof SurfaceEdge || origin.x==destination.x || origin.y==destination.y) { + g.drawLine(origin.x, origin.y, destination.x, destination.y); + } else { + int w = Math.abs(origin.x-destination.x); + int h = Math.abs(origin.y-destination.y); + if(origin.x <= destination.x && origin.y <= destination.y) { + g.drawArc(origin.x, origin.y-h, 2*w, 2*h, 180, 90); + } else if(origin.x <= destination.x && origin.y > destination.y) { + g.drawArc(origin.x, origin.y-h, 2*w, 2*h, 90, 90); + } else if(origin.x > destination.x && origin.y <= destination.y) { + g.drawArc(origin.x-2*w, origin.y-h, 2*w, 2*h, 270, 90); + } else if(origin.x > destination.x && origin.y > destination.y) { + g.drawArc(origin.x-2*w, origin.y-h, 2*w, 2*h, 0, 90); + } + } + if(selectedEdges.contains(edge.getTid())) { + if(networkPanel.isBlackBackground()) g.setColor(Color.WHITE); + else g.setColor(Color.BLACK); + g.setFont(getFont().deriveFont(Font.BOLD).deriveFont(10)); + g.drawString(edge.getName(), (origin.x+destination.x)/2, (origin.y+destination.y)/2); + } + } + for(Node node : getNetwork().getNodes()) { + ImageIcon icon = node.getNodeType().getIcon(); + Point point = nodeLocationMap.get(node.getTid()); + g.drawImage(icon.getImage(), point.x-nodeSize/2, point.y-nodeSize/2, nodeSize, nodeSize, null); + if(selectedNodes.contains(node.getTid())) { + if(networkPanel.isBlackBackground()) g.setColor(Color.WHITE); + else g.setColor(Color.BLACK); + g.setFont(getFont().deriveFont(Font.BOLD).deriveFont(10)); + g.drawString(node.getName(), point.x+icon.getIconWidth()/2, point.y+icon.getIconHeight()/2); + } + } + } + + /** + * Gets the location. + * + * @param node the node + * + * @return the location + */ + public Point getLocation(Node node) { + if(node instanceof SurfaceNode) return getLocation((SurfaceNode)node); + else if(node instanceof OrbitalNode) return getLocation((OrbitalNode)node); + else if(node instanceof LagrangeNode) return getLocation((LagrangeNode)node); + else return new Point(); + } + private Point getLocation(SurfaceNode node) { + /* Note: this function converts the latitude and longitude coordinates + * to a Lambert-Azimuthal projected area, formula was taken from + * http://mathworld.wolfram.com/LambertAzimuthalEqual-AreaProjection.html + */ + double d_pi = Math.PI/180D; + + Point bodyPoint = networkPanel.getBodyLayer().getBodyLocation(node.getBody()); + double bodyRadius = networkPanel.getBodyLayer().getBodySize(node.getBody())/2; + + double d_lat = node.getLatitude() * d_pi; + double d_lon = node.getLongitude()==180?179:node.getLongitude() * d_pi; + + double d_phi = 0 * d_pi; + double d_lam = 0 * d_pi; + + double kk0 = Math.sqrt( + 2 / (1 + Math.sin(d_phi) * + Math.sin(d_lat) + + Math.cos(d_phi) * + Math.cos(d_lat) * + Math.cos(d_lon - d_lam))); + + double xx0 = kk0 * Math.cos(d_lat) * Math.sin(d_lon - d_lam); + int d_xx1 = (int) Math.round(bodyPoint.x + 0.5 * bodyRadius * xx0); + + double yy0 = kk0 * (Math.cos(d_phi) * + Math.sin(d_lat) - + Math.sin(d_phi) * + Math.cos(d_lat) * + Math.cos(d_lon - d_lam)); + int d_yy1 = (int) Math.round(bodyPoint.y + 0.5 * bodyRadius * (-yy0)); + + return new Point(d_xx1, d_yy1); + } + private Point getLocation(OrbitalNode node) { + Point bodyPoint = networkPanel.getBodyLayer().getBodyLocation(node.getBody()); + double bodyRadius = networkPanel.getBodyLayer().getBodySize(node.getBody())/2d; + + double altitude = bodyRadius + bodyRadius*.25*getAltitude(0.5*(node.getApoapsis() + node.getPeriapsis())); + + int d_xx1; + if(node.getBody()==Body.EARTH||node.getBody()==Body.SUN) { + d_xx1 = (int) Math.round(bodyPoint.x + + altitude*Math.cos(node.getInclination()/180d*Math.PI)); + } else { + d_xx1 = (int) Math.round(bodyPoint.x + - altitude*Math.cos(node.getInclination()/180d*Math.PI)); + } + int d_yy1 = (int) Math.round(bodyPoint.y + + altitude*Math.sin(node.getInclination()/180d*Math.PI)); + + return new Point(d_xx1, d_yy1); + } + private Point getLocation(LagrangeNode node) { + Point minorBodyPoint = networkPanel.getBodyLayer().getBodyLocation(node.getMinorBody()); + double minorBodyRadius = networkPanel.getBodyLayer().getBodySize(node.getMinorBody())/2d; + Point majorBodyPoint = networkPanel.getBodyLayer().getBodyLocation(node.getBody()); + double majorBodyRadius = networkPanel.getBodyLayer().getBodySize(node.getBody())/2d; + + double R = Math.sqrt(Math.pow(majorBodyPoint.x+majorBodyRadius-minorBodyPoint.x+minorBodyRadius,2)+ + Math.pow(majorBodyPoint.y+majorBodyRadius-minorBodyPoint.y+minorBodyRadius,2)); + + switch(node.getNumber()) { + case 1: + return new Point((int)Math.round(minorBodyPoint.x - 1.5*minorBodyRadius), + (int)Math.round(minorBodyPoint.y)); + case 2: + return new Point((int)Math.round(minorBodyPoint.x + 1.5*minorBodyRadius), + (int)Math.round(minorBodyPoint.y)); + case 3: + return new Point((int)Math.round(majorBodyPoint.x - R), + (int)Math.round(majorBodyPoint.y)); + case 4: + return new Point((int)Math.round(majorBodyPoint.x + R*Math.cos(60/180d*Math.PI)), + (int)Math.round(majorBodyPoint.y + R*Math.sin(60/180d*(Math.PI/2d)))); + case 5: + return new Point((int)Math.round(majorBodyPoint.x + R*Math.cos(60/180d*Math.PI)), + (int)Math.round(majorBodyPoint.y - R*Math.sin(60/180d*Math.PI))); + } + return new Point(); + } + private Network getNetwork() { + return networkPanel.getNetwork(); + } + private double getAltitude(double altitude) { + return 1/(Math.PI)*Math.atan(altitudeScale*(altitude-altitudeBasis))+0.5; + } + + /** + * Gets the altitude scale. + * + * @return the altitude scale + */ + public double getAltitudeScale() { + return altitudeScale; + } + + /** + * Sets the altitude scale. + * + * @param altitudeScale the new altitude scale + */ + public void setAltitudeScale(double altitudeScale) { + this.altitudeScale = altitudeScale; + } + + /** + * Gets the altitude basis. + * + * @return the altitude basis + */ + public double getAltitudeBasis() { + return altitudeBasis; + } + + /** + * Sets the altitude basis. + * + * @param altitudeBasis the new altitude basis + */ + public void setAltitudeBasis(double altitudeBasis) { + this.altitudeBasis = altitudeBasis; + } + /* + private class NodeLabel extends JLabel { + private static final long serialVersionUID = -5320521626370983008L; + private Node node; + private NetworkLayer networkLayer; + + public NodeLabel(Node node, NetworkLayer networkLayer) { + super(NodeType.getInstance(node.getClass()).getIcon(), JLabel.LEADING); + this.node = node; + this.networkLayer = networkLayer; + setOpaque(false); + setIconTextGap(0); + setSize(new Dimension(getIcon().getIconWidth(),getIcon().getIconHeight())); + setToolTipText(node.getName() + " (" + + NodeType.getInstance(node.getClass()).getName() + ")" + + (node.getDescription()==null?"":": "+node.getDescription())); + } + public void paintComponent(Graphics g) { + setLocation(networkLayer.getLocation(node).x-getWidth()/2, + networkLayer.getLocation(node).y-getHeight()/2); + super.paintComponent(g); + } + public Node getNode() { + return node; + } + }*/ + /** + * Gets the selected edges. + * + * @return the selected edges + */ + public Set getSelectedEdges() { + return selectedEdges; + } + + /** + * Gets the selected nodes. + * + * @return the selected nodes + */ + public Set getSelectedNodes() { + return selectedNodes; + } + + /** + * Gets the edge width. + * + * @return the edge width + */ + public int getEdgeWidth() { + return edgeWidth; + } + + /** + * Sets the edge width. + * + * @param edgeWidth the new edge width + */ + public void setEdgeWidth(int edgeWidth) { + this.edgeWidth = edgeWidth; + } + + /** + * Gets the node size. + * + * @return the node size + */ + public int getNodeSize() { + return nodeSize; + } + + /** + * Sets the node size. + * + * @param nodeSize the new node size + */ + public void setNodeSize(int nodeSize) { + this.nodeSize = nodeSize; + } +} diff --git a/src/main/java/edu/mit/spacenet/gui/visualization/NetworkPanel.java b/src/main/java/edu/mit/spacenet/gui/visualization/NetworkPanel.java new file mode 100644 index 0000000..0c1196a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/gui/visualization/NetworkPanel.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.gui.visualization; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JLayeredPane; + +import edu.mit.spacenet.domain.network.Network; + +/** + * The component that is used for network visualization. There are three layers: + * the body layer displays the celestial bodies, the element layer displays the + * simulation elements, and the network layer displays the nodes and edges. + * + * @author Nii Armar, Paul Grogan + */ +public class NetworkPanel extends JLayeredPane { + private static final long serialVersionUID = 4872032814941089113L; + private Network network; + + private BodyLayer bodyLayer; + private NetworkLayer networkLayer; + private ElementLayer elementLayer; + + private boolean isBlackBackground = true; + + /** + * Instantiates a new network panel. + * + * @param network the network + */ + public NetworkPanel(Network network) { + this(); + setNetwork(network); + } + public NetworkPanel() { + bodyLayer = new BodyLayer(this); + add(bodyLayer); + networkLayer = new NetworkLayer(this); + add(networkLayer); + elementLayer = new ElementLayer(this); + add(elementLayer); + setPosition(bodyLayer, 2); + setPosition(networkLayer, 1); + setPosition(elementLayer, 0); + + if(isBlackBackground) + setBackground(Color.BLACK); + else + setBackground(Color.WHITE); + setOpaque(true); + setPreferredSize(new Dimension(600,400)); + } + + /* (non-Javadoc) + * @see java.awt.Component#setBounds(int, int, int, int) + */ + @Override + public void setBounds(int x, int y, int width, int height) { + // this function is used to synchronize the size of the layers + super.setBounds(x,y,width,height); + bodyLayer.setBounds(0,0,width,height); + networkLayer.setBounds(0,0,width,height); + elementLayer.setBounds(0,0,width,height); + } + + /* (non-Javadoc) + * @see javax.swing.JLayeredPane#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + super.paint(g); + if(isBlackBackground) + setBackground(Color.BLACK); + else + setBackground(Color.WHITE); + } + + /** + * Checks if is black background. + * + * @return true, if is black background + */ + public boolean isBlackBackground() { + return isBlackBackground; + } + + /** + * Sets the black background. + * + * @param isBlackBackground the new black background + */ + public void setBlackBackground(boolean isBlackBackground) { + this.isBlackBackground = isBlackBackground; + } + + /** + * Gets the network. + * + * @return the network + */ + public Network getNetwork() { + return network; + } + + /** + * Sets the network. + * + * @param network the new network + */ + public void setNetwork(Network network) { + this.network = network; + } + + /** + * Gets the body layer. + * + * @return the body layer + */ + public BodyLayer getBodyLayer() { + return bodyLayer; + } + + /** + * Gets the network layer. + * + * @return the network layer + */ + public NetworkLayer getNetworkLayer() { + return networkLayer; + } + + /** + * Gets the element layer. + * + * @return the element layer + */ + public ElementLayer getElementLayer() { + return elementLayer; + } +} diff --git a/src/main/java/edu/mit/spacenet/io/XLSFileFilter.java b/src/main/java/edu/mit/spacenet/io/XLSFileFilter.java new file mode 100644 index 0000000..68e04c2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/io/XLSFileFilter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.io; + +import java.io.File; + +import javax.swing.filechooser.FileFilter; + +/** + * A filter for file dialogs to only show .xls files. + * + * @author Paul Grogan + */ +public class XLSFileFilter extends FileFilter { + + /* (non-Javadoc) + * @see javax.swing.filechooser.FileFilter#accept(java.io.File) + */ + public boolean accept(File f) { + if(f.isDirectory()) { + return true; + } + String extension = null; + + String s = f.getName(); + int i = s.lastIndexOf('.'); + if (i > 0 && i < s.length() - 1) { + extension = s.substring(i+1).toLowerCase(); + } + + if(extension != null) { + if(extension.equals("xls")) return true; + else return false; + } else return false; + } + + /* (non-Javadoc) + * @see javax.swing.filechooser.FileFilter#getDescription() + */ + public String getDescription() { + return "XLS Files"; + } +} diff --git a/src/main/java/edu/mit/spacenet/io/XLSXFileFilter.java b/src/main/java/edu/mit/spacenet/io/XLSXFileFilter.java new file mode 100644 index 0000000..053e81a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/io/XLSXFileFilter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.io; + +import java.io.File; + +import javax.swing.filechooser.FileFilter; + +/** + * A filter for file dialogs to only show .xlsx files. + * + * @author Takuto Ishimatsu + */ +public class XLSXFileFilter extends FileFilter { + + /* (non-Javadoc) + * @see javax.swing.filechooser.FileFilter#accept(java.io.File) + */ + public boolean accept(File f) { + if(f.isDirectory()) { + return true; + } + String extension = null; + + String s = f.getName(); + int i = s.lastIndexOf('.'); + if (i > 0 && i < s.length() - 1) { + extension = s.substring(i+1).toLowerCase(); + } + + if(extension != null) { + if(extension.equals("xlsx")) return true; + else return false; + } else return false; + } + + /* (non-Javadoc) + * @see javax.swing.filechooser.FileFilter#getDescription() + */ + public String getDescription() { + return "XLSX Files"; + } +} diff --git a/src/main/java/edu/mit/spacenet/io/XMLFileFilter.java b/src/main/java/edu/mit/spacenet/io/XMLFileFilter.java new file mode 100644 index 0000000..f390ea1 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/io/XMLFileFilter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.io; + +import java.io.File; + +import javax.swing.filechooser.FileFilter; + +/** + * A filter for file dialogs to only show .xml files. + * + * @author Paul Grogan + */ +public class XMLFileFilter extends FileFilter { + + /* (non-Javadoc) + * @see javax.swing.filechooser.FileFilter#accept(java.io.File) + */ + public boolean accept(File f) { + if(f.isDirectory()) { + return true; + } + String extension = null; + + String s = f.getName(); + int i = s.lastIndexOf('.'); + if (i > 0 && i < s.length() - 1) { + extension = s.substring(i+1).toLowerCase(); + } + + if(extension != null) { + if(extension.equals("xml")) return true; + else return false; + } else return false; + } + + /* (non-Javadoc) + * @see javax.swing.filechooser.FileFilter#getDescription() + */ + public String getDescription() { + return "XML Files"; + } +} diff --git a/src/main/java/edu/mit/spacenet/io/XStreamEngine.java b/src/main/java/edu/mit/spacenet/io/XStreamEngine.java new file mode 100644 index 0000000..d43329d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/io/XStreamEngine.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.io; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import com.thoughtworks.xstream.XStream; + +import edu.mit.spacenet.data.DataSourceType; +import edu.mit.spacenet.data.ElementPreview; +import edu.mit.spacenet.data.Spreadsheet_2_5; +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.element.State; +import edu.mit.spacenet.domain.model.RatedDemandModel; +import edu.mit.spacenet.domain.model.SparingByMassDemandModel; +import edu.mit.spacenet.domain.model.TimedImpulseDemandModel; +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.LagrangeNode; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.scenario.Scenario; + +/** + * A class to help manage serialization/deserialization of objects. + * + * @author Paul Grogan + */ +public class XStreamEngine { + + /** + * Serializes and saves a scenario. + * + * @param scenario the scenario to save + * + * @throws FileNotFoundException the file not found exception + * @throws IOException the i/o exception + */ + public static void saveScenario(Scenario scenario) + throws FileNotFoundException, IOException { + XStream xs = new XStream(); + // TODO: correct references to node/edge libraries + //xs.omitField(DataSource.class, "nodeLibrary"); + //xs.omitField(DataSource.class, "edgeLibrary"); + // TODO: correct references to resource library + //xs.omitField(DataSource.class, "resourceLibrary"); + // TODO: correct references to item preview library + //xs.omitField(DataSource.class, "itemPreviewLibrary"); + xs.alias("scenario", Scenario.class); + xs.alias("excel", Spreadsheet_2_5.class); + xs.alias("surfaceNode", SurfaceNode.class); + xs.alias("orbitalNode", OrbitalNode.class); + xs.alias("lagrangeNode", LagrangeNode.class); + xs.alias("spaceEdge", SpaceEdge.class); + xs.alias("surfaceEdge", SurfaceEdge.class); + xs.alias("flightEdge", FlightEdge.class); + xs.alias("burn", Burn.class); + + FileOutputStream fos = new FileOutputStream(scenario.getFilePath()); + xs.toXML(scenario, fos); + fos.close(); + } + + /** + * Opens and deserializes a scenario based on a file path. + * + * @param filePath the file path to open + * + * @return the deserialized scenario + * + * @throws FileNotFoundException the file not found exception + * @throws IOException the i/o exception + */ + public static Scenario openScenario(String filePath) + throws FileNotFoundException, IOException { + XStream xs = new XStream(); + xs.alias("scenario", Scenario.class); + xs.alias("excel", Spreadsheet_2_5.class); + xs.alias("surfaceNode", SurfaceNode.class); + xs.alias("orbitalNode", OrbitalNode.class); + xs.alias("lagrangeNode", LagrangeNode.class); + xs.alias("spaceEdge", SpaceEdge.class); + xs.alias("surfaceEdge", SurfaceEdge.class); + xs.alias("flightEdge", FlightEdge.class); + xs.alias("burn", Burn.class); + xs.alias("edu.mit.spacenet.domain.demand.Demand", Demand.class); + xs.alias("edu.mit.spacenet.domain.demand.DemandSet", DemandSet.class); + xs.alias("edu.mit.spacenet.domain.demand.model.SparingByMassDemandModel", SparingByMassDemandModel.class); + xs.alias("edu.mit.spacenet.domain.demand.model.RatedDemandModel", RatedDemandModel.class); + xs.alias("edu.mit.spacenet.domain.demand.model.TimedImpulseDemandModel", TimedImpulseDemandModel.class); + xs.alias("edu.mit.spacenet.domain.demand.State", State.class); + xs.alias("edu.mit.spacenet.domain.demand.PartApplication", PartApplication.class); + xs.alias("edu.mit.spacenet.scenario.data.Spreadsheet_2_5", Spreadsheet_2_5.class); + xs.alias("edu.mit.spacenet.scenario.data.DataSourceType", DataSourceType.class); + xs.alias("edu.mit.spacenet.scenario.data.ElementPreview", ElementPreview.class); + Scenario scenario = new Scenario(); + + FileInputStream fis = new FileInputStream(filePath); + xs.fromXML(fis, scenario); + // TODO: re-load libraries when opening scenario + //scenario.getDataSource().loadLibraries(); + fis.close(); + return scenario; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/scenario/ItemDiscretization.java b/src/main/java/edu/mit/spacenet/scenario/ItemDiscretization.java new file mode 100644 index 0000000..eafc775 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/scenario/ItemDiscretization.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.scenario; + +/** + * Enumeration representing the different methods of item discretization. + * + * @author Paul Grogan + */ +public enum ItemDiscretization { + + /** Items are not discretized and are treated as continuous resources. */ + NONE("None"), + + /** Items are discretized on a per-element basis. */ + BY_ELEMENT("Element"), + + /** Items are discretized on a per-location basis. */ + BY_LOCATION("Location"), + + /** Items are discretized on a global basis. */ + BY_SCENARIO("Scenario"); + + private String name; + + private ItemDiscretization(String name) { + this.name = name; + } + + /** + * Gets the name of the item discretization. + * + * @return the item discretization name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return getName(); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/scenario/Manifest.java b/src/main/java/edu/mit/spacenet/scenario/Manifest.java new file mode 100644 index 0000000..edd9d58 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/scenario/Manifest.java @@ -0,0 +1,1127 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.scenario; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.Environment; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.element.ResourceContainer; +import edu.mit.spacenet.domain.element.ResourceContainerFactory; +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.scenario.SupplyEdge.SupplyPoint; +import edu.mit.spacenet.simulator.event.ManifestEvent; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * The manifest represents the packing of resources into resource containers, + * and the eventual movement of resource containers into carriers during + * simulation. + * + * @author Paul Grogan + */ +public class Manifest { + private Scenario scenario; + private SortedSet supplyEdges; + private SortedSet supplyPoints; + private SortedMap aggregatedNodeDemands; + private SortedMap aggregatedEdgeDemands; + private Map> demandsAsPacked; + private Map> packedDemands; + private SortedMap> cachedContainerDemands; + private SortedMap>> manifestedContainers; + + /** + * Instantiates a new manifest. + * + * @param scenario the scenario + */ + public Manifest(Scenario scenario) { + this.scenario = scenario; + supplyEdges = new TreeSet(); + supplyPoints = new TreeSet(); + aggregatedNodeDemands = new TreeMap(); + aggregatedEdgeDemands = new TreeMap(); + demandsAsPacked = new HashMap>(); + packedDemands = new HashMap>(); + cachedContainerDemands = new TreeMap>(); + manifestedContainers = new TreeMap>>(); + } + + /** + * Gets the remaining amount to pack for a given aggregated demand. + * + * @param demand the demand to find the remaining amount to pack + * + * @return the remaining amount to pack (units) + */ + public double getRemainingAmount(Demand demand) { + return demand.getAmount()-getPackedAmount(demand); + } + + /** + * Gets the cargo mass of a given resource container at the point in + * time referenced by a supply point. + * + * @param container the container for which to find the cargo mass + * @param point the point in time to reference + * + * @return the cargo mass (kilograms) + */ + public double getCargoMass(I_ResourceContainer container, SupplyPoint point) { + double amount = 0; + for(Demand demandAsPacked : getPackedDemands(container, point)) { + amount+=demandAsPacked.getMass(); + } + return amount; + } + + /** + * Gets the cargo volume of a given resource container at a point in time + * referenced by a supply point. + * + * @param container the container for which to find the cargo volume + * @param point the point in time to reference + * + * @return the cargo volume (cubic meters) + */ + public double getCargoVolume(I_ResourceContainer container, SupplyPoint point) { + double amount = 0; + for(Demand demandAsPacked : getPackedDemands(container, point)) { + amount+=demandAsPacked.getVolume(); + } + return amount; + } + + /** + * Gets the cargo mass of a given carrier at a point in time referenced by + * a supply point. + * + * @param carrier the carrier for which to find the cargo volume + * @param point the point in time to reference + * + * @return the cargo mass (kilograms) + */ + public double getCargoMass(I_Carrier carrier, SupplyPoint point) { + double amount = carrier.getCargoMass(); + for(I_ResourceContainer container : getManifestedContainers(carrier, point)) { + amount+=container.getMass() + getCargoMass(container, point); + } + return amount; + } + + /** + * Gets the cargo volume of a given carrier at a point in time referenced by + * a supply point. + * + * @param carrier the carrier for which to find the cargo volume + * @param point the point in time to reference + * + * @return the cargo volume (cubic meters) + */ + public double getCargoVolume(I_Carrier carrier, SupplyPoint point) { + double amount = carrier.getCargoVolume(); + for(I_ResourceContainer container : getManifestedContainers(carrier, point)) { + amount+=container.getVolume(); + } + return amount; + } + + /** + * Get the packed amount of a given aggregated demand. + * + * @param demand the aggregated demand + * + * @return the packed amount (units) + */ + public double getPackedAmount(Demand demand) { + if(getDemandsAsPacked().get(demand) == null) return 0; + double amount = 0; + for(Demand demandAsPacked : getDemandsAsPacked().get(demand)) { + amount += demandAsPacked.getAmount(); + } + return GlobalParameters.getRoundedDemand(amount); + } + + /** + * Get the supply point associated with a given aggregated demand. + * + * @param demand the demand to find the supply point + * + * @return the supply point + */ + public SupplyPoint getSupplyPoint(Demand demand) { + for(SupplyPoint p : supplyPoints) { + for(Demand d : aggregatedNodeDemands.get(p)) { + if(d.equals(demand)) return p; + } + for(Demand d : aggregatedEdgeDemands.get(p.getEdge())) { + if(d.equals(demand)) return p; + } + } + return null; + } + + /** + * Get the supply point (earlier in time) that services a supply edge. + * + * @param edge the edge to find the supply point for + * + * @return the supply point to service the supply edge + */ + public SupplyPoint getNextSupplyPoint(SupplyEdge edge) { + if(edge.getOrigin() instanceof SurfaceNode + && edge.getOrigin().getBody()==Body.EARTH) + return null; + + SupplyPoint point = null; + for(SupplyPoint p : supplyPoints) { + if(p.getNode().equals(edge.getOrigin()) + && p.getTime() <= edge.getStartTime() + && (point==null||p.getTime()>point.getTime())) { + point = p; + } + } + return point; + } + + /** + * Gets the aggregated demand for a given packed demand. + * + * @param demandAsPacked the packed demand + * + * @return the aggregated demand + */ + public Demand getDemand(Demand demandAsPacked) { + for(Demand demand : demandsAsPacked.keySet()) { + for(Demand d : demandsAsPacked.get(demand)) { + if(d.equals(demandAsPacked)) return demand; + } + } + return null; + } + + /** + * Gets the supply edge associated with a carrier. + * + * @param carrier the carrier + * + * @return the supply edge associated with the carrier + */ + public SupplyEdge getSupplyEdge(I_Carrier carrier) { + for(SupplyEdge e : supplyEdges) { + for(I_Carrier c : e.getCarriers()) { + // must use == because carriers are repeated on edges + if(c==carrier) return e; + } + } + return null; + } + + /** + * Gets all of the supply edges that can supply a supply point. + * + * @param point the supply point + * + * @return a set of supply edges that can supply the supply point + */ + public Set getSupplyEdges(SupplyPoint point) { + HashSet edges = new HashSet(); + for(SupplyEdge edge : supplyEdges) { + if(edge.getDestination().equals(point.getNode()) + && edge.getEndTime() <= point.getTime()) { + edges.add(edge); + } + } + return edges; + } + + /** + * Gets the initial supply point that a resource container is assigned to. + * + * @param container the resource container + * + * @return the intial supply point + */ + public SupplyPoint getInitialSupplyPoint(I_ResourceContainer container) { + SupplyEdge edge = null; + for(SupplyEdge e : supplyEdges) { + for(I_Carrier carrier : e.getCarriers()) { + if(manifestedContainers.get(e).get(carrier).contains(container) + && (edge==null||e.getEndTime()>edge.getEndTime())) { + edge = e; + } + } + } + SupplyPoint point = edge==null?null:edge.getPoint(); + for(Demand demandAsPacked : packedDemands.get(container)) { + SupplyPoint p = getSupplyPoint(getDemand(demandAsPacked)); + if(edge==null||p.getTime()>=edge.getEndTime()) { + if(point==null||(p.getTime() getEmptyContainers() { + HashSet containers = new HashSet(); + for(I_ResourceContainer container : packedDemands.keySet()) { + if(packedDemands.get(container).size()==0 + && getInitialSupplyPoint(container)==null) + containers.add(container); + } + return containers; + } + + /** + * Checks whether a demand is associated with an aggregated edge demand. + * + * @param demand the demand + * + * @return whether a demand is an edge demand + */ + public boolean isEdgeDemand(Demand demand) { + for(Demand d : aggregatedEdgeDemands.get(getSupplyPoint(demand).getEdge())) { + if(d.equals(demand)) return true; + } + return false; + } + + /** + * Checks whether a resource container contains any demands associated with + * an aggregated edge demand. + * + * @param container the resource container + * + * @return whether the resource container contains any edge demands + */ + public boolean isEdgeDemand(I_ResourceContainer container) { + if(packedDemands.get(container)!=null) { + for(Demand demandAsPacked : packedDemands.get(container)) { + Demand demand = getDemand(demandAsPacked); + if(isEdgeDemand(demand)) { + boolean isManifested = false; + SupplyPoint point = getSupplyPoint(demand); + for(I_Carrier carrier : point.getEdge().getAllCarriers()) { + if(manifestedContainers.get(point.getEdge()).get(carrier).contains(container)) + isManifested = true; + } + if(!isManifested) return true; + } + } + } + return false; + } + + /** + * Automatically packs a demand into an appropriate choice of resource + * container. + * + * @param d the aggregated demand to pack + */ + public void autoPackDemand(Demand d) { + if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS1) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS1)) { + // TODO: temporarily use liquid tanks + while(getRemainingAmount(d) > 0) { + I_ResourceContainer container; + if(getRemainingAmount(d)*d.getResource().getUnitMass() > ResourceContainerFactory.LTD_MAX_MASS + || (GlobalParameters.isVolumeConstrained()&&getRemainingAmount(d)*d.getResource().getUnitVolume() > ResourceContainerFactory.LTD_MAX_VOLUME)) { + container = ResourceContainerFactory.createLT(); + } else { + container = ResourceContainerFactory.createLTD(); + } + addContainer(container); + packDemand(d, container); + } + } else if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS203)) { + // use gas tank and gas tank derivative + for(I_ResourceContainer container : packedDemands.keySet()) { + if(container.getTid()==ResourceContainerFactory.GT_TID + || container.getTid()==ResourceContainerFactory.GTD_TID) { + if(canPackDemand(d, container)) packDemand(d, container); + } + } + while(getRemainingAmount(d) > 0) { + I_ResourceContainer container; + if(getRemainingAmount(d)*d.getResource().getUnitMass() > ResourceContainerFactory.GTD_MAX_MASS + || (GlobalParameters.isVolumeConstrained()&&getRemainingAmount(d)*d.getResource().getUnitVolume() > ResourceContainerFactory.GTD_MAX_VOLUME)) { + container = ResourceContainerFactory.createGT(); + } else { + container = ResourceContainerFactory.createGTD(); + } + addContainer(container); + packDemand(d, container); + } + } else if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS201)) { + // use liquid tank and liquid tank derivative + for(I_ResourceContainer container : packedDemands.keySet()) { + if(container.getTid()==ResourceContainerFactory.LT_TID + || container.getTid()==ResourceContainerFactory.LTD_TID) { + if(canPackDemand(d, container)) packDemand(d, container); + } + } + while(getRemainingAmount(d) > 0) { + I_ResourceContainer container; + if(getRemainingAmount(d)*d.getResource().getUnitMass() > ResourceContainerFactory.LTD_MAX_MASS + || (GlobalParameters.isVolumeConstrained()&&getRemainingAmount(d)*d.getResource().getUnitVolume() > ResourceContainerFactory.LTD_MAX_VOLUME)) { + container = ResourceContainerFactory.createLT(); + } else { + container = ResourceContainerFactory.createLTD(); + } + addContainer(container); + packDemand(d, container); + } + } else if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS2) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS2) + || d.getResource().getClassOfSupply().equals(ClassOfSupply.COS3) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS3) + || d.getResource().getClassOfSupply().equals(ClassOfSupply.COS7) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS7)){ + // use ctb + // try existing ctb's + for(I_ResourceContainer container : packedDemands.keySet()) { + if(container.getTid()==ResourceContainerFactory.CTB_TID + ||container.getTid()==ResourceContainerFactory.HCTB_TID) { + if(canPackDemand(d, container)) packDemand(d, container); + } + } + // create new ctb's + while(getRemainingAmount(d) > 0) { + I_ResourceContainer container; + if(getRemainingAmount(d)*d.getResource().getUnitMass() > ResourceContainerFactory.HCTB_MAX_MASS + || (GlobalParameters.isVolumeConstrained()&&getRemainingAmount(d)*d.getResource().getUnitVolume() > ResourceContainerFactory.HCTB_MAX_VOLUME)) { + container = ResourceContainerFactory.createCTB(); + } else { + container = ResourceContainerFactory.createHCTB(); + } + addContainer(container); + packDemand(d, container); + } + } else if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS4) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS4)) { + // try existing shoss boxes + for(I_ResourceContainer container : packedDemands.keySet()) { + if((d.getResource().getEnvironment().equals(Environment.UNPRESSURIZED) + && container.getTid()==ResourceContainerFactory.SHOSS_TID) + || (d.getResource().getEnvironment().equals(Environment.PRESSURIZED) + && container.getTid()==ResourceContainerFactory.PSHOSS_TID)) { + if(canPackDemand(d, container)) packDemand(d, container); + } + } + // create new shoss boxes + while(getRemainingAmount(d) > 0) { + I_ResourceContainer container; + if(d.getResource().getEnvironment().equals(Environment.UNPRESSURIZED)) { + container = ResourceContainerFactory.createShoss(); + } else { + container = ResourceContainerFactory.createPressShoss(); + } + addContainer(container); + packDemand(d, container); + } + } else if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS5) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS5)) { + // ignore demand -- only an estimate of stowage/restraint + } else if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS6) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS6)) { + // use custom resource container + I_ResourceContainer container; + container = new ResourceContainer(); + container.setMaxCargoMass(d.getMass()*1.1); + container.setVolume(d.getVolume()*1.1); + container.setMaxCargoVolume(d.getVolume()*1.1); + container.setName("Science " + container.getUid()); + if(d.getResource().getEnvironment().equals(Environment.UNPRESSURIZED)) { + container.setMass(d.getMass()*d.getResource().getPackingFactor()); + } else { + container.setMass(d.getMass()*d.getResource().getPackingFactor()); + container.setCargoEnvironment(Environment.PRESSURIZED); + } + addContainer(container); + packDemand(d, container); + } else if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS8) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS8) + || d.getResource().getClassOfSupply().equals(ClassOfSupply.COS9) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS9)) { + throw new RuntimeException("COS8, COS9 demands not yet handled"); + } else if(d.getResource().getClassOfSupply().equals(ClassOfSupply.COS10) + || d.getResource().getClassOfSupply().isSubclassOf(ClassOfSupply.COS10)) { + // use custom resource container + I_ResourceContainer container; + container = new ResourceContainer(); + container.setMaxCargoMass(d.getMass()*1.1); + container.setVolume(d.getVolume()*1.1); + container.setMaxCargoVolume(d.getVolume()*1.1); + container.setName("Miscellaneous " + container.getUid()); + if(d.getResource().getEnvironment().equals(Environment.UNPRESSURIZED)) { + container.setMass(d.getMass()*d.getResource().getPackingFactor()); + } else { + container.setMass(d.getMass()*d.getResource().getPackingFactor()); + container.setCargoEnvironment(Environment.PRESSURIZED); + } + addContainer(container); + packDemand(d, container); + } + } + + /** + * Packs a demand into a resource container. + * + * @param demand the aggregated demand + * @param container the resource container + */ + public void packDemand(Demand demand, I_ResourceContainer container) { + SupplyPoint demandPoint = getSupplyPoint(demand); + SupplyPoint containerPoint = getCurrentSupplyPoint(container); + + if(containerPoint==null + || (demandPoint.getNode().equals(containerPoint.getNode()) + && demandPoint.getTime() <= containerPoint.getTime())) { + double remainingAmountMass = demand.getResource().getUnitMass()==0? + Double.MAX_VALUE:GlobalParameters.getRoundedDemand((container.getMaxCargoMass() - getCargoMass(container, containerPoint))/demand.getResource().getUnitMass()); + double remainingAmountVolume = (!GlobalParameters.isVolumeConstrained()||demand.getResource().getUnitVolume()==0)? + Double.MAX_VALUE:GlobalParameters.getRoundedDemand((container.getMaxCargoVolume() - getCargoVolume(container, containerPoint))/demand.getResource().getUnitVolume()); + + double amount = GlobalParameters.isEnvironmentConstrained() + && demand.getResource().getEnvironment()==Environment.PRESSURIZED + && container.getCargoEnvironment()==Environment.UNPRESSURIZED? + 0:Math.min(getRemainingAmount(demand), Math.min(remainingAmountMass, remainingAmountVolume)); + if(amount > 0) { + Demand demandAsPacked = new Demand(demand.getResource(), amount); + demandsAsPacked.get(demand).add(demandAsPacked); + packedDemands.get(container).add(demandAsPacked); + rebuildCachedContainerDemands(); + } + } + } + + /** + * Unpacks an aggregated demand. + * + * @param demand the aggregated demand + */ + public void unpackDemand(Demand demand) { + if(canUnpackDemand(demand)) { + for(Demand demandAsPacked : demandsAsPacked.get(demand)) { + for(I_ResourceContainer container : packedDemands.keySet()) { + if(packedDemands.get(container).contains(demandAsPacked)) { + packedDemands.get(container).remove(demandAsPacked); + } + } + } + demandsAsPacked.get(demand).clear(); + rebuildCachedContainerDemands(); + } + } + + /** + * Unpacks a packed demand from a resource container. + * + * @param demandAsPacked the packed demand + * @param container the resourceContainer + */ + public void unpackDemand(Demand demandAsPacked, I_ResourceContainer container) { + if(canUnpackDemand(demandAsPacked, container)) { + packedDemands.get(container).remove(demandAsPacked); + for(Demand d : demandsAsPacked.keySet()) { + demandsAsPacked.get(d).remove(demandAsPacked); + } + rebuildCachedContainerDemands(); + } + } + + /** + * Gets whether an aggregated demand can be unpacked. + * + * @param demand the aggregated demand + * + * @return whether the demand can be unpacked + */ + public boolean canUnpackDemand(Demand demand) { + if(demand==null) return false; + else if(getPackedAmount(demand)==0) return false; + else return true; + } + + /** + * Gets whether an aggregated demand can be auto-packed. + * + * @param demand the aggregated demand + * + * @return whether the demand can be auto-packed + */ + public boolean canAutoPackDemand(Demand demand) { + if(demand==null) return false; + else if(getRemainingAmount(demand)==0) return false; + else return true; + } + + /** + * Gets whether a packed demand can be unpacked from a resource container. + * + * @param demandAsPacked the packed demand + * @param container the resource container + * + * @return whether the packed demand can be unpacked from the container + */ + public boolean canUnpackDemand(Demand demandAsPacked, I_ResourceContainer container) { + if(demandAsPacked==null || container==null) return false; + else if(packedDemands.get(container).contains(demandAsPacked)) return true; + else return false; + } + /** + * Gets whether a container has been manifested on a carrier to arrive at + * a given supply point. If false, the container has no present way of + * arriving at the supply point. + * @param container the resource container + * @param point the supply point + * @return whether the container has been manifested + */ + private boolean isManifested(I_ResourceContainer container, SupplyPoint point) { + if(container==null || point==null) return false; + for(SupplyEdge edge : supplyEdges) { + if(edge.getPoint().getNode().equals(point.getNode()) + && edge.getPoint().getTime() <= point.getTime()) { + for(I_Carrier carrier : edge.getAllCarriers()) { + if(manifestedContainers.get(edge).get(carrier).contains(container)) + return true; + } + } + } + return false; + } + + /** + * Gets whether an aggregated demand can be packed in a resource container. + * + * @param demand the aggregated demand + * @param container the resource container + * + * @return whether the demand can be packed in the resource container + */ + public boolean canPackDemand(Demand demand, I_ResourceContainer container) { + if(demand==null || container==null) return false; + else if(getRemainingAmount(demand)>0 + && getCargoMass(container, getSupplyPoint(demand))-container.getMaxCargoMass()()); + } + + /** + * Removes a resource container from the manifest. + * + * @param container the resource container + */ + public void removeContainer(I_ResourceContainer container) { + for(Demand demandAsPacked : packedDemands.get(container)) { + for(DemandSet demands : aggregatedNodeDemands.values()) { + for(Demand demand : demands) { + demandsAsPacked.get(demand).remove(demandAsPacked); + } + } + for(DemandSet demands : aggregatedEdgeDemands.values()) { + for(Demand demand : demands) { + demandsAsPacked.get(demand).remove(demandAsPacked); + } + } + } + packedDemands.remove(container); + for(SupplyPoint point : supplyPoints) { + cachedContainerDemands.get(point).remove(container); + } + for(SupplyEdge edge : supplyEdges) { + for(I_Carrier carrier : edge.getAllCarriers()) { + manifestedContainers.get(edge).get(carrier).remove(container); + } + } + } + + /** + * Gets the set of supply edges. + * + * @return the set of supply edges + */ + public SortedSet getSupplyEdges() { + return supplyEdges; + } + + /** + * Sets the set of supply edges. + * + * @param supplyEdges the set of supply edges + */ + public void setSupplyEdges(SortedSet supplyEdges) { + this.supplyEdges = supplyEdges; + for(SupplyEdge edge : supplyEdges) { + manifestedContainers.put(edge, new HashMap>()); + for(I_Carrier carrier : edge.getAllCarriers()) { + manifestedContainers.get(edge).put(carrier, new HashSet()); + } + } + } + + /** + * Gets the set of supply points. + * + * @return the set of supply points + */ + public SortedSet getSupplyPoints() { + return supplyPoints; + } + + /** + * Sets the set of supply points. + * + * @param supplyPoints the set of supply points + */ + public void setSupplyPoints(SortedSet supplyPoints) { + this.supplyPoints = supplyPoints; + for(SupplyPoint point : supplyPoints) { + cachedContainerDemands.put(point, new HashSet()); + } + } + + /** + * Gets the set of demands aggregated to supply points. + * + * @return the set of aggregated demands + */ + public SortedMap getAggregatedNodeDemands() { + return aggregatedNodeDemands; + } + + /** + * Sets the set of demands aggregated to supply points. + * + * @param aggregatedNodeDemands the set of aggregated demands + */ + public void setAggregatedNodeDemands(SortedMap aggregatedNodeDemands) { + this.aggregatedNodeDemands = aggregatedNodeDemands; + for(DemandSet demands : aggregatedNodeDemands.values()) { + for(Demand demand : demands) { + demandsAsPacked.put(demand, new HashSet()); + } + } + } + + /** + * Gets the set of demands aggregated to supply edges. + * + * @return the set of aggregated demands + */ + public SortedMap getAggregatedEdgeDemands() { + return aggregatedEdgeDemands; + } + + /** + * Sets the set of demands aggregated to supply edges. + * + * @param aggregatedEdgeDemands the set of aggregated demands + */ + public void setAggregatedEdgeDemands(SortedMap aggregatedEdgeDemands) { + this.aggregatedEdgeDemands = aggregatedEdgeDemands; + for(DemandSet demands : aggregatedEdgeDemands.values()) { + for(Demand demand : demands) { + demandsAsPacked.put(demand, new HashSet()); + } + } + } + + /** + * Gets the set of packed demands from aggregated demands. + * + * @return the set of packed demands + */ + public Map> getDemandsAsPacked() { + return demandsAsPacked; + } + + /** + * Gets the set of packed demands in resource containers. + * + * @return the set of packed demands + */ + public Map> getPackedDemands() { + return packedDemands; + } + + /** + * Gets the set of packed demands in a container at a point in time + * referenced by a supply point. + * + * @param container the resource container + * @param point the supply point + * + * @return the set of packed demands + */ + public Set getPackedDemands(I_ResourceContainer container, SupplyPoint point) { + HashSet demands = new HashSet(); + for(Demand demand : packedDemands.get(container)) { // got null pointer here ? + if(getSupplyPoint(getDemand(demand)).getTime()>=point.getTime()) + demands.add(demand); + } + return demands; + } + + /** + * Gets the set of resource containers at supply points. + * + * @return the set of resource containers + */ + public SortedMap> getCachedContainerDemands() { + return cachedContainerDemands; + } + + /** + * Gets the set of resource containers manifested to a supply edge. + * + * @return the set of resource containers + */ + public SortedMap>> getManifestedContainers() { + return manifestedContainers; + } + + /** + * Gets the set of resource containers manifested to a carrier at a point + * in time referenced by a supply point. + * + * @param carrier the carrier + * @param point the supply point + * + * @return the set of resource containers + */ + public Set getManifestedContainers(I_Carrier carrier, SupplyPoint point) { + HashSet containers = new HashSet(); + for(SupplyEdge edge : supplyEdges) { + if(manifestedContainers.get(edge).keySet().contains(carrier) + && edge.getEndTime() <= point.getTime()) { + for(I_ResourceContainer container : manifestedContainers.get(edge).get(carrier)) { + containers.add(container); + } + } + } + return containers; + } + private void rebuildCachedContainerDemands() { + for(SupplyPoint point : supplyPoints) { + cachedContainerDemands.get(point).clear(); + } + + for(I_ResourceContainer container : packedDemands.keySet()) { + SupplyEdge firstEdge = null; + for(SupplyEdge edge : supplyEdges) { + for(I_Carrier carrier : edge.getAllCarriers()) { + if(manifestedContainers.get(edge).get(carrier).contains(container)) { + SupplyPoint point = getNextSupplyPoint(edge); + if(point != null) cachedContainerDemands.get(point).add(container); + if(firstEdge==null||edge.getStartTime()>firstEdge.getStartTime()) { + firstEdge = edge; + } + } + } + } + SupplyPoint firstPoint = firstEdge==null?null:firstEdge.getPoint(); + for(Demand demandAsPacked : packedDemands.get(container)) { + SupplyPoint point = getSupplyPoint(getDemand(demandAsPacked)); + if(firstPoint==null||(point.getTime() getContainers() { + return packedDemands.keySet(); + } + + /** + * Generates a set of manifest events used at simulation time. + * + * @return the set of manifest events + */ + public Set generateManifestEvents() { + HashSet events = new HashSet(); + for(I_ResourceContainer container : packedDemands.keySet()) { + container.getContents().clear(); + for(Demand demand : packedDemands.get(container)) { + if(!container.add(demand.getResource(), demand.getAmount())) { + System.out.println(demand + " could not be added to " + container); + //throw new RuntimeException("ERROR!"); + } + } + } + for(SupplyEdge edge : supplyEdges) { + for(I_Carrier carrier : edge.getAllCarriers()) { + if(manifestedContainers.get(edge).get(carrier).size()>0) { + ManifestEvent event = new ManifestEvent(); + event.setName("Manifest Event"); + event.setPriority(0); + event.setTime(edge.getStartTime()); + event.setLocation(edge.getOrigin()); + for(I_Element element : getScenario().getElements()) { + if(element.equals(carrier)) { + event.setCarrier((I_Carrier)element); + break; + } + } + for(I_ResourceContainer container : manifestedContainers.get(edge).get(carrier)) { + event.getContainers().add(container); + } + events.add(event); + } + } + } + return events; + } + + /** + * Runs an auto-manifesting algorithm. + */ + public void autoManifest() { + for(SupplyPoint point : supplyPoints) { + // pack edge demands first + for(Demand demand : aggregatedEdgeDemands.get(point.getEdge())) { + autoPackDemand(demand); + } + // then pack node demands + for(Demand demand : aggregatedNodeDemands.get(point)) { + autoPackDemand(demand); + } + // manifest edge demands first + for(I_ResourceContainer container : packedDemands.keySet()) { + if(point.equals(getCurrentSupplyPoint(container)) + && isEdgeDemand(container)) { + boolean isManifested = false; + for(SupplyEdge edge : supplyEdges) { + for(I_Carrier carrier : edge.getCarriers()) { + isManifested = canManifestContainer(container, edge, carrier); + manifestContainer(container, edge, carrier); + if(isManifested) break; + } + if(isManifested) break; + } + } + } + // then manifest node demands + for(I_ResourceContainer container : packedDemands.keySet()) { + if(point.equals(getCurrentSupplyPoint(container)) + && !isEdgeDemand(container)) { + boolean isManifested = false; + for(SupplyEdge edge : supplyEdges) { + for(I_Carrier carrier : edge.getCarriers()) { + if(canManifestContainer(container, edge, carrier)) { + isManifested = canManifestContainer(container, edge, carrier); + manifestContainer(container, edge, carrier); + if(isManifested) break; + } + } + if(isManifested) break; + } + } + } + } + } + + /** + * Gets the scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return scenario; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/scenario/Mission.java b/src/main/java/edu/mit/spacenet/scenario/Mission.java new file mode 100644 index 0000000..bd3b783 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/scenario/Mission.java @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.scenario; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.element.Carrier; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.model.I_DemandModel; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.PreSimulator; +import edu.mit.spacenet.simulator.event.CreateEvent; +import edu.mit.spacenet.simulator.event.EvaEvent; +import edu.mit.spacenet.simulator.event.ExplorationProcess; +import edu.mit.spacenet.simulator.event.FlightTransport; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.I_Process; +import edu.mit.spacenet.simulator.event.I_Transport; +import edu.mit.spacenet.simulator.event.SpaceTransport; +import edu.mit.spacenet.util.DateFunctions; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A mission is usually described as one crew rotation or the unmanned delivery + * of supplies. + * + * @author Paul Grogan + */ +public class Mission implements Comparable { + private String name; + private Date startDate; + private Scenario scenario; + private List eventList; + private SortedSet demandModels; + private Node destination; + private Node origin; + private Node returnOrigin; + private Node returnDestination; + + /** + * The constructor takes a reference to the parent scenario. + * + * @param scenario the scenario + */ + public Mission(Scenario scenario) { + this.eventList = new ArrayList(); + this.demandModels = new TreeSet(); + setName("New Mission"); + setStartDate(new Date()); + setScenario(scenario); + } + + /** + * Gets the name of the mission. + * + * @return the mission name + */ + public String getName() { + return name; + } + + /** + * Sets the name of the mission and updates and member elements' prefix + * names appropriately with the first five letters. + * + * @param name the mission name + */ + public void setName(String name) { + this.name = name; + + for(I_Event event : getEventList()) { + if(event.getName().contains(" | ")) + event.setName(getName().substring(0,Math.min(getName().length(), 5)) + event.getName().substring(event.getName().indexOf(" | "))); + if(event instanceof CreateEvent) { + for(I_Element element : ((CreateEvent)event).getElements()) { + if(element.getName().contains(" | ")) + element.setName(getName().substring(0,Math.min(getName().length(), 5)) + element.getName().substring(element.getName().indexOf(" | "))); + } + } + } + } + + /** + * Gets the list of events. + * + * @return the event list + */ + public List getEventList() { + return eventList; + } + + /** + * Gets the mission start date. + * + * @return the mission start date + */ + public Date getStartDate() { + return startDate; + } + + /** + * Sets the mission start date. + * + * @param startDate the mission start date + */ + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + /** + * Gets the parent scenario. + * + * @return the scenario + */ + public Scenario getScenario() { + return scenario; + } + + /** + * Sets the parent scenario. + * + * @param scenario the scenario + */ + public void setScenario(Scenario scenario) { + this.scenario = scenario; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + SimpleDateFormat s = new SimpleDateFormat("M/d/yy"); + return getName() + " (" + s.format(getStartDate()) + ")"; + } + + /** + * Gets the set of mission-level demand models. + * + * @return the set of demand models + */ + public SortedSet getDemandModels() { + return demandModels; + } + + /** + * Generate demands from the mission-level models. + * + * @param simulator the simulator + * + * @return the set of mission-level demands + */ + public DemandSet generateDemands(I_Simulator simulator) { + DemandSet demands = new DemandSet(); + for(I_DemandModel model : demandModels) { + for(Demand demand : model.generateDemands(getDuration(), simulator)) { + demands.add(demand); + } + } + return demands; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Mission mission) { + if(getStartDate().equals(mission.getStartDate())) { + return getName().compareTo(mission.getName()); + } else { + return getStartDate().compareTo(mission.getStartDate()); + } + } + + /** + * Gets the mission destination node. + * + * @return the mission destination + */ + public Node getDestination() { + return destination; + } + + /** + * Sets the mission destination node. + * + * @param destination the mission destination + */ + public void setDestination(Node destination) { + this.destination = destination; + } + + /** + * Gets the mission origin node. + * + * @return the mission origin + */ + public Node getOrigin() { + return origin; + } + + /** + * Sets the missino origin node. + * + * @param origin the mission origin + */ + public void setOrigin(Node origin) { + this.origin = origin; + } + + /** + * Gets the mission return destination node. + * + * @return the mission return destination, null if no return + */ + public Node getReturnDestination() { + return returnDestination; + } + + /** + * Sets the mission return destination node. + * + * @param returnDestination the mission return destination, null if no return + */ + public void setReturnDestination(Node returnDestination) { + this.returnDestination = returnDestination; + } + + /** + * Gets the mission return origin node. + * + * @return the mission return origin, null if no return + */ + public Node getReturnOrigin() { + return returnOrigin; + } + + /** + * Sets the mission return origin node. + * + * @param returnOrigin the mission return origin, null if no return + */ + public void setReturnOrigin(Node returnOrigin) { + this.returnOrigin = returnOrigin; + } + private double getRemainingCapacityTo(Node node) { + double capacity = 0; + PreSimulator preSim = new PreSimulator(getScenario()); + for(I_Event e : getEventList()) { + if(e instanceof FlightTransport + && ((FlightTransport)e).getEdge().getDestination().equals(node)) { + capacity += ((FlightTransport)e).getEdge().getMaxCargoMass(); + preSim.simulate(e.getTime() + DateFunctions.getDaysBetween(getStartDate(), getScenario().getStartDate()), e.getPriority(), false); + for(I_Element element : ((FlightTransport)e).getElements()) { + if(element instanceof I_Carrier && preSim.getScenario().getNetwork().getRegistrar().containsKey(element.getUid())) { + capacity -= ((I_Carrier)preSim.getScenario().getNetwork().getRegistrar().get(element.getUid())).getCargoMass(); + } + } + } else if(e instanceof SpaceTransport + && ((SpaceTransport)e).getEdge().getDestination().equals(node)) { + preSim.simulate(e.getTime() + DateFunctions.getDaysBetween(getStartDate(), getScenario().getStartDate()), e.getPriority(), false); + for(I_Element element : ((SpaceTransport)e).getElements()) { + if(element instanceof I_Carrier && preSim.getScenario().getNetwork().getRegistrar().containsKey(element.getUid())) { + capacity += ((I_Carrier)element).getMaxCargoMass()-((I_Carrier)element).getCargoMass(); + } + } + } + } + return capacity; + } + + /** + * Gets the remaining delivery capacity to the destination node. + * + * @return the amount of remaining capacity (kilograms) + */ + public double getRemainingDeliveryCapacity() { + return getRemainingCapacityTo(getDestination()); + } + + /** + * Gets the remaining return capacity to the return destination node. + * + * @return the amount of remaining capacity (kilograms) + */ + public double getRemainingReturnCapacity() { + return getRemainingCapacityTo(getReturnDestination()); + } + + /** + * Gets the set of delivery carriers in the mission (elements that arrive at + * the mission destination). + * + * @return the set of carriers + */ + public Set getDeliveryCarriers() { + HashSet carriers = new HashSet(); + for(I_Event e : getEventList()) { + if(e instanceof I_Transport + && ((I_Transport)e).getDestination().equals(getDestination())) { + for(I_Element element : ((I_Transport)e).getElements()) { + if(element instanceof I_Carrier) { + carriers.add((I_Carrier)element); + } + } + break; + } + } + return carriers; + } + + /** + * Gets the set of return carriers in the missino (elements that arrive at + * the mission return destination). + * + * @return the set of carriers + */ + public Set getReturnCarriers() { + HashSet carriers = new HashSet(); + for(I_Event e : getEventList()) { + if(e instanceof I_Transport + && ((I_Transport)e).getDestination().equals(getReturnDestination())) { + for(I_Element element : ((I_Transport)e).getElements()) { + if(element instanceof I_Carrier) { + carriers.add((I_Carrier)element); + } + } + break; + } + } + return carriers; + } + private double getRawCapacityTo(Node node) { + double capacity = 0; + for(I_Event e : getEventList()) { + if(e instanceof FlightTransport + && ((FlightTransport)e).getEdge().getDestination().equals(node)) { + capacity += ((FlightTransport)e).getEdge().getMaxCargoMass(); + } else if(e instanceof SpaceTransport + && ((SpaceTransport)e).getEdge().getDestination().equals(node)) { + for(I_Element i : ((SpaceTransport)e).getElements()) { + if(i instanceof I_Carrier) { + capacity += ((I_Carrier)i).getMaxCargoMass(); + } + } + } + } + return capacity; + } + + /** + * Gets the raw delivery capacity to the mission destination. + * + * @return the raw delivery capacity (kilograms) + */ + public double getRawDeliveryCapacity() { + return getRawCapacityTo(getDestination()); + } + + /** + * Gets the raw return capacity to the mission return destination. + * + * @return the raw return capacity (kilograms) + */ + public double getRawReturnCapacity() { + return getRawCapacityTo(getReturnDestination()); + } + + /** + * Gets the crew size of the mission. + * + * @return the crew size + */ + public int getCrewSize() { + int crewSize = 0; + for(I_Event e : getEventList()) { + if(e instanceof CreateEvent) { + for(I_Element i : ((CreateEvent)e).getElements()) { + if(i instanceof CrewMember) { + crewSize++; + } else if(i instanceof Carrier) { + crewSize+=((Carrier)i).getCrewSize(); + } + } + } + } + return crewSize; + } + + /** + * Gets the number of EVAs. + * + * @return the number of EVAs + */ + public int getNumberEva() { + int numberEva = 0; + for(I_Event e : getEventList()) { + if(e instanceof EvaEvent) { + numberEva++; + } else if(e instanceof ExplorationProcess) { + numberEva += ((ExplorationProcess)e).getNumberEva(); + } + } + return numberEva; + } + + /** + * Gets the EVA crew time. + * + * @return the EVA crew time (crew-hour) + */ + public double getEvaCrewTime() { + double time = 0; + for(I_Event e : getEventList()) { + if(e instanceof EvaEvent) { + time += ((EvaEvent)e).getEvaDuration()*((EvaEvent)e).getStateMap().size(); + } else if(e instanceof ExplorationProcess) { + time += ((ExplorationProcess)e).getNumberEva()*((ExplorationProcess)e).getEvaDuration()*((ExplorationProcess)e).getStateMap().size(); + } + } + return time; + } + + /** + * Gets the total mission duration. + * + * @return the mission duration (days) + */ + public double getDuration() { + double startTime = DateFunctions.getDaysBetween(getStartDate(), getScenario().getStartDate()); + double endTime = startTime; + // if this is the last mission in the mission list + Collections.sort(getScenario().getMissionList()); + if(this.equals(getScenario().getMissionList().get(getScenario().getMissionList().size()-1))) { + // the end time is the start time plus the time of the last event + // or duration if it is a process + Collections.sort(getEventList()); + for(I_Event e : getEventList()) { + double newEndTime = startTime + e.getTime(); + if(e instanceof I_Process) newEndTime += ((I_Process)e).getDuration(); + if(newEndTime > endTime) endTime = newEndTime; + } + } else { + // else the end time is the days between the start of the scenario + // and the start of the next mission + endTime = DateFunctions.getDaysBetween(getScenario().getMissionList().get(getScenario().getMissionList().indexOf(this)+1).getStartDate(), + getScenario().getStartDate()); + } + return GlobalParameters.getRoundedTime(endTime - startTime); + } + + /** + * Gets the mission duration at the destination node. + * + * @return the destination duration (days) + */ + public double getDestinationDuration() { + double arrival = -1; + double departure = -1; + for(I_Event e : getEventList()) { + if(e instanceof I_Transport) { + if(((I_Transport)e).getDestination().equals(getDestination()) + && arrival == -1) { + arrival = e.getTime() + ((I_Transport)e).getDuration(); + } else if(((I_Transport)e).getOrigin().equals(getDestination())) { + departure = e.getTime(); + } + } + } + if(arrival < 0) return 0; + else if(departure < 0) return GlobalParameters.getRoundedTime(getDuration() - arrival); + else return GlobalParameters.getRoundedTime(departure - arrival); + } + + /** + * Gets the duration in transit to the destination node. The transit + * duration is defined as the time elapsed from the start of the mission to + * the arrival of a transport event at the mission destination node. + * + * @return the transit duration (days) + */ + public double getTransitDuration() { + double arrivalTime = -1; + for(I_Event e : getEventList()) { + if(e instanceof I_Transport) { + if(((I_Transport)e).getDestination().equals(getDestination()) + && arrivalTime == -1) { + arrivalTime = e.getTime() + ((I_Transport)e).getDuration(); + } + } + } + return GlobalParameters.getRoundedTime((arrivalTime!=-1) ? arrivalTime : getDuration()); + } + + /** + * Gets the return duration in transit from the destination node. The return + * transit duration is defined as the time elapsed from the start of the + * last transport event to leave the mission return origin node to the + * arrival of the last transport event to arrive at the mission return + * destination node. + * + * @return the transit duration (days) + */ + public double getReturnTransitDuration() { + double transitStart = -1; + double transitEnd = -1; + for(I_Event e : getEventList()) { + if(e instanceof I_Transport) { + if(((I_Transport)e).getDestination().equals(getReturnDestination())) { + transitEnd = e.getTime() + ((I_Transport)e).getDuration(); + } + if(((I_Transport)e).getOrigin().equals(getReturnOrigin())) { + transitStart = e.getTime(); + } + } + } + return GlobalParameters.getRoundedTime((transitEnd!=-1&&transitStart!=-1) ? transitEnd - transitStart : 0); + } + + /** + * Gets the duration not accounted for in the transit or destination duration. + * + * @return the dormant duration (days) + */ + public double getDormantDuration() { + return GlobalParameters.getRoundedTime(getDuration() - getTransitDuration() - getDestinationDuration() - getReturnTransitDuration()); + } + + /** + * Gets the set of elements that were created during this mission. + * + * @return the set of elements + */ + public SortedSet getElements() { + TreeSet elements = new TreeSet(); + for(I_Event event : getEventList()) { + if(event instanceof CreateEvent) { + elements.addAll(((CreateEvent)event).getElements()); + } + } + return elements; + } + + /** + * Gets whether this is a crewed mission (i.e. contains crew members). + * + * @return whether this is a crewed mission + */ + public boolean isCrewed() { + for(I_Element element : getElements()) { + if(element instanceof CrewMember) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/scenario/RepairItem.java b/src/main/java/edu/mit/spacenet/scenario/RepairItem.java new file mode 100644 index 0000000..ed49912 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/scenario/RepairItem.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.scenario; + +import java.text.DecimalFormat; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.resource.Demand; + +/** + * This class represents the repair of an item during simulation. + * + * @author Paul Grogan + */ +public class RepairItem implements Comparable { + private Demand demand; + private I_Element element; + + /** + * The constructor takes the demand that was eliminated by repair, and the + * element that received the repair. + * + * @param demand the demand that was eliminated + * @param element the element receiving repair + */ + public RepairItem(Demand demand, I_Element element) { + this.demand = demand; + this.element = element; + } + + /** + * Gets the demand eliminated by repair. + * + * @return the demand + */ + public Demand getDemand() { + return demand; + } + + /** + * Gets the element repaired. + * + * @return the repaired element + */ + public I_Element getElement() { + return element; + } + + /** + * Gets the unit mean repair time of the repair. + * + * @return the unit mean repair time (hours per unit) + */ + public double getUnitMeanRepairTime() { + for(PartApplication application : element.getParts()) { + if(application.getPart().equals(demand.getResource())) { + return application.getMeanTimeToRepair(); + } + } + return Double.MAX_VALUE; + } + + /** + * Gets the mean repair time of the repair. + * + * @return the repair time (hours) + */ + public double getMeanRepairTime() { + return getUnitMeanRepairTime()*demand.getAmount(); + } + + /** + * Gets the unit amount of mass require for repair. + * + * @return the amount of additional mass (kilograms per unit) + */ + public double getUnitMassToRepair() { + for(PartApplication application : element.getParts()) { + if(application.getPart().equals(demand.getResource())) { + return application.getMassToRepair(); + } + } + return 0; + } + + /** + * Gets the amount of mass required to perform the repair. + * + * @return the amount of mass (kilograms) + */ + public double getMassToRepair() { + return getUnitMassToRepair()*demand.getAmount(); + } + + /** + * Gets the value of the repair. + * + * @return the repair value (hours used per kilogram saved) + */ + public double getRepairValue() { + return getUnitMeanRepairTime()/(demand.getResource().getUnitMass() - getUnitMassToRepair()); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + DecimalFormat format = new DecimalFormat("0.000"); + return demand + " (" + format.format(getMassToRepair()) + " kg, " + format.format(getMeanRepairTime()) + " hr)"; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(RepairItem repairItem) { + return new Double(getRepairValue()).compareTo(repairItem.getRepairValue()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/scenario/Scenario.java b/src/main/java/edu/mit/spacenet/scenario/Scenario.java new file mode 100644 index 0000000..67fa5b4 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/scenario/Scenario.java @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.scenario; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import edu.mit.spacenet.data.I_DataSource; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.I_Transport; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * The scenario class is used to store all information used in a simulation. It + * is the class that is serialized to a file when saving. + * + * @author Paul Grogan + */ +public class Scenario { + private String name; + private String description; + private Date startDate; + private String filePath; + private String createdBy; + private ScenarioType scenarioType; + + private I_DataSource dataSource; + + private Network network; + + private List missionList; + + private Manifest manifest; + + /* Scenario Options */ + private double timePrecision, demandPrecision, massPrecision, volumePrecision; + private boolean volumeConstrained, environmentConstrained; + + /* Demand Options */ + private ItemDiscretization itemDiscretization; + private double itemAggregation; + private boolean scavengeSpares; + private Map> repairedItems; + + /* Simulation Options */ + private boolean detailedEva; + private boolean detailedExploration; + + /** + * The default constructor sets a default name and date, chooses the lunar + * scenario type, and initializes the data structures. + */ + public Scenario() { + setName("New Scenario"); + setStartDate(new Date()); + setScenarioType(ScenarioType.LUNAR); + network = new Network(); + missionList = new ArrayList(); + manifest = new Manifest(this); + detailedEva = true; + detailedExploration = true; + + timePrecision = GlobalParameters.getTimePrecision(); + demandPrecision = GlobalParameters.getDemandPrecision(); + massPrecision = GlobalParameters.getMassPrecision(); + volumePrecision = GlobalParameters.getVolumePrecision(); + volumeConstrained = GlobalParameters.isVolumeConstrained(); + environmentConstrained = GlobalParameters.isEnvironmentConstrained(); + + itemDiscretization = GlobalParameters.getItemDiscretization(); + itemAggregation = GlobalParameters.getItemAggregation(); + scavengeSpares = GlobalParameters.isScavengeSpares(); + repairedItems = new HashMap>(); + } + + /** + * Gets a list of all the elements instantiated in the scenario. + * + * @return the list of scenario elements + */ + public List getElements() { + ArrayList elements = new ArrayList(); + for(Mission m : missionList) { + elements.addAll(m.getElements()); + } + return elements; + } + + /** + * Gets a scenario element by its unique identifier. + * + * @param uid the unique identifier + * + * @return the element + */ + public I_Element getElementByUid(int uid) { + for(I_Element e : getElements()) { + if(e.getUid()==uid) return e; + } + return null; + } + + /** + * Gets the scenario network. + * + * @return the network + */ + public Network getNetwork() { + return this.network; + } + + /** + * Gets the scenario name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Sets the scenario name. + * + * @param name the name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the scenario description. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * Sets the scenario description. + * + * @param description the scenario description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets the scenario start date. + * + * @return the start date + */ + public Date getStartDate() { + return startDate; + } + + /** + * Sets the scenario start date. + * + * @param startDate the start date + */ + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + /** + * Gets the created-by text. + * + * @return the created-by text + */ + public String getCreatedBy() { + return createdBy; + } + + /** + * Sets the created-by text. + * + * @param createdBy the created-by text + */ + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + /** + * Gets the scenario type. + * + * @return the scenario type + */ + public ScenarioType getScenarioType() { + return scenarioType; + } + + /** + * Sets the scenario type. + * + * @param scenarioType the scenario type + */ + public void setScenarioType(ScenarioType scenarioType) { + this.scenarioType = scenarioType; + } + + /** + * Gets the mission list. + * + * @return the mission list + */ + public List getMissionList() { + return this.missionList; + } + + /** + * Gets the manifest. + * + * @return the manifest + */ + public Manifest getManifest() { + return manifest; + } + + /** + * Gets the data source. + * + * @return the data source + */ + public I_DataSource getDataSource() { + return dataSource; + } + + /** + * Sets the data source. + * + * @param dataSource the data source + */ + public void setDataSource(I_DataSource dataSource) { + this.dataSource = dataSource; + } + + /** + * Prints the. + */ + public void print() { + System.out.println("Scenario: " + getName()); + System.out.println(); + System.out.println("Mission List"); + for(Mission m : missionList) { + System.out.println("\t" + m.getName()); + } + System.out.println(); + dataSource.print(); + System.out.println(); + } + + /** + * Gets the scenario file path. + * + * @return the file path, null if never saved + */ + public String getFilePath() { + return filePath; + } + + /** + * Gets the scenario file name. + * + * @return the file name, empty string if never saved + */ + public String getFileName() { + if(filePath==null||filePath.length()==0) return ""; + int lastIndex = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\")); + return filePath.substring(lastIndex+1, filePath.length()); + } + + /** + * Sets the scenario file path. + * + * @param filePath the file path + */ + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + /** + * Gets whether a node is utilized somewhere in the scenario. + * + * @param node the node + * + * @return true if the node is used, false otherwise + */ + public boolean isNodeUsed(Node node) { + return getNodeUses(node).size()>0; + } + + /** + * Gets a list of usages of a node. + * + * @param node the node + * + * @return a list of objects that use the node + */ + public List getNodeUses(Node node) { + ArrayList uses = new ArrayList(); + for(Mission m : getMissionList()) { + if(node.equals(m.getOrigin()) + || node.equals(m.getDestination()) + || node.equals(m.getReturnOrigin()) + || node.equals(m.getReturnDestination())) + uses.add(m); + for(I_Event e : m.getEventList()) { + if(e.getLocation().equals(node) + || (e instanceof I_Transport + && (node.equals(((I_Transport)e).getOrigin()) + || node.equals(((I_Transport)e).getDestination())))) { + if(!uses.contains(m)) uses.add(m); + uses.add(e); + } + } + } + return uses; + } + + /** + * Gets whether an edge is utilized somewhere in the scenario. + * + * @param edge the edge + * + * @return true if the edge is used, false otherwise + */ + public boolean isEdgeUsed(Edge edge) { + return getEdgeUses(edge).size()>0; + } + + /** + * Gets a list of usages of an edge. + * + * @param edge the edge + * + * @return a list of objects that use the edge + */ + public List getEdgeUses(Edge edge) { + ArrayList uses = new ArrayList(); + for(Mission m : getMissionList()) { + for(I_Event e : m.getEventList()) { + if(e instanceof I_Transport + && edge.equals(((I_Transport)e).getEdge())) { + uses.add(m); + uses.add(e); + } + } + } + return uses; + } + + /** + * Gets whether detailed EVAs should be used in simulation. Detailed EVAs + * generate Move, Reconfigure, and Demand events and can bog down large + * simulations. + * + * @return whether detailed EVAs are used + */ + public boolean isDetailedEva() { + return detailedEva; + } + + /** + * Sets whether detailed EVAs should be used in simulation. Detailed EVAs + * generate Move, Reconfigure, and Demand events and can bog down large + * simulations. + * + * @param detailedEva whether detailed EVAs are used + */ + public void setDetailedEva(boolean detailedEva) { + this.detailedEva = detailedEva; + } + + /** + * Sets whether detailed explorations should be used in simulation. Detailed + * explorations generate EVA events and can bog down large simulations. + * + * @param detailedExploration whether detailed explorations are used + */ + public void setDetailedExploration(boolean detailedExploration) { + this.detailedExploration = detailedExploration; + } + + /** + * Gets whether detailed explorations should be used in simulation. Detailed + * explorations generate EVA events and can bog down large simulations. + * + * @return whether detailed explorations are used + */ + public boolean isDetailedExploration() { + return detailedExploration; + } + + /** + * Gets the time precision (smallest unit of time). + * + * @return the time precision (days) + */ + public double getTimePrecision() { + return timePrecision; + } + + /** + * Sets the time precision (smallest unit of time). + * + * @param timePrecision the time precision (days) + */ + public void setTimePrecision(double timePrecision) { + this.timePrecision = timePrecision; + GlobalParameters.setTimePrecision(timePrecision); + } + + /** + * Gets the demand precision (smallest unit of resource amount). + * + * @return the demand precision (units) + */ + public double getDemandPrecision() { + return demandPrecision; + } + + /** + * Sets the demand precision (smallest unit of resource amount). + * + * @param demandPrecision the demand precision (units) + */ + public void setDemandPrecision(double demandPrecision) { + this.demandPrecision = demandPrecision; + GlobalParameters.setDemandPrecision(demandPrecision); + } + + /** + * Gets the mass precision (smallest unit of mass). + * + * @return the mass precision (kilograms) + */ + public double getMassPrecision() { + return massPrecision; + } + + /** + * Sets the mass precision (smallest unit of mass). + * + * @param massPrecision the mass precision (kilograms) + */ + public void setMassPrecision(double massPrecision) { + this.massPrecision = massPrecision; + GlobalParameters.setMassPrecision(massPrecision); + } + + /** + * Gets the volume precision (smallest unit of volume). + * + * @return the volume precision (cubic meters) + */ + public double getVolumePrecision() { + return volumePrecision; + } + + /** + * Sets the volume precision (smallest unit of volume). + * + * @param volumePrecision the volume precision (cubic meters) + */ + public void setVolumePrecision(double volumePrecision) { + this.volumePrecision = volumePrecision; + GlobalParameters.setVolumePrecision(volumePrecision); + } + + /** + * Gets whether volume constraints should be enforced. + * + * @return volume constraints enforcement + */ + public boolean isVolumeConstrained() { + return volumeConstrained; + } + + /** + * Sets whether volume constraints should be enforced. + * + * @param volumeConstrained volume constraints enforcement + */ + public void setVolumeConstrained(boolean volumeConstrained) { + this.volumeConstrained = volumeConstrained; + GlobalParameters.setVolumeConstrained(volumeConstrained); + } + + /** + * Gets whether environment constraints should be enforced. + * + * @return environment constraints enforcement + */ + public boolean isEnvironmentConstrained() { + return environmentConstrained; + } + + /** + * Sets whether environment constraints should be enforced. + * + * @param environmentConstrained environment constraints enforcement + */ + public void setEnvironmentConstrained(boolean environmentConstrained) { + this.environmentConstrained = environmentConstrained; + GlobalParameters.setEnvironmentConstrained(environmentConstrained); + } + + /** + * Gets the item discretization scheme. + * + * @return the item discretization + */ + public ItemDiscretization getItemDiscretization() { + return itemDiscretization; + } + + /** + * Sets the item discretization scheme. + * + * @param itemDiscretization the item discretization + */ + public void setItemDiscretization(ItemDiscretization itemDiscretization) { + this.itemDiscretization = itemDiscretization; + GlobalParameters.setItemDiscretization(itemDiscretization); + } + + /** + * Gets whether spares scavenging is allowed. + * + * @return spares scavenging allowed + */ + public boolean isScavengeSpares() { + return scavengeSpares; + } + + /** + * Sets whether spares scavenging is allowed. + * + * @param scavengeSpares spares scavenging allowed + */ + public void setScavengeSpares(boolean scavengeSpares) { + this.scavengeSpares = scavengeSpares; + GlobalParameters.setScavengeSpares(scavengeSpares); + } + + /** + * Gets the item aggregation point. + * + * @return the item aggregation (0=pre-aggregation, 1=post-aggregation) + */ + public double getItemAggregation() { + return itemAggregation; + } + + /** + * Sets the item aggregation point. + * param itemAggregation the item aggregation (0=pre-aggregation, 1=post-aggregation) + * + * @param itemAggregation the item aggregation + */ + public void setItemAggregation(double itemAggregation) { + this.itemAggregation = itemAggregation; + GlobalParameters.setItemAggregation(itemAggregation); + } + + /** + * Gets the list of repair tasks. + * + * @return the repaired items + */ + public Map> getRepairedItems() { + return repairedItems; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/scenario/ScenarioType.java b/src/main/java/edu/mit/spacenet/scenario/ScenarioType.java new file mode 100644 index 0000000..63e4939 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/scenario/ScenarioType.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.scenario; + +import javax.swing.ImageIcon; + +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.Node; + +// TODO: Auto-generated Javadoc +/** + * An enumeration of the different types of scenarios used for network filtering. + * + * @author Paul Grogan + */ +public enum ScenarioType { + + /** An ISS scenario selects all of the EARTH surface and space nodes by default. */ + ISS("ISS", "icons/earth_icon.png"), + + /** A Lunar scenario selects all of the EARTH and MOON surface and space nodes by default. */ + LUNAR("Lunar", "icons/earth_moon_icon.png"), + + /** A Moon-only scenario selects all of the MOON surface and space nodes by default. */ + MOON_ONLY("Moon-only", "icons/moon_icon.png"), + + /** A Martian scenario selects all of the EARTH and MARS surface and space nodes by default. */ + MARTIAN("Martian", "icons/earth_mars_icon.png"), + + /** A Mars-only scenario selects all of the MARS surface and space nodes by default. */ + MARS_ONLY("Mars-only", "icons/mars_icon.png"), + + /** A scenario that selects all nodes by default. */ + SOLAR_SYSTEM("Solar System", "icons/solar_icon.png"); + + private String name; + private ImageIcon icon; + + private ScenarioType(String name, String iconUrl) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } + + /** + * Gets the name of the scenario type. + * + * @return the scenario type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon of the scenario type. + * + * @return the scenario type icon + */ + public ImageIcon getIcon() { + return icon; + } + + /** + * Method to get a particular instance of a scenario type based on a + * case-insensitive string. + * + * @param name case-insensitive string of name + * + * @return the scenario type, returns null if unknown name + */ + public static ScenarioType getInstance(String name) { + if(name.equals(ISS.getName())) return ISS; + else if(name.equals(LUNAR.getName())) return LUNAR; + else if(name.equals(MOON_ONLY.getName())) return MOON_ONLY; + else if(name.equals(MARTIAN.getName())) return MARTIAN; + else if(name.equals(MARS_ONLY.getName())) return MARS_ONLY; + else return null; + } + + /** + * Gets whether a node is visible under this scenario type. + * + * @param node the node to check + * + * @return whether the node is visible + */ + public boolean isNodeVisible(Node node) { + switch(this) { + case ISS: + if(node.getBody()==Body.EARTH) return true; + else return false; + case LUNAR: + if(node.getBody()==Body.EARTH || node.getBody()==Body.MOON) return true; + else return false; + case MOON_ONLY: + if(node.getBody()==Body.MOON) return true; + else return false; + case MARTIAN: + if(node.getBody()==Body.EARTH || node.getBody()==Body.MARS) return true; + else return false; + case MARS_ONLY: + if(node.getBody()==Body.MARS) return true; + else return false; + } + return false; + } + + /** + * Gets whether an edge is visible under this scenario type. + * + * @param edge the edge to check + * + * @return whether the edge is visible + */ + public boolean isEdgeVisible(Edge edge) { + if(isNodeVisible(edge.getOrigin()) + && isNodeVisible(edge.getDestination())) return true; + else return false; + } +} diff --git a/src/main/java/edu/mit/spacenet/scenario/SupplyEdge.java b/src/main/java/edu/mit/spacenet/scenario/SupplyEdge.java new file mode 100644 index 0000000..a5a2474 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/scenario/SupplyEdge.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.scenario; + +import java.text.DecimalFormat; +import java.util.HashSet; +import java.util.Set; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A supply edge represents an abstraction of a transport along an edge that + * has the capability to supply a location with resources. + * + * @author Paul Grogan + */ +public class SupplyEdge implements Comparable { + private Edge edge; + private boolean isReversed; + private double startTime, endTime; + private SupplyPoint point; + private Set carriers; + + /** + * The constructor initializes the data members. + * + * @param edge the associated network edge + * @param isReversed whether the edge is reversed or not (surface edges are reversible) + * @param startTime the simulation time of the start of the transport + * @param endTime the simulation time of the end of the transport + * @param carriers the list of carriers associated with the transport + */ + public SupplyEdge(Edge edge, boolean isReversed, double startTime, double endTime, Set carriers) { + this.edge = edge; + this.isReversed = isReversed; + this.startTime = startTime; + this.endTime = endTime; + this.point = new SupplyPoint(this); + this.carriers = carriers; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + DecimalFormat format = new DecimalFormat("0.0"); + return getOrigin() + " (" + format.format(startTime) + ") - " + getDestination() + " (" + format.format(endTime) + ")"; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(SupplyEdge edge) { + if(endTime==edge.endTime) + return getOrigin().compareTo(edge.getOrigin()); + else return new Double(endTime).compareTo(edge.endTime)*-1; + } + + /** + * Gets the network edge of the transport. + * + * @return the network edge + */ + public Edge getEdge() { + return edge; + } + + /** + * Gets the origin node of the network edge, taking into account possible + * reversing. + * + * @return the origin node + */ + public Node getOrigin() { + if(isReversed) return edge.getDestination(); + else return edge.getOrigin(); + } + + /** + * Gets the destination node of the network edge, taking into account + * possible reversing. + * + * @return the destination node + */ + public Node getDestination() { + if(isReversed) return edge.getOrigin(); + else return edge.getDestination(); + } + + /** + * Gets the simulation time of the start of the transport. + * + * @return the start time + */ + public double getStartTime() { + return GlobalParameters.getRoundedTime(startTime); + } + + /** + * Gets the simulation time of the end of the transport. + * + * @return the end time + */ + public double getEndTime() { + return GlobalParameters.getRoundedTime(endTime); + } + + /** + * Gets the capacity of the supply edge, measured by the excess cargo mass + * capacity of the carriers. + * + * @return the capacity (kilograms) + */ + public double getCapacity() { + double capacity = 0; + for(I_Carrier carrier : getCarriers()) { + capacity += carrier.getMaxCargoMass()-carrier.getCargoMass(); + } + return capacity; + } + + /** + * Gets the raw capacity of the supply edge, measured by the maximum cargo + * mass capacity of the carriers. + * + * @return the raw capacity (kilograms) + */ + public double getRawCapacity() { + double capacity = 0; + for(I_Carrier carrier : getCarriers()) { + capacity += carrier.getMaxCargoMass(); + } + return capacity; + } + + /** + * Gets the supply point being supplied by the supply edge. + * + * @return the supply point + */ + public SupplyPoint getPoint() { + return point; + } + + /** + * Gets a set carriers associated with the supply edge. + * + * @return the set of carriers + */ + public Set getCarriers() { + return carriers; + } + + /** + * Gets a set of all carriers (independent of nesting order) associated + * with the supply edge. + * + * @return the set of carriers + */ + public Set getAllCarriers() { + HashSet allCarriers = new HashSet(); + for(I_Carrier carrier : carriers) { + recursiveAddCarrier(allCarriers, carrier); + } + return allCarriers; + } + private void recursiveAddCarrier(Set allCarriers, I_Carrier carrier) { + allCarriers.add(carrier); + for(I_Element element : carrier.getContents()) { + if(element instanceof I_Carrier) { + recursiveAddCarrier(allCarriers, (I_Carrier)element); + } + } + } + + /** + * A supply point is the point in time and space that is supplied by a + * supply edge. + * + * @author Paul Grogan + */ + public class SupplyPoint implements Comparable { + private SupplyEdge edge; + + private SupplyPoint(SupplyEdge edge) { + this.edge = edge; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + DecimalFormat format = new DecimalFormat("0.0"); + return getNode() + " (" + format.format(getTime()) + ")"; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(SupplyPoint point) { + if(getTime()==point.getTime()) + return getNode().compareTo(point.getNode()); + return new Double(getTime()).compareTo(point.getTime())*-1; + } + + /** + * Gets the network node. + * + * @return the node + */ + public Node getNode() { + return edge.getDestination(); + } + + /** + * Gets the simulation time of the supply point. + * + * @return the time + */ + public double getTime() { + return edge.getEndTime(); + } + + /** + * Gets the associated supply edge. + * + * @return the supply edge + */ + public SupplyEdge getEdge() { + return edge; + } + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/AbstractSimulator.java b/src/main/java/edu/mit/spacenet/simulator/AbstractSimulator.java new file mode 100644 index 0000000..361a832 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/AbstractSimulator.java @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.scenario.ItemDiscretization; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.RepairItem; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.event.DemandEvent; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.ManifestEvent; +import edu.mit.spacenet.simulator.event.MissionEvent; +import edu.mit.spacenet.simulator.moe.MoeCrewTime; +import edu.mit.spacenet.util.DateFunctions; +import edu.mit.spacenet.util.SerializeUtil; + +/** + * An abstract implementation of the simulator interface. + * + * @author Paul Grogan + */ +public abstract class AbstractSimulator implements I_Simulator { + private Scenario scenario; + private Scenario clone; + private PriorityQueue events; + private double time; + private List spatialErrors; + private List unsatisfiedDemands; + private List warnings; + private List scavengedParts; + private List repairedParts; + private Map> itemDemandsByElement; + private Map itemDemandsByScenario; + private Map> itemDemandsByLocation; + private boolean packingDemandsAdded, demandsSatisfied; + private boolean itemsRepaired; + + protected double duration; + protected I_Event event; + + /** + * The constructor sets the scenario and initializes the data structures. + * + * @param scenario the scenario + */ + public AbstractSimulator(Scenario scenario) { + this.scenario = scenario; + events = new PriorityQueue(); + spatialErrors = new ArrayList(); + unsatisfiedDemands = new ArrayList(); + warnings = new ArrayList(); + scavengedParts = new ArrayList(); + repairedParts = new ArrayList(); + itemDemandsByElement = new HashMap>(); + itemDemandsByLocation = new HashMap>(); + itemDemandsByScenario = new HashMap(); + packingDemandsAdded = false; + demandsSatisfied = true; + itemsRepaired = false; + } + protected PriorityQueue getEvents() { + return events; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#schedule(edu.mit.spacenet.domain.event.I_Event) + */ + public void schedule(I_Event event) { + events.add(event); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getScenario() + */ + public Scenario getScenario() { + return clone; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getTime() + */ + public double getTime() { + return time; + } + + /** + * Sets the time. + * + * @param time the new time + */ + public void setTime(double time) { + this.time = time; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getWarnings() + */ + public List getWarnings() { + return warnings; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getErrors() + */ + public List getErrors() { + ArrayList errors = new ArrayList(); + errors.addAll(spatialErrors); + errors.addAll(unsatisfiedDemands); + Collections.sort(errors); + return errors; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getSpatialErrors() + */ + public List getSpatialErrors() { + return spatialErrors; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getUnsatisfiedDemands() + */ + public List getUnsatisfiedDemands() { + return unsatisfiedDemands; + } + protected void initializeSimulation() { + events.clear(); + spatialErrors.clear(); + unsatisfiedDemands.clear(); + warnings.clear(); + scavengedParts.clear(); + repairedParts.clear(); + time = 0; + + // serialize scenario for deep cloning + clone = (Scenario)SerializeUtil.deepClone(scenario); + for(Mission m : clone.getMissionList()) { + MissionEvent p = new MissionEvent(); + p.setMission(m); + schedule(p); + } + + if(clone.getItemDiscretization()==ItemDiscretization.BY_ELEMENT) { + for(I_Element element : clone.getElements()) { + itemDemandsByElement.put(element, new HashMap()); + } + } else if(clone.getItemDiscretization()==ItemDiscretization.BY_LOCATION) { + for(Location location : clone.getNetwork().getLocations()) { + itemDemandsByLocation.put(location, new HashMap()); + } + } + } + protected void scheduleManifestEvents() { + for(ManifestEvent event : getScenario().getManifest().generateManifestEvents()) { + schedule(event); + } + } + protected void getNextEvent() { + event = getEvents().poll(); + duration = event.getTime() - getTime(); + time = event.getTime(); + } + protected void handleDemands() { + if(duration > 0) { + for(I_Element element : getScenario().getNetwork().getRegistrar().values()) { + DemandEvent d = new DemandEvent(); + d.setTime(time); + d.setName("Demand Event for " + element); + d.setElement(element); + d.setLocation(element.getLocation()); + d.setDemands(repairDemands(discretizeDemands(element.generateDemands(duration, this), element, element.getLocation()), element)); + if(d.getDemands().size()>0) { + try { + d.execute(this); + } catch(SimError error) { + if(error instanceof SimSpatialError) { + spatialErrors.add((SimSpatialError)error); + } else if(error instanceof SimDemand) { + /* TODO double-counting? see DemandEvent.execute + if(isPackingDemandsAdded()) { + Demand packingDemand = new Demand(new GenericResource(ClassOfSupply.COS5), 0); + for(Demand demand : ((SimDemand)error).getDemands()) { + if(demand.getAmount()>0 + && demand.getResource().getPackingFactor()>0) + packingDemand.setAmount(packingDemand.getAmount() + + demand.getAmount()*demand.getResource().getPackingFactor()); + } + ((SimDemand)error).getDemands().add(packingDemand); + } + */ + unsatisfiedDemands.add((SimDemand)error); + } + } + } + } + } + if(event instanceof MissionEvent) { + Mission mission = ((MissionEvent)event).getMission(); + + DemandEvent d = new DemandEvent(); + d.setTime(time + mission.getTransitDuration()); + d.setPriority(Integer.MAX_VALUE); + d.setName("Demand Event for " + mission); + d.setElement(null); + d.setLocation(mission.getDestination()); + d.setDemands(discretizeDemands(mission.generateDemands(this), null, mission.getDestination())); + schedule(d); + } + } + private DemandSet discretizeDemands(DemandSet demands, I_Element element, Location location) { + if(getScenario().getItemDiscretization()==ItemDiscretization.BY_ELEMENT + && element!=null) { + for(Demand demand : demands) { + if(demand.getResource() instanceof Item) { + Item item = (Item)demand.getResource(); + if(!itemDemandsByElement.get(element).containsKey(item)) { + itemDemandsByElement.get(element).put(item, new Double(0)); + } + itemDemandsByElement.get(element).put(item, + itemDemandsByElement.get(element).get(item) + demand.getAmount()); + demand.setAmount(0); + while(itemDemandsByElement.get(element).get(item) >= getScenario().getItemAggregation()) { + demand.setAmount(demand.getAmount() + 1); + itemDemandsByElement.get(element).put(item, + itemDemandsByElement.get(element).get(item) - 1); + } + } + } + } else if(getScenario().getItemDiscretization()==ItemDiscretization.BY_LOCATION) { + for(Demand demand : demands) { + if(demand.getResource() instanceof Item) { + Item item = (Item)demand.getResource(); + if(!itemDemandsByLocation.get(location).containsKey(item)) { + itemDemandsByLocation.get(location).put(item, new Double(0)); + } + itemDemandsByLocation.get(location).put(item, + itemDemandsByLocation.get(location).get(item) + demand.getAmount()); + demand.setAmount(0); + while(itemDemandsByLocation.get(location).get(item) >= getScenario().getItemAggregation()) { + demand.setAmount(demand.getAmount() + 1); + itemDemandsByLocation.get(location).put(item, + itemDemandsByLocation.get(location).get(item) - 1); + } + } + } + } else if(getScenario().getItemDiscretization()==ItemDiscretization.BY_SCENARIO) { + for(Demand demand : demands) { + if(demand.getResource() instanceof Item) { + Item item = (Item)demand.getResource(); + if(!itemDemandsByScenario.containsKey(item)) { + itemDemandsByScenario.put(item, new Double(0)); + } + itemDemandsByScenario.put(item, + itemDemandsByScenario.get(item) + demand.getAmount()); + demand.setAmount(0); + while(itemDemandsByScenario.get(item) >= getScenario().getItemAggregation()) { + demand.setAmount(demand.getAmount() + 1); + itemDemandsByScenario.put(item, + itemDemandsByScenario.get(item) - 1); + } + } + } + } + demands.clean(); + return demands; + } + private DemandSet repairDemands(DemandSet demands, I_Element element) { + if(itemsRepaired) { + double lastTime = 0; + for(Mission mission : getScenario().getMissionList()) { + if(getScenario().getRepairedItems().get(mission)!=null + && getTime() < mission.getDuration() + DateFunctions.getDaysBetween(mission.getStartDate(), getScenario().getStartDate()) + && getTime() >= lastTime) { + if(mission.isCrewed()) + lastTime = mission.getDuration() + DateFunctions.getDaysBetween(mission.getStartDate(), getScenario().getStartDate()); + + for(RepairItem item : getScenario().getRepairedItems().get(mission)) { + if(item.getElement().equals(element)) { + for(Demand demand : demands) { + if(item.getDemand().getResource().equals(demand.getResource()) + && item.getDemand().getResource() instanceof I_Item + && item.getDemand().getAmount() > 0) { + double amountRepaired = Math.min(demand.getAmount(), item.getDemand().getAmount()); + if(this instanceof FullSimulator) { + ((FullSimulator)this).getCrewTimeHistory().add( + new MoeCrewTime(DateFunctions.getDaysBetween(mission.getStartDate(), getScenario().getStartDate()), + element.getLocation(), + MoeCrewTime.CORRECTIVE_MAINTENANCE, + item.getUnitMeanRepairTime()*amountRepaired)); + ((FullSimulator)this).getCrewTimeHistory().add( + new MoeCrewTime(DateFunctions.getDaysBetween(mission.getStartDate(), getScenario().getStartDate()), + element.getLocation(), + MoeCrewTime.EXPLORATION, + -item.getUnitMeanRepairTime()*amountRepaired)); + } + getRepairedParts().add(new SimRepair(getTime(), + (I_Item)demand.getResource(), amountRepaired, + amountRepaired*item.getUnitMeanRepairTime(), + amountRepaired*item.getUnitMassToRepair(), + element.getLocation(), element)); + demand.setAmount(demand.getAmount() - amountRepaired); + demands.add(new Demand(new GenericResource(ClassOfSupply.COS4), item.getUnitMassToRepair()*amountRepaired)); + item.getDemand().setAmount(item.getDemand().getAmount() - amountRepaired); + } + } + } + } + } + } + } + demands.clean(); + return demands; + } + protected void executeEvent() { + try { + event.execute(this); + } catch(SimError error) { + if(error instanceof SimSpatialError) { + spatialErrors.add((SimSpatialError)error); + } else if(error instanceof SimDemand) { + unsatisfiedDemands.add((SimDemand)error); + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemandHistory(edu.mit.spacenet.domain.element.I_Element) + */ + public List getDemandHistory(I_Element element) { + ArrayList demands = new ArrayList(); + for(SimDemand d : getUnsatisfiedDemands()) { + if(element.equals(d.getElement())) { + demands.add(d); + } + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemandHistory(edu.mit.spacenet.scenario.Mission) + */ + public List getDemandHistory(Mission mission) { + ArrayList demands = new ArrayList(); + double startTime = DateFunctions.getDaysBetween(mission.getStartDate(), getScenario().getStartDate()); + double endTime = startTime + mission.getDuration(); + for(SimDemand s : getUnsatisfiedDemands()) { + if(s.getTime() > startTime && s.getTime() <= endTime) { + demands.add(s); + } + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemandHistory(edu.mit.spacenet.domain.network.Location) + */ + public List getDemandHistory(Location location) { + ArrayList demands = new ArrayList(); + for(SimDemand d : getUnsatisfiedDemands()) { + if(location.equals(d.getLocation())) { + demands.add(d); + } + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemands(edu.mit.spacenet.scenario.Mission) + */ + public DemandSet getDemands(Mission mission) { + DemandSet demands = new DemandSet(); + for(SimDemand s : getDemandHistory(mission)) { + demands.addAll(s.getDemands()); + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemands(edu.mit.spacenet.scenario.Mission, edu.mit.spacenet.domain.ClassOfSupply) + */ + public DemandSet getDemands(Mission mission, ClassOfSupply cos) { + DemandSet demands = new DemandSet(); + for(Demand demand : getDemands(mission)) { + if(demand.getResource().getClassOfSupply().equals(cos) + || demand.getResource().getClassOfSupply().isSubclassOf(cos)) { + demands.add(demand); + } + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemands(edu.mit.spacenet.scenario.Mission, edu.mit.spacenet.domain.element.I_Element) + */ + public DemandSet getDemands(Mission mission, I_Element element) { + DemandSet demands = new DemandSet(); + for(SimDemand s : getDemandHistory(mission)) { + if((element == null && s.getElement() == null) + || (s.getElement() != null && s.getElement().equals(element))) + demands.addAll(s.getDemands()); + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemands(edu.mit.spacenet.scenario.Mission, edu.mit.spacenet.domain.element.I_Element, edu.mit.spacenet.domain.ClassOfSupply) + */ + public DemandSet getDemands(Mission mission, I_Element element, ClassOfSupply cos) { + DemandSet demands = new DemandSet(); + for(Demand demand : getDemands(mission, element)) { + if(demand.getResource().getClassOfSupply().equals(cos) || + demand.getResource().getClassOfSupply().isSubclassOf(cos)) + demands.add(demand); + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemands(edu.mit.spacenet.domain.element.I_Element, edu.mit.spacenet.domain.ClassOfSupply) + */ + public DemandSet getDemands(I_Element element, ClassOfSupply cos) { + DemandSet demands = new DemandSet(); + for(SimDemand d : getUnsatisfiedDemands()) { + for(Demand demand : d.getDemands()) { + if(element.equals(d.getElement()) + && (demand.getResource().getClassOfSupply().equals(cos) + || demand.getResource().getClassOfSupply().isSubclassOf(cos))) { + demands.add(demand); + } + } + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getDemands(edu.mit.spacenet.domain.network.Location, edu.mit.spacenet.domain.ClassOfSupply) + */ + public DemandSet getDemands(Location location, ClassOfSupply cos) { + DemandSet demands = new DemandSet(); + for(SimDemand d : getUnsatisfiedDemands()) { + for(Demand demand : d.getDemands()) { + if(location.equals(d.getLocation()) + && (demand.getResource().getClassOfSupply().equals(cos) + || demand.getResource().getClassOfSupply().isSubclassOf(cos))) { + demands.add(demand); + } + } + } + return demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#isPackingDemandsAdded() + */ + public boolean isPackingDemandsAdded() { + return packingDemandsAdded; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#setPackingDemandsAdded(boolean) + */ + public void setPackingDemandsAdded(boolean packingDemandsAdded) { + this.packingDemandsAdded = packingDemandsAdded; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#isResourcesConsumed() + */ + public boolean isDemandsSatisfied() { + return demandsSatisfied; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#setResourcesConsumed(boolean) + */ + public void setDemandsSatisfied(boolean demandsSatisfied) { + this.demandsSatisfied = demandsSatisfied; + } + + /** + * Checks if is items repaired. + * + * @return true, if is items repaired + */ + public boolean isItemsRepaired() { + return itemsRepaired; + } + + /** + * Sets the items repaired. + * + * @param itemsRepaired the new items repaired + */ + public void setItemsRepaired(boolean itemsRepaired) { + this.itemsRepaired = itemsRepaired; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getScavengedParts() + */ + public List getScavengedParts() { + return scavengedParts; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#getRepairedParts() + */ + public List getRepairedParts() { + return repairedParts; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/DemandSimulator.java b/src/main/java/edu/mit/spacenet/simulator/DemandSimulator.java new file mode 100644 index 0000000..e98afef --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/DemandSimulator.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PartApplication; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.domain.resource.Item; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.RepairItem; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.scenario.SupplyEdge; +import edu.mit.spacenet.scenario.SupplyEdge.SupplyPoint; +import edu.mit.spacenet.simulator.event.I_Transport; +import edu.mit.spacenet.simulator.event.SurfaceTransport; +import edu.mit.spacenet.util.DateFunctions; +import edu.mit.spacenet.util.SerializeUtil; + +/** + * A simulator that logs detailed demand information. + * + * @author Paul Grogan + */ +public class DemandSimulator extends AbstractSimulator { + private Map> sortedRepairItems; + private Map> unsortedRepairItems; + + private SortedSet supplyEdges; + private SortedSet supplyPoints; + private SortedMap aggregatedNodeDemands; + private SortedMap aggregatedEdgeDemands; + + /** + * The constructor sets the scenario and initializes the data structures. + * + * @param scenario the scenario + */ + public DemandSimulator(Scenario scenario) { + super(scenario); + + sortedRepairItems = new HashMap>(); + unsortedRepairItems = new HashMap>(); + + supplyEdges = new TreeSet(); + supplyPoints = new TreeSet(); + aggregatedNodeDemands = new TreeMap(); + aggregatedEdgeDemands = new TreeMap(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#simulate() + */ + public void simulate() { + initializeSimulation(); + + sortedRepairItems.clear(); + unsortedRepairItems.clear(); + + for(Mission mission : getScenario().getMissionList()) { + sortedRepairItems.put(getScenario().getMissionList().indexOf(mission), new ArrayList()); + unsortedRepairItems.put(getScenario().getMissionList().indexOf(mission), new ArrayList()); + } + + supplyEdges.clear(); + supplyPoints.clear(); + aggregatedNodeDemands.clear(); + aggregatedEdgeDemands.clear(); + + // simulate events, serializing and saving after each time step + while(getEvents().peek() != null) { + getNextEvent(); + + // find supply edges and supply points + if(event instanceof I_Transport) { + HashSet carriers = new HashSet(); + for(I_Element element : ((I_Transport)event).getElements()) { + if(element instanceof I_Carrier) { + carriers.add((I_Carrier)SerializeUtil.deepClone(element)); + } + } + + boolean isReversed = false; + if(event instanceof SurfaceTransport) + isReversed = ((SurfaceTransport)event).isReversed(); + + SupplyEdge edge = new SupplyEdge(((I_Transport)event).getEdge(), + isReversed, + ((I_Transport)event).getTime(), + ((I_Transport)event).getTime() + ((I_Transport)event).getDuration(), + carriers); + supplyEdges.add(edge); + aggregatedEdgeDemands.put(edge, new DemandSet()); + supplyPoints.add(edge.getPoint()); + aggregatedNodeDemands.put(edge.getPoint(), new DemandSet()); + } + + handleDemands(); + + executeEvent(); + } + tabulateRepairableDemands(); + aggregateDemands(); + } + private void tabulateRepairableDemands() { + double lastEndTime = 0; + for(int index = 0; index < getScenario().getMissionList().size(); index++) { + Mission mission = getScenario().getMissionList().get(index); + if(mission.isCrewed()) { + double startTime = lastEndTime; + double endTime = DateFunctions.getDaysBetween(getScenario().getStartDate(), mission.getStartDate()) + mission.getDuration(); + lastEndTime = endTime; + + for(SimDemand simDemand : getUnsatisfiedDemands()) { + if(simDemand.getTime() > startTime + && simDemand.getTime() <= endTime + && simDemand.getElement() != null) { + for(Demand demand : simDemand.getDemands()) { + if(demand.getResource() instanceof Item) { + for(PartApplication app : simDemand.getElement().getParts()) { + if(app.getPart().equals(demand.getResource()) + && app.getMeanTimeToRepair() > 0) { + RepairItem i = new RepairItem(demand, simDemand.getElement()); + sortedRepairItems.get(index).add(i); + break; + } + } + } + } + } + } + + for(RepairItem i : sortedRepairItems.get(index)) { + unsortedRepairItems.get(index).add(i); + } + + Collections.sort(sortedRepairItems.get(index)); + } + } + } + private void aggregateDemands() { + for(SimDemand demand : getUnsatisfiedDemands()) { + if(demand.getLocation() instanceof Node) { + SupplyPoint point = null; + for(SupplyPoint p : supplyPoints) { + if(p.getNode().equals(demand.getLocation()) + && p.getTime() <= demand.getTime() + && (point==null || p.getTime() > point.getTime())) { + point = p; + } + } + if(point==null + && demand.getLocation() instanceof SurfaceNode + && ((SurfaceNode)demand.getLocation()).getBody()==Body.EARTH) { + // ignore demands at earth surface nodes + } else if(point==null) { + System.out.println("No supply point found to satisfy demands! " + demand.getTime() + " " + demand.getDemands()); + } else { + aggregatedNodeDemands.get(point).addAll(demand.getDemands()); + } + } else if(demand.getLocation() instanceof Edge) { + SupplyEdge edge = null; + for(SupplyEdge e : supplyEdges) { + if(e.getEdge().equals((demand.getLocation())) + && demand.getTime() >= e.getStartTime() + && demand.getTime() <= e.getEndTime()) { + edge = e; + } + } + if(edge==null) { + System.out.println("No supply edge found to satisfy demands! " + demand.getTime() + " " + demand.getDemands()); + } else { + aggregatedEdgeDemands.get(edge).addAll(demand.getDemands()); + } + } + } + } + + /** + * Gets the repairable items, unsorted (in order of occurrence in simulation). + * + * @return the set of repairable items + */ + public Map> getUnsortedRepairItems() { + return unsortedRepairItems; + } + + /** + * Gets the repairable items, sorted by decreasing value. + * + * @return the set of repairable items + */ + public Map> getSortedRepairItems() { + return sortedRepairItems; + } + + /** + * Gets the set of supply edges. + * + * @return the set supply edges + */ + public SortedSet getSupplyEdges() { + return supplyEdges; + } + + /** + * Gets the set of supply points. + * + * @return the set of supply points + */ + public SortedSet getSupplyPoints() { + return supplyPoints; + } + + /** + * Gets the demands aggregated to supply points (nodes). + * + * @return the aggregated set of demands + */ + public SortedMap getAggregatedNodeDemands() { + return aggregatedNodeDemands; + } + + /** + * Gets the demands aggregated to supply edges (edges). + * + * @return the aggregated set of demands + */ + public SortedMap getAggregatedEdgeDemands() { + return aggregatedEdgeDemands; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/FullSimulator.java b/src/main/java/edu/mit/spacenet/simulator/FullSimulator.java new file mode 100644 index 0000000..0af0ba6 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/FullSimulator.java @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import java.util.ArrayList; +import java.util.List; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.Body; +import edu.mit.spacenet.domain.network.node.OrbitalNode; +import edu.mit.spacenet.domain.network.node.SurfaceNode; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.event.FlightTransport; +import edu.mit.spacenet.simulator.event.I_Transport; +import edu.mit.spacenet.simulator.event.SpaceTransport; +import edu.mit.spacenet.simulator.moe.MoeCrewSurfaceDays; +import edu.mit.spacenet.simulator.moe.MoeCrewTime; +import edu.mit.spacenet.simulator.moe.MoeExplorationCapability; +import edu.mit.spacenet.simulator.moe.MoeExplorationMassDelivered; +import edu.mit.spacenet.simulator.moe.MoeLaunchMass; +import edu.mit.spacenet.simulator.moe.MoeMassCapacityUtilization; +import edu.mit.spacenet.util.SerializeUtil; + +/** + * A simulator that logs and generates measures of effectiveness. + * + * @author Paul Grogan + */ +public class FullSimulator extends AbstractSimulator { + private List networkHistory; + private List crewSurfaceDaysHistory; + private List crewTimeHistory; + private List explorationMassDeliveredHistory; + private List launchMassHistory; + private List upMassCapacityUtilizationHistory, downMassCapacityUtilizationHistory; + private List explorationCapabilityHistory; + + /** + * Instantiates a new full simulator. + * + * @param scenario the scenario + */ + public FullSimulator(Scenario scenario) { + super(scenario); + setPackingDemandsAdded(false); + setItemsRepaired(true); + networkHistory = new ArrayList(); + crewSurfaceDaysHistory = new ArrayList(); + crewTimeHistory = new ArrayList(); + explorationMassDeliveredHistory = new ArrayList(); + launchMassHistory = new ArrayList(); + upMassCapacityUtilizationHistory = new ArrayList(); + downMassCapacityUtilizationHistory = new ArrayList(); + explorationCapabilityHistory = new ArrayList(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#simulate() + */ + public void simulate() { + initializeSimulation(); + networkHistory.clear(); + crewSurfaceDaysHistory.clear(); + crewTimeHistory.clear(); + explorationMassDeliveredHistory.clear(); + launchMassHistory.clear(); + upMassCapacityUtilizationHistory.clear(); + downMassCapacityUtilizationHistory.clear(); + explorationCapabilityHistory.clear(); + + scheduleManifestEvents(); + + // save initial conditions + networkHistory.add(new SimNetwork(getTime(), (Network)SerializeUtil.deepClone(getScenario().getNetwork()))); + + // simulate events, serializing and saving after each time step + while(getEvents().peek() != null) { + getNextEvent(); + + // tabulate MOEs + if(duration > 0) { + for(I_Element element : getScenario().getNetwork().getRegistrar().values()) { + if(element instanceof CrewMember) { + crewTimeHistory.add(new MoeCrewTime( + getTime(), + element.getLocation(), + MoeCrewTime.EXPLORATION, + duration*24*((CrewMember)element).getAvailableTimeFraction())); + crewTimeHistory.add(new MoeCrewTime( + getTime(), + element.getLocation(), + MoeCrewTime.UNAVAILABLE, + duration*24*(1-((CrewMember)element).getAvailableTimeFraction()))); + // if element location is a non-Earth surface node + // OR a sun-orbiting node + // OR a non-Earth surface edge + if(((element.getLocation() instanceof SurfaceNode + && !((SurfaceNode)element.getLocation()).getBody().equals(Body.EARTH))) + || (element.getLocation() instanceof OrbitalNode + && (((OrbitalNode)element.getLocation()).getBody().equals(Body.SUN))) + || (element.getLocation() instanceof SurfaceEdge + && !((SurfaceEdge)element.getLocation()).getOrigin().getBody().equals(Body.EARTH))) { + crewSurfaceDaysHistory.add(new MoeCrewSurfaceDays( + getTime(), + element.getLocation(), + duration)); + explorationCapabilityHistory.add(new MoeExplorationCapability( + getTime(), + element.getLocation(), + element.getLocation().getTotalMass(ClassOfSupply.COS6, this)+element.getLocation().getTotalMass(ClassOfSupply.COS8, this), + duration)); + } + } + } + } + // if event is a space transport OR flight transport + // AND either the destination is a non-Earth surface node + // OR the destination is a sun-orbiting node + if((event instanceof SpaceTransport || event instanceof FlightTransport) + && ((((I_Transport)event).getDestination() instanceof SurfaceNode + && !((I_Transport)event).getDestination().getBody().equals(Body.EARTH)) + || (((I_Transport)event).getDestination() instanceof OrbitalNode + && (((OrbitalNode)((I_Transport)event).getDestination()).getBody().equals(Body.SUN))))) { + double amount = 0; + for(I_Element element : ((I_Transport)event).getElements()) { + amount+=element.getTotalMass(ClassOfSupply.COS6); + amount+=element.getTotalMass(ClassOfSupply.COS8); + } + explorationMassDeliveredHistory.add(new MoeExplorationMassDelivered( + getTime()+((I_Transport)event).getDuration(), + ((I_Transport)event).getDestination(), + amount)); + } + // if event is a space transport OR flight transport + // AND origin is an Earth surface node + if((event instanceof SpaceTransport || event instanceof FlightTransport) + && ((I_Transport)event).getOrigin() instanceof SurfaceNode + && ((I_Transport)event).getOrigin().getBody().equals(Body.EARTH)) { + double mass = 0; + for(I_Element element : ((I_Transport)event).getElements()) { + mass+= element.getTotalMass(); + } + launchMassHistory.add(new MoeLaunchMass( + getTime(), + ((I_Transport)event).getOrigin(), + mass)); + + double capacity = 0; + if(event instanceof FlightTransport) { + capacity = ((FlightTransport)event).getEdge().getMaxCargoMass(); + } else { + for(I_Element element : ((I_Transport)event).getElements()) { + if(element instanceof I_Carrier) { + capacity += ((I_Carrier)element).getMaxCargoMass(); + } + } + } + double amount = 0; + for(I_Element element : ((I_Transport)event).getElements()) { + if(element instanceof I_Carrier) { + amount += ((I_Carrier)element).getCargoMass(); + } + } + upMassCapacityUtilizationHistory.add(new MoeMassCapacityUtilization( + getTime(), + ((I_Transport)event).getOrigin(), + amount, + capacity)); + // else if event is a space transport OR flight transport + // AND destination is an Earth surface node + } else if((event instanceof SpaceTransport || event instanceof FlightTransport) + && ((I_Transport)event).getDestination() instanceof SurfaceNode + && ((I_Transport)event).getDestination().getBody().equals(Body.EARTH)) { + double capacity = 0; + if(event instanceof FlightTransport) { + capacity = ((FlightTransport)event).getEdge().getMaxCargoMass(); + } else { + for(I_Element element : ((I_Transport)event).getElements()) { + if(element instanceof I_Carrier) { + capacity += ((I_Carrier)element).getMaxCargoMass(); + } + } + } + double amount = 0; + for(I_Element element : ((I_Transport)event).getElements()) { + if(element instanceof I_Carrier) { + amount += ((I_Carrier)element).getCargoMass(); + } + } + downMassCapacityUtilizationHistory.add(new MoeMassCapacityUtilization( + getTime(), + ((I_Transport)event).getDestination(), + amount, + capacity)); + } + + handleDemands(); + + executeEvent(); + + if(getEvents().peek()==null||getEvents().peek().getTime() > getTime()) + networkHistory.add(new SimNetwork(getTime(), (Network)SerializeUtil.deepClone(getScenario().getNetwork()))); + } + } + + /** + * Gets the network history. + * + * @return the network history + */ + public List getNetworkHistory() { + return networkHistory; + } + + /** + * Gets the crew surface days history. + * + * @return the crew surface days history + */ + public List getCrewSurfaceDaysHistory() { + return crewSurfaceDaysHistory; + } + + /** + * Gets the crew time history. + * + * @return the crew time history + */ + public List getCrewTimeHistory() { + return crewTimeHistory; + } + + /** + * Gets the exploration mass delivered history. + * + * @return the exploration mass delivered history + */ + public List getExplorationMassDeliveredHistory() { + return explorationMassDeliveredHistory; + } + + /** + * Gets the launch mass history. + * + * @return the launch mass history + */ + public List getLaunchMassHistory() { + return launchMassHistory; + } + + /** + * Gets the up mass capacity utilization history. + * + * @return the up mass capacity utilization history + */ + public List getUpMassCapacityUtilizationHistory() { + return upMassCapacityUtilizationHistory; + } + + /** + * Gets the down mass capacity utilization history. + * + * @return the down mass capacity utilization history + */ + public List getDownMassCapacityUtilizationHistory() { + return downMassCapacityUtilizationHistory; + } + + /** + * Gets the exploration capability history. + * + * @return the exploration capability history + */ + public List getExplorationCapabilityHistory() { + return explorationCapabilityHistory; + } + + /** + * Gets the total crew surface days. + * + * @return the total crew surface days + */ + public double getTotalCrewSurfaceDays() { + double amount = 0; + for(MoeCrewSurfaceDays moe : crewSurfaceDaysHistory) { + amount += moe.getAmount(); + } + return amount; + } + + /** + * Gets the total crew time. + * + * @return the total crew time + */ + public double getTotalCrewTime() { + double amount = 0; + for(MoeCrewTime moe : crewTimeHistory) { + amount += moe.getAmount(); + } + return amount; + } + + /** + * Gets the total exploration capability. + * + * @return the total exploration capability + */ + public double getTotalExplorationCapability() { + double amount = 0; + for(MoeExplorationCapability moe : explorationCapabilityHistory) { + amount += moe.getDuration()*moe.getMass(); + } + return amount; + } + + /** + * Gets the total exploration mass delivered. + * + * @return the total exploration mass delivered + */ + public double getTotalExplorationMassDelivered() { + double amount = 0; + for(MoeExplorationMassDelivered moe : explorationMassDeliveredHistory) { + amount += moe.getAmount(); + } + return amount; + } + + /** + * Gets the total launch mass. + * + * @return the total launch mass + */ + public double getTotalLaunchMass() { + double amount = 0; + for(MoeLaunchMass moe : launchMassHistory) { + amount += moe.getAmount(); + } + return amount; + } + + /** + * Gets the total up mass capacity utilization. + * + * @return the total up mass capacity utilization + */ + public double getTotalUpMassCapacityUtilization() { + double amount = 0; + double capacity = 0; + for(MoeMassCapacityUtilization moe : upMassCapacityUtilizationHistory) { + amount += moe.getAmount(); + capacity += moe.getCapacity(); + } + return amount/capacity; + } + + /** + * Gets the total down mass capacity utilization. + * + * @return the total down mass capacity utilization + */ + public double getTotalDownMassCapacityUtilization() { + double amount = 0; + double capacity = 0; + for(MoeMassCapacityUtilization moe : downMassCapacityUtilizationHistory) { + amount += moe.getAmount(); + capacity += moe.getCapacity(); + } + return amount/capacity; + } + + /** The Constant APOLLO_17_EXPLORATION_CAPABILITY. */ + public static final double APOLLO_17_EXPLORATION_CAPABILITY = 2594; + + /** The Constant APOLLO_17_LAUNCH_MASS. */ + public static final double APOLLO_17_LAUNCH_MASS = 2930000; + + /** + * Gets the total relative exploration capability. + * + * @return the total relative exploration capability + */ + public double getTotalRelativeExplorationCapability() { + return (getTotalExplorationCapability()/APOLLO_17_EXPLORATION_CAPABILITY)/(getTotalLaunchMass()/APOLLO_17_LAUNCH_MASS); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/I_Simulator.java b/src/main/java/edu/mit/spacenet/simulator/I_Simulator.java new file mode 100644 index 0000000..bdfa99a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/I_Simulator.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import java.util.List; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.event.I_Event; + +/** + * Interface for a simulator that executes events and updates a network of + * objects. + * + * @author Paul Grogan + */ +public interface I_Simulator { + + /** + * Runs the simulation. + */ + public void simulate(); + + /** + * Gets the current simulation time. + * + * @return the current simulation time (days) + */ + public double getTime(); + + /** + * Schedules an event. + * + * @param event the event + */ + public void schedule(I_Event event); + + /** + * Gets a list of warnings generated during simulation. + * + * @return the list of warnings + */ + public List getWarnings(); + + /** + * Gets a list of errors generated during simulation. + * + * @return the list of errors + */ + public List getErrors(); + + /** + * Gets a list of spatial errors generated during simulation. + * + * @return a list of errors. + */ + public List getSpatialErrors(); + + /** + * Gets a list of demand errors generated during simulation. + * + * @return a list of errors. + */ + public List getUnsatisfiedDemands(); + + /** + * Gets a list of the scavenging operations. + * + * @return the list of scavenging operations + */ + public List getScavengedParts(); + + /** + * Gets a list of the repairing operations. + * + * @return the list of the repairing operations + */ + public List getRepairedParts(); + + /** + * Gets the demand history for an element. + * + * @param element the element + * + * @return the demand history + */ + public List getDemandHistory(I_Element element); + + /** + * Gets the demand history for a mission. + * + * @param mission the mission + * + * @return the demand history + */ + public List getDemandHistory(Mission mission); + + /** + * Gets the demand history at a location. + * + * @param location the location + * + * @return the demand history + */ + public List getDemandHistory(Location location); + + /** + * Gets the aggregated set of demands associated with a mission. + * + * @param mission the mission + * + * @return the set of demands + */ + public DemandSet getDemands(Mission mission); + + /** + * Gets the aggregated set of demands associated with a mission, filtered + * by a class of supply. + * + * @param mission the mission + * @param cos the class of supply + * + * @return the set of demands + */ + public DemandSet getDemands(Mission mission, ClassOfSupply cos); + + /** + * Gets the aggregated set of demands associated with an element during a + * mission. + * + * @param mission the mission + * @param element the element + * + * @return the set of demands + */ + public DemandSet getDemands(Mission mission, I_Element element); + + /** + * Gets the aggregated set of demands associated with an element during a + * mission, filtered by a class of supply. + * + * @param mission the mission + * @param element the element + * @param cos the class of supply + * + * @return the set of demands + */ + public DemandSet getDemands(Mission mission, I_Element element, ClassOfSupply cos); + + /** + * Gets the aggregated set of demands associated with an element, filtered + * by a class of supply. + * + * @param element the element + * @param cos the class of supply + * + * @return the set of demands + */ + public DemandSet getDemands(I_Element element, ClassOfSupply cos); + + /** + * Gets the aggregated set of demands from a location, filtered by a class + * of supply. + * + * @param location the location + * @param cos the class of supply + * + * @return the set of demands + */ + public DemandSet getDemands(Location location, ClassOfSupply cos); + + /** + * Gets the scenario being simulated. + * + * @return the scenario + */ + public Scenario getScenario(); + + /** + * Gets whether estimated packing demands are added to the demands. + * + * @return whether estimated packing demands are included + */ + public boolean isPackingDemandsAdded(); + + /** + * Sets whether estimated packing demands are added to the demands. + * + * @param packingDemandsAdded whether estimated packing demands are included + */ + public void setPackingDemandsAdded(boolean packingDemandsAdded); + + /** + * Checks if is resources consumed. + * + * @return true, if is resources consumed + */ + public boolean isDemandsSatisfied(); + + /** + * Sets the resources consumed. + * + * @param demandsSatisfied the new resources consumed + */ + public void setDemandsSatisfied(boolean demandsSatisfied); +} diff --git a/src/main/java/edu/mit/spacenet/simulator/MiniSimulator.java b/src/main/java/edu/mit/spacenet/simulator/MiniSimulator.java new file mode 100644 index 0000000..1adf111 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/MiniSimulator.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import java.util.ArrayList; +import java.util.List; + +import edu.mit.spacenet.scenario.Scenario; + +/** + * A simulator that logs an element history. + * + * @author Paul Grogan + */ +public class MiniSimulator extends AbstractSimulator { + private List locationHistory; + + /** + * The constructor sets the scenario and initializes the location history. + * + * @param scenario the scenario + */ + public MiniSimulator(Scenario scenario) { + super(scenario); + locationHistory = new ArrayList(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#simulate() + */ + public void simulate() { + initializeSimulation(); + locationHistory.clear(); + + // simulate events, serializing and saving after each time step + while(getEvents().peek() != null) { + getNextEvent(); + + locationHistory.add(new SimState(getTime(), getScenario().getNetwork())); + handleDemands(); //TODO 7/12/2010: added demand cycle in for pre-manifested resources (delta-v feasibility en route) + executeEvent(); + locationHistory.add(new SimState(getTime(), getScenario().getNetwork())); + } + } + + /** + * Gets a list of states representing the location history during the + * simulation. + * + * @return the list of states + */ + public List getLocationHistory() { + return locationHistory; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/PreSimulator.java b/src/main/java/edu/mit/spacenet/simulator/PreSimulator.java new file mode 100644 index 0000000..1204a27 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/PreSimulator.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import edu.mit.spacenet.scenario.Scenario; +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.simulator.event.MissionEvent; + +/** + * A fast simulator that does not log any information. + * + * @author Paul Grogan + */ +public class PreSimulator extends AbstractSimulator { + + /** + * The constructor sets the scenario. + * + * @param scenario the scenario + */ + public PreSimulator(Scenario scenario) { + super(scenario); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.simulator.I_Simulator#simulate() + */ + public void simulate() { + simulate(Double.MAX_VALUE, Integer.MAX_VALUE); + } + + /** + * Simulates up to, but not including, an event. + * + * @param event the event + */ + public void simulate(I_Event event) { + simulate(event.getTime(), event.getPriority()); + } + + /** + * Simulates events up to, but not including, an event with an option to + * initialize before simulation. + * + * @param event the event + * @param reset whether to initialize before simulation + */ + public void simulate(I_Event event, boolean reset) { + simulate(event.getTime(), event.getPriority(), reset); + } + + /** + * Simulates events up to, but not including, a simulation time. + * + * @param time the time + */ + public void simulate(double time) { + simulate(time, Integer.MAX_VALUE); + } + + /** + * Simulates events up to a time and priority. + * + * @param time the time + * @param priority the priority + */ + public void simulate(double time, int priority) { + simulate(time, priority, true); + } + + /** + * Simulates events up to a time and priority with an option to initialize + * before simulation. + * + * @param time the time + * @param priority the priority + * @param reset whether to initialize before simulation + */ + public void simulate(double time, int priority, boolean reset) { + if(getScenario() == null || reset) { + initializeSimulation(); + } + // simulate events up to target event + while(getEvents().peek() != null + && getEvents().peek().getTime() <= time + && ((!(getEvents().peek() instanceof MissionEvent) + && getEvents().peek().getTime()==time)?getEvents().peek().getPriority() < priority:true)) { + getNextEvent(); + handleDemands(); // 7/12/2010: added demand cycle in pre-sim for pre-manifested resources (delta-v feasibility en route) + executeEvent(); + } + // 7-28-2011: added one last demands cycle to trigger demands before + // prospective event (e.g. resource transfer) + this.duration = time - getTime(); + setTime(time); + handleDemands(); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/SimDemand.java b/src/main/java/edu/mit/spacenet/simulator/SimDemand.java new file mode 100644 index 0000000..767712e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/SimDemand.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.event.I_Event; + +/** + * Represents a demand for resources that has not been satisfied in the demand + * cycle that has been logged during the simulation. + * + * @author Paul Grogan + */ +public class SimDemand extends SimError { + private static final long serialVersionUID = 8446495287458296511L; + private Location location; + private I_Element element; + private DemandSet demands; + + /** + * Instantiates a new sim demand. + * + * @param time the time of the demand + * @param event the event being executed when the demand occurs + * @param location the location of the demand + * @param element the element requesting the demand + * @param demands the set of demands + */ + public SimDemand(double time, I_Event event, Location location, I_Element element, DemandSet demands) { + super(time, event, "Insufficient resources for demand: " + demands); + this.location = location; + this.element = element; + demands.clean(); + setMessage("Insufficient resources for demand: " + demands); + this.demands = demands; + } + + /** + * Gets the location of the demand. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the element generating the demand, null if not associated with an + * element (e.g. a mission-level demand). + * + * @return the element + */ + public I_Element getElement() { + return element; + } + + /** + * Gets the set of demands. + * + * @return the set of demands + */ + public DemandSet getDemands() { + return demands; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/SimError.java b/src/main/java/edu/mit/spacenet/simulator/SimError.java new file mode 100644 index 0000000..3efdcc1 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/SimError.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Represents an abstracted error that occurs during simulation. + * + * @author Paul Grogan + */ +public abstract class SimError extends Exception implements Comparable { + private static final long serialVersionUID = -3741803666732501991L; + private double time; + private I_Event event; + private String message; + + /** + * Instantiates a new sim error. + * + * @param time the simulation time of the error + * @param event the event being executed when the error occurs + * @param message a message associated with the error + */ + public SimError(double time, I_Event event, String message) { + this.time = time; + this.event = event; + this.message = message; + } + + /** + * Gets the simulation time of the error. + * + * @return the simulation time + */ + public double getTime() { + return GlobalParameters.getRoundedTime(time); + } + + /** + * Gets the event that was being executed when the error occurred. + * + * @return the event + */ + public I_Event getEvent() { + return event; + } + + /* (non-Javadoc) + * @see java.lang.Throwable#getMessage() + */ + public String getMessage() { + return message; + } + + /** + * Sets the warning message. + * + * @param message the message + */ + public void setMessage(String message) { + this.message = message; + } + + /* (non-Javadoc) + * @see java.lang.Throwable#toString() + */ + public String toString() { + return event + " " + message; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(SimError error) { + return Double.compare(getTime(), error==null?0:error.getTime()); + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/SimNetwork.java b/src/main/java/edu/mit/spacenet/simulator/SimNetwork.java new file mode 100644 index 0000000..f8345fd --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/SimNetwork.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A log of the scenario network at a particular time. + * + * @author Paul Grogan + */ +public class SimNetwork implements Comparable { + private double time; + private Network network; + + /** + * Instantiates a new sim network. + * + * @param time the simulation time + * @param network the scenario network + */ + public SimNetwork(double time, Network network) { + this.time = time; + this.network = network; + } + + /** + * Gets the simulation time of the log. + * + * @return the simulation time + */ + public double getTime() { + return GlobalParameters.getRoundedTime(time); + } + + /** + * Gets the scenario network. + * + * @return the network + */ + public Network getNetwork() { + return network; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(SimNetwork network) { + return Double.compare(getTime(), network==null?0:network.getTime()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/SimRepair.java b/src/main/java/edu/mit/spacenet/simulator/SimRepair.java new file mode 100644 index 0000000..fd9070a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/SimRepair.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Logs a repair activity. + * + * @author Paul Grogan + */ +public class SimRepair { + private double time; + private I_Item item; + private double amount; + private double repairTime; + private double repairMass; + private Location location; + private I_Element element; + + /** + * Instantiates a new sim repair. + * + * @param time the simulation time of the repair + * @param item the item that was repaired + * @param amount the amount of the item that was repaired + * @param repairTime the crew time required for the repair + * @param repairMass the mass required for the repair + * @param location the location of the repair + * @param element the element being repaired + */ + public SimRepair(double time, I_Item item, double amount, double repairTime, + double repairMass, Location location, I_Element element) { + this.time = time; + this.item = item; + this.amount = amount; + this.repairTime = repairTime; + this.repairMass = repairMass; + this.location = location; + this.element = element; + } + + /** + * Gets the simulation time of the repair. + * + * @return the simulation time + */ + public double getTime() { + return GlobalParameters.getRoundedTime(time); + } + + /** + * Gets the item that was repaired. + * + * @return the item + */ + public I_Item getItem() { + return item; + } + + /** + * Gets the amount of the item that was repaired. + * + * @return the amount + */ + public double getAmount() { + return GlobalParameters.getRoundedDemand(amount); + } + + /** + * Gets the time required for the repair. + * + * @return the time + */ + public double getRepairTime() { + return repairTime; + } + + /** + * Gets the mass required for the repair. + * + * @return the mass + */ + public double getRepairMass() { + return repairMass; + } + + /** + * Gets the location of the repair. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the element that was repaired. + * + * @return the element + */ + public I_Element getElement() { + return element; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/SimScavenge.java b/src/main/java/edu/mit/spacenet/simulator/SimScavenge.java new file mode 100644 index 0000000..d4e600e --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/SimScavenge.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.resource.I_Item; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * A scavenging operation. + * + * @author Paul Grogan + */ +public class SimScavenge { + private double time; + private I_Item item; + private double amount; + private Location location; + private I_Element element; + + /** + * Instantiates a new sim scavenge. + * + * @param time the simulation time of the scavenging + * @param item the item that was scavenged + * @param amount the amount of item that was scavenged + * @param location the location of the scavenging + * @param element the element that received the scavenged part + */ + public SimScavenge(double time, I_Item item, double amount, Location location, + I_Element element) { + this.time = time; + this.item = item; + this.amount = amount; + this.location = location; + this.element = element; + } + + /** + * Gets the simulation time of the scavenging operation. + * + * @return the simulation time + */ + public double getTime() { + return GlobalParameters.getRoundedTime(time); + } + + /** + * Gets the item that was scavenged. + * + * @return the item + */ + public I_Item getItem() { + return item; + } + + /** + * Gets the amount of the item that was scavenged. + * + * @return the amount + */ + public double getAmount() { + return GlobalParameters.getRoundedDemand(amount); + } + + /** + * Gets the location of the scavenging. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the element that received the scavenged part. + * + * @return the element + */ + public I_Element getElement() { + return element; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/SimSpatialError.java b/src/main/java/edu/mit/spacenet/simulator/SimSpatialError.java new file mode 100644 index 0000000..b2a3d53 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/SimSpatialError.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import edu.mit.spacenet.simulator.event.I_Event; + +/** + * Represents an error when an element is not in the right place at the right + * time. + * + * @author Paul Grogan + */ +public class SimSpatialError extends SimError { + private static final long serialVersionUID = -4013581934283397903L; + + /** + * Instantiates a new sim spatial error. + * + * @param time the simulation time of the error + * @param event the event that was being executed at the time of the error + * @param message the error message + */ + public SimSpatialError(double time, I_Event event, String message) { + super(time, event, message); + System.out.println("!!! Error: (" + event + ") " + message); + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/SimState.java b/src/main/java/edu/mit/spacenet/simulator/SimState.java new file mode 100644 index 0000000..ff1aaec --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/SimState.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.domain.network.Network; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Logs the state of the network at a simulation time. + * + * @author Paul Grogan + */ +public class SimState implements Comparable { + private double time; + private SortedMap locationMap; + + /** + * Instantiates a new sim state. + * + * @param time the simulation time + * @param network the scenario network + */ + public SimState(double time, Network network) { + this.time = time; + locationMap = new TreeMap(); + for(I_Element element : network.getRegistrar().values()) { + locationMap.put(element, element.getContainer()); + } + } + + /** + * Gets the simulation time of the log. + * + * @return the simulation time + */ + public double getTime() { + return GlobalParameters.getRoundedTime(time); + } + + /** + * Gets the container for an element. + * + * @param element the element + * + * @return the element's container + */ + public I_Container getContainer(I_Element element) { + return locationMap.get(element); + } + + /** + * Gets the location of an element. + * + * @param element the element + * + * @return the element's location + */ + public Location getLocation(I_Element element) { + if(locationMap.get(element) instanceof Location) + return (Location)locationMap.get(element); + else if(locationMap.get(element) instanceof I_Carrier) + return getLocation((I_Carrier)locationMap.get(element)); + else return null; + } + + /** + * Gets the set of elements in the log. + * + * @return the set of elements + */ + public Set getElements() { + return locationMap.keySet(); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(SimState state) { + return Double.compare(getTime(), state==null?0:state.getTime()); + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/SimWarning.java b/src/main/java/edu/mit/spacenet/simulator/SimWarning.java new file mode 100644 index 0000000..fdbb648 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/SimWarning.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator; + +import edu.mit.spacenet.simulator.event.I_Event; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Represents a warning message that occurs during simulation. + * + * @author Paul Grogan + */ +public class SimWarning extends Exception implements Comparable { + private static final long serialVersionUID = -4715307155933350996L; + private double time; + private I_Event event; + private String message; + + /** + * Instantiates a new sim warning. + * + * @param time the simulation time of the warning + * @param event the event being executed when the warning occurred + * @param message the warning message + */ + public SimWarning(double time, I_Event event, String message) { + this.time = time; + this.event = event; + this.message = message; + System.out.println("!!! Warning: (" + event + ") " + message); + } + + /** + * Gets the simulation time of the warning. + * + * @return the simulation time + */ + public double getTime() { + return GlobalParameters.getRoundedTime(time); + } + + /** + * Gets the event that was being executed when the warning occurred. + * + * @return the event + */ + public I_Event getEvent() { + return event; + } + + /* (non-Javadoc) + * @see java.lang.Throwable#getMessage() + */ + public String getMessage() { + return message; + } + + /** + * Sets the warning message. + * + * @param message the message + */ + public void setMessage(String message) { + this.message = message; + } + + /* (non-Javadoc) + * @see java.lang.Throwable#toString() + */ + public String toString() { + return event + " " + message; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(SimWarning warning) { + return Double.compare(getTime(), warning==null?0:warning.getTime()); + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/AbstractEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/AbstractEvent.java new file mode 100644 index 0000000..36d7a38 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/AbstractEvent.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * Base class for all events. + * + * @author Paul Grogan + */ +public abstract class AbstractEvent implements I_Event { + private long uid; + private String name; + private double time; + private int priority; + private Location location; + private I_Event parent; + + /** + * The default constructor sets the priority to a default value in the + * middle of the priority levels and sets a generic name. + */ + public AbstractEvent() { + uid = (long)(Long.MAX_VALUE*Math.random()); + priority = 0; + name = getEventType()==null?"":getEventType().getName(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getLocation() + */ + public Location getLocation() { + return location; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#setLocation(edu.mit.spacenet.domain.network.Location) + */ + public void setLocation(Location location) { + this.location = location; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getName() + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#setName(java.lang.String) + */ + public void setName(String name) { + this.name = name; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getTime() + */ + public double getTime() { + return GlobalParameters.getRoundedTime(time); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#setTime(double) + */ + public void setTime(double time) { + this.time = time; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getPriority() + */ + public int getPriority() { + return priority; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#setPriority(int) + */ + public void setPriority(int priority) { + this.priority = priority; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getParent() + */ + public I_Event getParent() { + return parent; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getRoot() + */ + public I_Event getRoot() { + if(getParent()==null) return this; + else return getParent().getRoot(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#setParent(edu.mit.spacenet.domain.event.I_Event) + */ + public void setParent(I_Event parent) { + this.parent = parent; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#compareTo(edu.mit.spacenet.domain.event.I_Event) + */ + public int compareTo(I_Event e) { + if(getTime() < e.getTime()) { + return -1; + } else if(getTime() > e.getTime()) { + return 1; + } else if(getPriority() > e.getPriority()) { + return 1; + } else if(getPriority() < e.getPriority()) { + return -1; + } else { + return getName().compareTo(e.getName()); + } + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return getName(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#print() + */ + public void print() { + print(0); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#print(int) + */ + public void print(int tabOrder) { + String s = ""; + for(int i=0; i. + */ +package edu.mit.spacenet.simulator.event; + +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * An event that adds resources to a resource container. + * @author Paul Grogan + */ +public class AddEvent extends AbstractEvent { + private DemandSet demands; + private I_ResourceContainer container; + + /** + * Instantiates a new adds the event. + */ + public AddEvent() { + super(); + this.demands = new DemandSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(container.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + container + " was not found."); + } else if(!container.getLocation().equals(getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + container + " is located at " + container.getLocation() + + " instead of " + getLocation() + "."); + } + if(demands.size() == 0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No demands defined.")); + } else { + System.out.printf("%.3f: %s\n", + getTime(), "Adding " + demands + " to " + container); + for(Demand demand : demands) { + if(container.add(demand.getResource(), demand.getAmount())) { + // success + } else { + throw new SimSpatialError(simulator.getTime(), this, + demand + " could not be added to " + container + "."); + } + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + System.out.println("Add Event for " + demands + " -> " + container); + } + + /** + * Gets the demands. + * + * @return the demands + */ + public DemandSet getDemands() { + return demands; + } + + /** + * Sets the demands. + * + * @param demands the new demands + */ + public void setDemands(DemandSet demands) { + this.demands = demands; + } + + /** + * Gets the container. + * + * @return the container + */ + public I_ResourceContainer getContainer() { + return container; + } + + /** + * Sets the container. + * + * @param container the new container + */ + public void setContainer(I_ResourceContainer container) { + this.container = container; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.ADD; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/BurnEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/BurnEvent.java new file mode 100644 index 0000000..8e52f42 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/BurnEvent.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.PropulsiveVehicle; +import edu.mit.spacenet.domain.network.edge.Burn; +import edu.mit.spacenet.domain.network.edge.BurnType; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.util.Formulae; + +/** + * Event that represents a propulsive maneuver that may be composed of one or + * more burns or stages of individual elements. + * + * @author Paul Grogan + */ +public class BurnEvent extends AbstractEvent { + private SortedSet elements; + private Burn burn; + private List burnStageSequence; + + /** + * The default constructor initializes the items and burn stage sequence + * structures. + */ + public BurnEvent() { + super(); + this.elements = new TreeSet(); + this.burn = new Burn(); + this.burnStageSequence = new ArrayList(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + double deltaVReq = burn.getDeltaV(); + + int pcounter = Integer.MIN_VALUE; + + for(BurnStageItem i : burnStageSequence) { + if(i.getBurnStage().equals(BurnStageItem.BURN)) { + PropulsiveVehicle v = (PropulsiveVehicle)i.getElement(); + + double stackMass = 0; + for(I_Element element : elements) { + stackMass += element.getTotalMass(); + } + if(burn.getBurnType()==BurnType.OMS) { + System.out.printf("%.3f: %s %.2f %s", getTime(), "Starting " + v.getName() + " Burn (OMS) for target", deltaVReq, "m/s delta-V\n"); + if(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getOmsIsp()) > v.getOmsFuelTank().getAmount()) { + double deltaVAchieved = Formulae.getAchievedDeltaV(stackMass, v.getOmsIsp(), v.getOmsFuelTank().getAmount()); + deltaVReq -= deltaVAchieved; + v.getOmsFuelTank().setAmount(0); + /* + DemandSet demands = new DemandSet(); + Demand demand = new Demand(); + demand.setResource(v.getOmsFuelTank().getResource()); + demand.setAmount(v.getOmsFuelTank().getAmount()); + demands.add(demand); + DemandEvent d = new DemandEvent(); + d.setTime(getTime()); + d.setPriority(pcounter++); + d.setParent(this); + d.setLocation(getLocation()); + d.setElement(v.getOmsFuelTank()); + //d.setElement(v); + d.setDemands(demands); + //simulator.schedule(d); + d.execute(simulator); + */ + System.out.printf("%.3f: %s %.2f %s %.2f %s\n", getTime(), v.getName() + " Burn (OMS) achieved", deltaVAchieved, "m/s delta-V,", deltaVReq, "m/s delta-V remaining"); + } else { + v.getOmsFuelTank().remove(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getOmsIsp())); + /* + DemandSet demands = new DemandSet(); + Demand demand = new Demand(); + demand.setResource(v.getOmsFuelTank().getResource()); + demand.setAmount(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getOmsIsp())); + demands.add(demand); + DemandEvent d = new DemandEvent(); + d.setTime(getTime()); + d.setPriority(pcounter++); + d.setParent(this); + d.setLocation(getLocation()); + d.setElement(v.getOmsFuelTank()); + //d.setElement(v); + d.setDemands(demands); + //simulator.schedule(d); + d.execute(simulator); + */ + System.out.printf("%.3f: %s %.2f %s, %.2f %s\n", getTime(), v.getName() + " Burn (OMS) achieved", deltaVReq, "m/s delta-V", v.getOmsFuelTank().getCargoMass(), "kg fuel remaining"); + deltaVReq = 0; + } + } else if(burn.getBurnType()==BurnType.RCS) { + System.out.printf("%.3f: %s %.2f %s", getTime(), "Starting " + v.getName() + " Burn (RCS) for target", deltaVReq, "m/s delta-V\n"); + if(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getRcsIsp()) > v.getRcsFuelTank().getAmount()) { + double deltaVAchieved = Formulae.getAchievedDeltaV(stackMass, v.getRcsIsp(), v.getRcsFuelTank().getAmount()); + deltaVReq -= deltaVAchieved; + v.getRcsFuelTank().setAmount(0); + /* + DemandSet demands = new DemandSet(); + Demand demand = new Demand(); + demand.setResource(v.getRcsFuelTank().getResource()); + demand.setAmount(v.getRcsFuelTank().getAmount()); + demands.add(demand); + DemandEvent d = new DemandEvent(); + d.setTime(getTime()); + d.setPriority(pcounter++); + d.setParent(this); + d.setLocation(getLocation()); + d.setElement(v.getRcsFuelTank()); + //d.setElement(v); + d.setDemands(demands); + //simulator.schedule(d); + d.execute(simulator); + */ + System.out.printf("%.3f: %s %.2f %s %.2f %s\n", getTime(), v.getName() + " Burn (RCS) achieved", deltaVAchieved, "m/s delta-V,", deltaVReq, "m/s delta-V remaining"); + } else { + v.getRcsFuelTank().remove(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getRcsIsp())); + /* + DemandSet demands = new DemandSet(); + Demand demand = new Demand(); + demand.setResource(v.getRcsFuelTank().getResource()); + demand.setAmount(Formulae.getRequiredFuelMass(stackMass, deltaVReq, v.getRcsIsp())); + demands.add(demand); + DemandEvent d = new DemandEvent(); + d.setTime(getTime()); + d.setPriority(pcounter++); + d.setParent(this); + d.setLocation(getLocation()); + d.setElement(v.getRcsFuelTank()); + //d.setElement(v); + d.setDemands(demands); + //simulator.schedule(d); + d.execute(simulator); + */ + System.out.printf("%.3f: %s %.2f %s, %.2f %s\n", getTime(), v.getName() + " Burn (RCS) achieved", deltaVReq, "m/s delta-V", v.getRcsFuelTank().getCargoMass(), "kg fuel remaining"); + deltaVReq = 0; + } + } + } else if(i.getBurnStage().equals(BurnStageItem.STAGE)) { + RemoveEvent stage = new RemoveEvent(); + stage.setTime(getTime()); + stage.setPriority(pcounter++); + stage.setParent(this); + stage.setLocation(getLocation()); + stage.getElements().add(i.getElement()); + //simulator.schedule(d); + stage.execute(simulator); + elements.remove(i.getElement()); + } + } + if(deltaVReq > 0) { + DecimalFormat format = new DecimalFormat("0.0"); + throw new SimSpatialError(simulator.getTime(), this, "Insufficient delta-v achieved, - remaining delta-v: " + format.format(deltaVReq) + " m/s."); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#print(int) + */ + @Override + public void print(int tabOrder) { + String s = ""; + for(BurnStageItem i : burnStageSequence) { + if(i.getBurnStage().equals(BurnStageItem.BURN)) s+= i.getElement().getName() + " [B], "; + else if(i.getBurnStage().equals(BurnStageItem.STAGE)) s+= i.getElement().getName() + " [S], "; + } + s = s.substring(0, s.length() - 2); + super.print(tabOrder); + System.out.printf("%s% .1f %s\n", burn.getBurnType() + " Burn for",burn.getDeltaV(), "delta-V: " + s); + } + + /** + * Gets the set of elements to include in the maneuver. + * + * @return the set of elements + */ + public SortedSet getElements() { + return elements; + } + + /** + * Sets the set of elements to include in the maneuver. + * + * @param elements the set of elements + */ + public void setElements(SortedSet elements) { + this.elements = elements; + } + + /** + * Gets the burn. + * + * @return the burn + */ + public Burn getBurn() { + return burn; + } + + /** + * Sets the burn. + * + * @param burn the burn + */ + public void setBurn(Burn burn) { + this.burn = burn; + } + + /** + * Gets the burn / stage sequence. + * + * @return the burn / stage sequence + */ + public List getBurnStageSequence() { + return burnStageSequence; + } + + /** + * Sets the burn / stage sequence. + * + * @param burnStageSequence the burn / stage sequence + */ + public void setBurnStateSequence(List burnStageSequence) { + this.burnStageSequence = burnStageSequence; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.BURN; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/BurnStageItem.java b/src/main/java/edu/mit/spacenet/simulator/event/BurnStageItem.java new file mode 100644 index 0000000..6e3c907 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/BurnStageItem.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import javax.swing.ImageIcon; + +import edu.mit.spacenet.domain.element.I_Element; + +/** + * This class represents an entry into a burn/stage list, either a burn of a + * propulsive vehicle, or a staging of an expended element. + * + * @author Paul Grogan + */ +public class BurnStageItem { + + /** The Constant BURN. */ + public static final String BURN = "Burn"; + + /** The Constant STAGE. */ + public static final String STAGE = "Stage"; + + /** The Constant BURN_ICON. */ + public static final ImageIcon BURN_ICON = new ImageIcon(BurnStageItem.class.getClassLoader().getResource("icons/bullet_red.png")); + + /** The Constant STAGE_ICON. */ + public static final ImageIcon STAGE_ICON = new ImageIcon(BurnStageItem.class.getClassLoader().getResource("icons/bullet_black.png")); + private String burnStage; + private I_Element element; + + /** + * The default constructor. + */ + public BurnStageItem() {} + + /** + * The constructor which sets the burn/stage type, and target element. + * + * @param burnStage the burn stage type, accessible by static variables + * @param element the target element + */ + public BurnStageItem(String burnStage, I_Element element) { + this.burnStage = burnStage; + this.element = element; + } + + /** + * Gets the burn/stage type. + * + * @return the burn/stage type + */ + public String getBurnStage() { + return burnStage; + } + + /** + * Sets the burn/stage type. + * + * @param burnStage the burn/stage type, accessible by static variables + */ + public void setBurnStage(String burnStage) { + this.burnStage = burnStage; + } + + /** + * Gets the target element. + * + * @return the target element + */ + public I_Element getElement() { + return element; + } + + /** + * Sets the target element. + * + * @param element the target element + */ + public void setElement(I_Element element) { + this.element = element; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + if(burnStage.equals(BURN)) return "[B] " + element; + else if(burnStage.equals(STAGE)) return "[S] " + element; + else return ""; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/CreateEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/CreateEvent.java new file mode 100644 index 0000000..2d144c3 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/CreateEvent.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * An event that instantiates items in the simulation at a particular location. + * + * @author Paul Grogan + */ +public class CreateEvent extends AbstractEvent { + private SortedSet elements; + private I_Container container; + + /** + * The default constructor initializes the set of items and sets a default + * name. + */ + public CreateEvent() { + super(); + this.elements = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(container == null) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No container defined, defaulting to " + getLocation() + ".")); + container = getLocation(); + } + if(container instanceof I_Carrier + && ((I_Carrier)container).getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, container + " was not found."); + } + if(elements.size() == 0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No elements defined.")); + } + + System.out.printf("%.3f: %s\n", getTime(), + "Creating " + elements + " in " + container); + for(I_Element element : elements) { + if(element.getLocation()!=null) { + throw new SimSpatialError(simulator.getTime(), this, + element + " already exists at " + element.getLocation() + "."); + } else if(container.add(element)) { + recursiveCreate(simulator, element); + } else { + throw new SimSpatialError(simulator.getTime(), this, + element + " could not be added to " + container + "."); + } + } + } + private void recursiveCreate(I_Simulator simulator, I_Element element) { + if(element instanceof I_Carrier) { + for(I_Element e : ((I_Carrier)element).getContents()) { + recursiveCreate(simulator, e); + } + } + simulator.getScenario().getNetwork().getRegistrar().put(element.getUid(), element); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + System.out.println("Create Event for " + elements); + } + + /** + * Gets the elements. + * + * @return the elements + */ + public SortedSet getElements() { + return elements; + } + + /** + * Sets the elements. + * + * @param elements the new elements + */ + public void setElements(SortedSet elements) { + this.elements = elements; + } + + /** + * Gets the container at which to create the items. Null if creating at the + * specified Node. + * + * @return the container + */ + public I_Container getContainer() { + return container; + } + + /** + * Gets the container at which to create the items. Null if creating at the + * specified Node. + * + * @param container the container + */ + public void setContainer(I_Container container) { + this.container = container; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.CREATE; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/event/DemandEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/DemandEvent.java new file mode 100644 index 0000000..691cc7c --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/DemandEvent.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import edu.mit.spacenet.domain.ClassOfSupply; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.domain.resource.GenericResource; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimDemand; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; + +/** + * An event that schedules an instantaneous set of demands. + * + * @author Paul Grogan + */ +public class DemandEvent extends AbstractEvent { + private I_Element element; + private DemandSet demands; + + /** + * The default constructor initializes the set of demands. + */ + public DemandEvent() { + super(); + this.demands = new DemandSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(getLocation() == null) { + throw new SimSpatialError(simulator.getTime(), this, "Mission location."); + } else if(element!=null && element.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, element + " was not found."); + } else if(element!=null && !getLocation().equals(element.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, element + " is located at " + element.getLocation() + " instead of " + getLocation() + "."); + } + DemandSet d = new DemandSet(); + for(Demand demand : demands) { + //TODO review production demands if(demand.getAmount() > 0) d.add(demand); + if(Math.abs(demand.getAmount()) > 0) d.add(demand); + } + + System.out.printf("%.3f: %s\n", getTime(), + "Demand for " + demands + " from " + (element==null?getLocation():element)); + + if(simulator.isDemandsSatisfied()) { + if(element != null) { + element.satisfyDemands(d, simulator); + //TODO this was changed to look at container first in demands + if(element.getContainer() instanceof I_Carrier) { + ((I_Carrier)element.getContainer()).satisfyDemands(d, simulator); + } + } + for(I_Element e : getLocation().getContents()) { + e.satisfyDemands(d, simulator); + } + } + if(Math.abs(d.getTotalMass())>0) { + if(d.getTotalMass()>0 && simulator.isPackingDemandsAdded()) { + Demand packingDemand = new Demand(new GenericResource(ClassOfSupply.COS5), 0); + for(Demand demand : d) { + if(demand.getMass()>0 + && demand.getResource().getPackingFactor()>0) + packingDemand.setAmount(packingDemand.getAmount() + + demand.getAmount()*demand.getResource().getPackingFactor()); + } + d.add(packingDemand); + } + throw new SimDemand(simulator.getTime(), this, getLocation(), getElement(), d); + } + } + + /** + * Gets the element requesting the demand. + * + * @return the element requesting the demand + */ + public I_Element getElement() { + return element; + } + + /** + * Sets the element requesting the demand. + * + * @param element the element + */ + public void setElement(I_Element element) { + this.element = element; + } + + /** + * Gets the set of demands. + * + * @return the set of demands + */ + public DemandSet getDemands() { + return demands; + } + + /** + * Sets the set of demands. + * + * @param demands the set of demands + */ + public void setDemands(DemandSet demands) { + this.demands = demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.DEMAND; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/event/EvaEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/EvaEvent.java new file mode 100644 index 0000000..483e066 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/EvaEvent.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.SortedMap; +import java.util.TreeMap; + +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * Event that represents an EVA excursion outside a crew vehicle. It includes + * reconfigure events to/from the nominal states and move events to/from the + * external location. + * + * @author Paul Grogan + */ +public class EvaEvent extends AbstractEvent { + private I_Carrier vehicle; + private double evaDuration; + private SortedMap stateMap; + private DemandSet demands; + + /** + * The default constructor initializes the demands set and EVA states map + * and defaults the EVA duration to 8 hours. + */ + public EvaEvent() { + super(); + stateMap = new TreeMap(); + demands = new DemandSet(); + setEvaDuration(8); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(stateMap.size()==0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No crew members defined.")); + } + if(vehicle == null) { + throw new SimSpatialError(simulator.getTime(), this, + "No crew habitat defined."); + } + if(vehicle.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + vehicle + " was not found."); + } + if(!getLocation().equals(vehicle.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + vehicle + " is located at " + vehicle.getLocation() + " instead of " + getLocation() + "."); + } + for(CrewMember member : stateMap.keySet()) { + if(member.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + member + " was not found."); + } else if(!getLocation().equals(member.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + member + " is located at " + member.getLocation() + " instead of " + getLocation() + "."); + } + } + + System.out.printf("%.3f: %s\n", getTime(), "Commencing EVA at " + getLocation() + + " for " + getEvaDuration() + + " hours"); + + if(simulator.getScenario().isDetailedEva()) { + TreeMap previousStates = new TreeMap(); + for(CrewMember c : stateMap.keySet()) { + if(stateMap.get(c) != null) { + previousStates.put(c, c.getCurrentState()); + ReconfigureEvent r = new ReconfigureEvent(); + r.setTime(getTime()); + r.setPriority(getPriority()); + r.setParent(this); + r.setLocation(getLocation()); + r.setElement(c); + r.setState(stateMap.get(c)); + simulator.schedule(r); + } + } + + MoveEvent m1 = new MoveEvent(); + m1.setTime(getTime()); + m1.setPriority(getPriority()); + m1.setParent(this); + m1.setLocation(getLocation()); + m1.setContainer(getLocation()); + for(CrewMember c : stateMap.keySet()) m1.getElements().add(c); + simulator.schedule(m1); + + MoveEvent m2 = new MoveEvent(); + m2.setTime(getTime() + evaDuration/24); + m2.setParent(this); + m2.setLocation(getLocation()); + m2.setContainer(vehicle); + for(CrewMember c : stateMap.keySet()) m2.getElements().add(c); + simulator.schedule(m2); + + for(CrewMember c : stateMap.keySet()) { + if(previousStates.get(c) != null) { + ReconfigureEvent r = new ReconfigureEvent(); + r.setTime(getTime() + evaDuration/24); + r.setParent(this); + r.setLocation(getLocation()); + r.setElement(c); + r.setState(previousStates.get(c)); + simulator.schedule(r); + } + } + if(demands.size() > 0) { + DemandEvent d = new DemandEvent(); + d.setTime(getTime() + evaDuration/24); + d.setParent(this); + d.setLocation(getLocation()); + d.setElement(vehicle); + d.setDemands(demands); + simulator.schedule(d); + } + } + } + + /** + * Gets the crew member vehicle. + * + * @return the crew member vehicle + */ + public I_Carrier getVehicle() { + return vehicle; + } + + /** + * Sets the crew member vehicle. + * + * @param vehicle the crew member vehicle + */ + public void setVehicle(I_Carrier vehicle) { + this.vehicle = vehicle; + } + + /** + * Gets the duration of the EVA. + * + * @return the duration (hours) + */ + public double getEvaDuration() { + return evaDuration; + } + + /** + * Sets the duration of the EVA. + * + * @param evaDuration the duration (hours) + */ + public void setEvaDuration(double evaDuration) { + this.evaDuration = evaDuration; + } + + /** + * Gets the mapping of crew member's EVA states. + * + * @return the map of crew member's EVA states + */ + public SortedMap getStateMap() { + return stateMap; + } + + /** + * Sets the mapping of crew member's EVA states. + * + * @param evaStates the mapping of crew member's EVA states + */ + public void setStateMap(SortedMap evaStates) { + this.stateMap = evaStates; + } + + /** + * Gets the set of additional EVA demands. + * + * @return the set of additional EVA demands + */ + public DemandSet getDemands() { + return demands; + } + + /** + * Sets the set of additional EVA demands. + * + * @param demands the set of additional EVA demands + */ + public void setDemands(DemandSet demands) { + this.demands = demands; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.EVA; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/EventFactory.java b/src/main/java/edu/mit/spacenet/simulator/event/EventFactory.java new file mode 100644 index 0000000..ac2e5f2 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/EventFactory.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +/** + * A factory for creating events. + * + * @author Paul Grogan + */ +public abstract class EventFactory { + + /** + * Factory method that creates new events. + * + * @param type the type of event to create + * + * @return the event + */ + public static I_Event createEvent(EventType type) { + switch(type) { + case ADD: return new AddEvent(); + case BURN: return new BurnEvent(); + case CREATE: return new CreateEvent(); + case DEMAND: return new DemandEvent(); + case EVA: return new EvaEvent(); + case EXPLORATION: return new ExplorationProcess(); + case FLIGHT_TRANSPORT: return new FlightTransport(); + case MOVE: return new MoveEvent(); + case RECONFIGURE: return new ReconfigureEvent(); + case RECONFIGURE_GROUP: return new ReconfigureGroupEvent(); + case REMOVE: return new RemoveEvent(); + case SPACE_TRANSPORT: return new SpaceTransport(); + case SURFACE_TRANSPORT: return new SurfaceTransport(); + case TRANSFER: return new TransferEvent(); + default: throw new RuntimeException("Unsupported Event"); + } + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/EventType.java b/src/main/java/edu/mit/spacenet/simulator/event/EventType.java new file mode 100644 index 0000000..dfd94de --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/EventType.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import javax.swing.ImageIcon; + +/** + * Enumeration which represents the different concrete classes of events. + * + * @author Paul Grogan + */ +public enum EventType { + + /** The create event type. */ + CREATE("Create Elements", "icons/add.png"), + + /** The add event type. */ + ADD("Add Resources", "icons/add.png"), + + /** The move event type. */ + MOVE("Move Elements", "icons/arrow_right.png"), + + /** The transfer event type. */ + TRANSFER("Transfer Resources", "icons/arrow_right.png"), + + /** The remove event type. */ + REMOVE("Remove Elements", "icons/delete.png"), + + /** The reconfigure event type. */ + RECONFIGURE("Reconfigure Element", "icons/arrow_switch.png"), + + /** The reconfigure group event type. */ + RECONFIGURE_GROUP("Reconfigure Group", "icons/arrow_switch.png"), + + /** The demand event type. */ + DEMAND("Demand Resources", "icons/comment.png"), + + /** The burn event type. */ + BURN("Propulsive Burn", "icons/flame.png"), + + /** The EVA event type. */ + EVA("Crewed EVA", "icons/door_open.png"), + + /** The exploration process type. */ + EXPLORATION("Crewed Exploration", "icons/flag_blue.png"), + + /** The space transport type. */ + SPACE_TRANSPORT("Space Transport", "icons/flag_red.png"), + + /** The surface transport type. */ + SURFACE_TRANSPORT("Surface Transport", "icons/flag_green.png"), + + /** The flight transport. */ + FLIGHT_TRANSPORT("Flight Transport", "icons/flag_yellow.png"); + + private String name; + private ImageIcon icon; + + private EventType(String name, String iconUrl) { + this.name = name; + this.icon = new ImageIcon(getClass().getClassLoader().getResource(iconUrl)); + } + + /** + * Gets the name of the event type. + * + * @return the event type name + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Enum#toString() + */ + public String toString() { + return name; + } + + /** + * Gets the icon representation for the event type. + * + * @return the event type icon + */ + public ImageIcon getIcon() { + return icon; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/ExplorationProcess.java b/src/main/java/edu/mit/spacenet/simulator/event/ExplorationProcess.java new file mode 100644 index 0000000..b631f07 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/ExplorationProcess.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.SortedMap; +import java.util.TreeMap; + +import edu.mit.spacenet.domain.element.CrewMember; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * Event that automatically schedules EVA events with equal time before and + * after each EVA. + * + * @author Paul Grogan + */ +public class ExplorationProcess extends AbstractEvent implements I_Process { + private I_Carrier vehicle; + private double duration; + private double evaPerWeek; + private double evaDuration; + private SortedMap stateMap; + private DemandSet demands; + + /** + * The default constructor initializes the demands set and EVA states map + * and defaults the EVA duration to 8 hours. + */ + public ExplorationProcess() { + super(); + stateMap = new TreeMap(); + demands = new DemandSet(); + setEvaDuration(8); + } + + /** + * Get the number of EVAs to schedule. + * + * @return the number of EVAs + */ + public int getNumberEva() { + return (int)Math.floor(duration*evaPerWeek / 7); + } + + /** + * Gets the hours between EVAs. + * + * @return the time between EVAs (hours) + */ + public double getHoursBetweenEva() { + return (duration*24 - evaDuration*getNumberEva()) / (getNumberEva()+1); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(stateMap.size()==0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No crew members defined.")); + } + if(vehicle == null) { + throw new SimSpatialError(simulator.getTime(), this, + "No crew habitat defined."); + } + if(vehicle.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + vehicle + " was not found."); + } + if(!getLocation().equals(vehicle.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + vehicle + " is located at " + vehicle.getLocation() + " instead of " + getLocation() + "."); + } + for(CrewMember member : stateMap.keySet()) { + if(member.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + member + " was not found."); + } else if(!getLocation().equals(member.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + member + " is located at " + member.getLocation() + " instead of " + getLocation() + "."); + } + } + + System.out.printf("%.3f: %s\n", getTime(), "Commencing exploration at " + getLocation() + + " for " + getDuration() + + " days with " + getNumberEva() + + " EVAs"); + + if(simulator.getScenario().isDetailedEva()) { + for(int i = 0; i < getNumberEva(); i++) { + EvaEvent e = new EvaEvent(); + e.setTime(getTime() + (i+1)*getHoursBetweenEva()/24); + e.setParent(this); + e.setLocation(getLocation()); + e.setEvaDuration(evaDuration); + e.setVehicle(vehicle); + e.setStateMap(stateMap); + e.setDemands(demands); + simulator.schedule(e); + } + } + } + + /** + * Gets the crew member vehicle. + * + * @return the crew member vehicle + */ + public I_Carrier getVehicle() { + return vehicle; + } + + /** + * Sets the crew member vehicle. + * + * @param vehicle the crew member vehicle + */ + public void setVehicle(I_Carrier vehicle) { + this.vehicle = vehicle; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Process#getDuration() + */ + public double getDuration() { + return duration; + } + + /** + * Sets the duration of the exploration process. + * + * @param duration the duration (days) + */ + public void setDuration(double duration) { + this.duration = duration; + } + + /** + * Gets the mapping of crew member's EVA states. + * + * @return the map of crew member's EVA states + */ + public SortedMap getStateMap() { + return stateMap; + } + + /** + * Sets the mapping of crew member's EVA states. + * + * @param evaStates the mapping of crew member's EVA states + */ + public void setStateMap(SortedMap evaStates) { + this.stateMap = evaStates; + } + + /** + * Gets the set of additional EVA demands. + * + * @return the set of additional EVA demands + */ + public DemandSet getDemands() { + return demands; + } + + /** + * Sets the set of additional EVA demands. + * + * @param demands the set of additional EVA demands + */ + public void setDemands(DemandSet demands) { + this.demands = demands; + } + + /** + * Gets the number of EVAs per week. + * + * @return the number of EVAs per week + */ + public double getEvaPerWeek() { + return evaPerWeek; + } + + /** + * Sets the number of EVAs per week. + * + * @param evaPerWeek the number of EVAs per week + */ + public void setEvaPerWeek(double evaPerWeek) { + this.evaPerWeek = evaPerWeek; + } + + /** + * Gets the duration of each EVA. + * + * @return the duration of each EVA (hours) + */ + public double getEvaDuration() { + return evaDuration; + } + + /** + * Sets the duration of each EVA. + * + * @param evaDuration the duration of each EVA (hours) + */ + public void setEvaDuration(double evaDuration) { + this.evaDuration = evaDuration; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.EXPLORATION; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/FlightTransport.java b/src/main/java/edu/mit/spacenet/simulator/event/FlightTransport.java new file mode 100644 index 0000000..60e73d9 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/FlightTransport.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.text.DecimalFormat; +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.FlightEdge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * Event that represents an abstract flight with capacity constraints. + * + * @author Paul Grogan + */ +public class FlightTransport extends AbstractEvent implements I_Transport { + private FlightEdge edge; + private SortedSet elements; + + /** + * The default constructor initializes the item mapping. + */ + public FlightTransport() { + super(); + elements = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(elements.size()==0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No elements defined.")); + } + if(edge == null) { + throw new SimSpatialError(simulator.getTime(), this, + "No flight edge defined."); + } + double mass = 0; + double crew = 0; + for(I_Element element : getElements()) { + if(element.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + element + " was not found."); + } else if(!getLocation().equals(element.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + element + " is located at " + element.getLocation() + " instead of " + getLocation() + "."); + } + if(element instanceof I_Carrier) { + mass+=((I_Carrier)element).getCargoMass(); + crew+=((I_Carrier)element).getCrewSize(); + } + } + DecimalFormat format = new DecimalFormat("0.0"); + if(mass > edge.getMaxCargoMass()) { + throw new SimSpatialError(simulator.getTime(), this, + "Flight cargo mass over capacity: " + format.format(mass) + "/" + format.format(edge.getMaxCargoMass()) + " kg"); + } else if(crew > edge.getMaxCrewSize()) { + throw new SimSpatialError(simulator.getTime(), this, + "Flight crew size over capacity: " + crew + "/" + format.format(edge.getMaxCrewSize())); + } + + System.out.printf("%.3f: %s\n", getTime(), "Commencing flight"); + + MoveEvent m1 = new MoveEvent(); + m1.setTime(getTime()); + m1.setPriority(getPriority()); + m1.setParent(this); + m1.setLocation(edge.getOrigin()); + m1.setContainer(edge); + m1.setElements(elements); + m1.execute(simulator); + + MoveEvent m2 = new MoveEvent(); + m2.setTime(getTime() + edge.getDuration()); + m2.setParent(this); + m2.setLocation(edge); + m2.setContainer(edge.getDestination()); + m2.setElements(elements); + simulator.schedule(m2); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + System.out.println("Flight Process for " + edge.getName()); + + } + + /** + * Gets the flight edge. + * + * @return the flight edge + */ + public FlightEdge getEdge() { + return edge; + } + + /** + * Sets the flight edge. + * + * @param edge the edge + */ + public void setEdge(FlightEdge edge) { + this.edge = edge; + } + + /** + * Gets the top-level elements. + * + * @return the element mapping + */ + public SortedSet getElements() { + return elements; + } + + /** + * Sets the top-level elements. + * + * @param elements the elements + */ + public void setElements(SortedSet elements) { + this.elements = elements; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Process#getDuration() + */ + public double getDuration() { + return edge.getDuration(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Transport#getOrigin() + */ + public Node getOrigin() { + return edge.getOrigin(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Transport#getDestination() + */ + public Node getDestination() { + return edge.getDestination(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.FLIGHT_TRANSPORT; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/I_Event.java b/src/main/java/edu/mit/spacenet/simulator/event/I_Event.java new file mode 100644 index 0000000..be57d4a --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/I_Event.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import edu.mit.spacenet.domain.network.Location; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; + +/** + * Interface for any event to be executed in the simulator. + * + * @author Paul Grogan + */ +public interface I_Event extends Comparable { + + /** + * Gets the time of event execution. + * + * @return the time of execution (days) + */ + public double getTime(); + + /** + * Sets the time of event execution. + * + * @param time the time of execution (days) + */ + public void setTime(double time); + + /** + * Gets the priority of this event over other events with the same time + * (Lowest value first). + * + * @return the priority of execution (lowest value first) + */ + public int getPriority(); + + /** + * Sets the priority of this event over other events with the same time + * (Lowest value first). + * + * @param priority the priority of execution (lowest value first) + */ + public void setPriority(int priority); + + /** + * Gets the parent event that generated this event, null if no parent. + * + * @return the parent event + */ + public I_Event getParent(); + + /** + * Sets the parent event that generated this event, null if no parent. + * + * @param parent the parent event + */ + public void setParent(I_Event parent); + + /** + * Gets the root-generating event. + * + * @return the root event + */ + public I_Event getRoot(); + + /** + * Gets the location that the event will act at (in the case of processes, + * this returns the initial location. + * + * @return the node + */ + public Location getLocation(); + + /** + * Sets the location that the event will act at (in the case of processes, + * this sets the initial location. + * + * @param location the location + */ + public void setLocation(Location location); + + /** + * Gets the name of the event. + * + * @return the name + */ + public String getName(); + + /** + * Sets the name of the event. + * + * @param name the name + */ + public void setName(String name); + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(I_Event e); + + /** + * Executes the event inside the specified simulator. + * + * @param simulator the simulator + * + * @throws SimError the sim error + */ + public void execute(I_Simulator simulator) throws SimError; + + /** + * Prints the event to console without any indentation. + */ + public void print(); + + /** + * Prints the event to console at a specific tab indentation level. + * + * @param tabOrder the indentation level + */ + public void print(int tabOrder); + + /** + * Gets the event's unique identifier. + * + * @return the unique identifier + */ + public long getUid(); + + /** + * Resets the event's unique identifier (used during copy operations). + */ + public void resetUid(); + + /** + * Gets the event's type. + * + * @return the event type + */ + public EventType getEventType(); +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/event/I_Process.java b/src/main/java/edu/mit/spacenet/simulator/event/I_Process.java new file mode 100644 index 0000000..1c3a260 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/I_Process.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +/** + * The I_Process interface is used for events of finite duration. + * + * @author Paul Grogan + */ +public interface I_Process extends I_Event { + + /** + * Gets the duration of the process. + * + * @return the duration (days) + */ + public double getDuration(); +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/I_Transport.java b/src/main/java/edu/mit/spacenet/simulator/event/I_Transport.java new file mode 100644 index 0000000..0893c89 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/I_Transport.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.Set; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.Edge; +import edu.mit.spacenet.domain.network.node.Node; + +/** + * The I_Transport interface is used for processes that have a distinct origin + * and destination location. + * + * @author Paul Grogan + */ +public interface I_Transport extends I_Process { + + /** + * Gets the network edge for the transport. + * + * @return the edge + */ + public Edge getEdge(); + + /** + * Gets the origin node of the transport. + * + * @return the origin node + */ + public Node getOrigin(); + + /** + * Gets the destination node of the transport. + * + * @return the destination node + */ + public Node getDestination(); + + /** + * Gets the set of elements. + * + * @return the elements + */ + public Set getElements(); +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/ManifestEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/ManifestEvent.java new file mode 100644 index 0000000..ec36ebf --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/ManifestEvent.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.HashSet; +import java.util.Set; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; + +/** + * An event that either creates or moves a set of resource containers to a new + * carrier. + * + * @author Paul Grogan + */ +public class ManifestEvent extends AbstractEvent { + private Set containers; + private I_Carrier carrier; + + /** + * Instantiates a new manifest event. + */ + public ManifestEvent() { + super(); + setName("Manifest Event"); + containers = new HashSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + for(I_ResourceContainer container : containers) { + if(!carrier.getContents().contains(container)) { + System.out.printf("%.3f: %s\n", + getTime(), "Manifesting " + container + " into " + carrier); + if(carrier.add(container)) { + simulator.getScenario().getNetwork().getRegistrar().put(container.getUid(), container); + } else { + throw new SimSpatialError(simulator.getTime(), this, + container + " could not be manifested in " + carrier); + } + } + } + } + + /** + * Gets the containers. + * + * @return the containers + */ + public Set getContainers() { + return containers; + } + + /** + * Sets the containers. + * + * @param items the new containers + */ + public void setContainers(Set items) { + this.containers = items; + } + + /** + * Gets the carrier. + * + * @return the carrier + */ + public I_Carrier getCarrier() { + return carrier; + } + + /** + * Sets the carrier. + * + * @param carrier the new carrier + */ + public void setCarrier(I_Carrier carrier) { + this.carrier = carrier; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/event/MissionEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/MissionEvent.java new file mode 100644 index 0000000..5e04ef5 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/MissionEvent.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import edu.mit.spacenet.scenario.Mission; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimWarning; +import edu.mit.spacenet.util.DateFunctions; + +/** + * Simple event that pushes a mission's events onto the simulation stack. + * + * @author Paul Grogan + */ +public class MissionEvent extends AbstractEvent { + private Mission mission; + + /** + * The default constructor. + */ + public MissionEvent() { + super(); + } + + /** + * Gets the mission. + * + * @return the mission + */ + public Mission getMission() { + return mission; + } + + /** + * Sets the mission. + * + * @param mission the mission + */ + public void setMission(Mission mission) { + this.mission = mission; + setLocation(mission.getOrigin()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) { + if(mission.getEventList().size()==0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No events defined.")); + } + + System.out.printf("%.3f: %s\n", + getTime(), "Commencing Mission: " + mission.getName()); + for(I_Event e : mission.getEventList()) { + e.setTime(e.getTime() + getTime()); + simulator.schedule(e); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + System.out.println("Mission: " + mission.getName()); + for(I_Event e : mission.getEventList()) { + e.print(tabOrder+1); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#getName() + */ + @Override + public String getName() { + return mission.getName(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#getTime() + */ + @Override + public double getTime() { + return DateFunctions.getDaysBetween(mission.getStartDate(), mission.getScenario().getStartDate()); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/event/MoveEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/MoveEvent.java new file mode 100644 index 0000000..58290ad --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/MoveEvent.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.I_Container; +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * An event that moves a set of elements to a new container. + * + * @author Paul Grogan + */ +public class MoveEvent extends AbstractEvent { + private SortedSet elements; + private I_Container container; + + /** + * Instantiates a new move event. + */ + public MoveEvent() { + super(); + this.elements = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(container == null) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No container defined, defaulting to " + getLocation() + ".")); + container = getLocation(); + } + if(container instanceof I_Carrier + && ((I_Carrier)container).getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + container + " was not found."); + } + + if(elements.size() == 0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No elements defined.")); + } else { + System.out.printf("%.3f: %s\n", + getTime(), "Transferring " + elements + " to " + container); + for(I_Element element : elements) { + if(element.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + element + " was not found."); + } else if(!getLocation().equals(element.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + element + " is located at " + element.getLocation() + " instead of " + getLocation() + "."); + } else if(container.add(element)) { + // successful for element 'element' + } else { + throw new SimSpatialError(simulator.getTime(), this, + element + " could not be added to " + container + "."); + } + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + System.out.println("Move Event for " + elements.toString() + " -> " + container.getName()); + } + + /** + * Gets the elements. + * + * @return the elements + */ + public SortedSet getElements() { + return elements; + } + + /** + * Sets the elements. + * + * @param elements the new elements + */ + public void setElements(SortedSet elements) { + this.elements = elements; + } + + /** + * Gets the container. + * + * @return the container + */ + public I_Container getContainer() { + return container; + } + + /** + * Sets the container. + * + * @param container the new container + */ + public void setContainer(I_Container container) { + this.container = container; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.MOVE; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/ReconfigureEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/ReconfigureEvent.java new file mode 100644 index 0000000..baee1e0 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/ReconfigureEvent.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * An event that reconfigures an element to a new operational state. + * + * @author Paul Grogan + */ +public class ReconfigureEvent extends AbstractEvent { + private I_Element element; + private I_State state; + + /** + * The default constructor. + */ + public ReconfigureEvent() { + super(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(element == null) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No element defined.")); + } else { + if(element.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + element + " was not found."); + } else if(!getLocation().equals(element.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + element + " is located at " + element.getLocation() + " instead of " + getLocation() + "."); + } else if(element.setCurrentState(state)) { + System.out.printf("%.3f: %s\n", + getTime(), "Reconfiguring " + element + " to " + state + " state"); + } else { + throw new SimSpatialError(simulator.getTime(), this, + "Element " + element + " does not contain state " + state + "."); + } + } + } + + /** + * Gets the element to reconfigure. + * + * @return the element to reconfigure + */ + public I_Element getElement() { + return element; + } + + /** + * Sets the element to reconfigure. + * + * @param element the element to reconfigure + */ + public void setElement(I_Element element) { + this.element = element; + } + + /** + * Gets the state to reconfigure to. + * + * @return the state to reconfigure to + */ + public I_State getState() { + return state; + } + + /** + * Sets the state to reconfigure to. + * + * @param state the state to reconfigure to + */ + public void setState(I_State state) { + this.state = state; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.RECONFIGURE; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/event/ReconfigureGroupEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/ReconfigureGroupEvent.java new file mode 100644 index 0000000..a155ee6 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/ReconfigureGroupEvent.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.element.StateType; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * An event that reconfigures a group of elements to a new operational state + * type. + */ +public class ReconfigureGroupEvent extends AbstractEvent { + private SortedSet elements; + private StateType stateType; + + /** + * The default constructor. + */ + public ReconfigureGroupEvent() { + super(); + elements = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(elements.size() == 0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No elements defined.")); + } else { + for(I_Element element : elements) { + I_State state = null; + for(I_State s : element.getStates()) { + if(s.getStateType().equals(stateType)) { + state = s; + break; + } + } + + if(element.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + element + " was not found."); + } else if(!getLocation().equals(element.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + element + " is located at " + element.getLocation() + " instead of " + getLocation() + "."); + } else if(state==null) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No " + stateType + " state for " + element + ".")); + } else if(element.setCurrentState(state)) { + System.out.printf("%.3f: %s\n", + getTime(), "Reconfiguring " + element + " to " + state + " state"); + } else { + throw new SimSpatialError(simulator.getTime(), this, + "Element " + element + " does not contain state " + state + "."); + } + } + } + } + + /** + * Gets the elements to reconfigure. + * + * @return the elements to reconfigure + */ + public SortedSet getElements() { + return elements; + } + + /** + * Sets the elements to reconfigure. + * + * @param elements the elements to reconfigure + */ + public void setElements(SortedSet elements) { + this.elements = elements; + } + + /** + * Gets the state type to reconfigure to. + * + * @return the state type to reconfigure to + */ + public StateType getStateType() { + return stateType; + } + + /** + * Sets the state type to reconfigure to. + * + * @param stateType the state type to reconfigure to + */ + public void setStateType(StateType stateType) { + this.stateType = stateType; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.RECONFIGURE_GROUP; + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/event/RemoveEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/RemoveEvent.java new file mode 100644 index 0000000..e8ecfff --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/RemoveEvent.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.element.I_Carrier; +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * An event that removes a set of elements from the simulation. + * + * @author Paul Grogan + */ +public class RemoveEvent extends AbstractEvent { + private SortedSet elements; + + /** + * Instantiates a new removes the event. + */ + public RemoveEvent() { + super(); + this.elements = new TreeSet(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(elements.size() == 0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No elements defined.")); + } else { + for(I_Element element : elements) { + if(element.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + element + " was not found."); + } else if(!getLocation().equals(element.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + element + " is located at " + element.getLocation() + " instead of " + getLocation() + "."); + } else { + System.out.printf("%.3f: %s\n", getTime(), + "Removing " + elements.toString() + " from Simulation"); + element.getContainer().remove(element); + recursiveRemove(simulator, element); + } + } + } + } + private void recursiveRemove(I_Simulator simulator, I_Element element) { + if(element instanceof I_Carrier) { + for(I_Element e : ((I_Carrier)element).getContents()) { + recursiveRemove(simulator, e); + } + } + simulator.getScenario().getNetwork().getRegistrar().remove(element.getUid()); + simulator.getScenario().getNetwork().getRemovedRegistrar().put(element.getUid(),element); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + System.out.println("Remove Event for " + elements.toString()); + } + + /** + * Gets the set of elements to remove. + * + * @return the set of elements to remove + */ + public SortedSet getElements() { + return elements; + } + + /** + * Sets the set of elements to remove. + * + * @param element the element + */ + public void setElements(SortedSet element) { + this.elements = element; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.REMOVE; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/SpaceTransport.java b/src/main/java/edu/mit/spacenet/simulator/event/SpaceTransport.java new file mode 100644 index 0000000..ee73599 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/SpaceTransport.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.ArrayList; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.network.edge.SpaceEdge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * Event that represents a series of propulsive burns to move from node to node. + * + * @author Paul Grogan + */ +public class SpaceTransport extends AbstractEvent implements I_Transport { + private SpaceEdge edge; + private SortedSet elements; + private List> burnStageSequence; + + /** + * The default constructor initializes the items and burn / stage sequence + * for each burn. + */ + public SpaceTransport() { + super(); + this.elements = new TreeSet(); + this.burnStageSequence = new ArrayList>(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(elements.size()==0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No elements defined.")); + } + if(edge == null) { + throw new SimSpatialError(simulator.getTime(), this, + "No flight edge defined."); + } + + for(I_Element element : getElements()) { + if(element.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + element + " was not found."); + } else if(!getLocation().equals(element.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + element + " is located at " + element.getLocation() + " instead of " + getLocation() + "."); + } + } + + System.out.printf("%.3f: %s\n", getTime(), "Commencing space transport"); + + MoveEvent m1 = new MoveEvent(); + m1.setTime(getTime()); + m1.setPriority(getPriority()); + m1.setParent(this); + m1.setLocation(edge.getOrigin()); + m1.setContainer(edge); + m1.setElements(elements); + m1.execute(simulator); + + for(int i=0; i1?"s":"")); + } + + /** + * Gets the space edge. + * + * @return the space edge + */ + public SpaceEdge getEdge() { + return edge; + } + + /** + * Sets the space edge. Note that currently this method also re-initializes + * the burn stage sequence with the proper number of burns... this may cause + * errors. + * + * @param edge the space edge + */ + public void setEdge(SpaceEdge edge) { + this.edge = edge; + // TODO: this may cause problems overwriting the existing sequence... + burnStageSequence.clear(); + for(int i = 0; i < edge.getBurns().size(); i++) { + burnStageSequence.add(new ArrayList()); + } + } + + /** + * Gets the set of elements. + * + * @return the set of elements + */ + public SortedSet getElements() { + return elements; + } + + /** + * Sets the set of elements. + * + * @param elements the set of elements + */ + public void setElements(SortedSet elements) { + this.elements = elements; + } + + /** + * Gets the burn / stage sequence for each burn. + * + * @return the burn / stage sequence for each burn + */ + public List> getBurnStageSequence() { + return burnStageSequence; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Process#getDuration() + */ + public double getDuration() { + return edge.getDuration(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Transport#getOrigin() + */ + public Node getOrigin() { + return edge.getOrigin(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Transport#getDestination() + */ + public Node getDestination() { + return edge.getDestination(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.SPACE_TRANSPORT; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/SurfaceTransport.java b/src/main/java/edu/mit/spacenet/simulator/event/SurfaceTransport.java new file mode 100644 index 0000000..c53d23b --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/SurfaceTransport.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import java.util.HashSet; +import java.util.Set; + +import edu.mit.spacenet.domain.element.I_Element; +import edu.mit.spacenet.domain.element.I_State; +import edu.mit.spacenet.domain.element.SurfaceVehicle; +import edu.mit.spacenet.domain.network.edge.SurfaceEdge; +import edu.mit.spacenet.domain.network.node.Node; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.util.GlobalParameters; + +/** + * An event that models the surface transport along a surface edge using a + * surface vehicle. + * + * @author Paul Grogan + */ +public class SurfaceTransport extends AbstractEvent implements I_Transport { + private double dutyCycle; + private SurfaceVehicle vehicle; + private I_State transportState; + private double speed; + private SurfaceEdge edge; + + /** + * The default constructor sets the duty cycle to 1. + */ + public SurfaceTransport() { + super(); + dutyCycle = 1; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(edge == null) { + throw new SimSpatialError(simulator.getTime(), this, + "No surface edge defined."); + } + if(vehicle == null) { + throw new SimSpatialError(simulator.getTime(), this, + "No surface vehicle defined."); + } + if(vehicle.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + vehicle + " was not found."); + } + if(!getLocation().equals(vehicle.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + vehicle + " is located at " + vehicle.getLocation() + " instead of " + getLocation() + "."); + } + if(speed<=0||dutyCycle<=0) { + throw new SimSpatialError(simulator.getTime(), this, + "Infinite travel duration."); + } + + System.out.printf("%.3f: %s\n", getTime(), "Commencing surface transport"); + + I_State previousState = vehicle.getCurrentState(); + + if(transportState != null) { + ReconfigureEvent r1 = new ReconfigureEvent(); + r1.setTime(getTime()); + r1.setPriority(getPriority()); + r1.setParent(this); + if(isReversed()) r1.setLocation(edge.getDestination()); + else r1.setLocation(edge.getOrigin()); + r1.setElement(vehicle); + r1.setState(transportState); + r1.execute(simulator); + } + + MoveEvent m1 = new MoveEvent(); + m1.setTime(getTime()); + m1.setPriority(getPriority()); + m1.setParent(this); + m1.setLocation(getLocation()); + m1.setContainer(edge); + m1.getElements().add(vehicle); + m1.execute(simulator); + + MoveEvent m2 = new MoveEvent(); + m2.setTime(getTime() + getDuration()); + m2.setPriority(-1); + m2.setParent(this); + m2.setLocation(edge); + if(isReversed()) m2.setContainer(edge.getOrigin()); + else m2.setContainer(edge.getDestination()); + m2.getElements().add(vehicle); + simulator.schedule(m2); + + if(previousState != null) { + ReconfigureEvent r2 = new ReconfigureEvent(); + r2.setTime(getTime() + getDuration()); + r2.setPriority(0); + r2.setParent(this); + if(isReversed()) r2.setLocation(edge.getOrigin()); + else r2.setLocation(edge.getDestination()); + r2.setElement(vehicle); + r2.setState(previousState); + simulator.schedule(r2); + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Process#getDuration() + */ + public double getDuration() { + if(getSpeed()==0||getDutyCycle()==0) return Double.POSITIVE_INFINITY; + else return GlobalParameters.getRoundedTime(edge.getDistance()/(getSpeed()*getDutyCycle()*24)); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Transport#getOrigin() + */ + public Node getOrigin() { + return isReversed()?edge.getDestination():edge.getOrigin(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Transport#getDestination() + */ + public Node getDestination() { + return isReversed()?edge.getOrigin():edge.getDestination(); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Transport#getElements() + */ + public Set getElements() { + HashSet elements = new HashSet(); + elements.add(vehicle); + return elements; + } + + /** + * Gets the duty cycle (percent of time in motion). + * + * @return the duty cycle (percent) + */ + public double getDutyCycle() { + return dutyCycle; + } + + /** + * Sets the duty cycle (percent of time in motion). + * + * @param dutyCycle the duty cycle (percent) + */ + public void setDutyCycle(double dutyCycle) { + this.dutyCycle = dutyCycle; + } + + /** + * Gets the surface vehicle. + * + * @return the surface vehicle + */ + public SurfaceVehicle getVehicle() { + return vehicle; + } + + /** + * Sets the surface vehicle. + * + * @param vehicle the surface vehicle + */ + public void setVehicle(SurfaceVehicle vehicle) { + this.vehicle = vehicle; + } + + /** + * Gets the transport speed. + * + * @return the transport speed (meters per second) + */ + public double getSpeed() { + return speed; + } + + /** + * Sets the transport speed. + * + * @param speed the transport speed (meters per second) + */ + public void setSpeed(double speed) { + this.speed = speed; + } + + /** + * Gets the surface edge. + * + * @return the surface edge + */ + public SurfaceEdge getEdge() { + return edge; + } + + /** + * Sets the surface edge. + * + * @param edge the surface edge + */ + public void setEdge(SurfaceEdge edge) { + this.edge = edge; + } + + /** + * Gets whether the edge is reversed or not. + * + * @return true if the edge's origin and destination are swapped, false + * otherwise + */ + public boolean isReversed() { + return getLocation().equals(edge.getDestination()); + } + + /** + * Gets the state of the transport vehicle during transport. + * + * @return the transport state + */ + public I_State getTransportState() { + return transportState; + } + + /** + * Sets the state of the transport vehicle during transport. + * + * @param transportState the transport state + */ + public void setTransportState(I_State transportState) { + this.transportState = transportState; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.SURFACE_TRANSPORT; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/event/TransferEvent.java b/src/main/java/edu/mit/spacenet/simulator/event/TransferEvent.java new file mode 100644 index 0000000..6eb82d5 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/event/TransferEvent.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.event; + +import edu.mit.spacenet.domain.element.I_ResourceContainer; +import edu.mit.spacenet.domain.resource.Demand; +import edu.mit.spacenet.domain.resource.DemandSet; +import edu.mit.spacenet.simulator.I_Simulator; +import edu.mit.spacenet.simulator.SimError; +import edu.mit.spacenet.simulator.SimSpatialError; +import edu.mit.spacenet.simulator.SimWarning; + +/** + * An event that transfers resources from one resource container to another. + * + * @author Paul Grogan + */ +public class TransferEvent extends AbstractEvent { + private DemandSet demands; + private I_ResourceContainer originContainer, destinationContainer; + + /** + * Instantiates a new transfer event. + */ + public TransferEvent() { + super(); + this.demands = new DemandSet(); + setName("Transfer Event"); + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#execute(edu.mit.spacenet.simulator.I_Simulator) + */ + public void execute(I_Simulator simulator) throws SimError { + if(destinationContainer.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + destinationContainer + " was not found."); + } else if(originContainer.getLocation()==null) { + throw new SimSpatialError(simulator.getTime(), this, + originContainer + " was not found."); + } else if(!originContainer.getLocation().equals(destinationContainer.getLocation())) { + throw new SimSpatialError(simulator.getTime(), this, + destinationContainer + " is located at " + destinationContainer.getLocation() + + " instead of " + originContainer.getLocation() + "."); + } + + if(demands.size() == 0) { + simulator.getWarnings().add(new SimWarning(simulator.getTime(), this, + "No demands defined.")); + } else { + System.out.printf("%.3f: %s\n", + getTime(), "Transferring " + demands + " to " + destinationContainer); + for(Demand demand : demands) { + if(originContainer.remove(demand.getResource(), demand.getAmount())) { + if(destinationContainer.add(demand.getResource(), demand.getAmount())) { + // success + } else { + originContainer.add(demand.getResource(), demand.getAmount()); + throw new SimSpatialError(simulator.getTime(), this, + demand + " could not be added to " + destinationContainer + "."); + } + } else { + throw new SimSpatialError(simulator.getTime(), this, + demand + " could not be removed from " + originContainer + "."); + } + } + } + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.AbstractEvent#print(int) + */ + @Override + public void print(int tabOrder) { + super.print(tabOrder); + System.out.println("Transfer Event for " + demands + " -> " + destinationContainer.getName()); + } + + /** + * Gets the transfer demands. + * + * @return the transfer demands + */ + public DemandSet getTransferDemands() { + return demands; + } + + /** + * Sets the transfer demands. + * + * @param demands the new transfer demands + */ + public void setTransferDemands(DemandSet demands) { + this.demands = demands; + } + + /** + * Gets the origin container. + * + * @return the origin container + */ + public I_ResourceContainer getOriginContainer() { + return originContainer; + } + + /** + * Sets the origin container. + * + * @param originContainer the new origin container + */ + public void setOriginContainer(I_ResourceContainer originContainer) { + this.originContainer = originContainer; + } + + /** + * Gets the destination container. + * + * @return the destination container + */ + public I_ResourceContainer getDestinationContainer() { + return destinationContainer; + } + + /** + * Sets the destination container. + * + * @param destinationContainer the new destination container + */ + public void setDestinationContainer(I_ResourceContainer destinationContainer) { + this.destinationContainer = destinationContainer; + } + + /* (non-Javadoc) + * @see edu.mit.spacenet.domain.event.I_Event#getEventType() + */ + public EventType getEventType() { + return EventType.TRANSFER; + } +} diff --git a/src/main/java/edu/mit/spacenet/simulator/moe/MoeCrewSurfaceDays.java b/src/main/java/edu/mit/spacenet/simulator/moe/MoeCrewSurfaceDays.java new file mode 100644 index 0000000..47e8677 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/moe/MoeCrewSurfaceDays.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.moe; + +import edu.mit.spacenet.domain.network.Location; + +/** + * The measure of effectiveness that tabulates the number of crew surface days. + * + * @author Paul Grogan + */ +public class MoeCrewSurfaceDays implements Comparable { + private double time; + private Location location; + private double amount; + + /** + * Instantiates a new MOE crew surface days. + * + * @param time the simulation time of a crew surface day to log + * @param location the location of the crew surface day to log + * @param amount the amount time to log (crew-hours) + */ + public MoeCrewSurfaceDays(double time, Location location, double amount) { + this.time = time; + this.location = location; + this.amount = amount; + } + + /** + * Gets the simulation time of the log. + * + * @return the simulation time + */ + public double getTime() { + return time; + } + + /** + * Gets the location of the log. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the amount of man-hours logged. + * + * @return the amount (crew-hours) + */ + public double getAmount() { + return amount; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(MoeCrewSurfaceDays moe) { + return Double.compare(getTime(), moe==null?0:moe.getTime()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/moe/MoeCrewTime.java b/src/main/java/edu/mit/spacenet/simulator/moe/MoeCrewTime.java new file mode 100644 index 0000000..e80d956 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/moe/MoeCrewTime.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.moe; + +import edu.mit.spacenet.domain.network.Location; + +/** + * The measure of effectiveness that logs the crew time usage. + * + * @author Paul Grogan + */ +public class MoeCrewTime implements Comparable { + + /** Unavailable crew time. */ + public static final String UNAVAILABLE = "Unavailable"; + + /** Corrective maintenance crew time. */ + public static final String CORRECTIVE_MAINTENANCE = "Corrective Maintenance"; + + /** Preventative maintenance crew time. */ + public static final String PREVENTATIVE_MAINTENANCE = "Preventative Maintenance"; + + /** Exploration crew time. */ + public static final String EXPLORATION = "Exploration"; + + private double time; + private Location location; + private String type; + private double amount; + + /** + * Instantiates a new MOE crew time. + * + * @param time the simulation time of the crew time to log + * @param location the location of the crew time to log + * @param type the type of time to log + * @param amount the amount of time to log (crew-hours) + */ + public MoeCrewTime(double time, Location location, String type, double amount) { + this.time = time; + this.location = location; + this.type = type; + this.amount = amount; + } + + /** + * Gets the simulation time of the log. + * + * @return the simulation time + */ + public double getTime() { + return time; + } + + /** + * Gets the location of the log. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the type of time logged. + * + * @return the type of time + */ + public String getType() { + return type; + } + + /** + * Gets the amount of time logged. + * + * @return the amount (crew-hours) + */ + public double getAmount() { + return amount; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(MoeCrewTime moe) { + return Double.compare(getTime(), moe==null?0:moe.getTime()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/moe/MoeExplorationCapability.java b/src/main/java/edu/mit/spacenet/simulator/moe/MoeExplorationCapability.java new file mode 100644 index 0000000..9f5cbd5 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/moe/MoeExplorationCapability.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.moe; + +import edu.mit.spacenet.domain.network.Location; + +/** + * The measure of effectiveness that logs exploration capability. + * + * @author Paul Grogan + */ +public class MoeExplorationCapability implements Comparable { + private double time; + private Location location; + private double mass; + private double duration; + + /** + * Instantiates a new MOE exploration capability. + * + * @param time the simulation time of exploration to log + * @param location the location to log + * @param mass the mass of exploration-conducive material to log + * @param duration the exploration duration to log + */ + public MoeExplorationCapability(double time, Location location, double mass, double duration) { + this.time = time; + this.location = location; + this.mass = mass; + this.duration = duration; + } + + /** + * Gets the simulation time of the exploration. + * + * @return the simulation time + */ + public double getTime() { + return time; + } + + /** + * Gets the location of the exploration. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the mass of exploration-conducive material. + * + * @return the mass (kilograms) + */ + public double getMass() { + return mass; + } + + /** + * Gets the duration of the exploration. + * + * @return the duration (days) + */ + public double getDuration() { + return duration; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(MoeExplorationCapability moe) { + return Double.compare(getTime(), moe==null?0:moe.getTime()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/moe/MoeExplorationMassDelivered.java b/src/main/java/edu/mit/spacenet/simulator/moe/MoeExplorationMassDelivered.java new file mode 100644 index 0000000..5f2fa27 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/moe/MoeExplorationMassDelivered.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.moe; + +import edu.mit.spacenet.domain.network.Location; + +/** + * Measure of effectiveness that logs exploration mass that is delivered to a + * location. + * + * @author Paul Grogan + */ +public class MoeExplorationMassDelivered implements Comparable { + private double time; + private Location location; + private double amount; + + /** + * Instantiates a new MOE exploration mass delivered. + * + * @param time the simulation time of delivery + * @param location the location of delivery + * @param amount the amount of exploration mass delivered + */ + public MoeExplorationMassDelivered(double time, Location location, double amount) { + this.time = time; + this.location = location; + this.amount = amount; + } + + /** + * Gets the simulation time of delivery. + * + * @return the simulation time + */ + public double getTime() { + return time; + } + + /** + * Gets the location of delivery. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the amount of exploration mass delivered. + * + * @return the amount (kilograms) + */ + public double getAmount() { + return amount; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(MoeExplorationMassDelivered moe) { + return Double.compare(getTime(), moe==null?0:moe.getTime()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/moe/MoeLaunchMass.java b/src/main/java/edu/mit/spacenet/simulator/moe/MoeLaunchMass.java new file mode 100644 index 0000000..034c737 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/moe/MoeLaunchMass.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.moe; + +import edu.mit.spacenet.domain.network.Location; + +/** + * Measure of effectiveness that logs the launch mass. + * + * @author Paul Grogan + */ +public class MoeLaunchMass implements Comparable { + private double time; + private Location location; + private double amount; + + /** + * Instantiates a new MOE launch mass. + * + * @param time the simulation time of launch + * @param location the location of launch + * @param amount the amount of launch mass (kilograms) + */ + public MoeLaunchMass(double time, Location location, double amount) { + this.time = time; + this.location = location; + this.amount = amount; + } + + /** + * Gets the simulation time of launch. + * + * @return the simulation time + */ + public double getTime() { + return time; + } + + /** + * Gets the location of launch. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the amount of launch mass. + * + * @return the launch mass (kilograms) + */ + public double getAmount() { + return amount; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(MoeLaunchMass moe) { + return Double.compare(getTime(), moe==null?0:moe.getTime()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/simulator/moe/MoeMassCapacityUtilization.java b/src/main/java/edu/mit/spacenet/simulator/moe/MoeMassCapacityUtilization.java new file mode 100644 index 0000000..31b4a68 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/simulator/moe/MoeMassCapacityUtilization.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.simulator.moe; + +import edu.mit.spacenet.domain.network.Location; + +/** + * Measure of effectiveness that logs the utilization of mass capacity. + * + * @author Paul Grogan + */ +public class MoeMassCapacityUtilization implements Comparable { + private double time; + private Location location; + private double amount; + private double capacity; + + /** + * Instantiates a new MOE mass capacity utilization. + * + * @param time the simulation time to log + * @param location the location to log + * @param amount the amount of mass apacity used (kilograms) + * @param capacity the mass capacity (kilograms) + */ + public MoeMassCapacityUtilization(double time, Location location, double amount, double capacity) { + this.time = time; + this.location = location; + this.amount = amount; + this.capacity = capacity; + } + + /** + * Gets the simulation time. + * + * @return the simulation time + */ + public double getTime() { + return time; + } + + /** + * Gets the location. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Gets the amount of mass capacity used. + * + * @return the amount (kilograms) + */ + public double getAmount() { + return amount; + } + + /** + * Gets the mass capacity. + * + * @return the capacity (kilograms) + */ + public double getCapacity() { + return capacity; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(MoeMassCapacityUtilization moe) { + return Double.compare(getTime(), moe==null?0:moe.getTime()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/util/DateFunctions.java b/src/main/java/edu/mit/spacenet/util/DateFunctions.java new file mode 100644 index 0000000..93114a0 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/util/DateFunctions.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.util; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +/** + * Some useful functions for performing operations with dates. + * + * @author Paul Grogan + */ +public class DateFunctions { + + /** + * Gets the number of days between two dates. + * + * @param d1 the first date + * @param d2 the second date + * + * @return the number of days between + */ + public static double getDaysBetween(Date d1, Date d2) { + long l1 = d1.getTime(); + long l2 = d2.getTime(); + return GlobalParameters.getRoundedTime(Math.abs((l1-l2)/(1000d*60d*60d*24d))); + } + + /** + * Gets the date that is a number of days after a reference date. + * + * @param date the reference date + * @param offset the number of days offset + * + * @return the date + */ + public static Date getDate(Date date, Double offset) { + GregorianCalendar g = new GregorianCalendar(); + g.setTime(date); + g.add(Calendar.SECOND, + (int) Math.round(Math.floor(offset * 24 * 60 * 60))); + + return g.getTime(); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/util/Formulae.java b/src/main/java/edu/mit/spacenet/util/Formulae.java new file mode 100644 index 0000000..2f469e3 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/util/Formulae.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.util; + +/** + * Class to contain various useful mathematical formulae, including the rocket + * equation. + * + * @author Paul Grogan + */ +public final class Formulae { + + /** The gravitational constant (meters per second squared). */ + public static final double g0 = 9.81; + + /** + * Gets the required fuel mass to achieve a specified delta-v by a stack of + * vehicles with a specified specific impulse. + * + * @param stackMass the mass of the vehicle stack (kilograms) + * @param deltaV the delta-v to achieve (meters per second) + * @param isp the specific impulse of the engine (seconds) + * + * @return the mass of fuel required for the burn (kilograms) + */ + public static final double getRequiredFuelMass(double stackMass, + double deltaV, double isp) { + return stackMass*(1-Math.exp(-deltaV/(isp*g0))); + } + + /** + * Gets the achieved delta-v from a specified fuel mass by a stack of + * vehicles with a specified specific impulse. + * + * @param stackMass the mass of the vehicle stack (kilograms) + * @param isp the specific impulse of the engine (seconds) + * @param fuelMass the mass of fuel to be burned (kilograms) + * + * @return the delta-v achieved (meters per second) + */ + public static final double getAchievedDeltaV(double stackMass, + double isp, double fuelMass) { + return isp*g0*Math.log(stackMass/(stackMass-fuelMass)); + } +} diff --git a/src/main/java/edu/mit/spacenet/util/GlobalParameters.java b/src/main/java/edu/mit/spacenet/util/GlobalParameters.java new file mode 100644 index 0000000..880e250 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/util/GlobalParameters.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.util; + +import edu.mit.spacenet.scenario.ItemDiscretization; + +/** + * A global access point to scenario options. + * + * @author Paul Grogan + */ +public class GlobalParameters { + private static final int DECIMAL_PRECISION = 1000; + + private static double timePrecision = 0.05; + + /** + * Gets the time precision. + * + * @return the time precision (days) + */ + public static double getTimePrecision() { + return timePrecision; + } + + /** + * Sets the time precision. + * + * @param timePrecision the time precision (days) + */ + public static void setTimePrecision(double timePrecision) { + GlobalParameters.timePrecision = timePrecision; + } + + /** + * Gets the rounded time according to the time precision. + * + * @param time the raw time (days) + * + * @return the rounded time (days) + */ + public static double getRoundedTime(double time) { + return Math.round(Math.round(time/timePrecision)*timePrecision*DECIMAL_PRECISION)/((double)DECIMAL_PRECISION); + } + + private static double demandPrecision = 0.01; + + /** + * Gets the demand precision. + * + * @return the demand precision (units) + */ + public static double getDemandPrecision() { + return demandPrecision; + } + + /** + * Sets the demand precision. + * + * @param demandPrecision the demand precision (units) + */ + public static void setDemandPrecision(double demandPrecision) { + GlobalParameters.demandPrecision = demandPrecision; + } + + /** + * Gets the rounded demand amount according to the demand precision. + * + * @param demand the raw demand amount + * + * @return the rounded demand amount + */ + public static double getRoundedDemand(double demand) { + return Math.round(demand/demandPrecision)*demandPrecision; + } + + private static double massPrecision = 0.01; + + /** + * Gets the mass precision. + * + * @return the mass precision (kilograms) + */ + public static double getMassPrecision() { + return massPrecision; + } + + /** + * Sets the mass precision. + * + * @param massPrecision the mass precision (kilograms) + */ + public static void setMassPrecision(double massPrecision) { + GlobalParameters.massPrecision = massPrecision; + } + + /** + * Gets the rounded mass according to the mass precision. + * + * @param mass the raw mass (kilograms) + * + * @return the rounded mass (kilograms) + */ + public static double getRoundedMass(double mass) { + return Math.round(mass/massPrecision)*massPrecision; + } + + private static double volumePrecision = 0.000001; + + /** + * Gets the volume precision. + * + * @return the volume precision (cubic meters) + */ + public static double getVolumePrecision() { + return volumePrecision; + } + + /** + * Sets the volume precision. + * + * @param volumePrecision the volume precision (cubic meters) + */ + public static void setVolumePrecision(double volumePrecision) { + GlobalParameters.volumePrecision = volumePrecision; + } + + /** + * Gets the rounded volume according to the volume precision. + * + * @param volume the raw volume (cubic meters) + * + * @return the rounded volume (cubic meters) + */ + public static double getRoundedVolume(double volume) { + return Math.round(volume/volumePrecision)*volumePrecision; + } + + private static boolean volumeConstrained = false; + + /** + * Sets whether volume constraints should be active. + * + * @param volumeConstrained true if volume constraints are active, false otherwise + */ + public static void setVolumeConstrained(boolean volumeConstrained) { + GlobalParameters.volumeConstrained = volumeConstrained; + } + + /** + * Gets whether volume constraints are active. + * + * @return true if volume constraints are active, false otherwise + */ + public static boolean isVolumeConstrained() { + return volumeConstrained; + } + + private static boolean environmentConstrained = true; + + /** + * Sets whether environment constraints (pressurized items can only go + * inside pressurized containers) should be active. + * + * @param environmentConstrained true if environment constraints are active, false otherwise + */ + public static void setEnvironmentConstrained(boolean environmentConstrained) { + GlobalParameters.environmentConstrained = environmentConstrained; + } + + /** + * Gets whether environment constraints (pressurized items can only go + * inside pressurized containers) are active. + * + * @return true if environment constraints are active, false otherwise + */ + public static boolean isEnvironmentConstrained() { + return environmentConstrained; + } + + private static ItemDiscretization itemDiscretization = ItemDiscretization.NONE; + + /** + * Gets the item discretization option. + * + * @return how items are discretized + */ + public static ItemDiscretization getItemDiscretization() { + return itemDiscretization; + } + + /** + * Sets the item discretization option. + * + * @param itemDiscretization how items are discretized + */ + public static void setItemDiscretization(ItemDiscretization itemDiscretization) { + GlobalParameters.itemDiscretization = itemDiscretization; + } + + private static double itemAggregation = 0; + + /** + * Gets the item aggregation point, which ranges between 0 and 1. 0 + * aggregates whole items at the first partial demand, 1 aggregates whole + * items after demands totaling one unit. + * + * @return the item aggregation point (between 0 and 1) + */ + public static double getItemAggregation() { + return itemAggregation; + } + + /** + * Sets the item aggregation point, which ranges between 0 and 1. 0 + * aggregates whole items at the first partial demand, 1 aggregates whole + * items after demands totaling one unit. + * + * @param itemAggregation the item aggregation point (between 0 and 1) + */ + public static void setItemAggregation(double itemAggregation) { + if(itemAggregation < 0) itemAggregation = 0; + else if(itemAggregation > 1) itemAggregation = 1; + GlobalParameters.itemAggregation = itemAggregation; + } + + private static boolean scavengeSpares = false; + + /** + * Gets whether spares can be scavenged from decommissioned elements. + * + * @return true if spares can be scavenged, false otherwise + */ + public static boolean isScavengeSpares() { + return scavengeSpares; + } + + /** + * Sets whether spares can be scavenged from decommissioned elements. + * + * @param scavengeSpares true if spares can be scavenged, false otherwise + */ + public static void setScavengeSpares(boolean scavengeSpares) { + GlobalParameters.scavengeSpares = scavengeSpares; + } +} diff --git a/src/main/java/edu/mit/spacenet/util/IconLibrary.java b/src/main/java/edu/mit/spacenet/util/IconLibrary.java new file mode 100644 index 0000000..e3ee947 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/util/IconLibrary.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.util; + +import java.util.HashMap; +import java.util.Map; + +import javax.swing.ImageIcon; + +/** + * Loads and stores all of the icons in one place for quick retrieval. + */ +public class IconLibrary { + private static Map library; + private static String[] files = { + "icons/spacenet_icon_16.png", + "icons/spacenet_icon_32.png", + "icons/sun_icon.png", + "icons/venus_icon.png", + "icons/earth_icon.png", + "icons/moon_icon.png", + "icons/mars_icon.png", + "icons/phobos_icon.png", + "icons/jupiter_icon.png", + "icons/earth_moon_icon.png", + "icons/earth_mars_icon.png", + "icons/solar_icon.png", + "icons/bullet_purple.png", + "icons/bullet_red.png", + "icons/bullet_green.png", + "icons/bullet_yellow.png", + "icons/edge_yellow.png", + "icons/edge_red.png", + "icons/edge_green.png", + "icons/bullet_pink.png", + "icons/bullet_blue.png", + "icons/bullet_wrench.png", + "icons/clock_play.png", + "icons/clock_pause.png", + "icons/clock_stop.png", + "icons/clock_red.png", + "icons/brick.png", + "icons/user.png", + "icons/user_female.png", + "icons/user_green.png", + "icons/user_orange.png", + "icons/user_red.png", + "icons/package.png", + "icons/lorry.png", + "icons/car.png", + "icons/crew_module.png", + "icons/service_module.png", + "icons/ascent_stage.png", + "icons/descent_stage.png", + "icons/lunar_lander.png", + "icons/crew_capsule.png", + "icons/launch_abort.png", + "icons/ares_i_fs.png", + "icons/ares_i_us.png", + "icons/ares_v_srbs.png", + "icons/ares_v_core.png", + "icons/ares_v_eds.png", + "icons/astronaut_white.png", + "icons/astronaut_orange.png", + "icons/shuttle.png", + "icons/orbiter.png", + "icons/habitat.png", + "icons/power_supply.png", + "icons/comment.png", + "icons/add.png", + "icons/arrow_right.png", + "icons/delete.png", + "icons/arrow_switch.png", + "icons/comment.png", + "icons/flame.png", + "icons/bullet_red.png", + "icons/bullet_black.png", + "icons/door_open.png", + "icons/flag_blue.png", + "icons/flag_red.png", + "icons/flag_green.png", + "icons/flag_yellow.png", + "icons/database.png", + "icons/page_white_excel.png", + "icons/database_edit.png", + "icons/database_yellow.png", + "icons/database_refresh.png", + "icons/database_go.png", + "icons/folder_explore.png", + "icons/cog_edit.png"}; + + /** + * Gets the icon. + * + * @param name the icon name (file name without extension, + * e.g. icons/icon_name.png is icon_name) + * + * @return the icon + */ + public static ImageIcon getIcon(String name) { + if(library==null) initialize(); + return library.get(name); + } + + /** + * Initializes the library. + */ + private static void initialize() { + library = new HashMap(); + for(String file : files) { + try { + library.put(file.substring(file.lastIndexOf('/')+1, file.lastIndexOf(".")), + new ImageIcon(ClassLoader.getSystemResource(file))); + } catch(Exception ex) { + System.err.println("An error occurred while loading image " + file); + ex.printStackTrace(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/util/IdGenerator.java b/src/main/java/edu/mit/spacenet/util/IdGenerator.java new file mode 100644 index 0000000..d032f9d --- /dev/null +++ b/src/main/java/edu/mit/spacenet/util/IdGenerator.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.util; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Keeps track of the sequence of unique identifiers that are assigned to + * newly instantiated items. + * + * @author Paul Grogan + */ +public class IdGenerator { + private static AtomicInteger uid = new AtomicInteger(1); + + /** + * Gets the next unique identifier in the sequence. + * + * @return the next unique identifier + */ + public static int getUid() { + return uid.getAndIncrement(); + } + + /** + * Sets the sequence of unique identifies to restart after the last uid. + * + * @param lastUid the last uid + */ + public static void setLastUid(int lastUid) { + uid.set(lastUid+1); + } +} \ No newline at end of file diff --git a/src/main/java/edu/mit/spacenet/util/SerializeUtil.java b/src/main/java/edu/mit/spacenet/util/SerializeUtil.java new file mode 100644 index 0000000..405eb61 --- /dev/null +++ b/src/main/java/edu/mit/spacenet/util/SerializeUtil.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 MIT Strategic Engineering Research Group + * + * This file is part of SpaceNet 2.5r2. + * + * SpaceNet 2.5r2 is free software: you can 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. + * + * SpaceNet 2.5r2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SpaceNet 2.5r2. If not, see . + */ +package edu.mit.spacenet.util; + +import com.thoughtworks.xstream.XStream; + +/** + * A utility class used to serialize (clone) objects. + * + * @author Paul Grogan + */ +public class SerializeUtil { + + /** + * Creates a serialized version of an object. + * + * @param object the object to serialize + * + * @return the serialized object + */ + public static Object deepClone(Object object) { + XStream xStream = new XStream(); + return xStream.fromXML((String)xStream.toXML(object)); + } +} diff --git a/src/main/resources/icons/EARTH.jpg b/src/main/resources/icons/EARTH.jpg new file mode 100644 index 0000000..9f1ee1d Binary files /dev/null and b/src/main/resources/icons/EARTH.jpg differ diff --git a/src/main/resources/icons/MARS.jpg b/src/main/resources/icons/MARS.jpg new file mode 100644 index 0000000..746910d Binary files /dev/null and b/src/main/resources/icons/MARS.jpg differ diff --git a/src/main/resources/icons/MOON.jpg b/src/main/resources/icons/MOON.jpg new file mode 100644 index 0000000..761edf4 Binary files /dev/null and b/src/main/resources/icons/MOON.jpg differ diff --git a/src/main/resources/icons/add.png b/src/main/resources/icons/add.png new file mode 100644 index 0000000..6332fef Binary files /dev/null and b/src/main/resources/icons/add.png differ diff --git a/src/main/resources/icons/aeroshell.png b/src/main/resources/icons/aeroshell.png new file mode 100644 index 0000000..b16b00b Binary files /dev/null and b/src/main/resources/icons/aeroshell.png differ diff --git a/src/main/resources/icons/ams.png b/src/main/resources/icons/ams.png new file mode 100644 index 0000000..672d4fd Binary files /dev/null and b/src/main/resources/icons/ams.png differ diff --git a/src/main/resources/icons/application_add.png b/src/main/resources/icons/application_add.png new file mode 100644 index 0000000..2e94507 Binary files /dev/null and b/src/main/resources/icons/application_add.png differ diff --git a/src/main/resources/icons/application_delete.png b/src/main/resources/icons/application_delete.png new file mode 100644 index 0000000..0a335ac Binary files /dev/null and b/src/main/resources/icons/application_delete.png differ diff --git a/src/main/resources/icons/application_double.png b/src/main/resources/icons/application_double.png new file mode 100644 index 0000000..647592f Binary files /dev/null and b/src/main/resources/icons/application_double.png differ diff --git a/src/main/resources/icons/application_edit.png b/src/main/resources/icons/application_edit.png new file mode 100644 index 0000000..fb2efb8 Binary files /dev/null and b/src/main/resources/icons/application_edit.png differ diff --git a/src/main/resources/icons/application_go.png b/src/main/resources/icons/application_go.png new file mode 100644 index 0000000..5cc2b0d Binary files /dev/null and b/src/main/resources/icons/application_go.png differ diff --git a/src/main/resources/icons/ares_i_fs.png b/src/main/resources/icons/ares_i_fs.png new file mode 100644 index 0000000..9e43bcb Binary files /dev/null and b/src/main/resources/icons/ares_i_fs.png differ diff --git a/src/main/resources/icons/ares_i_us.png b/src/main/resources/icons/ares_i_us.png new file mode 100644 index 0000000..43a6de1 Binary files /dev/null and b/src/main/resources/icons/ares_i_us.png differ diff --git a/src/main/resources/icons/ares_v_core.png b/src/main/resources/icons/ares_v_core.png new file mode 100644 index 0000000..2517c18 Binary files /dev/null and b/src/main/resources/icons/ares_v_core.png differ diff --git a/src/main/resources/icons/ares_v_eds.png b/src/main/resources/icons/ares_v_eds.png new file mode 100644 index 0000000..e4fce45 Binary files /dev/null and b/src/main/resources/icons/ares_v_eds.png differ diff --git a/src/main/resources/icons/ares_v_is.png b/src/main/resources/icons/ares_v_is.png new file mode 100644 index 0000000..648c1ff Binary files /dev/null and b/src/main/resources/icons/ares_v_is.png differ diff --git a/src/main/resources/icons/ares_v_plf.png b/src/main/resources/icons/ares_v_plf.png new file mode 100644 index 0000000..36aa840 Binary files /dev/null and b/src/main/resources/icons/ares_v_plf.png differ diff --git a/src/main/resources/icons/ares_v_srbs.png b/src/main/resources/icons/ares_v_srbs.png new file mode 100644 index 0000000..8c05446 Binary files /dev/null and b/src/main/resources/icons/ares_v_srbs.png differ diff --git a/src/main/resources/icons/arrow_refresh.png b/src/main/resources/icons/arrow_refresh.png new file mode 100644 index 0000000..0de2656 Binary files /dev/null and b/src/main/resources/icons/arrow_refresh.png differ diff --git a/src/main/resources/icons/arrow_right.png b/src/main/resources/icons/arrow_right.png new file mode 100644 index 0000000..b1a1819 Binary files /dev/null and b/src/main/resources/icons/arrow_right.png differ diff --git a/src/main/resources/icons/arrow_switch.png b/src/main/resources/icons/arrow_switch.png new file mode 100644 index 0000000..258c16c Binary files /dev/null and b/src/main/resources/icons/arrow_switch.png differ diff --git a/src/main/resources/icons/ascent_stage.png b/src/main/resources/icons/ascent_stage.png new file mode 100644 index 0000000..b90df6f Binary files /dev/null and b/src/main/resources/icons/ascent_stage.png differ diff --git a/src/main/resources/icons/asterisk.png b/src/main/resources/icons/asterisk.png new file mode 100644 index 0000000..3ce935c Binary files /dev/null and b/src/main/resources/icons/asterisk.png differ diff --git a/src/main/resources/icons/asterisk_add.png b/src/main/resources/icons/asterisk_add.png new file mode 100644 index 0000000..53e26b2 Binary files /dev/null and b/src/main/resources/icons/asterisk_add.png differ diff --git a/src/main/resources/icons/asterisk_delete.png b/src/main/resources/icons/asterisk_delete.png new file mode 100644 index 0000000..763c241 Binary files /dev/null and b/src/main/resources/icons/asterisk_delete.png differ diff --git a/src/main/resources/icons/asterisk_edit.png b/src/main/resources/icons/asterisk_edit.png new file mode 100644 index 0000000..e57ecd1 Binary files /dev/null and b/src/main/resources/icons/asterisk_edit.png differ diff --git a/src/main/resources/icons/astronaut_orange.png b/src/main/resources/icons/astronaut_orange.png new file mode 100644 index 0000000..b009743 Binary files /dev/null and b/src/main/resources/icons/astronaut_orange.png differ diff --git a/src/main/resources/icons/astronaut_white.png b/src/main/resources/icons/astronaut_white.png new file mode 100644 index 0000000..c360408 Binary files /dev/null and b/src/main/resources/icons/astronaut_white.png differ diff --git a/src/main/resources/icons/atv.png b/src/main/resources/icons/atv.png new file mode 100644 index 0000000..fb467a2 Binary files /dev/null and b/src/main/resources/icons/atv.png differ diff --git a/src/main/resources/icons/basket.png b/src/main/resources/icons/basket.png new file mode 100644 index 0000000..b0686d7 Binary files /dev/null and b/src/main/resources/icons/basket.png differ diff --git a/src/main/resources/icons/basket_add.png b/src/main/resources/icons/basket_add.png new file mode 100644 index 0000000..3554368 Binary files /dev/null and b/src/main/resources/icons/basket_add.png differ diff --git a/src/main/resources/icons/basket_delete.png b/src/main/resources/icons/basket_delete.png new file mode 100644 index 0000000..1349974 Binary files /dev/null and b/src/main/resources/icons/basket_delete.png differ diff --git a/src/main/resources/icons/basket_edit.png b/src/main/resources/icons/basket_edit.png new file mode 100644 index 0000000..8138bbd Binary files /dev/null and b/src/main/resources/icons/basket_edit.png differ diff --git a/src/main/resources/icons/basket_go.png b/src/main/resources/icons/basket_go.png new file mode 100644 index 0000000..ed8b9a5 Binary files /dev/null and b/src/main/resources/icons/basket_go.png differ diff --git a/src/main/resources/icons/basket_put.png b/src/main/resources/icons/basket_put.png new file mode 100644 index 0000000..be62faa Binary files /dev/null and b/src/main/resources/icons/basket_put.png differ diff --git a/src/main/resources/icons/basket_remove.png b/src/main/resources/icons/basket_remove.png new file mode 100644 index 0000000..04dd7fd Binary files /dev/null and b/src/main/resources/icons/basket_remove.png differ diff --git a/src/main/resources/icons/book_add.png b/src/main/resources/icons/book_add.png new file mode 100644 index 0000000..8ea0f2b Binary files /dev/null and b/src/main/resources/icons/book_add.png differ diff --git a/src/main/resources/icons/book_delete.png b/src/main/resources/icons/book_delete.png new file mode 100644 index 0000000..1a02521 Binary files /dev/null and b/src/main/resources/icons/book_delete.png differ diff --git a/src/main/resources/icons/book_open.png b/src/main/resources/icons/book_open.png new file mode 100644 index 0000000..7d863f9 Binary files /dev/null and b/src/main/resources/icons/book_open.png differ diff --git a/src/main/resources/icons/book_open_lightning.png b/src/main/resources/icons/book_open_lightning.png new file mode 100644 index 0000000..6e6ac00 Binary files /dev/null and b/src/main/resources/icons/book_open_lightning.png differ diff --git a/src/main/resources/icons/book_open_refresh.png b/src/main/resources/icons/book_open_refresh.png new file mode 100644 index 0000000..475773b Binary files /dev/null and b/src/main/resources/icons/book_open_refresh.png differ diff --git a/src/main/resources/icons/box.png b/src/main/resources/icons/box.png new file mode 100644 index 0000000..8443c23 Binary files /dev/null and b/src/main/resources/icons/box.png differ diff --git a/src/main/resources/icons/box_in.png b/src/main/resources/icons/box_in.png new file mode 100644 index 0000000..28002ff Binary files /dev/null and b/src/main/resources/icons/box_in.png differ diff --git a/src/main/resources/icons/box_lightning.png b/src/main/resources/icons/box_lightning.png new file mode 100644 index 0000000..968627f Binary files /dev/null and b/src/main/resources/icons/box_lightning.png differ diff --git a/src/main/resources/icons/box_out.png b/src/main/resources/icons/box_out.png new file mode 100644 index 0000000..ffb05c5 Binary files /dev/null and b/src/main/resources/icons/box_out.png differ diff --git a/src/main/resources/icons/brick.png b/src/main/resources/icons/brick.png new file mode 100644 index 0000000..7851cf3 Binary files /dev/null and b/src/main/resources/icons/brick.png differ diff --git a/src/main/resources/icons/brick_add.png b/src/main/resources/icons/brick_add.png new file mode 100644 index 0000000..fac186b Binary files /dev/null and b/src/main/resources/icons/brick_add.png differ diff --git a/src/main/resources/icons/brick_delete.png b/src/main/resources/icons/brick_delete.png new file mode 100644 index 0000000..3a8c373 Binary files /dev/null and b/src/main/resources/icons/brick_delete.png differ diff --git a/src/main/resources/icons/brick_edit.png b/src/main/resources/icons/brick_edit.png new file mode 100644 index 0000000..eb06df3 Binary files /dev/null and b/src/main/resources/icons/brick_edit.png differ diff --git a/src/main/resources/icons/brick_go.png b/src/main/resources/icons/brick_go.png new file mode 100644 index 0000000..fe0d335 Binary files /dev/null and b/src/main/resources/icons/brick_go.png differ diff --git a/src/main/resources/icons/bullet_black.png b/src/main/resources/icons/bullet_black.png new file mode 100644 index 0000000..5761970 Binary files /dev/null and b/src/main/resources/icons/bullet_black.png differ diff --git a/src/main/resources/icons/bullet_blue.png b/src/main/resources/icons/bullet_blue.png new file mode 100644 index 0000000..a7651ec Binary files /dev/null and b/src/main/resources/icons/bullet_blue.png differ diff --git a/src/main/resources/icons/bullet_error.png b/src/main/resources/icons/bullet_error.png new file mode 100644 index 0000000..bca2b49 Binary files /dev/null and b/src/main/resources/icons/bullet_error.png differ diff --git a/src/main/resources/icons/bullet_green.png b/src/main/resources/icons/bullet_green.png new file mode 100644 index 0000000..058ad26 Binary files /dev/null and b/src/main/resources/icons/bullet_green.png differ diff --git a/src/main/resources/icons/bullet_orange.png b/src/main/resources/icons/bullet_orange.png new file mode 100644 index 0000000..fa63024 Binary files /dev/null and b/src/main/resources/icons/bullet_orange.png differ diff --git a/src/main/resources/icons/bullet_pink.png b/src/main/resources/icons/bullet_pink.png new file mode 100644 index 0000000..0c9f73e Binary files /dev/null and b/src/main/resources/icons/bullet_pink.png differ diff --git a/src/main/resources/icons/bullet_purple.png b/src/main/resources/icons/bullet_purple.png new file mode 100644 index 0000000..52ba503 Binary files /dev/null and b/src/main/resources/icons/bullet_purple.png differ diff --git a/src/main/resources/icons/bullet_red.png b/src/main/resources/icons/bullet_red.png new file mode 100644 index 0000000..0cd8031 Binary files /dev/null and b/src/main/resources/icons/bullet_red.png differ diff --git a/src/main/resources/icons/bullet_white.png b/src/main/resources/icons/bullet_white.png new file mode 100644 index 0000000..a9af8d4 Binary files /dev/null and b/src/main/resources/icons/bullet_white.png differ diff --git a/src/main/resources/icons/bullet_wrench.png b/src/main/resources/icons/bullet_wrench.png new file mode 100644 index 0000000..67817e6 Binary files /dev/null and b/src/main/resources/icons/bullet_wrench.png differ diff --git a/src/main/resources/icons/bullet_yellow.png b/src/main/resources/icons/bullet_yellow.png new file mode 100644 index 0000000..6469cea Binary files /dev/null and b/src/main/resources/icons/bullet_yellow.png differ diff --git a/src/main/resources/icons/car.png b/src/main/resources/icons/car.png new file mode 100644 index 0000000..4f3a770 Binary files /dev/null and b/src/main/resources/icons/car.png differ diff --git a/src/main/resources/icons/clock.png b/src/main/resources/icons/clock.png new file mode 100644 index 0000000..e2672c2 Binary files /dev/null and b/src/main/resources/icons/clock.png differ diff --git a/src/main/resources/icons/clock_add.png b/src/main/resources/icons/clock_add.png new file mode 100644 index 0000000..598b839 Binary files /dev/null and b/src/main/resources/icons/clock_add.png differ diff --git a/src/main/resources/icons/clock_delete.png b/src/main/resources/icons/clock_delete.png new file mode 100644 index 0000000..8bf9efe Binary files /dev/null and b/src/main/resources/icons/clock_delete.png differ diff --git a/src/main/resources/icons/clock_edit.png b/src/main/resources/icons/clock_edit.png new file mode 100644 index 0000000..7d35718 Binary files /dev/null and b/src/main/resources/icons/clock_edit.png differ diff --git a/src/main/resources/icons/clock_go.png b/src/main/resources/icons/clock_go.png new file mode 100644 index 0000000..a1a24d3 Binary files /dev/null and b/src/main/resources/icons/clock_go.png differ diff --git a/src/main/resources/icons/clock_pause.png b/src/main/resources/icons/clock_pause.png new file mode 100644 index 0000000..ba74725 Binary files /dev/null and b/src/main/resources/icons/clock_pause.png differ diff --git a/src/main/resources/icons/clock_play.png b/src/main/resources/icons/clock_play.png new file mode 100644 index 0000000..fb4ebc8 Binary files /dev/null and b/src/main/resources/icons/clock_play.png differ diff --git a/src/main/resources/icons/clock_red.png b/src/main/resources/icons/clock_red.png new file mode 100644 index 0000000..2842cc3 Binary files /dev/null and b/src/main/resources/icons/clock_red.png differ diff --git a/src/main/resources/icons/clock_stop.png b/src/main/resources/icons/clock_stop.png new file mode 100644 index 0000000..6fe8a6f Binary files /dev/null and b/src/main/resources/icons/clock_stop.png differ diff --git a/src/main/resources/icons/cog.png b/src/main/resources/icons/cog.png new file mode 100644 index 0000000..67de2c6 Binary files /dev/null and b/src/main/resources/icons/cog.png differ diff --git a/src/main/resources/icons/cog_add.png b/src/main/resources/icons/cog_add.png new file mode 100644 index 0000000..04f22ba Binary files /dev/null and b/src/main/resources/icons/cog_add.png differ diff --git a/src/main/resources/icons/cog_delete.png b/src/main/resources/icons/cog_delete.png new file mode 100644 index 0000000..8ce71c4 Binary files /dev/null and b/src/main/resources/icons/cog_delete.png differ diff --git a/src/main/resources/icons/cog_edit.png b/src/main/resources/icons/cog_edit.png new file mode 100644 index 0000000..47b75a4 Binary files /dev/null and b/src/main/resources/icons/cog_edit.png differ diff --git a/src/main/resources/icons/cog_go.png b/src/main/resources/icons/cog_go.png new file mode 100644 index 0000000..3262767 Binary files /dev/null and b/src/main/resources/icons/cog_go.png differ diff --git a/src/main/resources/icons/comment.png b/src/main/resources/icons/comment.png new file mode 100644 index 0000000..7bc9233 Binary files /dev/null and b/src/main/resources/icons/comment.png differ diff --git a/src/main/resources/icons/comment_add.png b/src/main/resources/icons/comment_add.png new file mode 100644 index 0000000..75e78de Binary files /dev/null and b/src/main/resources/icons/comment_add.png differ diff --git a/src/main/resources/icons/comment_delete.png b/src/main/resources/icons/comment_delete.png new file mode 100644 index 0000000..643fdbe Binary files /dev/null and b/src/main/resources/icons/comment_delete.png differ diff --git a/src/main/resources/icons/comment_edit.png b/src/main/resources/icons/comment_edit.png new file mode 100644 index 0000000..73db110 Binary files /dev/null and b/src/main/resources/icons/comment_edit.png differ diff --git a/src/main/resources/icons/comment_go.png b/src/main/resources/icons/comment_go.png new file mode 100644 index 0000000..f563b3e Binary files /dev/null and b/src/main/resources/icons/comment_go.png differ diff --git a/src/main/resources/icons/control_end.png b/src/main/resources/icons/control_end.png new file mode 100644 index 0000000..036e04d Binary files /dev/null and b/src/main/resources/icons/control_end.png differ diff --git a/src/main/resources/icons/control_fastforward.png b/src/main/resources/icons/control_fastforward.png new file mode 100644 index 0000000..31f7fd3 Binary files /dev/null and b/src/main/resources/icons/control_fastforward.png differ diff --git a/src/main/resources/icons/control_pause.png b/src/main/resources/icons/control_pause.png new file mode 100644 index 0000000..2d9ce9c Binary files /dev/null and b/src/main/resources/icons/control_pause.png differ diff --git a/src/main/resources/icons/control_play.png b/src/main/resources/icons/control_play.png new file mode 100644 index 0000000..0846555 Binary files /dev/null and b/src/main/resources/icons/control_play.png differ diff --git a/src/main/resources/icons/control_rewind.png b/src/main/resources/icons/control_rewind.png new file mode 100644 index 0000000..c029447 Binary files /dev/null and b/src/main/resources/icons/control_rewind.png differ diff --git a/src/main/resources/icons/control_start.png b/src/main/resources/icons/control_start.png new file mode 100644 index 0000000..7dd1c07 Binary files /dev/null and b/src/main/resources/icons/control_start.png differ diff --git a/src/main/resources/icons/control_stop.png b/src/main/resources/icons/control_stop.png new file mode 100644 index 0000000..893bb60 Binary files /dev/null and b/src/main/resources/icons/control_stop.png differ diff --git a/src/main/resources/icons/crew_capsule.png b/src/main/resources/icons/crew_capsule.png new file mode 100644 index 0000000..563e100 Binary files /dev/null and b/src/main/resources/icons/crew_capsule.png differ diff --git a/src/main/resources/icons/crew_module.png b/src/main/resources/icons/crew_module.png new file mode 100644 index 0000000..f04fc22 Binary files /dev/null and b/src/main/resources/icons/crew_module.png differ diff --git a/src/main/resources/icons/cross.png b/src/main/resources/icons/cross.png new file mode 100644 index 0000000..1514d51 Binary files /dev/null and b/src/main/resources/icons/cross.png differ diff --git a/src/main/resources/icons/cygnus.png b/src/main/resources/icons/cygnus.png new file mode 100644 index 0000000..ff9576c Binary files /dev/null and b/src/main/resources/icons/cygnus.png differ diff --git a/src/main/resources/icons/database.png b/src/main/resources/icons/database.png new file mode 100644 index 0000000..3d09261 Binary files /dev/null and b/src/main/resources/icons/database.png differ diff --git a/src/main/resources/icons/database_edit.png b/src/main/resources/icons/database_edit.png new file mode 100644 index 0000000..e501b66 Binary files /dev/null and b/src/main/resources/icons/database_edit.png differ diff --git a/src/main/resources/icons/database_go.png b/src/main/resources/icons/database_go.png new file mode 100644 index 0000000..61a8556 Binary files /dev/null and b/src/main/resources/icons/database_go.png differ diff --git a/src/main/resources/icons/database_refresh.png b/src/main/resources/icons/database_refresh.png new file mode 100644 index 0000000..ff803be Binary files /dev/null and b/src/main/resources/icons/database_refresh.png differ diff --git a/src/main/resources/icons/database_yellow.png b/src/main/resources/icons/database_yellow.png new file mode 100644 index 0000000..81f9572 Binary files /dev/null and b/src/main/resources/icons/database_yellow.png differ diff --git a/src/main/resources/icons/deimos_icon.png b/src/main/resources/icons/deimos_icon.png new file mode 100644 index 0000000..cdc048d Binary files /dev/null and b/src/main/resources/icons/deimos_icon.png differ diff --git a/src/main/resources/icons/delete.png b/src/main/resources/icons/delete.png new file mode 100644 index 0000000..08f2493 Binary files /dev/null and b/src/main/resources/icons/delete.png differ diff --git a/src/main/resources/icons/descent_stage.png b/src/main/resources/icons/descent_stage.png new file mode 100644 index 0000000..32994f6 Binary files /dev/null and b/src/main/resources/icons/descent_stage.png differ diff --git a/src/main/resources/icons/door_open.png b/src/main/resources/icons/door_open.png new file mode 100644 index 0000000..64bab57 Binary files /dev/null and b/src/main/resources/icons/door_open.png differ diff --git a/src/main/resources/icons/dragon.png b/src/main/resources/icons/dragon.png new file mode 100644 index 0000000..b68e79e Binary files /dev/null and b/src/main/resources/icons/dragon.png differ diff --git a/src/main/resources/icons/earth.png b/src/main/resources/icons/earth.png new file mode 100644 index 0000000..a025c7b Binary files /dev/null and b/src/main/resources/icons/earth.png differ diff --git a/src/main/resources/icons/earth_icon.png b/src/main/resources/icons/earth_icon.png new file mode 100644 index 0000000..74ac212 Binary files /dev/null and b/src/main/resources/icons/earth_icon.png differ diff --git a/src/main/resources/icons/earth_mars_icon.png b/src/main/resources/icons/earth_mars_icon.png new file mode 100644 index 0000000..e4583c3 Binary files /dev/null and b/src/main/resources/icons/earth_mars_icon.png differ diff --git a/src/main/resources/icons/earth_moon_icon.png b/src/main/resources/icons/earth_moon_icon.png new file mode 100644 index 0000000..e1eb182 Binary files /dev/null and b/src/main/resources/icons/earth_moon_icon.png differ diff --git a/src/main/resources/icons/edge_green.png b/src/main/resources/icons/edge_green.png new file mode 100644 index 0000000..fbf67f4 Binary files /dev/null and b/src/main/resources/icons/edge_green.png differ diff --git a/src/main/resources/icons/edge_red.png b/src/main/resources/icons/edge_red.png new file mode 100644 index 0000000..4803a48 Binary files /dev/null and b/src/main/resources/icons/edge_red.png differ diff --git a/src/main/resources/icons/edge_yellow.png b/src/main/resources/icons/edge_yellow.png new file mode 100644 index 0000000..3bfe3d1 Binary files /dev/null and b/src/main/resources/icons/edge_yellow.png differ diff --git a/src/main/resources/icons/elc.png b/src/main/resources/icons/elc.png new file mode 100644 index 0000000..b35b6fb Binary files /dev/null and b/src/main/resources/icons/elc.png differ diff --git a/src/main/resources/icons/error.png b/src/main/resources/icons/error.png new file mode 100644 index 0000000..628cf2d Binary files /dev/null and b/src/main/resources/icons/error.png differ diff --git a/src/main/resources/icons/exclamation.png b/src/main/resources/icons/exclamation.png new file mode 100644 index 0000000..c37bd06 Binary files /dev/null and b/src/main/resources/icons/exclamation.png differ diff --git a/src/main/resources/icons/eye.png b/src/main/resources/icons/eye.png new file mode 100644 index 0000000..564a1a9 Binary files /dev/null and b/src/main/resources/icons/eye.png differ diff --git a/src/main/resources/icons/flag_blue.png b/src/main/resources/icons/flag_blue.png new file mode 100644 index 0000000..003924f Binary files /dev/null and b/src/main/resources/icons/flag_blue.png differ diff --git a/src/main/resources/icons/flag_green.png b/src/main/resources/icons/flag_green.png new file mode 100644 index 0000000..e4bc611 Binary files /dev/null and b/src/main/resources/icons/flag_green.png differ diff --git a/src/main/resources/icons/flag_red.png b/src/main/resources/icons/flag_red.png new file mode 100644 index 0000000..e8a602d Binary files /dev/null and b/src/main/resources/icons/flag_red.png differ diff --git a/src/main/resources/icons/flag_yellow.png b/src/main/resources/icons/flag_yellow.png new file mode 100644 index 0000000..14c89a5 Binary files /dev/null and b/src/main/resources/icons/flag_yellow.png differ diff --git a/src/main/resources/icons/flame.png b/src/main/resources/icons/flame.png new file mode 100644 index 0000000..5a2e49d Binary files /dev/null and b/src/main/resources/icons/flame.png differ diff --git a/src/main/resources/icons/folder_explore.png b/src/main/resources/icons/folder_explore.png new file mode 100644 index 0000000..0ba9391 Binary files /dev/null and b/src/main/resources/icons/folder_explore.png differ diff --git a/src/main/resources/icons/hab_lander.png b/src/main/resources/icons/hab_lander.png new file mode 100644 index 0000000..045899b Binary files /dev/null and b/src/main/resources/icons/hab_lander.png differ diff --git a/src/main/resources/icons/habitat.png b/src/main/resources/icons/habitat.png new file mode 100644 index 0000000..f9b1d2a Binary files /dev/null and b/src/main/resources/icons/habitat.png differ diff --git a/src/main/resources/icons/htv.png b/src/main/resources/icons/htv.png new file mode 100644 index 0000000..5a17841 Binary files /dev/null and b/src/main/resources/icons/htv.png differ diff --git a/src/main/resources/icons/information.png b/src/main/resources/icons/information.png new file mode 100644 index 0000000..12cd1ae Binary files /dev/null and b/src/main/resources/icons/information.png differ diff --git a/src/main/resources/icons/iss.png b/src/main/resources/icons/iss.png new file mode 100644 index 0000000..0687b63 Binary files /dev/null and b/src/main/resources/icons/iss.png differ diff --git a/src/main/resources/icons/jupiter_icon.png b/src/main/resources/icons/jupiter_icon.png new file mode 100644 index 0000000..8b4472a Binary files /dev/null and b/src/main/resources/icons/jupiter_icon.png differ diff --git a/src/main/resources/icons/launch_abort.png b/src/main/resources/icons/launch_abort.png new file mode 100644 index 0000000..5d8b7ca Binary files /dev/null and b/src/main/resources/icons/launch_abort.png differ diff --git a/src/main/resources/icons/lh2_drop_tank.png b/src/main/resources/icons/lh2_drop_tank.png new file mode 100644 index 0000000..1cc9838 Binary files /dev/null and b/src/main/resources/icons/lh2_drop_tank.png differ diff --git a/src/main/resources/icons/lh2_tank.png b/src/main/resources/icons/lh2_tank.png new file mode 100644 index 0000000..fa2cad4 Binary files /dev/null and b/src/main/resources/icons/lh2_tank.png differ diff --git a/src/main/resources/icons/lightning.png b/src/main/resources/icons/lightning.png new file mode 100644 index 0000000..9680afd Binary files /dev/null and b/src/main/resources/icons/lightning.png differ diff --git a/src/main/resources/icons/lightning_go.png b/src/main/resources/icons/lightning_go.png new file mode 100644 index 0000000..29039e6 Binary files /dev/null and b/src/main/resources/icons/lightning_go.png differ diff --git a/src/main/resources/icons/lorry.png b/src/main/resources/icons/lorry.png new file mode 100644 index 0000000..8f95f5a Binary files /dev/null and b/src/main/resources/icons/lorry.png differ diff --git a/src/main/resources/icons/lunar_lander.png b/src/main/resources/icons/lunar_lander.png new file mode 100644 index 0000000..9d8e3c1 Binary files /dev/null and b/src/main/resources/icons/lunar_lander.png differ diff --git a/src/main/resources/icons/mars.png b/src/main/resources/icons/mars.png new file mode 100644 index 0000000..5bd59d7 Binary files /dev/null and b/src/main/resources/icons/mars.png differ diff --git a/src/main/resources/icons/mars_icon.png b/src/main/resources/icons/mars_icon.png new file mode 100644 index 0000000..b017bef Binary files /dev/null and b/src/main/resources/icons/mars_icon.png differ diff --git a/src/main/resources/icons/mit_footer.png b/src/main/resources/icons/mit_footer.png new file mode 100644 index 0000000..87bf2ed Binary files /dev/null and b/src/main/resources/icons/mit_footer.png differ diff --git a/src/main/resources/icons/mlm.png b/src/main/resources/icons/mlm.png new file mode 100644 index 0000000..b080ded Binary files /dev/null and b/src/main/resources/icons/mlm.png differ diff --git a/src/main/resources/icons/moon.png b/src/main/resources/icons/moon.png new file mode 100644 index 0000000..db2fc94 Binary files /dev/null and b/src/main/resources/icons/moon.png differ diff --git a/src/main/resources/icons/moon_icon.png b/src/main/resources/icons/moon_icon.png new file mode 100644 index 0000000..aafab60 Binary files /dev/null and b/src/main/resources/icons/moon_icon.png differ diff --git a/src/main/resources/icons/mth.png b/src/main/resources/icons/mth.png new file mode 100644 index 0000000..9afa7cb Binary files /dev/null and b/src/main/resources/icons/mth.png differ diff --git a/src/main/resources/icons/node.gif b/src/main/resources/icons/node.gif new file mode 100644 index 0000000..f94b70c Binary files /dev/null and b/src/main/resources/icons/node.gif differ diff --git a/src/main/resources/icons/node_selected.gif b/src/main/resources/icons/node_selected.gif new file mode 100644 index 0000000..9da24e2 Binary files /dev/null and b/src/main/resources/icons/node_selected.gif differ diff --git a/src/main/resources/icons/ntr.png b/src/main/resources/icons/ntr.png new file mode 100644 index 0000000..c900a1e Binary files /dev/null and b/src/main/resources/icons/ntr.png differ diff --git a/src/main/resources/icons/orbiter.png b/src/main/resources/icons/orbiter.png new file mode 100644 index 0000000..4d5454e Binary files /dev/null and b/src/main/resources/icons/orbiter.png differ diff --git a/src/main/resources/icons/package.png b/src/main/resources/icons/package.png new file mode 100644 index 0000000..da3c2a2 Binary files /dev/null and b/src/main/resources/icons/package.png differ diff --git a/src/main/resources/icons/package_add.png b/src/main/resources/icons/package_add.png new file mode 100644 index 0000000..9c8a9da Binary files /dev/null and b/src/main/resources/icons/package_add.png differ diff --git a/src/main/resources/icons/package_delete.png b/src/main/resources/icons/package_delete.png new file mode 100644 index 0000000..86f7fbc Binary files /dev/null and b/src/main/resources/icons/package_delete.png differ diff --git a/src/main/resources/icons/package_edit.png b/src/main/resources/icons/package_edit.png new file mode 100644 index 0000000..afb5ae8 Binary files /dev/null and b/src/main/resources/icons/package_edit.png differ diff --git a/src/main/resources/icons/package_go.png b/src/main/resources/icons/package_go.png new file mode 100644 index 0000000..aace63a Binary files /dev/null and b/src/main/resources/icons/package_go.png differ diff --git a/src/main/resources/icons/page_white.png b/src/main/resources/icons/page_white.png new file mode 100644 index 0000000..8b8b1ca Binary files /dev/null and b/src/main/resources/icons/page_white.png differ diff --git a/src/main/resources/icons/page_white_edit.png b/src/main/resources/icons/page_white_edit.png new file mode 100644 index 0000000..b93e776 Binary files /dev/null and b/src/main/resources/icons/page_white_edit.png differ diff --git a/src/main/resources/icons/page_white_excel.png b/src/main/resources/icons/page_white_excel.png new file mode 100644 index 0000000..b977d7e Binary files /dev/null and b/src/main/resources/icons/page_white_excel.png differ diff --git a/src/main/resources/icons/phobos_icon.png b/src/main/resources/icons/phobos_icon.png new file mode 100644 index 0000000..6eec178 Binary files /dev/null and b/src/main/resources/icons/phobos_icon.png differ diff --git a/src/main/resources/icons/pmm.png b/src/main/resources/icons/pmm.png new file mode 100644 index 0000000..fb057ef Binary files /dev/null and b/src/main/resources/icons/pmm.png differ diff --git a/src/main/resources/icons/power_supply.png b/src/main/resources/icons/power_supply.png new file mode 100644 index 0000000..1192d36 Binary files /dev/null and b/src/main/resources/icons/power_supply.png differ diff --git a/src/main/resources/icons/priority.png b/src/main/resources/icons/priority.png new file mode 100644 index 0000000..bfe461b Binary files /dev/null and b/src/main/resources/icons/priority.png differ diff --git a/src/main/resources/icons/progress.png b/src/main/resources/icons/progress.png new file mode 100644 index 0000000..69a8437 Binary files /dev/null and b/src/main/resources/icons/progress.png differ diff --git a/src/main/resources/icons/readme.txt b/src/main/resources/icons/readme.txt new file mode 100644 index 0000000..2cf67dc --- /dev/null +++ b/src/main/resources/icons/readme.txt @@ -0,0 +1,22 @@ +Silk icon set 1.3 + +_________________________________________ +Mark James +http://www.famfamfam.com/lab/icons/silk/ +_________________________________________ + +This work is licensed under a +Creative Commons Attribution 2.5 License. +[ http://creativecommons.org/licenses/by/2.5/ ] + +This means you may use it for any purpose, +and make any changes you like. +All I ask is that you include a link back +to this page in your credits. + +Are you using this icon set? Send me an email +(including a link or picture if available) to +mjames@gmail.com + +Any other questions about this icon set please +contact mjames@gmail.com \ No newline at end of file diff --git a/src/main/resources/icons/service_module.png b/src/main/resources/icons/service_module.png new file mode 100644 index 0000000..28102a7 Binary files /dev/null and b/src/main/resources/icons/service_module.png differ diff --git a/src/main/resources/icons/shuttle.png b/src/main/resources/icons/shuttle.png new file mode 100644 index 0000000..636b889 Binary files /dev/null and b/src/main/resources/icons/shuttle.png differ diff --git a/src/main/resources/icons/solar_icon.png b/src/main/resources/icons/solar_icon.png new file mode 100644 index 0000000..54fdd5a Binary files /dev/null and b/src/main/resources/icons/solar_icon.png differ diff --git a/src/main/resources/icons/soyuz.png b/src/main/resources/icons/soyuz.png new file mode 100644 index 0000000..fabd118 Binary files /dev/null and b/src/main/resources/icons/soyuz.png differ diff --git a/src/main/resources/icons/spacenet_icon_16.png b/src/main/resources/icons/spacenet_icon_16.png new file mode 100644 index 0000000..5d68aad Binary files /dev/null and b/src/main/resources/icons/spacenet_icon_16.png differ diff --git a/src/main/resources/icons/spacenet_icon_32.png b/src/main/resources/icons/spacenet_icon_32.png new file mode 100644 index 0000000..8c861c3 Binary files /dev/null and b/src/main/resources/icons/spacenet_icon_32.png differ diff --git a/src/main/resources/icons/spacenet_splash.png b/src/main/resources/icons/spacenet_splash.png new file mode 100644 index 0000000..f6c627f Binary files /dev/null and b/src/main/resources/icons/spacenet_splash.png differ diff --git a/src/main/resources/icons/sun.png b/src/main/resources/icons/sun.png new file mode 100644 index 0000000..818b3b4 Binary files /dev/null and b/src/main/resources/icons/sun.png differ diff --git a/src/main/resources/icons/sun_icon.png b/src/main/resources/icons/sun_icon.png new file mode 100644 index 0000000..8dc7027 Binary files /dev/null and b/src/main/resources/icons/sun_icon.png differ diff --git a/src/main/resources/icons/tick.png b/src/main/resources/icons/tick.png new file mode 100644 index 0000000..a9925a0 Binary files /dev/null and b/src/main/resources/icons/tick.png differ diff --git a/src/main/resources/icons/time.png b/src/main/resources/icons/time.png new file mode 100644 index 0000000..911da3f Binary files /dev/null and b/src/main/resources/icons/time.png differ diff --git a/src/main/resources/icons/transparent_icon.png b/src/main/resources/icons/transparent_icon.png new file mode 100644 index 0000000..98b7ab9 Binary files /dev/null and b/src/main/resources/icons/transparent_icon.png differ diff --git a/src/main/resources/icons/user.png b/src/main/resources/icons/user.png new file mode 100644 index 0000000..79f35cc Binary files /dev/null and b/src/main/resources/icons/user.png differ diff --git a/src/main/resources/icons/user_add.png b/src/main/resources/icons/user_add.png new file mode 100644 index 0000000..deae99b Binary files /dev/null and b/src/main/resources/icons/user_add.png differ diff --git a/src/main/resources/icons/user_delete.png b/src/main/resources/icons/user_delete.png new file mode 100644 index 0000000..acbb563 Binary files /dev/null and b/src/main/resources/icons/user_delete.png differ diff --git a/src/main/resources/icons/user_female.png b/src/main/resources/icons/user_female.png new file mode 100644 index 0000000..7c71de0 Binary files /dev/null and b/src/main/resources/icons/user_female.png differ diff --git a/src/main/resources/icons/user_green.png b/src/main/resources/icons/user_green.png new file mode 100644 index 0000000..30383c2 Binary files /dev/null and b/src/main/resources/icons/user_green.png differ diff --git a/src/main/resources/icons/user_orange.png b/src/main/resources/icons/user_orange.png new file mode 100644 index 0000000..b818127 Binary files /dev/null and b/src/main/resources/icons/user_orange.png differ diff --git a/src/main/resources/icons/user_red.png b/src/main/resources/icons/user_red.png new file mode 100644 index 0000000..c6f66e8 Binary files /dev/null and b/src/main/resources/icons/user_red.png differ diff --git a/src/main/resources/icons/venus_icon.png b/src/main/resources/icons/venus_icon.png new file mode 100644 index 0000000..eceb31d Binary files /dev/null and b/src/main/resources/icons/venus_icon.png differ diff --git a/src/main/resources/icons/world.png b/src/main/resources/icons/world.png new file mode 100644 index 0000000..68f21d3 Binary files /dev/null and b/src/main/resources/icons/world.png differ diff --git a/src/main/resources/icons/wrench.png b/src/main/resources/icons/wrench.png new file mode 100644 index 0000000..5c8213f Binary files /dev/null and b/src/main/resources/icons/wrench.png differ diff --git a/src/main/resources/icons/wrench_add.png b/src/main/resources/icons/wrench_add.png new file mode 100644 index 0000000..3b33d13 Binary files /dev/null and b/src/main/resources/icons/wrench_add.png differ diff --git a/src/main/resources/icons/wrench_delete.png b/src/main/resources/icons/wrench_delete.png new file mode 100644 index 0000000..e4f987d Binary files /dev/null and b/src/main/resources/icons/wrench_delete.png differ diff --git a/src/main/resources/icons/wrench_edit.png b/src/main/resources/icons/wrench_edit.png new file mode 100644 index 0000000..56fff31 Binary files /dev/null and b/src/main/resources/icons/wrench_edit.png differ diff --git a/src/main/resources/icons/zoom_icon.gif b/src/main/resources/icons/zoom_icon.gif new file mode 100644 index 0000000..cbe4c80 Binary files /dev/null and b/src/main/resources/icons/zoom_icon.gif differ