Author: fdesbois Date: 2012-08-23 12:22:44 +0200 (Thu, 23 Aug 2012) New Revision: 462 Url: http://forge.codelutin.com/repositories/revision/sammoa/462 Log: refs #1204 : - create new FlightController for validation - add interfaces for Deletable and Validatable+ highlighters - add scope and context for validation vs onBoard Added: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/RouteEvent.java trunk/sammoa-persistence/src/test/java/fr/ulr/sammoa/persistence/ObservationsTest.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/DeletedRowHighlightPredicate.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/ValidRowHighlightPredicate.java trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-onBoard-warning-validation.xml trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-validation-error-validation.xml trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-onBoard-error-validation.xml trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-validation-error-validation.xml Removed: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-warning-validation.xml trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-error-validation.xml Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerListener.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/io/FlightStorage.java trunk/sammoa-persistence/pom.xml trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/GeoPoints.java trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Observations.java trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/RouteDAOImpl.java trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java trunk/sammoa-persistence/src/main/xmi/sammoa.zargo trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaColors.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaUIContext.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StopAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBar.jaxx trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBarHandler.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUI.jaxx trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIModel.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/TransectFlightModel.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanel.jaxx trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanelHandler.java trunk/sammoa-ui-swing/src/test/java/fr/ulr/sammoa/ui/swing/BeanValidatorDetectorTest.java Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java 2012-08-23 10:22:44 UTC (rev 462) @@ -569,17 +569,24 @@ } /** - * Retrieve the last {@link Route} of the given {@code flight}. + * Retrieve the last {@link Route} of the given {@code flight}. If the + * flight is ended or not started, a null route is returned. * * @param flight Flight - * @return the last existing route for the flight or null otherwise + * @return the last unfinished route for the flight or null otherwise */ - public Route getLastRoute(Flight flight) { + public Route getLastUnfinishedRoute(Flight flight) { TopiaContext transaction = beginTransaction(); try { - RouteDAO dao = SammoaDAOHelper.getRouteDAO(transaction); - Route result = dao.findLastByFlight(flight); + Route result; + if (flight.getEndDate() == null) { + RouteDAO dao = SammoaDAOHelper.getRouteDAO(transaction); + result = dao.findLastByFlight(flight); + + } else { + result = null; + } return result; } catch (TopiaException e) { throw new TopiaRuntimeException(e); @@ -589,14 +596,13 @@ } } - public TransectFlight getLastTransectDone(Flight flight) { + public Route getPreviousRoute(Route route) { TopiaContext transaction = beginTransaction(); try { RouteDAO dao = SammoaDAOHelper.getRouteDAO(transaction); - Route route = dao.findLastByFlightAndType(flight, RouteType.LEG); - TransectFlight result = route == null ? null : route.getTransectFlight(); + Route result = dao.findPreviousRoute(route); return result; } catch (TopiaException e) { throw new TopiaRuntimeException(e); @@ -604,7 +610,29 @@ } finally { endTransaction(transaction); } + } + public TransectFlight getPreviousTransect(Route previousRoute) { + + TransectFlight result; + if (previousRoute.getRouteType() == RouteType.LEG) { + result = previousRoute.getTransectFlight(); + + } else { + TopiaContext transaction = beginTransaction(); + try { + + RouteDAO dao = SammoaDAOHelper.getRouteDAO(transaction); + Route previousLEG = dao.findPreviousLEG(previousRoute); + result = previousLEG == null ? null : previousLEG.getTransectFlight(); + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + endTransaction(transaction); + } + } + return result; } public List<Observation> getObservations(Flight flight) { Copied: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java (from rev 461, trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java) =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,802 @@ +/* + * #%L + * SAMMOA :: Application + * * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2012 UMS 3462, Code Lutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ +package fr.ulr.sammoa.application.flightController; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Sets; +import fr.ulr.sammoa.application.FlightService; +import fr.ulr.sammoa.application.SammoaServiceSupport; +import fr.ulr.sammoa.application.device.DeviceManager; +import fr.ulr.sammoa.application.device.DeviceManagerProvider; +import fr.ulr.sammoa.application.io.CampaignStorage; +import fr.ulr.sammoa.application.io.FlightStorage; +import fr.ulr.sammoa.persistence.Campaign; +import fr.ulr.sammoa.persistence.Flight; +import fr.ulr.sammoa.persistence.FlightDAO; +import fr.ulr.sammoa.persistence.GeoPoint; +import fr.ulr.sammoa.persistence.Observation; +import fr.ulr.sammoa.persistence.ObservationDAO; +import fr.ulr.sammoa.persistence.ObservationStatus; +import fr.ulr.sammoa.persistence.ObserverPosition; +import fr.ulr.sammoa.persistence.Position; +import fr.ulr.sammoa.persistence.Route; +import fr.ulr.sammoa.persistence.RouteType; +import fr.ulr.sammoa.persistence.Routes; +import fr.ulr.sammoa.persistence.SammoaDAOHelper; +import fr.ulr.sammoa.persistence.TransectFlight; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; +import org.nuiton.topia.TopiaRuntimeException; +import org.nuiton.util.TimeLog; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.Set; + +/** + * Created: 11/06/12 + * + * @author fdesbois <desbois@codelutin.com> + */ +abstract class BaseFlightController extends SammoaServiceSupport implements FlightController { + + private static final Logger logger = LoggerFactory.getLogger(BaseFlightController.class); + + private static final TimeLog timeLog = new TimeLog(BaseFlightController.class, 500, 1000); + + protected FlightService service; +// +// protected AudioRecorder audioRecorder; +// +// protected GpsHandler gpsHandler; + + protected boolean initialized; + + protected FlightState state; + + protected Flight flight; + + protected Route currentRoute; + + protected TransectFlight nextTransect; + + protected TransectFlight lastTransect; + + protected final Set<FlightControllerListener> listeners; + + private DeviceManagerProvider deviceManagerProvider; + + protected FlightStorage flightStorage; + + public BaseFlightController() { + listeners = Sets.newHashSet(); + } + + protected abstract GeoPoint getLocation(TopiaContext tx) throws TopiaException; + + @Override + public void addFlightControllerListener(FlightControllerListener listener) { + listeners.add(listener); + } + + @Override + public void removeFlightControllerListener(FlightControllerListener listener) { + listeners.remove(listener); + } + + @Override + public FlightState getState() { + return state; + } + +// @Override +// public AudioRecorder getAudioRecorder() { +// return audioRecorder; +// } + + @Override + public Route getCurrentRoute() { + return currentRoute; + } + + @Override + public TransectFlight getNextTransect() { + return nextTransect; + } + +// @Override +// public GpsHandler getGpsHandler() { +// return gpsHandler; +// } +// +// @Override +// public <T extends DeviceManager> void openDeviceManager(Class<T> deviceManagerClass) { +// boolean autoStart = initialized && isRunning(); +// deviceManagerProvider.openDeviceManager(deviceManagerClass, autoStart); +// } + + @Override + public <T extends DeviceManager> T getDeviceManager(Class<T> deviceManagerClass) { + return getDeviceManagerProvider().getDeviceManager(deviceManagerClass); + } + + @Override + public boolean isWaiting() { + return state == FlightState.WAITING; + } + + @Override + public boolean isEnded() { + return state == FlightState.ENDED; + } + + @Override + public boolean isOnEffort() { + return state == FlightState.ON_EFFORT; + } + + @Override + public boolean isOffEffort() { + return state == FlightState.OFF_EFFORT; + } + + @Override + public boolean isRunning() { + return isOnEffort() || isOffEffort(); + } + + @Override + public void init(Flight flight) { + + Preconditions.checkNotNull(flight); + + this.flight = flight; + + if (initialized) { + if (logger.isWarnEnabled()) { + logger.warn("The FlightController is already initialized"); + } + return; + } + + if (logger.isInfoEnabled()) { + logger.info("Initialize the FlightController for flight {}", + this.flight.getFlightNumber()); + } + + initialized = true; + + Campaign campaign = flight.getCampaign(); + CampaignStorage campaignStorage = + getCampaignStorage(campaign.getTopiaId()); + flightStorage = campaignStorage.getFlightStorage(flight.getTopiaId()); + + service = context.getService(FlightService.class); + } + + @Override + public void start() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isWaiting(), "You can call start() only if flight is waiting (not started, not ended)"); + + TopiaContext transaction = beginTransaction(); + try { + + GeoPoint geoPoint = getLocation(transaction); + + Date currentDate = geoPoint.getRecordTime(); + + setFlightBeginDate(transaction, flight, currentDate); + + if (logger.isInfoEnabled()) { + logger.info("Start Flight {} at {}", flight.getFlightNumber(), flight.getBeginDate()); + } + + // Start with TRANSIT route + if (logger.isInfoEnabled()) { + logger.info(String.format("Create TRANSIT [START] at %1$tH:%1$tM:%1$tS", currentDate)); + } + currentRoute = service.createTransit(transaction, flight, currentDate, currentRoute); + + // Auto selection of the next transect starting from the begining + nextTransect = flight.getNextTransectFlightFrom(null); + + state = FlightState.OFF_EFFORT; + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "start()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + timeLog.log(startTime, "start()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + endTransaction(transaction); + } + } + + @Override + public void setNextTransect(TransectFlight nextTransect) { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + nextTransect == null || !nextTransect.isDeleted(), "You can't use a deleted transect as next value"); + + this.nextTransect = nextTransect; + + // Fire transect changed + fireNextTransectChanged(nextTransect); + + timeLog.log(startTime, "setNextTransect()", "Fired"); + } + + @Override + public void setCurrentRoute(Route currentRoute) { + setCurrentRoute(currentRoute, true); + } + + protected void initCurrentRoute(Route currentRoute) { + setCurrentRoute(currentRoute, false); + } + + private void setCurrentRoute(Route currentRoute, boolean fireChanges) { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + if (logger.isInfoEnabled()) { + logger.info("Set currentRoute : {}", Routes.toString(currentRoute)); + } + + if (currentRoute == null) { + + if (flight.getEndDate() == null) { + state = FlightState.WAITING; + + } else { + state = FlightState.ENDED; + } + this.currentRoute = null; + + } else { + + if (currentRoute.isDeleted()) { + this.currentRoute = service.getPreviousRoute(currentRoute); + } else { + this.currentRoute = currentRoute; + } + + if (this.currentRoute.getRouteType() == RouteType.LEG) { + state = FlightState.ON_EFFORT; + + } else { + state = FlightState.OFF_EFFORT; + } + + lastTransect = service.getPreviousTransect(this.currentRoute); + + // Selection of the nextTransect, keep the last one for circleBack + if (this.currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { + nextTransect = lastTransect; + + } else { + nextTransect = flight.getNextTransectFlightFrom(lastTransect); + } + } + + if (fireChanges) { + + fireStateChanged(state); + fireNextTransectChanged(nextTransect); + fireCurrentRouteChanged(this.currentRoute); + } + + timeLog.log(startTime, "setCurrentRoute()"); + } + + @Override + public void begin() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isOffEffort(), "You can call begin() only if flight is running (started, not ended, not on effort)"); + + Preconditions.checkState( + nextTransect != null, "You can't call begin() if no transect is selected. " + + "Call setNextTransect() method first"); + + TopiaContext transaction = beginTransaction(); + try { + + GeoPoint geoPoint = getLocation(transaction); + + Date currentDate = geoPoint.getRecordTime(); + + // The next transect becomes the last one (or current in this case) + lastTransect = nextTransect; + + // Create new LEG route + if (logger.isInfoEnabled()) { + logger.info(String.format("Create LEG [BEGIN] at %1$tH:%1$tM:%1$tS", currentDate)); + } + currentRoute = service.createLeg(transaction, flight, currentDate, currentRoute, lastTransect); + + // automatic selection of the next transect + nextTransect = flight.getNextTransectFlightFrom(lastTransect); + + state = FlightState.ON_EFFORT; + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "begin()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + timeLog.log(startTime, "begin()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + endTransaction(transaction); + } + } + + @Override + public void circleBack(Observation observation) { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + currentRoute != null + && currentRoute.getRouteType() != RouteType.TRANSIT, + "You can't call circleBack() during TRANSIT"); + + + TopiaContext transaction = beginTransaction(); + try { + + GeoPoint geoPoint = getLocation(transaction); + + Date currentDate = geoPoint.getRecordTime(); + + setObservationStatus(transaction, observation, ObservationStatus.CIRCLE_BACK); + + // Create CIRCLE_BACK + if (logger.isInfoEnabled()) { + logger.info(String.format("Create CIRCLE_BACK at %1$tH:%1$tM:%1$tS", currentDate)); + } + + currentRoute = service.createCircleBack(transaction, flight, currentDate, currentRoute, observation); + + nextTransect = lastTransect; + + state = FlightState.OFF_EFFORT; + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "circleBack()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + timeLog.log(startTime, "circleBack()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + endTransaction(transaction); + } + } + + @Override + public void add() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isOnEffort(), "You can call add() only if flight is on effort (started, not ended, on effort)"); + + TopiaContext transaction = beginTransaction(); + try { + + GeoPoint geoPoint = getLocation(transaction); + + Date currentDate = geoPoint.getRecordTime(); + + // Create new LEG route + if (logger.isInfoEnabled()) { + logger.info(String.format("Create LEG [ADD] at %1$tH:%1$tM:%1$tS", currentDate)); + } + currentRoute = service.createLeg(transaction, flight, currentDate, currentRoute, lastTransect); + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "add()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + + timeLog.log(startTime, "add()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + endTransaction(transaction); + } + } + + public void insert(RouteType routeType) { + + switch (routeType) { + case LEG: + + if (currentRoute != null) { + + switch (currentRoute.getRouteType()) { + case LEG: + add(); + break; + + case CIRCLE_BACK: + case TRANSIT: + begin(); + break; + + default: + } + } + break; + + case TRANSIT: + + if (currentRoute != null) { + + switch (currentRoute.getRouteType()) { + case LEG: + end(); + break; + + case CIRCLE_BACK: + case TRANSIT: + default: + } + } + break; + + default: + } + } + + @Override + public void next() { + + long startTime = TimeLog.getTime(); + + if (isOnEffort()) { + end(); + } + + begin(); + + timeLog.log(startTime, "next()"); + } + + @Override + public void observation(Position position) { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isRunning(), "You can call observation() only if flight is running (started, not ended)"); + + TopiaContext transaction = beginTransaction(); + try { + + GeoPoint geoPoint = getLocation(transaction); + + Date currentDate = geoPoint.getRecordTime(); + + ObserverPosition observer; + if (currentRoute == null) { + + // problem we don't have any observerPosition + observer = null; + + } else { + observer = currentRoute.getObserverPositionByPosition(position); + } + + if (logger.isInfoEnabled()) { + logger.info(String.format("Create Observation %2$s at %1$tH:%1$tM:%1$tS (observer = %3$s)", + currentDate, + position, + observer != null && observer.getObserver() != null + ? observer.getObserver().getInitials() : "") + ); + } + Observation observation = service.createObservation(transaction, flight, currentDate, observer); + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "observation()", "Commited"); + + fireObservationAdded(observation, geoPoint); + + timeLog.log(startTime, "observation()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + endTransaction(transaction); + } + } + + @Override + public void end() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isOnEffort(), "You can call end() only if flight is on effort (started, not ended, on effort)"); + + TopiaContext transaction = beginTransaction(); + try { + + GeoPoint geoPoint = getLocation(transaction); + + Date currentDate = geoPoint.getRecordTime(); + + // Create new TRANSIT route + if (logger.isInfoEnabled()) { + logger.info(String.format("Create TRANSIT [END] at %1$tH:%1$tM:%1$tS", currentDate)); + } + currentRoute = service.createTransit(transaction, flight, currentDate, currentRoute); + + state = FlightState.OFF_EFFORT; + + transaction.commitTransaction(); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + endTransaction(transaction); + } + + timeLog.log(startTime, "end()"); + } + + @Override + public void stop() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isOffEffort() && flight.getEndDate() == null, "You can call stop() only if flight is running (started, not ended, not on effort)"); + + TopiaContext transaction = beginTransaction(); + try { + + GeoPoint geoPoint = getLocation(transaction); + + Date currentDate = geoPoint.getRecordTime(); + + if (logger.isInfoEnabled()) { + logger.info(String.format("Stop flight %2$d at %1$tH:%1$tM:%1$tS", + currentDate, + flight.getFlightNumber()) + ); + } + setFlightEndDate(transaction, flight, currentDate); + + currentRoute = null; + + nextTransect = null; + + state = FlightState.ENDED; + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "stop()", "Commited"); + + // Fire events after commit + fireCurrentRouteChanged(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + timeLog.log(startTime, "stop()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + endTransaction(transaction); + } + } + + @Override + public void close() { + getDeviceManagerProvider().close(); + persistence.stopAutoSaveListener(); + } + + protected void setFlightBeginDate(TopiaContext transaction, + Flight flight, + Date beginDate) + throws TopiaException { + + FlightDAO flightDAO = SammoaDAOHelper.getFlightDAO(transaction); + flight.setBeginDate(beginDate); + flightDAO.update(flight); + } + + protected void setFlightEndDate(TopiaContext transaction, + Flight flight, + Date endDate) + throws TopiaException { + + FlightDAO flightDAO = SammoaDAOHelper.getFlightDAO(transaction); + flight.setEndDate(endDate); + flightDAO.update(flight); + } + + protected void setObservationStatus(TopiaContext transaction, + Observation observation, + ObservationStatus status) + throws TopiaException { + + ObservationDAO observationDAO = + SammoaDAOHelper.getObservationDAO(transaction); + observation.setObservationStatus(status); + observationDAO.update(observation); + } +// +// protected Date saveGPS(TopiaContext transaction) +// throws TopiaException { +// +// GeoPoint geoPoint = gpsHandler.getCurrentLocation(); +// +// Date result; +// if (geoPoint == null) { +// result = new Date(); +// +// if (logger.isWarnEnabled()) { +// logger.warn("No GPS point at {}", result); +// } +// +// } else { +// +//// lastLocation = geoPoint; +// +// if (logger.isTraceEnabled()) { +// logger.trace("Create GPS Point : {}", geoPoint); +// } +// +// result = geoPoint.getRecordTime(); +// +// GeoPointDAO dao = SammoaDAOHelper.getGeoPointDAO(transaction); +// +// geoPoint.setFlight(flight); +// +// dao.create(geoPoint); +// } +// return result; +// } + + protected DeviceManagerProvider getDeviceManagerProvider() { + if (deviceManagerProvider == null) { + deviceManagerProvider = context.getService(DeviceManagerProvider.class); + } + return deviceManagerProvider; + } + + protected void fireObservationAdded(Observation observation, GeoPoint location) { + ObservationEvent event = new ObservationEvent(this, observation, location); + for (FlightControllerListener listener : listeners) { + listener.onObservationAdded(event); + } + } + + protected void fireStateChanged(FlightState state) { + for (FlightControllerListener listener : listeners) { + listener.onStateChanged(state); + } + } + + protected void fireRouteAdded(Route newRoute) { + Preconditions.checkNotNull(newRoute); + RouteEvent event = new RouteEvent(this, newRoute, true); + for (FlightControllerListener listener : listeners) { + listener.onCurrentRouteChanged(event); + } + } + + protected void fireCurrentRouteChanged(Route route) { + RouteEvent event = new RouteEvent(this, route, false); + for (FlightControllerListener listener : listeners) { + listener.onCurrentRouteChanged(event); + } + } + + protected void fireNextTransectChanged(TransectFlight nextTransect) { + for (FlightControllerListener listener : listeners) { + listener.onNextTransectChanged(nextTransect); + } + } + +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java 2012-08-23 10:22:44 UTC (rev 462) @@ -24,13 +24,8 @@ */ import fr.ulr.sammoa.application.SammoaService; -import fr.ulr.sammoa.application.device.DeviceTechnicalException; -import fr.ulr.sammoa.application.device.audio.AudioRecorder; -import fr.ulr.sammoa.application.device.audio.AudioRecorderDefault; -import fr.ulr.sammoa.application.device.gps.GpsConfig; -import fr.ulr.sammoa.application.device.gps.GpsHandler; +import fr.ulr.sammoa.application.device.DeviceManager; import fr.ulr.sammoa.persistence.Flight; -import fr.ulr.sammoa.persistence.GeoPoint; import fr.ulr.sammoa.persistence.Observation; import fr.ulr.sammoa.persistence.ObservationStatus; import fr.ulr.sammoa.persistence.Position; @@ -54,25 +49,10 @@ /** @return the {@link FlightState} */ FlightState getState(); - /** @return the {@link AudioRecorderDefault} used to save audio files */ - AudioRecorder getAudioRecorder(); + <T extends DeviceManager> void openDeviceManager(Class<T> deviceManager); - /** - * @return the {@link GpsHandler} used to retrieve GPS {@link GeoPoint} and - * save them. - */ - GpsHandler getGpsHandler(); + <T extends DeviceManager> T getDeviceManager(Class<T> deviceManagerClass); - /** - * @param config GpsConfig to initialize the Gps - * @throws fr.ulr.sammoa.application.device.DeviceTechnicalException - * if the gps device can't be opened properly - */ - void openGpsDevice(GpsConfig config) throws DeviceTechnicalException; - - /** @throws DeviceTechnicalException if the audio device can't be opened properly */ - void openAudioDevice() throws DeviceTechnicalException; - /** @return The current {@link Route} */ Route getCurrentRoute(); @@ -116,6 +96,8 @@ */ void setNextTransect(TransectFlight nextTransect); + void setCurrentRoute(Route currentRoute); + /** * Begin operation. A new {@link RouteType#LEG} is created based on GPS * current date and next transect that becomes the current one. The state Deleted: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java 2012-08-23 10:22:44 UTC (rev 462) @@ -1,886 +0,0 @@ -/* - * #%L - * SAMMOA :: Application - * * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2012 UMS 3462, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ -package fr.ulr.sammoa.application.flightController; - -import com.google.common.base.Preconditions; -import com.google.common.base.Supplier; -import com.google.common.base.Throwables; -import com.google.common.collect.Sets; -import fr.ulr.sammoa.application.FlightService; -import fr.ulr.sammoa.application.SammoaServiceSupport; -import fr.ulr.sammoa.application.device.DeviceManager; -import fr.ulr.sammoa.application.device.DeviceStateListener; -import fr.ulr.sammoa.application.device.DeviceTechnicalException; -import fr.ulr.sammoa.application.device.audio.AudioRecorder; -import fr.ulr.sammoa.application.device.audio.AudioRecorderDefault; -import fr.ulr.sammoa.application.device.gps.GpsConfig; -import fr.ulr.sammoa.application.device.gps.GpsHandler; -import fr.ulr.sammoa.application.device.gps.GpsLocationEvent; -import fr.ulr.sammoa.application.device.gps.GpsLocationListener; -import fr.ulr.sammoa.application.io.CampaignStorage; -import fr.ulr.sammoa.application.io.FlightStorage; -import fr.ulr.sammoa.persistence.Campaign; -import fr.ulr.sammoa.persistence.Flight; -import fr.ulr.sammoa.persistence.FlightDAO; -import fr.ulr.sammoa.persistence.GeoPoint; -import fr.ulr.sammoa.persistence.GeoPointDAO; -import fr.ulr.sammoa.persistence.GeoPoints; -import fr.ulr.sammoa.persistence.Observation; -import fr.ulr.sammoa.persistence.ObservationDAO; -import fr.ulr.sammoa.persistence.ObservationStatus; -import fr.ulr.sammoa.persistence.ObserverPosition; -import fr.ulr.sammoa.persistence.Position; -import fr.ulr.sammoa.persistence.Route; -import fr.ulr.sammoa.persistence.RouteType; -import fr.ulr.sammoa.persistence.SammoaDAOHelper; -import fr.ulr.sammoa.persistence.TransectFlight; -import org.nuiton.topia.TopiaContext; -import org.nuiton.topia.TopiaException; -import org.nuiton.topia.TopiaRuntimeException; -import org.nuiton.util.TimeLog; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Date; -import java.util.Set; - -/** - * Created: 11/06/12 - * - * @author fdesbois <desbois@codelutin.com> - */ -public class FlightControllerDefault extends SammoaServiceSupport implements GpsLocationListener, FlightController { - - private static final Logger logger = LoggerFactory.getLogger(FlightControllerDefault.class); - - private static final TimeLog timeLog = new TimeLog(FlightControllerDefault.class, 500, 1000); - - protected FlightService service; - - protected AudioRecorder audioRecorder; - - protected GpsHandler gpsHandler; - - protected boolean initialized; - - protected FlightState state; - - protected Flight flight; - - protected Route currentRoute; - - protected TransectFlight nextTransect; - - protected TransectFlight lastTransect; - - protected final Set<FlightControllerListener> listeners; - - protected FlightStorage flightStorage; - - public FlightControllerDefault() { - listeners = Sets.newHashSet(); - } - -// protected GeoPoint lastLocation; - - @Override - public void addFlightControllerListener(FlightControllerListener listener) { - listeners.add(listener); - } - - @Override - public void removeFlightControllerListener(FlightControllerListener listener) { - listeners.remove(listener); - } - - @Override - public FlightState getState() { - return state; - } - - @Override - public AudioRecorder getAudioRecorder() { - return audioRecorder; - } - - @Override - public Route getCurrentRoute() { - return currentRoute; - } - - @Override - public TransectFlight getNextTransect() { - return nextTransect; - } - - @Override - public GpsHandler getGpsHandler() { - return gpsHandler; - } - - @Override - public void openGpsDevice(final GpsConfig config) throws DeviceTechnicalException { - - Set<GpsLocationListener> locationListeners; - if (gpsHandler != null) { - - // Remove all existing listeners and keep them for the new instance - locationListeners = Sets.newHashSet(gpsHandler.getGpsLocationListeners()); - for (GpsLocationListener listener : locationListeners) { - gpsHandler.removeGpsLocationListener(listener); - } - - } else { - locationListeners = Sets.newHashSet(); - } - - gpsHandler = newDeviceManager(gpsHandler, new Supplier<GpsHandler>() { - - @Override - public GpsHandler get() { - - // Instanciate the GpsHandler - Class<? extends GpsHandler> gpsHandlerClass = config.getGpsHandlerClass(); - try { - - Constructor<? extends GpsHandler> constructor = - gpsHandlerClass.getConstructor(GpsConfig.class); - - GpsHandler result = constructor.newInstance(config); - result.addGpsLocationListener(FlightControllerDefault.this); - return result; - - } catch (InstantiationException e) { - throw Throwables.propagate(e); - } catch (IllegalAccessException e) { - throw Throwables.propagate(e); - } catch (NoSuchMethodException e) { - throw Throwables.propagate(e); - } catch (InvocationTargetException e) { - throw Throwables.propagate(e); - } - } - }); - - for (GpsLocationListener listener : locationListeners) { - gpsHandler.addGpsLocationListener(listener); - } - - if (initialized && isRunning()) { - gpsHandler.start(); - } else { - gpsHandler.open(); - } - } - - @Override - public void openAudioDevice() throws DeviceTechnicalException { - - audioRecorder = newDeviceManager(audioRecorder, new Supplier<AudioRecorder>() { - - @Override - public AudioRecorder get() { - return new AudioRecorderDefault(); - } - }); - - if (initialized && isRunning()) { - audioRecorder.start(); - } else { - audioRecorder.open(); - } - } - - @Override - public boolean isWaiting() { - return state == FlightState.WAITING; - } - - @Override - public boolean isEnded() { - return state == FlightState.ENDED; - } - - @Override - public boolean isOnEffort() { - return state == FlightState.ON_EFFORT; - } - - @Override - public boolean isOffEffort() { - return state == FlightState.OFF_EFFORT; - } - - @Override - public boolean isRunning() { - return isOnEffort() || isOffEffort(); - } - - @Override - public void init(Flight flight) { - - Preconditions.checkNotNull(flight); - - Preconditions.checkState(gpsHandler != null, - "The GpsHandler must be created using #openGpsDevice"); - - Preconditions.checkState(audioRecorder != null, - "The AudioRecorder must be created using #openAudioDevice"); - - this.flight = flight; - - this.service = context.getService(FlightService.class); - - this.currentRoute = service.getLastRoute(flight); - this.lastTransect = service.getLastTransectDone(flight); - - Campaign campaign = flight.getCampaign(); - CampaignStorage campaignStorage = - getCampaignStorage(campaign.getTopiaId()); - flightStorage = campaignStorage.getFlightStorage(flight.getTopiaId()); - - if (initialized) { - if (logger.isWarnEnabled()) { - logger.warn("The FlightController is already initialized"); - } - return; - } - - if (logger.isInfoEnabled()) { - logger.info("Initialize the FlightController for flight {}", - this.flight.getFlightNumber()); - } - - initialized = true; - - // Note that a flight can't finished by a leg, so effort not null - // implies that the flight is started and not ended - if (currentRoute != null - && currentRoute.getRouteType() == RouteType.LEG) { - - state = FlightState.ON_EFFORT; - - } else if (currentRoute != null - && this.flight.getBeginDate() != null - && this.flight.getEndDate() == null) { - - state = FlightState.OFF_EFFORT; - - } else if (this.flight.getEndDate() != null) { - - state = FlightState.ENDED; - - } else { - state = FlightState.WAITING; - } - - if (isRunning()) { - - gpsHandler.start(); - - audioRecorder.start(); - - // Selection of the nextTransect, keep the last one for circleBack - if (currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { - nextTransect = lastTransect; - - } else { - nextTransect = this.flight.getNextTransectFlightFrom(lastTransect); - } - - // Restart recording audio if onEffort or circleBack - if (state == FlightState.ON_EFFORT - || currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { - - saveAudio(0); - } - } - } - - @Override - public void start() { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isWaiting(), "You can call start() only if flight is waiting (not started, not ended)"); - - gpsHandler.start(); - - audioRecorder.start(); - - TopiaContext transaction = beginTransaction(); - try { - - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - setFlightBeginDate(transaction, flight, currentDate); - - if (logger.isInfoEnabled()) { - logger.info("Start Flight {} at {}", flight.getFlightNumber(), flight.getBeginDate()); - } - - // Start with TRANSIT route - if (logger.isInfoEnabled()) { - logger.info(String.format("Create TRANSIT [START] at %1$tH:%1$tM:%1$tS", currentDate)); - } - currentRoute = service.createTransit(transaction, flight, currentDate, currentRoute); - - // Auto selection of the next transect starting from the begining - nextTransect = flight.getNextTransectFlightFrom(null); - - state = FlightState.OFF_EFFORT; - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "start()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - timeLog.log(startTime, "start()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - endTransaction(transaction); - } - } - - @Override - public void setNextTransect(TransectFlight nextTransect) { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - nextTransect == null || !nextTransect.isDeleted(), "You can't use a deleted transect as next value"); - - this.nextTransect = nextTransect; - - // Fire transect changed - fireNextTransectChanged(nextTransect); - - timeLog.log(startTime, "setNextTransect()", "Fired"); - } - - @Override - public void begin() { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isOffEffort(), "You can call begin() only if flight is running (started, not ended, not on effort)"); - - Preconditions.checkState( - nextTransect != null, "You can't call begin() if no transect is selected. " + - "Call setNextTransect() method first"); - - TopiaContext transaction = beginTransaction(); - try { - - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - // The next transect becomes the last one (or current in this case) - lastTransect = nextTransect; - - // Create new LEG route - if (logger.isInfoEnabled()) { - logger.info(String.format("Create LEG [BEGIN] at %1$tH:%1$tM:%1$tS", currentDate)); - } - currentRoute = service.createLeg(transaction, flight, currentDate, currentRoute, lastTransect); - - // automatic selection of the next transect - nextTransect = flight.getNextTransectFlightFrom(lastTransect); - - state = FlightState.ON_EFFORT; - - // Record the audio for the current LEG - saveAudio(3); - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "begin()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - timeLog.log(startTime, "begin()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - endTransaction(transaction); - } - } - - @Override - public void circleBack(Observation observation) { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - currentRoute != null - && currentRoute.getRouteType() != RouteType.TRANSIT, - "You can't call circleBack() during TRANSIT"); - - - TopiaContext transaction = beginTransaction(); - try { - - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - setObservationStatus(transaction, observation, ObservationStatus.CIRCLE_BACK); - - // Create CIRCLE_BACK - if (logger.isInfoEnabled()) { - logger.info(String.format("Create CIRCLE_BACK at %1$tH:%1$tM:%1$tS", currentDate)); - } - - currentRoute = service.createCircleBack(transaction, flight, currentDate, currentRoute, observation); - - nextTransect = lastTransect; - - state = FlightState.OFF_EFFORT; - - // Record the audio of the LEG in an other file - saveAudio(3); - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "circleBack()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - timeLog.log(startTime, "circleBack()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - endTransaction(transaction); - } - } - - @Override - public void add() { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isOnEffort(), "You can call add() only if flight is on effort (started, not ended, on effort)"); - - TopiaContext transaction = beginTransaction(); - try { - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - // Create new LEG route - if (logger.isInfoEnabled()) { - logger.info(String.format("Create LEG [ADD] at %1$tH:%1$tM:%1$tS", currentDate)); - } - currentRoute = service.createLeg(transaction, flight, currentDate, currentRoute, lastTransect); - - // Record the audio of the LEG in an other file - saveAudio(3); - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "add()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - - timeLog.log(startTime, "add()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - endTransaction(transaction); - } - } - - @Override - public void next() { - - long startTime = TimeLog.getTime(); - - if (isOnEffort()) { - doEndWithAudioDelay(3); - } - - begin(); - - timeLog.log(startTime, "next()"); - } - - @Override - public void observation(Position position) { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isRunning(), "You can call observation() only if flight is running (started, not ended)"); - - TopiaContext transaction = beginTransaction(); - try { - GeoPoint location = gpsHandler.getCurrentLocation(); - - Date currentDate = saveGPS(transaction, location, flight); - - ObserverPosition observer; - if (currentRoute == null) { - - // problem we don't have any observerPosition - observer = null; - - } else { - observer = currentRoute.getObserverPositionByPosition(position); - } - - if (logger.isInfoEnabled()) { - logger.info(String.format("Create Observation %2$s at %1$tH:%1$tM:%1$tS (observer = %3$s)", - currentDate, - position, - observer != null && observer.getObserver() != null - ? observer.getObserver().getInitials() : "") - ); - } - Observation observation = service.createObservation(transaction, flight, currentDate, observer); - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "observation()", "Commited"); - - fireObservationAdded(observation, location); - - timeLog.log(startTime, "observation()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - endTransaction(transaction); - } - } - - @Override - public void end() { - - long startTime = TimeLog.getTime(); - - // Stop recording after 2 minutes (120 seconds) - doEndWithAudioDelay(120); - - timeLog.log(startTime, "end()"); - } - - @Override - public void stop() { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isOffEffort(), "You can call stop() only if flight is running (started, not ended, not on effort)"); - - TopiaContext transaction = beginTransaction(); - try { - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - if (logger.isInfoEnabled()) { - logger.info(String.format("Stop flight %2$d at %1$tH:%1$tM:%1$tS", - currentDate, - flight.getFlightNumber()) - ); - } - setFlightEndDate(transaction, flight, currentDate); - - // Stop audio - getAudioRecorder().stop(); - - // Stop gps - getGpsHandler().stop(); - - currentRoute = null; - - nextTransect = null; - - state = FlightState.ENDED; - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "stop()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - timeLog.log(startTime, "stop()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - endTransaction(transaction); - } - } - - @Override - public void close() { - - audioRecorder.close(); - audioRecorder = null; - - gpsHandler.close(); - gpsHandler = null; - - persistence.stopAutoSaveListener(); - } - - protected void doEndWithAudioDelay(long audioDelay) { - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isOnEffort(), "You can call end() only if flight is on effort (started, not ended, on effort)"); - - TopiaContext transaction = beginTransaction(); - try { - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - // Create new TRANSIT route - if (logger.isInfoEnabled()) { - logger.info(String.format("Create TRANSIT [END] at %1$tH:%1$tM:%1$tS", currentDate)); - } - currentRoute = service.createTransit(transaction, flight, currentDate, currentRoute); - - audioRecorder.stopRecord(audioDelay); - - state = FlightState.OFF_EFFORT; - - transaction.commitTransaction(); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - endTransaction(transaction); - } - } - -// protected void setNextTransect(TransectFlight nextTransect, boolean fireEvents) { -// -// this.nextTransect = nextTransect; -// -// if (fireEvents) { -// // Fire transect changed -// for (FlightControllerListener listener : listeners) { -// listener.onNextTransectChanged(nextTransect); -// } -// } -// } -// -// protected void setNextTransectFrom(TransectFlight transect, boolean fireEvents) { -// -// TransectFlight nextTransect = -// flight.getNextTransectFlightFrom(transect); -// -// setNextTransect(nextTransect, fireEvents); -// } - - protected void setFlightBeginDate(TopiaContext transaction, - Flight flight, - Date beginDate) - throws TopiaException { - - FlightDAO flightDAO = SammoaDAOHelper.getFlightDAO(transaction); - flight.setBeginDate(beginDate); - flightDAO.update(flight); - } - - protected void setFlightEndDate(TopiaContext transaction, - Flight flight, - Date endDate) - throws TopiaException { - - FlightDAO flightDAO = SammoaDAOHelper.getFlightDAO(transaction); - flight.setEndDate(endDate); - flightDAO.update(flight); - } - - protected void setObservationStatus(TopiaContext transaction, - Observation observation, - ObservationStatus status) - throws TopiaException { - - ObservationDAO observationDAO = - SammoaDAOHelper.getObservationDAO(transaction); - observation.setObservationStatus(status); - observationDAO.update(observation); - } - - protected void saveAudio(long delay) { - - String extension = getAudioRecorder().getOutputType().getExtension(); - - File audioFile = flightStorage.getAudioFile(currentRoute, extension); - - getAudioRecorder().record(audioFile, delay); - } - - protected Date saveGPS(TopiaContext transaction, - GeoPoint geoPoint, - Flight flight) - throws TopiaException { - - Date result; - if (geoPoint == null) { - result = new Date(); - - if (logger.isWarnEnabled()) { - logger.warn("No GPS point at {}", result); - } - - } else { - -// lastLocation = geoPoint; - - if (logger.isTraceEnabled()) { - logger.trace("Create GPS Point : {}", geoPoint); - } - - result = geoPoint.getRecordTime(); - - GeoPointDAO dao = SammoaDAOHelper.getGeoPointDAO(transaction); - - geoPoint.setFlight(flight); - - dao.create(geoPoint); - } - return result; - } - - protected void fireObservationAdded(Observation observation, GeoPoint location) { - for (FlightControllerListener listener : listeners) { - listener.onObservationAdded(new ObservationEvent(this, observation, location)); - } - } - - protected void fireStateChanged(FlightState state) { - for (FlightControllerListener listener : listeners) { - listener.onStateChanged(state); - } - } - - protected void fireRouteAdded(Route route) { - for (FlightControllerListener listener : listeners) { - listener.onRouteAdded(route); - } - } - - protected void fireNextTransectChanged(TransectFlight nextTransect) { - for (FlightControllerListener listener : listeners) { - listener.onNextTransectChanged(nextTransect); - } - } - - protected <T extends DeviceManager> T newDeviceManager(T oldInstance, Supplier<T> supplier) - throws DeviceTechnicalException { - - Set<DeviceStateListener> stateListeners; - if (oldInstance != null) { - - // Remove all existing listeners and keep them for the new instance - stateListeners = Sets.newHashSet(oldInstance.getDeviceStateListeners()); - for (DeviceStateListener listener : stateListeners) { - oldInstance.removeDeviceStateListener(listener); - } - - oldInstance.close(); - - } else { - stateListeners = Sets.newHashSet(); - } - - T result = supplier.get(); - - // Attach all updateListener - for (DeviceStateListener listener : stateListeners) { - result.addDeviceStateListener(listener); - } - - return result; - } - - @Override - public void locationChanged(GpsLocationEvent event) { - GeoPoint newLocation = event.getNewValue(); - if (!GeoPoints.isCoordinatesEmpty(newLocation) /* && newLocation.getTopiaId() == null*/) { -// lastLocation = newLocation; - newLocation.setFlight(flight); - persistence.delayEntityCreation(newLocation); - } - } - -} Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerListener.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerListener.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerListener.java 2012-08-23 10:22:44 UTC (rev 462) @@ -23,7 +23,6 @@ * #L% */ -import fr.ulr.sammoa.persistence.Route; import fr.ulr.sammoa.persistence.TransectFlight; /** @@ -37,11 +36,12 @@ public interface FlightControllerListener { /** - * Fired when a new {@code route} has been created and added to the flight + * Fired when a the current {@code route} has changed. It could be a + * new created route. * - * @param route The new route added + * @param event The event containing route change */ - void onRouteAdded(Route route); + void onCurrentRouteChanged(RouteEvent event); /** * Fired when the next transect has been updated. Added: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,154 @@ +package fr.ulr.sammoa.application.flightController; + +import com.google.common.base.Preconditions; +import fr.ulr.sammoa.application.device.DeviceManager; +import fr.ulr.sammoa.application.device.audio.AudioRecorder; +import fr.ulr.sammoa.application.device.gps.GpsHandler; +import fr.ulr.sammoa.application.device.gps.GpsLocationEvent; +import fr.ulr.sammoa.application.device.gps.GpsLocationListener; +import fr.ulr.sammoa.persistence.Flight; +import fr.ulr.sammoa.persistence.GeoPoint; +import fr.ulr.sammoa.persistence.GeoPoints; +import fr.ulr.sammoa.persistence.Route; +import fr.ulr.sammoa.persistence.RouteType; +import fr.ulr.sammoa.persistence.SammoaDAOHelper; +import fr.ulr.sammoa.persistence.TransectFlight; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; + +import java.io.File; + +/** + * Created: 21/08/12 + * + * @author fdesbois <florian.desbois@codelutin.com> + */ +public class FlightControllerOnBoard extends BaseFlightController implements GpsLocationListener, FlightControllerListener { + + protected GpsHandler gpsHandler; + + protected AudioRecorder audioRecorder; + + @Override + public <T extends DeviceManager> void openDeviceManager(Class<T> deviceManager) { + boolean autoStart = initialized && isRunning(); + + T result = getDeviceManagerProvider().openDeviceManager(deviceManager, autoStart); + + if (result instanceof GpsHandler) { + ((GpsHandler) result).addGpsLocationListener(this); + } + } + + @Override + public void init(Flight flight) { + + gpsHandler = getDeviceManager(GpsHandler.class); + Preconditions.checkNotNull(gpsHandler, "You must open the gpsHandler device before init"); + + audioRecorder = getDeviceManager(AudioRecorder.class); + Preconditions.checkNotNull(audioRecorder, "You must open the audioRecorder device before init"); + + super.init(flight); + + addFlightControllerListener(this); + + initCurrentRoute(service.getLastUnfinishedRoute(flight)); + + if (isRunning()) { + + gpsHandler.start(); + + audioRecorder.start(); + + // Restart recording audio if onEffort or circleBack + if (state == FlightState.ON_EFFORT + || currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { + + saveAudio(0); + } + } + } + + @Override + public void start() { + + gpsHandler.start(); + + audioRecorder.start(); + + super.start(); + } + + @Override + public void stop() { + + super.stop(); + + audioRecorder.stop(); + + gpsHandler.stop(); + } + + @Override + public void locationChanged(GpsLocationEvent event) { + GeoPoint newLocation = event.getNewValue(); + if (!GeoPoints.isCoordinatesEmpty(newLocation) /* && newLocation.getTopiaId() == null*/) { +// lastLocation = newLocation; + newLocation.setFlight(flight); + persistence.delayEntityCreation(newLocation); + } + } + + @Override + protected GeoPoint getLocation(TopiaContext tx) throws TopiaException { + GeoPoint result = gpsHandler.getCurrentLocation(); + result.setFlight(flight); + SammoaDAOHelper.getGeoPointDAO(tx).create(result); + return result; + } + + @Override + public void onCurrentRouteChanged(RouteEvent event) { + if (event.isNew()) { + + Route newRoute = event.getRoute(); + + if (RouteType.LEG == newRoute.getRouteType() + || RouteType.CIRCLE_BACK == newRoute.getRouteType()) { + + // Stop previous recording after 3 seconds + saveAudio(3); + + } else { + + // Stop recording after 2 minutes (120 seconds) + audioRecorder.stopRecord(120); + } + } + } + + @Override + public void onNextTransectChanged(TransectFlight nextTransect) { + // nothing to do + } + + @Override + public void onStateChanged(FlightState state) { + // nothing to do + } + + @Override + public void onObservationAdded(ObservationEvent event) { + // nothing to do + } + + protected void saveAudio(long delaySeconds) { + + String extension = audioRecorder.getOutputType().getExtension(); + + File audioFile = flightStorage.getAudioFile(currentRoute, extension); + + audioRecorder.record(audioFile, delaySeconds); + } +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Added: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,105 @@ +package fr.ulr.sammoa.application.flightController; + +import com.google.common.base.Preconditions; +import fr.ulr.sammoa.application.device.DeviceManager; +import fr.ulr.sammoa.application.device.audio.AudioReader; +import fr.ulr.sammoa.persistence.Flight; +import fr.ulr.sammoa.persistence.GeoPoint; +import fr.ulr.sammoa.persistence.GeoPoints; +import fr.ulr.sammoa.persistence.Route; +import fr.ulr.sammoa.persistence.Routes; +import fr.ulr.sammoa.persistence.SammoaDAOHelper; +import org.apache.commons.lang3.time.DateUtils; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Date; +import java.util.List; + +/** + * Created: 21/08/12 + * + * @author fdesbois <florian.desbois@codelutin.com> + */ +public class FlightControllerValidation extends BaseFlightController { + + private static final Logger logger = LoggerFactory.getLogger(FlightControllerValidation.class); + + protected AudioReader audioReader; + + protected List<GeoPoint> geoPoints; + + @Override + public <T extends DeviceManager> void openDeviceManager(Class<T> deviceManager) { + getDeviceManagerProvider().openDeviceManager(deviceManager, false); + } + + @Override + public void init(Flight flight) { + + audioReader = getDeviceManager(AudioReader.class); + Preconditions.checkNotNull(audioReader, "You must open the audioReader device before init"); + + super.init(flight); + + initCurrentRoute(null); + + geoPoints = service.getFlightGeoPoints(flight); + } + + @Override + public void setCurrentRoute(Route currentRoute) { + super.setCurrentRoute(currentRoute); + + if (currentRoute != null) { + + File file = flightStorage.getAudioFile(currentRoute, + audioReader.getOutputType().getExtension()); + audioReader.load(file); + } + } + + @Override + protected GeoPoint getLocation(TopiaContext tx) throws TopiaException { + + Preconditions.checkNotNull(currentRoute, "You must set the current route to retrieve location"); + Preconditions.checkState(!geoPoints.isEmpty(), "No geoPoints available"); + + Date time = currentRoute.getBeginTime(); + + long position = audioReader.getPosition(); + if (position > 0) { + time = DateUtils.addMilliseconds(time, (int) position); + + // Allow creating any route after a LEG with different time + // to avoid constraints error (naturalId = routeType + flight + beginTime) + } else if (Routes.isRouteLeg(currentRoute)) { + time = DateUtils.addMilliseconds(time, 1); + } + + int index = GeoPoints.getClosestPointIndex(geoPoints, time); + + GeoPoint result = geoPoints.get(index); + + // Maybe a problem when using same time for previous/next searches + // Note that the captureDelay is keeped but maybe we need to update it + // depends on modified time ? + + // Create a new entity for the new time + if (!result.getRecordTime().equals(time)) { + + GeoPoint newPoint = GeoPoints.copy(result); + newPoint.setRecordTime(time); + SammoaDAOHelper.getGeoPointDAO(tx).create(newPoint); + geoPoints.add(index, newPoint); + + if (logger.isDebugEnabled()) { + logger.debug("Create a new GeoPoint : {}", newPoint); + } + } + return result; + } +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Added: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/RouteEvent.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/RouteEvent.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/RouteEvent.java 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,60 @@ +package fr.ulr.sammoa.application.flightController; +/* + * #%L + * SAMMOA :: Application + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2012 UMS 3462, Code Lutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import fr.ulr.sammoa.persistence.Route; + +/** + * Created: 06/08/12 + * + * @author fdesbois <florian.desbois@codelutin.com> + */ +public class RouteEvent { + + protected FlightController source; + + protected Route route; + + protected boolean isNew; + + public RouteEvent(FlightController source, + Route route, + boolean isNew) { + this.source = source; + this.route = route; + this.isNew = isNew; + } + + public FlightController getSource() { + return source; + } + + public Route getRoute() { + return route; + } + + public boolean isNew() { + return isNew; + } +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/RouteEvent.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/io/FlightStorage.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/io/FlightStorage.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/io/FlightStorage.java 2012-08-23 10:22:44 UTC (rev 462) @@ -55,12 +55,7 @@ public File getAudioFile(Route route, String ext) { - String fileName = String.format( - "%1$tF-%1$tH-%1$tM-%1$tS.%2$s.%3$s", - route.getBeginTime(), - route.getTopiaId(), - ext - ); + String fileName = route.getTopiaId() + "." + ext; return new File(getAudioDirectory(), fileName); } Modified: trunk/sammoa-persistence/pom.xml =================================================================== --- trunk/sammoa-persistence/pom.xml 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-persistence/pom.xml 2012-08-23 10:22:44 UTC (rev 462) @@ -114,6 +114,7 @@ <defaultPackage>fr.ulr.sammoa.persistence</defaultPackage> <templates> org.nuiton.eugene.java.JavaEnumerationTransformer, + org.nuiton.eugene.java.JavaInterfaceTransformer, org.nuiton.topia.generator.TopiaMetaTransformer </templates> </configuration> Modified: trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/GeoPoints.java =================================================================== --- trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/GeoPoints.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/GeoPoints.java 2012-08-23 10:22:44 UTC (rev 462) @@ -47,6 +47,15 @@ // static class do not have instanciation } + public static GeoPoint copy(GeoPoint source) { + GeoPoint result = new GeoPointImpl(source.getLatitude(), source.getLongitude()); + result.setFlight(source.getFlight()); + result.setSpeed(source.getSpeed()); + result.setAltitude(source.getAltitude()); + result.setCaptureDelay(source.getCaptureDelay()); + return result; + } + public static boolean equal(GeoPoint geoPoint1, GeoPoint geoPoint2) { boolean result = geoPoint1 == null && geoPoint2 == null; @@ -111,6 +120,22 @@ return result; } + public static int getClosestPointIndex(List<GeoPoint> geoPoints, Date date) { + + int result = -1; + + if (!geoPoints.isEmpty()) { + + List<Date> geoPointDates = FluentIterable + .from(geoPoints) + .transform(toDate()) + .toSortedImmutableList(Ordering.natural()); + + result = getClosestDateIndex(0, geoPointDates, date); + } + return result; + } + protected static int getClosestDateIndex(int startIndex, List<Date> source, Date date) { int size = source.size(); for (int index = startIndex; index < size; index++) { Modified: trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Observations.java =================================================================== --- trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Observations.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Observations.java 2012-08-23 10:22:44 UTC (rev 462) @@ -26,12 +26,15 @@ import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.commons.collections.CollectionUtils; import org.nuiton.util.DateUtil; import org.nuiton.util.PeriodDates; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Date; import java.util.Iterator; @@ -45,6 +48,9 @@ */ public final class Observations { + /** Logger. */ + private static final Logger logger = LoggerFactory.getLogger(Observations.class); + private Observations() { // static class do not have instanciation } @@ -57,18 +63,71 @@ return Sets.newHashSet(Iterables.transform(observations, TO_OBSERVER_POSITION_FUNCTION)); } - public static boolean inRoute(Observation observation, Route route, Route nextRoute) { + public static Observation findFirstInRoute(Iterable<Observation> observations, + Route route, + Iterable<Route> routes, + boolean ignoreDeleted) { - Date begin = route.getBeginTime(); + Observation result; + if (route == null) { + result = null; + + } else { + + result = FluentIterable.from(observations) + .filter(Observations.inRoute(route, routes, ignoreDeleted)) + .first() + .orNull(); + } + return result; + } + + public static boolean inRoute(Observation observation, + Route route, + Iterable<Route> routes, + boolean ignoreDeleted) { + + if (ignoreDeleted) { + routes = Routes.filterNotDeleted(routes); + } + + Route previousRoute = route; + if (ignoreDeleted && route.isDeleted()) { + previousRoute = Routes.findPrevious(routes, route); + } + if (previousRoute == null) { + previousRoute = Routes.findNext(routes, route); + } + + Preconditions.checkNotNull(previousRoute); + + Route nextRoute = Routes.findNext(routes, previousRoute); + + if (logger.isTraceEnabled()) { + logger.trace("inRoute obs {} [{}]: previousRoute:[{}], nextRoute:[{}]", + new Object[]{observation.getObservationNumber(), + observation.getObservationTime(), + Routes.toString(previousRoute), + Routes.toString(nextRoute) + }); + } + + Date begin = previousRoute.getBeginTime(); Date end = nextRoute != null ? nextRoute.getBeginTime() : null; boolean result = DateUtil.between(observation.getObservationTime(), begin, end); + + // Max bound exclusive + result &= !observation.getObservationTime().equals(end); + return result; } - public static Predicate<Observation> inRoute(Route route, Route nextRoute) { - return new ObservationInRoutePredicate(route, nextRoute); + public static Predicate<Observation> inRoute(Route route, + Iterable<Route> routes, + boolean ignoreDeleted) { + return new ObservationInRoutePredicate(route, routes, ignoreDeleted); } public static void removeOtherSpecies(List<Observation> observations, @@ -86,22 +145,6 @@ } } - protected static Function<Observation, Date> TO_DATE_FUNCTION = new Function<Observation, Date>() { - - @Override - public Date apply(Observation input) { - return input.getObservationTime(); - } - }; - - protected static Function<Observation, ObserverPosition> TO_OBSERVER_POSITION_FUNCTION = new Function<Observation, ObserverPosition>() { - - @Override - public ObserverPosition apply(Observation input) { - return input.getObserverPosition(); - } - }; - public static List<Observation> retainsObservations(List<Observation> observations, PeriodDates periodDate) { @@ -131,21 +174,43 @@ return result; } - protected static class ObservationInRoutePredicate implements Predicate<Observation> { + private static Function<Observation, Date> TO_DATE_FUNCTION = new Function<Observation, Date>() { + @Override + public Date apply(Observation input) { + return input.getObservationTime(); + } + }; + + private static Function<Observation, ObserverPosition> TO_OBSERVER_POSITION_FUNCTION = new Function<Observation, ObserverPosition>() { + + @Override + public ObserverPosition apply(Observation input) { + return input.getObserverPosition(); + } + }; + + private static class ObservationInRoutePredicate implements Predicate<Observation> { + protected Route route; - protected Route nextRoute; + protected Iterable<Route> routes; - public ObservationInRoutePredicate(Route route, Route nextRoute) { + protected boolean ignoreDeleted; + + public ObservationInRoutePredicate(Route route, + Iterable<Route> routes, + boolean ignoreDeleted) { Preconditions.checkNotNull(route); + Preconditions.checkNotNull(routes); this.route = route; - this.nextRoute = nextRoute; + this.routes = routes; + this.ignoreDeleted = ignoreDeleted; } @Override public boolean apply(Observation input) { - return Observations.inRoute(input, route, nextRoute); + return Observations.inRoute(input, route, routes, ignoreDeleted); } } Modified: trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/RouteDAOImpl.java =================================================================== --- trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/RouteDAOImpl.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/RouteDAOImpl.java 2012-08-23 10:22:44 UTC (rev 462) @@ -37,11 +37,9 @@ public List<E> findAllByFlightOrderedByBeginTime(Flight flight) { - String ql = String.format("FROM %1$s WHERE %2$s = :flight ORDER BY %3$s", - RouteImpl.class.getSimpleName(), - Route.PROPERTY_FLIGHT, - Route.PROPERTY_BEGIN_TIME - ); + String ql = "FROM RouteImpl " + + "WHERE flight = :flight " + + "ORDER BY beginTime"; try { List<E> result = findAllByQuery(ql, "flight", flight); @@ -53,15 +51,14 @@ public E findLastByFlight(Flight flight) { - String ql = String.format("FROM %1$s WHERE %2$s = :flight ORDER BY %3$s DESC", - RouteImpl.class.getSimpleName(), - Route.PROPERTY_FLIGHT, - Route.PROPERTY_BEGIN_TIME - ); + String ql = "FROM RouteImpl " + + "WHERE flight = :flight " + + "AND deleted = :deleted " + + "ORDER BY beginTime DESC"; try { List<E> queryResults = findAllByQueryWithBound( - ql, 0, 1, "flight", flight); + ql, 0, 1, "flight", flight, "deleted", false); E result = queryResults.isEmpty() ? null : queryResults.get(0); return result; } catch (TopiaException e) { @@ -69,18 +66,25 @@ } } - public E findLastByFlightAndType(Flight flight, RouteType type) { + public E findPreviousLEG(Route route) throws TopiaException { - String ql = String.format("FROM %1$s WHERE %2$s = :flight AND %3$s = :type ORDER BY %4$s DESC", - RouteImpl.class.getSimpleName(), - Route.PROPERTY_FLIGHT, - Route.PROPERTY_ROUTE_TYPE, - Route.PROPERTY_BEGIN_TIME - ); + route = findByTopiaId(route.getTopiaId()); + String ql = "FROM RouteImpl " + + "WHERE flight = :flight " + + "AND routeType = :type " + + "AND beginTime <= :date " + + "AND deleted = :deleted " + + "ORDER BY beginTime DESC"; + try { List<E> queryResults = findAllByQueryWithBound( - ql, 0, 1, "flight", flight, "type", type); + ql, 0, 1, + "flight", route.getFlight(), + "type", RouteType.LEG, + "date", route.getBeginTime(), + "deleted", false + ); E result = queryResults.isEmpty() ? null : queryResults.get(0); return result; } catch (TopiaException e) { @@ -88,13 +92,36 @@ } } + public E findPreviousRoute(Route route) throws TopiaException { + + route = findByTopiaId(route.getTopiaId()); + + String ql = "FROM RouteImpl " + + "WHERE flight = :flight " + + "AND beginTime <= :date " + + "AND deleted = :deleted " + + "ORDER BY beginTime DESC"; + + try { + List<E> queryResults = findAllByQueryWithBound( + ql, 0, 1, + "flight", route.getFlight(), + "date", route.getBeginTime(), + "deleted", false + ); + E result = queryResults.isEmpty() ? null : queryResults.get(0); + return result; + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + } + } + public int getLastEffortNumber(Flight flight) { - String ql = String.format("SELECT max(%1$s) FROM %2$s WHERE %1$s IS NOT NULL AND %3$s = :flight", - Route.PROPERTY_EFFORT_NUMBER, - RouteImpl.class.getSimpleName(), - Route.PROPERTY_FLIGHT - ); + String ql = "SELECT max(effortNumber) " + + "FROM RouteImpl " + + "WHERE effortNumber IS NOT NULL " + + "AND flight = :flight"; try { Integer queryResult = findByQuery( Modified: trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java =================================================================== --- trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java 2012-08-23 10:22:44 UTC (rev 462) @@ -25,10 +25,15 @@ import com.google.common.base.Function; import com.google.common.base.Objects; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; import com.google.common.collect.Iterables; +import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; +import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Set; @@ -88,22 +93,6 @@ return result; } - protected static Function<Route, Date> TO_DATE_FUNCTION = new Function<Route, Date>() { - - @Override - public Date apply(Route input) { - return input.getBeginTime(); - } - }; - - protected static Function<Route, TransectFlight> TO_TRANSECT_FLIGHT_FUNCTION = new Function<Route, TransectFlight>() { - - @Override - public TransectFlight apply(Route input) { - return input.getTransectFlight(); - } - }; - public static boolean equal(Route o1, Route o2) { boolean result = Objects.equal(o1.getRouteType(), o2.getRouteType()); @@ -138,4 +127,144 @@ return result; } + public static String toString(Route route) { + String result; + if (route != null) { + result = new ToStringBuilder(route) + .append(Route.PROPERTY_BEGIN_TIME, route.getBeginTime()) + .append(Route.PROPERTY_ROUTE_TYPE, route.getRouteType()) + .append(Route.PROPERTY_EFFORT_NUMBER, route.getEffortNumber()) + .append(Route.PROPERTY_DELETED, route.isDeleted()) + .append(Route.PROPERTY_VALID, route.isValid()) + .build(); + + } else { + result = "null"; + } + return result; + } + + public static Iterable<Route> filterNotDeleted(Iterable<Route> routes) { + return Iterables.filter(routes, Predicates.not(isDeleted())); + } + + public static Route findPrevious(Iterable<Route> routes, Route route) { + return getPrevious(routes, route, orderByDate()); + } + + public static Route findNext(Iterable<Route> routes, Route route) { + return getNext(routes, route, orderByDate()); + } + + public static Predicate<Route> isDeleted() { + return IS_DELETED_PREDICATE; + } + + public static Comparator<Route> orderByDate() { + return BY_DATE_COMPARATOR; + } + + private static Comparator<Route> BY_DATE_COMPARATOR = new Comparator<Route>() { + + @Override + public int compare(Route o1, Route o2) { +// int result = ComparisonChain +// .start() +// .compare(o1.getBeginTime(), o2.getBeginTime()) +// .compare(o1.getTopiaCreateDate(), o2.getTopiaCreateDate()) +// .result(); + return o1.getBeginTime().compareTo(o2.getBeginTime()); + } + }; + + private static Predicate<Route> IS_DELETED_PREDICATE = new Predicate<Route>() { + + @Override + public boolean apply(Route input) { + return input.isDeleted(); + } + }; + + private static Function<Route, Date> TO_DATE_FUNCTION = new Function<Route, Date>() { + + @Override + public Date apply(Route input) { + return input.getBeginTime(); + } + }; + + private static Function<Route, TransectFlight> TO_TRANSECT_FLIGHT_FUNCTION = new Function<Route, TransectFlight>() { + + @Override + public TransectFlight apply(Route input) { + return input.getTransectFlight(); + } + }; + + private static <T> T getNext(Iterable<T> elements, + final T element, + final Comparator<T> comparator) { + Iterable<T> nextElements = + Iterables.filter(elements, new Predicate<T>() { + + @Override + public boolean apply(T input) { + return comparator.compare(input, element) > 0; + } + }); + + T result; + if (Iterables.isEmpty(nextElements)) { + result = null; + + } else { + result = Ordering.from(comparator).min(nextElements); + } +// +// int index = Iterables.indexOf(elements, Predicates.equalTo(element)); +// +// T result; +// if (index < Iterables.size(elements) - 1) { +// List<T> ordered = Ordering.from(comparator).sortedCopy(elements); +// result = ordered.get(index + 1); +// +// } else { +// result = null; +// } + return result; + } + + private static <T> T getPrevious(Iterable<T> elements, + final T element, + final Comparator<T> comparator) { + Iterable<T> previousElements = + Iterables.filter(elements, new Predicate<T>() { + + @Override + public boolean apply(T input) { + return comparator.compare(input, element) < 0; + } + }); + + T result; + if (Iterables.isEmpty(previousElements)) { + result = null; + + } else { + result = Ordering.from(comparator).max(previousElements); + } +// +// int index = Iterables.indexOf(elements, Predicates.equalTo(element)); +// +// T result; +// if (index > 0) { +// List<T> ordered = Ordering.from(comparator).sortedCopy(elements); +// result = ordered.get(index - 1); +// +// } else { +// result = null; +// } + return result; + } + } Modified: trunk/sammoa-persistence/src/main/xmi/sammoa.zargo =================================================================== --- trunk/sammoa-persistence/src/main/xmi/sammoa.zargo 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-persistence/src/main/xmi/sammoa.zargo 2012-08-23 10:22:44 UTC (rev 462) @@ -1,150 +1,164 @@ -PK�X -Asammoa.argo�TM��0�ﯰr����B�K�Z��ʍ��Hv����zƱ�8�v%�RT�{��a�L�M���E=��Es�X-t��;BB���f� -��ʌ��Q��hE>Eh��w���dEN�m -�s,�"Q]0\&V[p��&_����C�y��졤�WL<`{}�j)B-��qi���`z�G)Aiw.��#�V�8ŋ>����5�ڣ�-Jt�<����K����B��g9��=�r����#����Y�㢼hϼu`@G4�Ù�^�Kn�*p�����G;N���Ї -�7����(�Q�h�cprk(B�v���s�7M�#ݠ���̼���<���d,S=�������.�4c����p��Lk%�X���f��|Bh\�i�����v�����/��?7��� -VMjK��F��\V��%iL�/Լ*,��&)ʓ2����K�me`_>7vJ��|'ҍ��'��L�U�MW��,×�҆m�n,uC뼁�cI�dN�0/�����8�_��;�v��\-� -�:��laM���-o����,�5:-�+�=ѩ����hD���)��d��TVs�PK��,�=�PK�X -Asammoa_Diagrammedeclasses.pgml�]m��6���_����Lbo�k�u���L�nkk+��8c�j�)�8��������$o$�$Q$��T,�4��ht?��ӟ�x�����$��y�ΝW�p6�Ɠ�ӛW��߾�_ -�����������_?�^�� -w����e�*���x9~ůH~���|�L�͟·�h�/��O�O����b9\NF�-���h��������������5�����y���^3'D����0xd�;D?�����?>���$���9|�j��k0��.^}��_���<Z�l.��<9��O�?%���<� -�� �7u�����_�2YL����t��X��0Z~{ �2 �����a��.��?����a����~������A��y�L��!ҟG�4��y�g�)��I����7�����0����6�������pn������w�p�Ξ���F��w�ǛW�����������o����/K>r�NP�_���ٙ'7|���2�c)IG���6p�� y�N�q;e�����f�Dl������r8��J���ˇh:V������w�~���b9y���kq� -g|կ|{?�����}|�JU,��G -����ĻT�?Ǐ�B����P���]x�!�^W�3�����vs�,P�Hm�*O���w�+T[��U��Sd�iS/��a�����t����sdk6ޡf�/f ̑A���P����t�c��v����'�'��$��'���@_� -ؠ�31���3ik ��zZS.$ç�r�H����e8_>sܶ�y[ -CqWU)U1� -%�0����d֔�|�BJ�x"6�Vh����2�-1��w\ffO�J1�K����b����i��#~��q�q�� �/F������#N�Gj�t�p6��7-��E=ހ�W8�q��%��^o�o��%xO��pz5��8�Q4 -��R���~�,A~�p?y��lY�wP�w�;1�\�>��A���d�n6��-çp^���1Je�Ig}�]��1���g}���Y���Y�Q#��&�N���SY3�xv� ��C��� !�43&��g -� !)&�1��w�S�y�DŽ� -<O8��ј�ݒ/��("��E��[HDَ &�)�p�E�����ЦG���a6}Dh���"B��F��+ٍ�5��F�P�U -��4�� �d�����!-T>��AH��x����:�-�Ņt�i�i)A~��+�u�u���`Av,��ӳ�`9��Su��u17�����.����y����К{��������po����9&s~��{:����"�^f�-X����z����!�kz�= - K>r����ș:�.y\�(y]�5�K�* M��̚�E�����Xs���T[����$���.�L�w��{O-���/��FHK�0��ې���%6��hEn� -?�l��g��{��F����i�����;"%k.�&�]���Nj��B�|/�MĹh�7��ݿ�*��-��Ę���{���M)ФhU�tw�Z�n.>�k`��-����&X#V=Z[[��6��%�� �"�K� �>P�5Χ�i�*���"M�5�Â�L��V�Qx�f�=����+qN�]�v��n�vn����#(��a�?��m}��C4�{��{~ڼ�b?"_E�|]=e�[4G�ORr`}i��ğ��?��o����L>�{���K���g���B�>��s��Qص<>.�X��+��/7�_V���o����a~U���(�*�� -�\P�7���l-e-z��u�IC�?̂�.W2.�@�� -�ӆb~�_�?r+.y�\�)~� �=,׆z -��v~�����M����l@�� ]0���p��U��]��6������zDŽ�Pb]f��%��AhBK�?���$�_��C R'��R"�E���3-M�4���w�u[�&�ct�(tti؞6lOv�Ш>� �~|X���/E�Qb��KdR?ij��8�/�p�b�K�꙲���jGE��c����5�R5$Z{. -p7����.*jf�W������6�l��ي aGU�ND�đ� -∡q�}A���^o��E��U� F�m�V���N|tw�ĉ�q7����%.��?#�*]����=�"�/����\�mcɳm�q8�Hvܴncųn��0��h��T����z�Ť�U��"�=c��l�����$Z�����K������~�<_O��`P����Y���M�ӯI�'��F��7�X�\4�D���^x��g=�R�s삩�������Y����W��q�%^x��pˬLm -��p.���Y)�Yt������Y˙�gߥ�k���Y=�YC�k�q��lܶ��]�� -#�g�7:��"ô(��&&<�O�>�V�?cU�x�YM���>�c�T���ƭu��ߜ?� ����>���!�Lj9��B����� E���T��S]��2�M�m�Z��d�A��'�qOy�T�����s�GDmg5'J�s�yD�!]�2j4_LP0��}��ί?衿 -FN���˻�/�?~.<�S-��Am*��C-B}��������g�S-l�am*��c�c�����^6)�T��[����?`�C�ٮ��N�a˚c -���g[����ߌ�#��=����g��&��V]����#d9a���l�7� -�1Fr���wO�"�6�4.=����A=������T]T��q`,���SA�Ь�v���_�ͬ�C�T1�K�@�Vo�'긻�T�9Z7�`֜������Egl��GU�Ls� -�S]��ڤ�*�9c�O�Ϩ�%��I~XEOZ�L�Ӈ6�ݔ��v �F���RN����I���d�H�����2�[{ݥ^=�Op^Ӝ�*��t����W~&��b��彂��� �JymF'���j�t�B��rZ95z��h���������,�ㅛW��s\�x��� -F>��_�1f�/�\�&c~$[1-�J����s���6*>�c�=�ګ�p�2��',T`���4�M�� �~�y:IuЂ/>���=����n�O�P��O���~���t8����5PKG}��F!���Y��f��)��c^|�M��z�5��¯�n/��C�1��G]C�v=WY��R�T��G]D=||��˴,���o��d�t6�y4�V�諩 *��䀨�l9B���ɔ�����FI�R蜳�����C�N�T��i�jp�jW�H�>��F*R�2��;���˃8 -��l��F�.�̚E4�h�ID;,^2��v�pS�]x~��ɳ�$��������:갻��[/��g����,��6́�G�����'��(wX)g8���+��ʝ�Q��O����B��$ʝ������k�CS�<����v!�F����8=��2�4�44 �q�1�E�Wwvvm��zTZ�n�w~u�'#mu3�ɫ�����h�A/���6��^ވsڵ9�eV�l�#���4݉����қ�J��?�����;��з�zsP���Aa���zsP�oZ~��A�n7��-W2�:�}oP8��{��M� -*5�Z������Π����\�]j#���vw��I�������Y�W�6��*�����N��3>�qM�ّ��UH��˭Duo|��V��i<�"|`��'mD<E�|�W��wUK�7Mnk��Ҝ��惯?���.>�@��+�Z��u���������%��'��V���S/�^�Hc��D��h���ןGg��-�q�����hy���>F=�䏉En�h����VF=����!_ޣ�4���I1�ƖF=�j]��ujMi]�@�W7����8سq�Y1ަ�&��[�����(��QΨF�&��T�^ͦ^�B�CΎ�4q5���f�]6P\�M�r��F<�ʌ+ă+��֮ă�L�l2fJ�|S -�r:�=�*�n�R�@�)r�;�>�*���}�1��p�m�8���\i�X -r`�ɉ��3��(9M� ��H`��S@�é�r�@p)�Ƽ��kc^_�s��Ƽ���m�@X�K��ۘ�Mf�D�ۘ�Z�>{�r�;mb^_��n��D��Y�&&궉y]Σ�\�hX�{�lۘ��6fl�Fc�k7ژ��}F*ژ��w4�Ʋ�ƪ�f~�\7f�~43��S��p�-̛r/�,L�m��NL�[��'?�`��n��7�N4�YT�����o��č70�� -q��</f������03�Ļ�F��V�R��<�c�t�!����١ZY�=�=�z�o�`��f묁�Rȕ2��l�$Te-S�Д;�:>L�8��J�R��V��RI��{.E�RL[�R�E��I7M�m�K݊���bDZ�'h�iI[���K%�A�f�'L��N��)�>Ĵ)Ek�Z���[���̛�����,�1��6��Z�z��F͜�D����$�HO�G�T2��Gwi���/>ܽ�/��'H�B���iE��������Qv�Q6��0���4��w�����vyq�U7H1�A� Y��Ш +PKx�Asammoa.argo�TK��0�ﯰr��l�B��.�bϕO���8��zƱ�8}����JQ5��y�̔\7��@T�*{�Uw��Bծ��rK�G�ζJ����,#e��(Ot�#T���weq�'���)c�(��+ +X�}c��^N�q�������)��V�7J +_���\(�9��@�PJ�= ����j�V�����N���%�C�H�N��I����L<�'9�h���R���Vh��I�Ijì�`O���A4��^�I��*p�����G[N�i�P�= +�V�Ch��(`�5��18��!F��NݹU�'��nP5eq&��/�����<��-�����휈3F��@ o4�|T���jIm�Q��j��tFh`��ہۖ�����ӷ�~�?=e�5t�7X�g�ʨ �(!��~��Uf(��Q���繟����{�������O�" �I~y"^�(XeJ7�߂����"��/굡~��Ӑ;�i�<�S1�U�!�k���%q#��]`���ǥ��Z��cI��zmQ�0��|Hr�W϶��ލ-oTe�P/t�HǑ*����c��?��(��z���PK/UgH�PKx�Asammoa_Diagrammedeclasses.pgml�]m��8��>��;��#R$%�L���2I��ٻ�b1p��w�V�/��������cGɶ�7I%��eI�M0���X�z��?��<| +�I4{� +�;��l�'��7�~��}�����w?���ǫ��~��<���zw���U���x9~ůH~1���e�<-�?��Oъ_�O�O����b9\NF�-���h��������������5�����y���^3'D����0xd�;D?�����?>���$���9|�j��k0��.^}��_���<Z�l.��<9��O�?%���<� +�� ���g���_��/�,&����p�\,�y-�������q~�^��0�g�������|�Z����x���G����҇<N�S���Q4��o^a�`J�?������ +�o6�<L��ƿz��������pn~�^�q��<-���i(���������t��7��rp�?�>/���K8y���#G���OO��yr����-�?����4p$�jG�� ���T�S6�� ����h�L�f=m��,����ͫd�n�|��c���������w�X-����h���p�W���o���ق�������@���y��P4גx�J�����\(Q"�4��?��O�"D��*}c��V���n.�J��P�>�-y�jkԴJ�u���;m�e37L<�~�NU�5|�l��;�l���,�92h�B�J"_X�.���o'�oz�?�?�d~����}�*`����$__+ZϤ�%�*�iM���*��"ݒ����|��q�j�m5�]U1�T�0(�ä��/�eXS�)�.��0�<Z�]އ��T��p~�q��=�*ň7.��w{������u��DžR��ă�G�q~�/��8)F!���Y��ٸo�xV�_ሳ�I�k� �Wx���Y�k��=�F���<L~ǁ��i8��"� ���g ���s���Of�R����މ������/_&�w�q���l>��g����Q*M:닇� +g���W^?�cl��u���ʎ�5 F0��p����ʚ�Ƴ{L(�X��MLa��1�l?k`LI1!���w8����r�c?&���P�y���6��Ƅ�|��E!d-"��B"��vDH0 OA�#-"$�Om�6="������#B�D��R�5���X��nDh�av7���j5 ��$ &�xN�G<i�����yBZ<H����+%x��l!-.�#O{OK �hl^逭St��[��@��`�l��u��m���ED���q�L�vq���Vϛ%�7���[�.����½ +�G����������^�A�2�o���%W�CeUa_�C�QH�Xr���,\��F�ԑw��r�E��낭y]�W�Hh�e��.�$��fǚ�E\��:5��&�]��w�e:��E�{jy_��}Qu7BZ�Aw؆�u�/� �ݠE+r�l�Ye�l<;��T6�F�N#��$��)�Xs��0����>^��z��{1m"��@�@������U)�n�&�\������nJ�&e@��r&�����xus�A^�kDthiֈ��5������"���E,��N�Q]Z)��q>�L{T .�h������e��E���«h6��!�X��]�sZ����lt;���s�͗A��S�E�����o>D�P�G�Ez�O���C�G�虯���}���IJ�/-X��s���~�� +c]��@�/Þ�Gvϵs�s�\��,�[Yh�'z.��# +�6���E�1}%��%����j�����w���?̯J1w�`^r�����f6��͢��E�?��>i(��Y���J�eȑ_s�P�����Gn�%���?��@0�����PO�#���/����O�4]�������} +���^ž:���QZa��,��i��7pL8 +%�e� ,P���&�t�ӈ�HB�Ep�> u2� %2!]�iPO;��4J�_|G^����lr;FG�BG���i���aW +��>���LJE8����(6J,2�c�L�x���c`�G��?@|t�;@=S���]�����vW��\��Dkϥ�F�\t"s�EE�����>���f�� +�:[�[$�jщ�82c��A14β� (1���M�r�蔵�Ĉ������!��ω��.��8�=�f����ą��g�]%�˰SC��]��%������m,y֣-�=G�����m�x��-�=|&�4� +���Y��Բ��W�g�sփ-��~~�D�9r�rc��r������ � +�6�9����p�5��\ݨ����������h�@���1��\J}�]0�x��38���>����>n�� ��|N�e�9�5+�:��Y���|4�5k9��l�4u�v�3��9�bu�5����V��됳cd����F�8_d�����䃇���� +��c��/=�)P��g�c�J1|סҸ�.C5��}"A�O�bR���"��5ĒI-�6_��;_����ڜj!|a}�+�Rf�i�V�mT��ן4���d`"�)��J�|Y_{N����D�x�6�9��ZF�櫂�A +�C`���p>�����=��A�ȉ�y�����υ�}�E�5�M�z�E�o?�p������r���5�M��z�u�?������&�`����`�`_^\�l]�b�=�u� 5lY�b����P�l밾���qw�ڢgV6��,�$S۪k61�}�,'쟞���fU!4�HN"]?�� U����ƥ'}�\\7��]_�����j=>�e�?�c*(�u�ݮ2_�k��UyȜ*&�c�H���M�Dw7��>G��̚3���X�B�>�茭^B���i�Xaq��Ӵ@��P�4gl���U�dT1����@���z���!��R��.�hXʩ:=��za5�4Q�L��yx^X�yakϣ�ԫ��i��a�3VE���=��j��$�Q���W0�|����O�!���d�cVC�@ +��"^H04BN�!���Cy]-Ӽ��^�u�����p�*���k����B���_Á��7��{�E�����d���d+�%[i��"�=�rn[8��FŇ:c�G[B{���V&_��ㄅ +�tcz╆�)���/���o?O'��Z��gQcP�\<�-�� +x�I�����᯳qR�j�������(��8���l>��r̋ϣ��^S����]�5���ET|(5����k��Σ�*k��@ꛊ5��������|��%_| �Mu��a��&2���j|}5U�DE����-G�����טB4�rՙ���(�U +�s6������y�ى���:M\ +�;B +�J��G�ԈCE�]�}v���xy�A#� +|����Y���<�h���A����n�C��O��!yv�ij�R�����]Gv7xv�������Y��ḚEӦ9��(w�bו��x�+�,�p�p�{�C��4�]�����](w�D�S46�R�u�}hʝg�r��.��h[���]TƝ&��&�<N>Fh���ήMZ�V�J����ίn�d��n�7yu��q�9��~�Fs��qN�6��ʖ�r���;��4]\zsP���=�m��7�������vsPA�0���V��vsP���A/o˕�y���ޠ~�{�J��֟$�)���3����e9�e��ڈf>��]�~�G4q�'���kf��U�M5� +i 9�}�����r\��ov�?d�@���r+Q�����U��v϶�X���I��O�=��h�@Ւ@���j�M��Zd�4�i����O��A��>�|����}�E]���z)�>��vI|��v�U|��ԋ��$����$��,>hi�����jv�o��}~7�ewZ���Q��cbQ�[�Z⻆���Q������yȗ�h5M~_��ycK�y����:����F�快��j�K�ٸ +ެoSQ +��-RZTT`����(gT�^��Q�P��fS�i��!g�rW ��RT�H��.(�Ǧ^��G#\eF�����WkW��U&z��3��@���9�\E7q����9�f\�E��>����8����N���p�90^���A��_�����S|j$ 0��) ���x9�S ��fc^_ڵ1���9�jc^�[�6f �ȥ���mL�&��Y��P�mLa�i���[9�61��JA�ob��Ĭ��uu�ļ.�ѿF�R4� +꽍 �mL�t36u�1��mL��>#m�l�;��ycُycՏy�??f�3[?�����L�)QC���M�s&ys'&�-� +���T0vp�M̛r'��,*�yo`��m`���Hۆ�ňP�3�LNO�z���i�]r�nf�� +)�o�1e:ΐ�qu��P�,���C=�7���`��f묁�Rȕ2��l�$Te-S�Д;�:>L�8��J�R��V��RI��{.E�RL[�R�E��I7M�m�K݊���bDZ�'h�iI[���K%�A�f�'L��N��)�>Ĵ)Ek�Z���[���̛�����,�1��6��Z�z��F͜�D����$�HO�G�T2��Gwi���/>ܽ�/��'H�B���iE��������Qv�Q6��0���4��w�����vyq�U7H1�A� Y��Ш �j�B�=2�n�G[�Op{T�4145�5�a�� -�������d+�[�����L�ڎߥD�ߥ�I�I7I���?/�p�VcVf��E�H�#x�~)����W�������#�� �F��x��U��v�4=��<M#&GȜʆ�1�'^�Il�#Y��-�KqN;[���`fQB�� �B�]�0/�5�<� ຟv��,��p��^�{��*�x�q#�<��VW��2+�ʗ��)��1׃ڜ�4mN����}��Z���I������]?e�����K�Tm�b��Ru�o�O�0s�����I���m1�Z�3����jQ�4c֘f(���߃]��(Me�F4��U"\H���X-1���3� -�4��=��L3&1�d�Mp�f�6�,Q4o�fQ�f�hSaN�h��_��Q�f���?�A�H̜�7W���|Ŝb�L�J��.�n��e�e -�u叿UXԤnh���}���6��I�>�" R��Q�Uj�� �ԾS�GTj�&��a�8j_f�+�z��/,^/iN;^/��{x�����X��qvS�o��n�U\k�g�>��qWQ �@�_���î�N��:uw�<��S��>�Z��>��aV��z�ˡ��\���qS)�bǮŁG`0�m�w*ʱ��ŗn�a*���$T�K�R�K\{����m -�0A�8���+��Xi�y��m��:��D��wɉ�0B�[���אHe`�w�(EPOw��{ -|-D*�Pm�Z�^l������Hw�N� i��4�i�1b|TU�A�Ls:�![ma��2�hK�8NQ˨�Q],`�ȣ���i��T�'��~��'[=��n�:.F�ul��n�1��N� �n ��9�r�5�O��pz5�=��hgUwQ1���.�hF��E��ֻ�K��.j+�w����ӥ�@��6.��Y�G� �W��������^V��zX/}��K+zXO�I�!����t8�'v�U?�n+�Z�!��=�vX���-�>,�Z�[k�����Z�~�$�ۑ=R �id/8�OA�5����|�a;�4>��`MB���A��˹!�U��eA!�f'}t��p���9cL�a�L����?�J���u��%)ٜYK39�{��{��n_��:�L��G�[٩��,�a�:�D��ǭ�To�����p+;���1� �N#í�So~~�"��}�M������1��6�1����}A!�͊]�Ie;g�8)��'$��cV¢��2�$N͎�I�q ��l����#i�Hy�)���GX�*������D,a��:bt��Q%PE�x��H�N*K��lM�'��B*��B$��:�6�TƇl�T�Q2tK*� ��2*�LKQ�;0���,�I��Ϥ����l����qJ@�%���TV��d�X~3����} �����C`U�I �z=�"�|��&��e�A����#��|���y8�V@�� ��[i ��z�z0=�����4Z�$�W �����y:�J^����@d�6�T��.�P6�+,h�c�6�J�6HYcj� -���H�����n*�����6���fJYŰx3x�i~yɥ�F�p�`��6��{>~��r��L�� -D��6pOۀÏ�xu>��:P�n<S��������0^����X�S�F������Q��c� -���;B������0��Dk��5F��b[5�8�><��ec4(�g�%���E���-�� -9�]�E�PT��mQ��E��[NP��7���1�g�F˲��%�C3�q4;4��a�����v�C/T��vh�F*ء�=%�t��-UQ�a��}x[dL:m�^��7;��vh�A.i -/��I��Ћ���2���rn���-Q�@�?;EI�MQbl�pN���B ��0�2[�����m�H���vq�>�,{m���b^��ר���!����<:K<��m��ls����횼F��57#F��Gg��ʹk�q�H���a�)RJ��Ri-w���m�hD��� 2�M)rt��R�\����dY$���\Sgn'��j�k�gS%qm��4�����5*%�����-ڠ�˕�]f&����(�u��D�8��FM[Se��c�(�� �^�֨��V"U����\$�7_!�||?Iry��*��S-iM���4��\�n�=M��q�8Z�#C9�n1��=�r�ڲ*�sS#�s��2�sSo�s���K�+� -���&�� S�XM�z4|�]K��t�Mo#1��l)�$���,���j�Tb�SmLrK�R'h���R��RF�bظT))����6zNV -����s6p_1Tv,A�%u���\�2�q�2� +�勆ä����B�R@:(�bn���`ٙM[���|����/�p�_x�3A���s��Q3���j��_N���.w�k��<����c�4�O�u�����^��<�5�*Qvq�����4��ǩ�v�8]�����Wك*����k��'���[z����#���)i?�i��kJ]>\U'��T}��e���s�g�n�,������2S���j�����t8���ץ'��D�W�p%���������(���6z6��q���,|������ο�����2�yv�(���3�.6���)�Y�XL�D�:�@L�e��E��c���m����&�0�ͮ��!I�9J`���������y3ʶ�&���є$ -�h�����#��#G��;Z��%M�E!��^Wy��D���u��4���M�������՛��0����N4 -�����5S� �,7��(߅��m��Q��X�K�����U~��t�h�(C�� -�u�����??G� -uh����}9�R�c&EU�I �}I�2ԓ]�"�uh5��^����*t�Y���@�8|�L�UX�^ �pC�n��ؕ`r.�,ʹ;�<Y%���E�qA��|,R�,�(r����8:K�C,���/�̖*(q��Xi.qX&Q��I鬵ʿi\C%I7I1����d�uE.�,4�����A�\ԑ�<����^��&���.��oa��:;F��k�m�pa~۵ւ��35"}Js���˓�}%~FF�����);�,&i��� �3�V�g��ᰌ��7>��q���_fNC�N�!��#�3�����9�=���Q�=�d>|;#�ݎ�>n$�ۓƭU����"g��>r��|8[��~;�g]������h�Kf�+pYE��$A���8�� FTq�T]����E��;FP�� K���Ш=���34�����Ѕ����#�J�H4L�x -CYg5���Pe20e��d��0�`g$�(�-�yT�&��n���h��̞>��¹��k�Î -n�v����c`�4A�-F�5��L�W���q8 -�a��S��)�'S�x�jG����|��-�jl�9l�z{it��X5ا����@Ě���c�@T -T%�!� -��*}HA����9�����`�̜dj0�9hQ@�&��b���Z��ִ����k d�������o;��oa �֮���H��� ����P��� -�}m�ߜ���@��ȩZ���[y6���:|5�N��xH�A�'X���I���&�avҴM�e �Gpy����������д����V���#�y�۷.[�^�&��A�����B�Ξ���}����m�o۸l|w��ѻn.�m7e��������<�#��+���FOC6��d� -Q�����-�=�q�n�����}n�DA7�� `7z����k,3��?ӵ���k�b��M��w���u�h;����/��o����E�m��oFon�I�K��wk\��|�����x9�j�ػ�0��c~� -��_$�1)>`u����p4rh�����@�ox��#��t��~�e�B�r=��PS ��9dyL�H �k]-�y5|~�0��X˽�/"�K -��YK�N�FC�B�֨�J�^ 3��5��@�N�DJ�P����_��K��_����$`�Z��;�e�M,]S�I,Ŧ��� ZF��t���>f8.ܔ|�.>WLwK7�^?�O�Y�D�K7���`N�VKg1g�J���=`%��V �Ą��b��j&�����D�9E31��z��6�"]*�l\�@W*�g5[�"nӇe����J59�B�>D{q�j5"��{���|��H��U?����Zm�gQq�ƨx-���5c�����hy���۰%�m����E� �&�m�[�yDV@����=h6=lx�H5?��D���V�zXh�R�$���qP�����˘��жp�mbh[���f]�X����@H�����fRh���<rW9QGލ�����Y�f���5$RsM��]B'�K`Z`[X��5��F����a:}`{��6�۪��4��Ae�+l�Kf7���2�j�tVͨ�m].=���(�� �^B�Lm�0���*�����1��m���5���p���/�8�7�V��V9)��D��!W!�QrZ����C.��gOՖ9+��D�0a�e:�<g�C�r�G�X宗�He�[���r�6V�-� �*�@GSP�86�G�Y(G� PM� -�����U����� eC�����쮒��a:Ja(��<�cT��z�@��3��3�Q����v[e��P��t����~��y��A�S���a���ёlN�\���ª�y�7��sWlN��]�ڜ~�mN@��6��q��t�6��ۜ�ns��9/���u���m� -�ۮ��7����HO�y�f+�X����1ٱ�U���dzJa���σ�_�?m��2�x��*��ZUA��ңt` -:n��S�[��n��J�;�F�)R��.���vi�t���ӦP��vf��8���xW��Av)����YE� ���S��c��ā$Z��hH���A��1� ��F�S2��9Sđr�bd��&�qC��m�IS����4��{�t�1�\�ZN��E,\�/�p�_z�\"f�%Y�D�h*e���֣6%7`� -�� -����#g�o� ����Sx�xS9C����d%�7��N�(Y��pI�:*��:�����;�X!��(e_|S��*]�6�U� -w�0d:���甚��|���s��$����@�����q�W�y8��./�j��������s��.Κ,�|ͅ���lNE�n�qT�iz�qt3~ -?D�cG2��Ɖtӭ�a��'�o�Zyw -���+^���� -u�0�%�|L�!?����*�~�|N�i� -~���g�<9����AzO�/���j�e�}R�K�*���ig[����|� �����/�E�m�|I;����>���V|P�;|m��r�>���_��&��7yg}���u��L�xy���FjŖ�y����y���7��l@q�����F�:[a������������$[�E��I�,&�:v�q�3,���Yۦf4ZC���r[��v,�E\���'�i#�}ސr[�o��B*��7��c4��PTt��֊n�/#Q���*+�UG���n -�t���Q�U(L�jZ�5jn��n�"N2dk:К[;O�Y��5�ҽ�V�-�J��T�ʹZ��]������n�����b��F�0w�kHa��ͺF-��'3T�1 'q`¹��[�Dʴt"�z-m�2R퐻w�|zSX�%A� m*aB\��uH_��RF����,��fZ����jm���f�Vm�fi��VK�h2�A�`�J�������"�|������/!5D�9d��t��Mo*�_����1R�vX����Q)8�֣R��Q�r���XB��~�I�4=�b�CŹ9����� ^�,��} x9mmؖT"t�h[R�"�lˢD�\���J��9��B�>��-[�8��4�an߶l}�@��[�-[�(�Ύ���}۲�}m�o۶l|_�ے���)������ -*6*Vj!V���y(x�$����1D�q�e���J-��IT��J-�e��z�*���Ѳ5j�n2Z�%����~��ִ��X�F��@�n߂em�`��o݄em4ak�y�۷aY�mX���6bYӍX��T4n3FrLL#��崘�Ͽzz�����PK���Yh*��PK�X -A&sammoa_Diagrammedecasdutilisation.pgmlMN=o�0��+�7�ٵAuM 0�1Q�d`���aY"qd'U~|������ݻw��Os'���m�q ���P�G��l7��eޕ���l:�\/��D`$���c�:����|�L�d�8m�n�����Xu��"����1���4TrR*�����M��9U�����o�� �n��gV��I�������л��z�Y��:��d�PKǒV9�PK�X -Asammoa.todoeO�j�0<�_��.YnkW6�M��{��Xk#P�ERL?�5%Ѕeg��aV�/�,`�ƙ�H�3��Tz���ٝ�HɾI����Н?�ģBҞ���J�H��*%a%�u�|�� +�������d+�[�����L�ڎߥD�ߥ�I�I7I���?/�p�VcVf��E�H�#x�~)����W�������#�� �F��x��U��v�4=��<M#&GȜʆ�1�'^�Il�#Y��-�KqN;[���`fQB�� �B�]�0/�5�<� ຟv��,��p��^�{��*�x�q#�<��VW��2+�ʗ��)��1׃ڜ�4mN����}��Z���I������]?e�����K�Tm�b��Ru�o�O�0s�����I���m1�Z�3����բ�iƬ1�P\����L3Q��"\�h�#�D��8y�Zb���;f2di6}{�ݙfLb��ڛ�&2͘m�Y�h�2�<�YE�2�T�$�&�<D���2�j��j����9�o�.>�������4���5�~�]�?��g9�n1��5�0����I1��FS�Zwmj��}�E��G�,�Ծ�=v�}�h���>M(öqԾ�9V����_X�^:Ҝv�^:���`���ͱBs�������ִ���}^�㮢@�n�8�ׇ]+�o���u:�*�y�ۧ�y}е���}^�ì(0q���C�˹�R�Ŏ]�/��`�o��T�co]�/ݬ�6$TJ3�=H�ԗB�B +��� +GW=��a��q���5V�K��������u.���K�Oa�Է!�!���n�bQ���*���Z�TX���Խ�4u;_���0��A���i��~�b�.��������t0�C���x�e��2�*q���Q㣺X�N�G-��k���O:e�"w1N�zpK�u\������:�c<a�t���1�st�8^k�F���jn{?D�4Ϊ�bLO�E]�ь��Z +�wQ�x�]�VT�wQ5��K%���m\X/�ʏ�:�Z �ewa��6���^�-��:V���t�����o�ᰞ��W�l��PPj�������a=R����Xj�n�A�0h�����nG�H�̧���<?��T�*o����߆�8_��8��5 M��AN�/�8T)֗�l�����á���1�3-�k�K�8@+Q����I���dsf,�����S��p�z��Yf�go<2��N�ud1s��@%��F>n}�z��3P�'�Ї[٩�Ύ��un}�z����l��hl��w�w]�Q��w���4_� +fhV�Z_H*��9 �IIe>9 ���M�a$q�hv�O��e3<$���I#G��{N�F��8�BVF�Xe�E$b c����Tň*�**ƛ�E�tRY2dk:=�lR"�L�ٴ��2>d������[RYL(猪QIe�X�"X(���>Xe�L�x&��7Mf�%�0�S:.�����'����Y����e�E���NJ@7��AA��p6��-� +<- ��{������ɴ�q��JK0W��{%Ѓ鉝% +�L�Ѳ&Y���,������ӑU���t�<"��p�r�ua�z�q\aA;��!TZ�A��S[ m̀F���H�FvSI|w���D6S�*(���!p��L���K.�&0چ[����!�#8E���eچh j���{�~$ƫ���ԁ25p���%�����r��|=����0jG���e� +�hh5 +�:M��d�6��=%Z���1Z�۪��!���S�.�Ay]8�(9�- +���lQo���-*��r �o���- +��r���hN��<K40Z�U/�-y��)��١YM +v腔���z�Z��C�7R�M�)�X��v�m��z +����"c�i;��ͽ١��C+�rISx�L:m�^��A�s+�^Ho��_� ��)J�n�csh�s��05J/�ٖٚ�=}�E(�"��_�ob���M����5�Êy �^�R��t�SN���v��m��ls����횼F��57#F�4�vԁ�s���>�ܵ���S��Fե�Z�i�h�Z� Cޔ"GG�MQ-u��{�M��{je��3��XB�̵�������l���C���dum����rem��I��% +f�+:�^']�0jښ*���&�tL(���F�����´?u�"ѽ� +����I��s͗P1ǞjIk�Ʀ�=�Rv��i�\�c��ъ�Aw�A7���A�R֖U1'ŘI�����1�Ř�z[��K�-^�p\pV85��0^)a�U���/���:����D ���3%���R�a�[M�Jsꢍan)c��r5cJFS�Q�0%����F�ɊA_1���e�l�@����^R����!+�zW,�\�BR�h8L� +ᘩ*�)e���R_�v�(Q��ܴ��<�'�8�q�2��':���0i�=��5R_���xyP�r�����c�x�8�,Lcz��^�ߏ��/�\S�1a�; +H�Lc�{��l��ӥ#,�}�=�Ҿ�|��j2�,��7Yُ9��~̑��c�������v��M��gىV��<}&�6���jo�8Z�+3��^��Ql_pqL������w]�b���K��q5QR�1��l���c4�]>����:_V�ŀ���?����w�s�ۛA�;�E6Uv2�Ŧ�?�"K���(Z'艸��X£h|oyL�d�� +�|�؊ƣ��[9$ �8G)�R?��c�a�@}2~4oF�V��2�rky!��$�М2�rky�Py�HyG�߽��I�(dR��-��C"�T���F ����B�5��*�zk���WމL!��WU�fJ7�Ε���%㻰*�m�2*�BKpAѣV�{��0�Ζ.EchYT���x_����hV���\^��/�Z +{̧��:)A�/�Z�z��WD������]�k���5r�=����ϓ� +��+��n�ݭ���C�E"�E9a���"�d���;.��o��E*�EEPGg�t��B���R�.����+ͅ.��$�v0)��V�7�k�$�&)Ɣ�T����E���}�9hc��:Ҙ���RA�K]Vܥ�-�tQg��C�~ŵ��u.l�o��Z�tz�&B�Oi�xy�������>eg��$ +�?A=v��ª����!�Q����G�8����i?�� :?�u$~���B���1��'75*��̇`gd�ۑ��Ǎ�q{Ҹ�:Y��Z�}�'Bθ�g��o��8Q[ +�6bɌ}.+�hԒ$����]�sĈ*na��+մVw�h8�c`�j2di6U�g���}�"CCVځ���Е���|�V �� o�a(묆Q��L�W�LR`f�dź<��ѤS�-2W`-��Ӈ��C8׳uͰ�bر����.���?|��&��ň��� ��1�� >��2���{�q<e�dj�P�谷�Ә�Z��9g���Oo/̓����4�50�X��{���!@��d9Xa�\�)�Vx8's��Ӳ�����L +f>- +(�$�&�E���E���Zk�goa@�xÀ�2t�q@�y��V���0Xk�ȃ�z$�Em�Z��r(�EM����o�A�P��r�T-y���<��B�|'xt]<$�� �,L��Qf�0;i�&�2�#�˼t�m�.�n����Yh�g�e+��ב�<��[��o2o�נ�J�U�o�yYg���ܾu��.�6�m\6��|��]7��2��|}���_b��ˑ���������!yn�چ(�|�\��֓�8HOz���ד>7E��'}n��'���5���ٟ��Ξ�5d1s��k�{�[�ߺ_��-�k�y��7\�ߒ�"�� +�Ʒ�77��y�%�ϻ5.Gy>��TMY�f�V�`_�}�1?NO�/���:�k�a894Y��{|��k\�7����c�DJ�I��a�)����<�K���ȵ���Ǽ>���S�{A��^���%�Ǭ%G'Q�!�T�m kT[�M/��LٚN_ s��"�_(J���/�_�%v�/�Z�M0b-����2j�&��)s�$�b���g`-��D�[�^3�nJ�����&��%��r/z�E�§�,n�騛`NJ0�P������q%�i ��iw�jbB�D1�H5����f�՜���PP��V��j�.�P6�`�+�׳�-_��C�����CR���l!��T���8J���ܽzH\�KJ$J�*�����k�6����8mcT��H�����@�ހ[� +�<Hn�mX���6F�k�"y���Ӷ�ɭ�<"+��T�p�4lN�6<S����s"��V�z=,�m�{�v�8��]��Fq�2�72�-f�ږ���Y�$V�u6��ldG惆���v}*���FNԑw#��9|�_����6 +�T�\D��E��I���V��FM��Q�m��w�N��)�ͤ����=�ciP�� +ۮǒ� +lo��G�Z�!�U3jd[�K��4ʥC`����6�B�;̤�A� +�m���u�C��fh�i�m +p#y�\i���$����?��CNJ 7�7z�UȇT���@n"p��ˡ��S�e�J078L�w�N�1�Y��\�(V��>�FY�Vyk�����Un�Gp�F��#�����(���d��xT���E�*<mU�����#HE�Pv47�>��$��u�G��R��8������9P����́cT��z�@���V�9�1�8�5�8 �����y��d���.�zq@�{t$�S(�d�漰js^���������sW�6��e�Plž��w��(ݾ���6g��ۜ~�m��r=c���{�����:�M�215�Sc����4V#�|}Lv�f�f{��RX�%�� ���O�_���/^%�J��VFU�e��(���[�����Vi��[�Aǭ��@��A��TA��K�o��]4�.��) ���s=r��9�U�z�]J����iV�sB�@|=���o��ـ8�D�\� +)sC��5�X8FC���٨ sJ&>"g�8R�T����o�bGm�M�z��\��IG�����J�r�4�,b�:�����rn1-�b' +GS)[Lͭ(��)��o@Uo�ǿ��9s�|�0�L�M��«=����*ߐ��h%+y��9�o�D��7�K�{�Q�%�9�?֘��1� +�.F)����V銴���U�s�!�i|]>�ԼW��F��v&Y��r��Ռ��v�Z��A���p9x�Vs>�h��p>�=�O���wq��`1�k.<g�p*�u����M�s����S�!�dx[�8�9�0N��n���F8i|#�ʻk���^�z�U��V�ㇱ��(��c���ͤ�]P�,���sBN+T���W<��Ɂ�/,O�{�}���Pk,3�z_V���5�H;ۢ��7�#����_��}Q-�o��K�������8&��*����k���������7I%��;��g��Lfj���T4R+�<�;��Vϛ��!'`g�c0�6��� +�'��/f�o���L�UYTnk�$8��a� �cWqg=��^aY��mJ`F�5T�((���o�r[ĕ�m�{�ȑ6r�� +)��?��:.�r[|#X>F��{.EE��k��V�2bEIO���[uD�,�� N�ϻ��\���D^���Z��i�V*�$�A������t�՟[s+�{j�"�TxKU�L��hP���j�?q�ފM��-&�ot +s7��*ڬk��[�p2Ce�p&�����L�L�@'���-#��{�˧�7�UZ�q Ҧ�&��UZZ����_/e�!�[�͢(n��ۚ����fY�m�l�vqm�6�m�4�&�$�6�4��:z!*�G�?�����R1PCT�CF�QI7IA����%�n��#��n�����@H���o=*E��*g�[ώ%�J�ᷜ�@H��P�!�8T�k�C.LY�����������fцmI%B�%*ʶ,Jt͵-�y��}��,4��?۲���Hc��m��w +� �u۲����y�۷-[�'�&��m���̱-�˟r���^�ܠb���b�R��`�J-����!KR��OC\.���D�ʩ�Z���Wj�ª_-[C��&�e[��X���ZkM��πem4`k d��-X�v�*��MX�F�֮��}��݆���m#�5݈5W�#�䘘F�}��i1O���<}���PK�Ā_*��PKx�A&sammoa_Diagrammedecasdutilisation.pgmlMN=o�0��+�7�ٵAuM 0�1Q�d`���aY"qd'U~|������ݻw��Os'���m�q ���P�G��l7��eޕ���l:�\/��D`$���c�:����|�L�d�8m�n�����Xu��"����1���4TrR*�����M��9U�����o�� �n��gV��I�������л��z�Y��:��d�PKǒV9�PKx�Asammoa_Diagrammedeclasses2.pgml��o�8��_���t'�)~�k:��r��ݪ[7i��Mʍ��v=�6 c ���,�V���c?���>��7?ƾrG��&}�4U!�A0�&n_�t}y`�ʛ���_�?�]��P�.���/�/�+*�� +�Pe5�C +BoJ�ւ��9��X%�3�7tƽ�:���p6����f^���wg�E��:�hh��;04�G�r�с�iڑ��X���)�g�I_]�5&�[ʀ�N"�{'�ֱ����j�W���Z�M����� d�+�}�oS��~�"��'���G�uDIH�0%�=r��^S:��FbE��л�Q�+O�{��������Jy�����}��֣$��,��l�yɢ����['���i��9�,���yYHԙ�>��E/��}��fr�����\�{Cz�W�'%��soi_�()��Uf�dU�Q�r����4�a t6��l��@�V��ڪ+ +�jQ�(�И?p�2�:�7諱�%�7�?��6#�_>b0)�gQo� +�99gd�\|~�䯀9��!��b����v��Ή��r���d������}��2 +�4I�T4U�u��"r#��`�����-�!�.Y�K��2��r�,.w����<S�Z2�ܼ��V�Z!mżU�\�O_�V�чW.�b?��1�'�8 +�r 6S"�q.��aa�j�aE�㫡�3��:,�-�Yl9M�`<uB:fc�"Vl�����\ʆ����W3Cf��6D:7�k�@,=h5z)��s``��(F30>�{�0��c��K``�``�C\d�Ҽ6�T����a%e_vSI����RX�%O,��(���_IGaS��O��>�D$���T�)О�B���f{b*�K����Z^���)낖��jjŋ�j&�@NJU+)]�l��0�v����ʁ���i"Kٰ�q$%�c�HH�=d*�@��� �j,� +JG�hUG�k�i/�\^�H��E�XV�=;Jj�@=^I馑H)��� +���CgGC[+���ߗs�)))�F�ZK�~(-����aIL�;w(u:��M������S�5=Ŧ!T��ө&�t\PAIPe<�\��;����jnƋ�j&�� �rY�<v5 [>��� +o��T.e��N��k*�ւ�ca^ᆭ���Z��r_�1.�=�z��S�t�� +I�T���To�Z6r�+�m�0f:�3k(�X����\SA�$�SmL0�S��y75��@6���4/QP����XS!�| + �ú�a)������:�u��j�x + N���C+�T^:.��|>ĤX�-��r +�T���i9�%S#E��C*1[R�K���9�lQS�T�y�Ée.� ��p">�9� +�E�g +'xU8�k��7����4�xQ���᯿)G���'Τ$�Tl��h��ոa��x�66���gY�`�UR����U�<�����ο����������7R�;^��W̫�����f=;��_r�W��+��[������W� ����d=�f�o�ʛ�'$le:�O�����`RF��p�uu�E��G=���4�^L=7���KF�iH"6�1M|,����N�Z��qpGh���$��R��{�Eu��iu�젰aX��������=p}�7*����V�Q���W_p��Í ��ˀK~��lpc+��$�*�u\T}m���_� +�־�m��⌮fÍ�>ad�^�HO���b;�}�t����p3�ڻ-t8���q��?{6�3kv�̇�-���ߒ��W5p{�pck/2^~�t^t�"��F>�,x���/����p3��F6"�(�$EAD~�|��r>��ًp�V>|��Z�ȡ��$ +9|�|�)�Û�����x!\6|�&��i�Ӎi�d��(Y��Z�Z��e-}Z�t��1���1�������%�2�Z'Y��ZZ���g�⸫��㮚�ۻ��J���,c�{=����丫���=S}m����7w�]��$�4^�p��2�O��k!n�Dh[�xIB��q��gE��?��PKhg{��WPKx�Asammoa.todoeO�j�0<�_��.YnkW6�M��{��Xk#P�ERL?�5%Ѕeg��aV�/�,`�ƙ�H�3��Tz���ٝ�HɾI����Н?�ģBҞ���J�H��*%a%�u�|�� ���,���\�l�v� -l�:�L�A;��Nx�{�i7�����D�7��=�l5�^8�0�@h�@���h^PZ���ˢ����CYV�j*8�5���ӓ��LB�l�)�?�~�$?PKP����KPK�X -Asammoa_profile.profile�����Q(K-*���S�UP2�3PRH�K�O��K ����Z()��qq��e��qqr�䔦g恘���> +l�:�L�A;��Nx�{�i7�����D�7��=�l5�^8�0�@h�@���h^PZ���ˢ����CYV�j*8�5���ӓ��LB�l�)�?�~�$?PKP����KPKx�Asammoa_profile.profile�����Q(K-*���S�UP2�3PRH�K�O��K ����Z()��qq��e��qqr�䔦g恘���> �z& Q}�0� -�����������b<��SR�S�R�K�����+�,EȂ9PK8��7y�PK�X -A -sammoa.xmi�]ݖ�8r�ߧ���cϜL�E��({�>�u���=�=���9 ���H -z��k�.�q����IPM�(��?��xa�$�, +�����������b<��SR�S�R�K�����+�,EȂ9PK8��7y�PKx�A +sammoa.xmi�]ݖ�8r�ߧ���cϜl��CR�=�9�klj������\�HP�5EjH��ޫ�F�r��U�!~�<IJT�%��xa�$�, _ -����~�9�#��s�?+/�Z���]ӳlwJ���~ta�T��O��^�<�k�捗�;� -^������5o6�ц.��`�L\#?�TB�|�lNۍ|[�FSE�+������Jxw�4�j��?( -}^�#�o�����! - ����y��!i���%��(��p��1Fn�P���ۤ�������e�7�Y4S�5��[?(>~�l)����D�/�ꅪ*�ƫF���)�D��+����+*��ܸ�ʟ��3��Ǐ^��x͘�&��,�( ��y��V���ߩ5���7�;=10��!���-I�W����xH��y���V�����R�-ܙ��&R_]�z�U}�2Z��'�Q��]��l桗��ͱiOl3~��9���z^���F��/��h�q��\i�%�WK)�~w�5t�l���F}oF���=�����mλ�=��H�m��:8P�˦ -�z��^����;/���_�|�r�U�k�u=" -��{n� xzAOv}Ǯ��2Eƥ�v��~w�[��~�J�xws��H�y1EV���(�0tFE��@n�}�-��h��_��2G��9�?2���̙Q���7�:�91 3`v�9�)߾Nт|���>V�o_�c��.�(�(1LY������'|�a���4|�|��'2�?(&i@T�ŷ���lr/��B��O��o�Ww���^�|���/j�#������DJ��&t�xjmS���[e/���g�1#������E�������&�����WpxIF��J`R<%�0Q�ɪXv@��ʓX���&6�BR���9�E�/�^�b;����� ���<��������L��`���'� ^���{���g[߾���v��T6"� -�]"#��Ћ��P1�����Ww!��m�ǾO_ʊ�b:��}����ά�P[�� -A��� -A��S�(�!W�3���0 s��I�r��b%s&�W���_�y��[�2��Sy{$4���OǢx(G�/�B%��V"���M�t�R���l�����Q��q���<�\s��g�dV�&�[�rG�葻P��PI;$O!C`:��7'�nE -YP�p�Z�h�ؒ�'M�D�Mk��F���Aϐ�n�\D�Iu�b6&�j�cD~'���ꢼ�ލg��~o�ydS���� -�r�{;^T��$�P��=��z��O�X�;i�;����v,�it&:stӺ.Y�N�Z��� ^���t��t�ɬQSR�^�rש��۶V]6�d��/��S�@w�%��vG�* -�\���7�9�;���v�-?,�˚�:ի���7���9l�<�}�Wÿ�����_O�Ҧn`�cN(L4Zc�Ь &��������U���m�f�D�n���7O�`.?VC�دM0�g�|7}���l�p�0��ttı��;�Sg�x�7�.��>��h��&���y4vl�� �������ې5H��Za<ʌMz�|����&D�����d�[�B?2 ې3Z��6��Оr��Y���J�}Y�c��|Tͧ/�՜�ᖶߗ@&n&���NV���/�h>O�f@���2/�ٚ9��� -f��_�Y���{�Dyx���p����͜��O/�Zbb�%�%�B�.-<A�����GD�u�X[���l�e���E��\g#�v�8�M!.p|����w������nW�:�������pt_Z�i�}�Al�G,�)��Wm+�Gf�����@��ם&W!-�Q����(���Z�;� -�ӆBf�hc��J��B�:��O��5��b_�9ΥN���ݻB̤ΐ��}��_B�˻�7E�!u;�����{%��N����}�rï���^�\|b�� +����<w�'���*R^�͗ +v +ϴ���燛��K�7����?�S>��F�y�%��q�W?���~����7�5hC�q�@n�_*�M>�h�����Me��)����j�^�}e4�P��V���) +}^�#�oe�����! + ����y��!i;�g%��e@���S��@���ŷI��������To�-��j�������)>~�B?���(į(�ͫf��"/���|�R�"�5�o��?*��An��;�J�����G�~b�fD��y&v�������7�q��7������՝���ixnH%������l3�v��yE^��Jo▮�Z�Z�-��A�WW�f�����z��r�7J��=��=�R���6l�6�W�?Y� 0��煩/�cd=����A�##�v3J�n7R���bs���� +7�Fޜ~{�{�����*�w�z���rۦ�up���M��-��7 +��u^���|��M��I��u=" +��{n� X����C�q�{y�"�Z��T��pp�M�u��F�x��^AKe�E�Xqv��п)�0��r����_��Ͱ���QP�W|���G��B��93�0�NYc,9'�d$aGY��%��o3�"_��ߡ���oȱ�h�`�L�G��������X��'|�~���,|�|��-��w�AU��?�L�܋<�5���������������� +����?��܀Lc"%A`:|<��6�������c�aG�����b2��UL&���=&��ɞr����k2JV��)���S�1���i�?����@�6��V���'�QLj9��r�!ݜ���D��tx$�� �����d���},}қ�Et��GH1}�����2��,�ʦB�PA�Kd��zK*2T������7w%��m�žO_ʌ�b8��}�~�#���������`�l� +���3+�! +�W�H�9�$�@���j�s&�W��[ +�/~Yz�도ex���ÉX��Nf>����?� +�\*_X�>y6��!KL��!�;G�B��G�y�F��gdV��[�rO�葻P��PI;�O!C`:��� �n.����F �fO?�%�Y�A��&;ݦ�V����{r�:H��H1�n\��x��V��j���DY]�������ߚx��)BR����L����U>6�E?�axOb�~@�'�h��:Ӿf :�}����-�9�i]/H-��t�F�K�TB:�d֨)�I�V������[�nN\���W��wR��d�ݳ�ݓ�Zy,ן��g�M�� g��n����Dzf�Mu�='�����?N8l�>�#�������1�Ȼ������{}â0�֧ZO5-&L���?z�q�~��`��2���m�H�4;%�,��6���"O�~��~|�1�0�mb���U����o�ǚ���~�=�ވ��W���ʓ�S��[��˩c<Q$�� +o݆�ABD� +�QFdң��_8�6!�g8ܽ�.S�l���A؆�����B.�=�[��M4;��C&}�G5|��Y�>�������r�_�J�����\,��&�Z�v[3�����̐���"��a�B�@�(�k��1�����y˹����5YKX6Yr]�/Z굉-Dh��;zBt[���m;��X֛�I\���u6��nj���ׁ�?�{;x��Xu=�x��|��}�����C)hm��㻷�\b;<b�MQ��{I=1[� +�!WFw;hr��b�ɴ�"7�[� +n����P(Ì��Yo' }?y[ +"�KY���YS�>��^�\���H:�/�L�O�>���ލJA(way���C|H�~�G��h2���g�>�{�[��u�7<j��O�ī�p+���j��}�3���;���~�Nz9|����}�&�qh6��lsS�s9� +�K$s՛fZc���,�hۓ��t�M��3�e)c�8��0W�GJ Y�[Hr�����Xߘ�H�V�1ۣ�s�N�Lճ���x�6���L���8/����M +�Yq���6�60�L��Uep6:=�c �k�ΐj��9]���RU�5�C��RZ�ÛK�&�*$C��ڥX���X#�K���D�L�6Ֆ�6��6�ն̌}�a��H<b����g_���r��c� �W� +NP�E+���ɋQ��h�b1Y�D�y*��*���Bq��~�u����M)m1v �b��b7e�ŘN��[�"뵲�b��u�L.�)r~���J������{x��^u;lr�>�D�U�d��^�0�Jk��Ϻ"�NʶyFe���sH�{��M�pa�5w9x�LlP{<>�o�Y�� +36'�`at���;Y�W��w���*A�|t�%C���T���R̰a�镬���rRr +�����n{�,���[��{�}c0(F�����ƒ���I0A�̴2���*3�U�����"�Z��Pe&�/p�Td#�$ ��0Vwc�B2��b?�">ܭ[����0��BjX8~1�����̓ +.��S��E��%0�q��xf���u��=n�O��L��x{^�F.&�0yb��@#_�F�b�&�+#�VA���4�]���8�4q�b������x�S̓��%B�O-#��8PV�.|):x�B�j������[.˰}��Cd|�%wI�a�Z�儇�J�t�N�M:vѲ����C��a���������C��!��1�*^!���Yq��Bfa�\n|=B@ڏ�dD��^0'9p�� C��8��1<d5���n/��闄)Ox�����bV^F�r"���d�y��i��M�,�EwGY)�gS�,v��4�F�C��5Q����ث�n���!w�΄z�2,-&ݤ(}�&ӏ_�9Dt�j�+�ϱԽ�=՛S�{!���V{�"uu��O�X �ׂ���L_��c"Z�9O@й�=������=�#�c�D�=GvJ����JU�1Xg�Z̨��xf�;���.�<h�<�ϰ%���`(�Q� m� +2���,m��b��U��E��ؖP�{����( +ִng�/3�$�@@f�����=�>��~Zb�KX�5���]#�6��,�����P��A��V�#z����-�Ob�#]�6������ ����`��횉�\���͙>��'N�=�Z�����f�Brl��l�?:��F�����̪��T[u�ᩁ�{��f(�43�O�V+�矒EF>;P��[\�1��n��J���go��Z�v��h'Y�-�(�:���ş��7�7�v܄�̲�%�nU��y�M�_����F�d0�w�����tʈ^�T�&�:�x�k��C��[*��n!�Rq�2�Uz���R��|cIӻ��p$j�o�����ʌ��t��[-g�P:\�Mf^��I�_a��SfX`4<�[N����'Zm����-I>S���%�-�>x�!�VaG/.���h3�R��mx��`�!"A���b����L�_`cW*!' 2cTb p<wf�Kp@��%O���� y]�d�PA(`Wl��Lp@Y��%G���|z� ė�f��M�PpO�ɓ*A�X�r�Kn�B����1��L�� �T�z#��n�E��~Ӛjf��2�4�Q`��s���@��Ř��Q��P�\��f�ʁ���t7 +��tXr��|96�o��5i@���+2��Tl��]ݾ��f��a��j�����`�R��a�i�I�6d�i�3�=(��ې}�)�\#D<A"w5�=cȁ��7�z�q��0��%��5F�ݸP�� H8(���� �Y�� +D4�:@DCs�3w�c4Xx��غ��VnЙ�E���P��f�����ϊ������9�R,-�ڲ8}��7�Hp�H��ԌfR�,y���gNu��Q¼����@���dc��1�:��F/LW��P�A��%/��C�B�C�q@�:�n��� +( �+W�&�8}�I��Po���r��y���C����Rjl +�D�[�a��`�?��� N�dHu8�-��0.'�݃�oP��%wv�E��Pcc@���n�qz�0��N:�1T-�I�QfAz]����[��n�(1���q�d{O�A�&vp��%YZL��F��PY,(IF����O:R2j�5�f�����ԎM�B�CY���r�!{̐���<�Q�5��o�{]32"�V]������1X�������]��t���E�wI0 �҂�� ���T���xč:%L@���S�\0� + +<�OS +�Lp����`�? +7���Rj�u���-�@���`�3����B��T���. !Biz����i�б�b�X�p#���Aܙ?��;���R*eɧ;�Yjn�2�� �bgs9����g�����G��e�b�H��3��$�a��T�d�b +�3�fO��(�'{��������`jAE�� �p�C�3��� +7hĴ��<-&hD�@�Iu�w�%a�6�9,�,�1,�)7[�c��uyXP�"��(|�� �Ң�a�(Hu��{xM�$��0=����N��3�.���6����6���Y��D�v������WV�;�i��/ t1<�X�>�m�o�˒�+6r���%�{̔��*�cb��', +���q�#�H����0������횉�\���͙C��IG�1^4_�s�E��jy���L�\$�-�G��sd&�r�ƈ#�g��v�`|VM�&ܪ�O +�\�*0>� �y�e�i��<��d���e��l93`rGF�pvő2��Dn +<Hz#��br�II�R�����B��x^��3��!6?ڳGy���TH�l1�g��~Nu���Y\f���.����cG��>�Z|� �+ls�*��I���SFO�>(���e3Vb�=���8�,��b.���S"�и`9�;�·�<�W�S�q� �ނ<µt�c���"�L��>}y���*��N�a@cf���˃0V6#��F��}�9�z�H�SIC�>(���Po$��L�a4�N��kM�~�)�]0s��v�CR��$�ZP��8�b��P�a{�[$!B�(�)�ђ�H`�����A���z(� +-�P�?av%�ZPd�0}Y��P�5��X0��)8��9@�O��C3�e|]��,N��M��-�����| +�9�T�[�>Ȉ��Pg(�&3��mr�8��yЬ!3u\n�@e�����Ae�%I�<��$͈���w˟NU55C���-a�갭~�� o0��ZL�=q���^�Ceu�ض�0���b8p���,?��'I�T���':`�a�j[G����� ֒���?9�Z���p�oXT���T멦�N��ѺYJRx��[`-y�`s7"B9hv�!Nl@�:��t� n�H���soa)��b����yRj»�C�9g��n�i��<�7�:�����r8 ��b�q���8Rj��s�g���|8c�9�,A qNu��OY�6��G���U���-�X�4a����1&)��&���56�e�y�m� � ��I�!�Y�-��%�S��;Y6�ˡP�������3�v����J��Dh_9���/d��Z�P)��b�\ ��Mu����;��[�_�3��bB5�T�z;����pB�d�Y��(��PM��4�ޝ�{1p<9�g6/e��B���j;ʫ�3tl������7���pR�>7�=�{e�Y��}Hh��PM'��5[���T(:����i�)c�y���P@��� � ΄�:�� +�w���;?�+��G��� 6zS��[��&��?�f!N T�Hu�B�/rE����hQ��Bx��@f +��5( ��b +bK�Sj���\�Ș�[p��P���Z;}��d +��s��Mq�`� ա�[*��Gg��N���tfV� ���s��x��w��?Ȱ� 4�� ա�emN*'�{`G��C�n{�(0�u���S�96�o��`�k0Dm���Q���5[mL��W��lu;l��Y2s���O�ÂK�# ���f}O�Q�O��.ִng̔17aQsw��O���6}��K�ױ��^���%��$������G��%��A������=ď����@>aK���;D����0����,�O�k&ZrM� +��i�D��O���j��kQ��Z�al�{�ɱYlf��ѱ������1��0��$�j"5�V]6�xZ?E�����|��K'Ide(-愯8}p�7ա�� +Q�P�G�b<xB�m��B���rÀ�j�/��ݾи�n����.R-&ۭ8}��6ա�@�ǡ���fk�#�P{��m�� ���١���)�CSfG�I�i����C��U( +�*����o +rg�?R�\sO���+/u�q�3��6cj�,�1�-�Z������d&H�����2�`�Ax��Z��r,!2�{��Wi0u���Myn<!�y�3}j�n�h̨�#�A�M���~�t�O�d=�f>�mn�z.�q�u�d��4ӊ/Ƨ"A`�aI��S��p�\�U�J��� +I�be��t��O��(�'E�2V���ӯr$H��0bk +6K�Ê�( DȤ<#D�ɴ9vZ`��H���Fk���}��i#���VK�,\_Q+L�͙+0����a��k>O�S�ǎ-&��8}b�`�ɺ0F�ͬ�L0q�`�s,o�(&��8}b'u r�����4�F� j���� 7;��*n��9�\<�_��*��q1)����3x����7崿�%��x�n��F?���L�a4�H��]k��;LA�4w<lW���bF�u33Z-(O�8��U�z��b�%�� �ܥE�_H�U##�鄤�����Ƣ���y�q����슘��_���0���p�oX���֧ZO5���Ò�GH`��-���p�����p�b3�_b3Ϥ��e��b�{A�z��$��G@���T�ߋ��m����X��V[+��8}��6������$�A3���xfR ������G��0����-e�!��?*%N �Ju�s iq�g��2��]Сq�� +\ +���'�hCu(9�vʎ���uy8p��P���B�JLB�z0r���B@�Pp�P�܇x.���,�ei�����h��,�X,�f_���I���]�@����PY,�#�Z�K͝��@Fh�@�v�j���ܦ����YLX��L7b|]���2-��u(��4?��N�;)�P`o5�)��.1� +�ZL%? ��_�C�PPAWR��V���&�4K�Iu(A`ER� +j�m6�V$Z��4�6ӫ1��;͞�����ih ��b���� ա���N�V���L�4u�ii<��ߛMۜ�ݖnD<0U����ӯ?7+��l'3�='�g���fq9���Y�3q�{�<4+.�C����j%��xg8T�W��*����R떷D��/3mI���BH.2o���Թ��Y���Ż|8� X��A���s�m9 +�w\�(�x�,�1�-߯������?��pX�Ӑ� +3��<�#s%x{پ��[A��u�J�I�:�>;S�`1�7$��[�*���$ q��� �(��)�ڎg��zX�͙�ڠ�s�4)�ST��V'�ج%��tpe +�3g��v[�)ң� +��Yn��\�3sNVT K��)���ha FtdF�@�Ԍ��%3~ʺ��S8�.B��V�Y�u\�nk*�ژ|}�V�Î��v��2ʼn�F�>/A9#�]�t�/�kb���03�7G�c��]���mr�HC?��w.yqypz,@4���0?��I�Y� +afQ~�A�܄yg��̢�/�ڴ���6%�k"�m��&�Z#��҅y��#��X쏱��ՙ�"�k0G2��9�3�i�oRe�_��,�K���K(V���sU> +�sC��={���I��d�v&Y�� +��%��$������}�M��eIԠ������#�C���l/1Ld-N����ׇ�ͱÑY�/�\�?ٮ�h�ť +ݜ��i|���C�EI�j�= �Fw�e3�؆�عԍesZ~'�Lx嗼�E��X��D�0�(�dOau����\)V��r���^���D�u�䵤�r��A�&XP�gA�ͬC��-�V?ݒ��S�Ns������f|BI�[s��N"�z��眃!��y��7 �ާ1E^�GJ@�]S�VB�J� +D_{?�l���4c�v��ѵ'��\x6A�h�q�(�_3�CZ�ݜ:�N���M�E/f�YvI�=��Ϋ_E��rK�Fޜ̑��鹝�SόT��7��X1�� �� bP`e��%vV��������@/x�?/<?T����G��9��Q��,�e@of�0��r��Or>�ʽ(Z��=���q�,����g|"��Nl��;������;���7��z! +��i.�Ɪ��w���ґj'���Vv\�11O��۹�õTb5s�B�o$V��/�3~�Mb�/�NJ�1A����'7�r*�� -�r���ά��[�;�:s�+�ϰ��x�w��U/�oa�)&0r�O�b=M�>�.o�z.ǹ�u�d�z�L�͑�e��{�S�����|ƥ,e�'�� -uO)!��b��|c�{ǃ||c���7&9��CĦչ��h��@��&S�l�<�6�m���h��|��6>� -Gs�\pV�>��M�%��W`��48�x -c �k�ΐj���]]��R��5�C��BZ���9Z�'�w�\,����l,�>ӥ\yK��L�5Uo�TK[hҘX���Nّ����W�O�����^�wLAH������Vě��g����d�*b�����h�UrN���2�����G:n�}�B�b�(@��n���n�1����XI�kE�ņ����S��;4 -��Í��0v�X�V����Y��*UTE<�3��"1�J+��O�"^Oʶ|Fi�xČ9$>x�٨xL���;<f&6�<�>��^/��hČ�I.X��:>�NV����'�|�S%��N=g������֫3���7� |ZNJ��<9=�n�ф�1�c�5�FSc��v����2�#�u��$�t��$���{ZfZ��kc�������NM+����1�s%8EJ�x�`f��1vJ!�5Oj��V�nW-�^��@_"5,�?��ya����A���1��,��s��V8J@<3Gfi���a���S>>S#3����砑�I&L�X*0��g���clcUD#seD����Av�檫bvV^X:M\'�5�8}�(^�T�`=qɀ��c��i3Uo���ެ�G���`�a)!��2m�tp���(��.)=�[K ���0�UJ���,�I�.Z�\[�+��6���Z�Z�R��9d��^�+$�3+N�X�,������@H�����s���U��0�о#Ǟ>��l��5����4��0�oQ�b��:Tņ� ���5�d!�y^F-i��n� �x��QVJ��=�����u}�[f�I�6�H�� -���q�'_���Ի�ai>�&E�֙~��*�!�SU�_ �K���S�*u/!��j��X]]E�1����ӑBq��`����`�BD�=Z���BB���I���y�9�d?�#;%�� �~�s��Kr�,�Z*3�>�1��.�N�=��6Ԃg��b�� -v����P�`� (��@ �R��@�ۦ (\��g�ք�a�-����h���;8#ـ�&!2�ɨ���ޗ��1v�s��/+�bz��>v����a7���աN��6������h{+7G>aP�}�t�$m������A�1!����'۵VZrajI7g�,9�^��KQ��Z�bl� -�c.g��ѱO72{��8��,�HM�E�%(�G)�e����DS0�(L��(��^I��y�iu��(��'�Sz�?F�^�u}��\��Z��ܴ��nV�;�V5l����|�� -^[�|o�m� )<<�e%���6=6�~Ղ�����$�]ڲ�V[mQF -K�ԑ�d��h\��)� -��2m��,�/�Z��JK��7��V[� ˄��֘�?Ԙq6������J�+c���kT;��+L�qʬB̝������mA�+��~X�⚤���X�$�{7������ы�=� <�̵�3v��o��3�H�aj/�����1-$�إ�G8��1* 8�;�����i��glf8X����^(!0�+�P@&8 �,K[G���|zT ė�]f��e�P�O�ɓ*A�X�r�sn�B0���14�L�� �T�j#��vG��b�>��Ԙ{ :�(0ќ�9��p ��|�a��(Hu(m���n3I����g���-9B�|��,y��3��H����S�\\��{�;fbܼ�C�y���-N�ة�ի���k�}�H�is��� �Y����:lΧ:��|}�bn�&h0��;�����^lh1>$���@��ak��5���ͮ;u �X�O�`q�2O"���\���tM��Y�J,]�4��P�Sq�Zp�� �7�I,,N�Nu 2�݈/ΦEPu@���bނ}�T� -〸u��,~�gP@jW.�Mq�`� ա�Nq�� -$0�����= ND�:T���6�����=�~�S^@�>�.��p[�ͭ�[L�!u�<G�"l��0ա�ƀ���:��J`�96ړc�V�C{����:?��=p�R�V�a�����M�y�k0�Z��!��di>Q�Ba�Ci�� �!� -I�ۥ�9$�,jrH�����j�M3�CY���b�! -fHAr��¨�R��m�F��6�ٶ0{{��٘������ -A�X9�6��a��n��8K�. ��Y��14a�`���0P��Q�� ȵ��c��3��~N����A�i�@� n��!���gN�f��A�Y�C�1@���F�����y��S�Q�@��P��%!DP��jb���4��Tv��&7�ln;ĝI�3��3q� �,ա�0P������.��;���g�m>�w7�d�o="�%�!8U�_ƺR��-'��ᖳ�S{�ԛ4d$��S�q�ə�P���B1��?Xv�*�@����?H��.}#,�:3#�ۇ��bcAOe��N��Â*o{���[p�f��eFA�Ci=�O�_�AZL�u���q�l6 -kҦra��62���.��M�E&�߲��PLze��#�YA�s����k������+6r����%�F˔��"���͑OXb�#b7I�=����Óa�1!��a�'۵VZr�jI7g-��T��fd���s)J�Z�S�Mf6���l�>:�!Gf�F�4F�1>]�+�(�h"5�]��xl��zW����C�݆(3�8&��)�&�M��Fgˉ�;22�K�����fs��-��'�����-ա����w����ş�d�ukO��FRY A��������9ա��gq�eZ�h�O��/6t�G����J` \,�[�P9�-�tX'��4��p��AE�T���a��w���\)~�sO�>8���0���u���8>���\+�_���W�E�0{s����A�,��2��KH���cC�K�ņ���-���8X،ܒFw!���#��OQq��&D�C���9F�Yכq��d�w�L���肩�|��k�սz` �՜B� ��T���ۋ�|�1�C�H)�<�?;7���(�ˇ�Ђ��#�aGQ��9E����^#��s阂���� -dx�*8038&��AA�����ܬ�x2���*���Y �֜�J��=S���d��eNj���S-� -�0SŶ 4fHIr��vyP�,���FҌA�zPI���T5K7uJ)�z2AX�4�V��x�7��lͧ|�8}P>.ա�:Cl�Y��� �PER�����$�R�C�R��+ -BᨽS\��YJJk�T��Ɵw-�� -lt� ��Fk��5a�Lوh].%)<`��-��<�ZR|��&���;�ـ�6 R*l:��7}$M��W���dj>�y���<�������Cf7��4O����S�Lp�qL}/���4�j��A1�T� -�D�\��f�)���|N8KG�SJ�SB�VS�[ȠG];����Xl�41A3ہcLR��M N� R*l���h�2A*! @��ÂC�[r� -�l�6�",7�C�DI��-?�'�����*��C�}�j`K\�����r!�R��������PNw�Jnp~���|�H�R���?���eg>0 N�@�C9��¬{7�%�qO䀞�<�����Vk�8��a���"��у��!��I :ܤ���eg��w �}�C9���R͖ڴ�P4M]��q�)�y���P@��� � ΄�:��w���;?���G��� 6zS��[����?s�f!N T�Hu�B�/rE����h^��Bx��@f -�kP@���Ė *b�:T��#�(�1�36/8&� աڑ1�;��Mw|o�v�V=(�h>�����A�C�s�n!ԉ� -�M��-fV�!���s�4�����?Ȱ5'4�� ա�em�*'�{`C��C�F�=}��[��z��!]G�гk2�lfz��[�ӡE�z��3}��=F�z`��7^`����$�+��P.�?G���2��皑�c� -�o�����L ���h{+}�|�"2�4�I��;D����0�����'۵VZr�ڒn�.���-���+~Υ(Uk-O06�m�ձ�/g��ѱ92C7��1b���2��(�h"5�]��x�%w�����|���Idilma��sXU�>8���PXh�:�ȱ-Xr��3�����A}�T���b�sS���1]�8�O�Vq� qk�Cف`�C���,u�c�Ќ��2[Ap*��C)r��M�)G��'y�=�WEx�t�{|�����xO w����#���Z��]�Rg:�l:s�z9���N23-���j���M�Y@J��9<Rb߽�is�V|�}ÿ�H�L*�݀l�UjL]l�vS��l���L��|V�+"S��X����mwJ�����X�Cө��˛���q�p�-�j"ʹ<���H�iX�k�T��8U.r�H%k� p����:-;���LlǓ"C��I@��W�$B?�X����cD�$� -2��Nm2m���;�a-�OƚN˱�Τ�l ��Ume�`/�&��̕ -a���Z�9i4��<�';N4�t4��mp� &���s7��3�����,�CD>����;tq OZ�/]����n� �N�0�Lmd+��%���#�` «8��d�O,��U��ꌊi�KS�V�����~Z|�#Ӭ뱠5ړ��i2mX��\ ���ʌ<-,�ff��S�q�ɖ����u5��%@��K �x���� F��� IQ��������y����芘��\���0�����ol�ƺ�Y��A�^A�#$0�y������=L�P��L�W�����N���XZ�Å��; -F@h��2tm�1b6��9��,lj���)a#N_�MzA`�9�B8y)el���O�]r��V����(��8�2��LB:dQ��gN��� �zG�U��,��3P}W~6r:�#N���?@�sB�7���6:��h��8��/�^�G� -� -�((0��U(@P�D����C��Mr�-0�!�� �S0dYZ���3(�����c,�@���$`� 2��:����K����@�h6G�v�*���ܦ�����OX��L7br����2-��u(��4?��Nj�;)�P`k5�1��.1� -䘚O%? ��_��ᡠ���&ӭ�@v-i���P����� ��Fê7&�L�f�l5�^����i�L��}Os@��@������w\��p}�Ff����Q�d���l���j�-3恥M��Z1�Z�s��o�v2ñY�3q�|�� l���X�9'^9�(�Yq�8�R'�M/8>��;á�C,áك�_Z��y�-�p��c�Y���:��|>i��b�&vgB�8(�x��z[��� -�� J��c���ɘ}+-?,��������7��0��8drÌ���\�V�o4��V�8s]��g���N+�O� - ���Z�R&1: -H�e�3�6�jy�E���,�sf�6��o��)��St�xl�$��tpi -�g�n�����荖�O&X�0����9YR%,��ǘc磅%�ӑq�R3�����-�ZX\2��0;=\P[�@zx��Q����F㝭������n�� ��~���4�$Φ���|�#$��=�m�|�}jc�E��K? }e��U��7YM����Y�{4����ؙhY�9�l�<�3�/�"��&~f3JQX�'� -3,��ѳ�<l!������嚬���=㵻鹝�cϊ�Ǖ7�X��2'�� ���2Cn�����Z�U�h����� -��|��g"nj��܉z3�!V��#��|ў܋�($����Ce�E������;�� ����b�^g���{���\�Q�P -�M�E -bc_n��v:R풯�k���'O_<��[AN�����ox+�?�f������rV1~Ϻ� ���|h�Xƛ>?��p��>!����r[ngr��˿}|OW@a����7�PKn�V�/ �PK�X -A��,�=�sammoa.argoPK�X -A���Yh*��vsammoa_Diagrammedeclasses.pgmlPK�X -AǒV9�&*-sammoa_Diagrammedecasdutilisation.pgmlPK�X -AP����KL.sammoa.todoPK�X -A8��7y�i/sammoa_profile.profilePK�X -An�V�/ � -&0sammoa.xmiPK��P \ No newline at end of file +��`���;*�#�ѯ�>?��p� +�>#�;��3r[ngr������F9��G����PK��Ts"��PKx�A/UgH�sammoa.argoPKx�A�Ā_*���sammoa_Diagrammedeclasses.pgmlPKx�AǒV9�&,-sammoa_Diagrammedecasdutilisation.pgmlPKx�Ahg{��WN.sammoa_Diagrammedeclasses2.pgmlPKx�AP����K�6sammoa.todoPKx�A8��7y��7sammoa_profile.profilePKx�A��Ts"�� +s8sammoa.xmiPK�[ \ No newline at end of file Added: trunk/sammoa-persistence/src/test/java/fr/ulr/sammoa/persistence/ObservationsTest.java =================================================================== --- trunk/sammoa-persistence/src/test/java/fr/ulr/sammoa/persistence/ObservationsTest.java (rev 0) +++ trunk/sammoa-persistence/src/test/java/fr/ulr/sammoa/persistence/ObservationsTest.java 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,214 @@ +package fr.ulr.sammoa.persistence; + +import com.google.common.collect.Lists; +import junit.framework.Assert; +import org.junit.Test; +import org.nuiton.util.DateUtil; + +import java.util.List; + +/** + * Created: 22/08/12 + * + * @author fdesbois <florian.desbois@codelutin.com> + */ +public class ObservationsTest { + + @Test + public void testInRoute() throws Exception { + + List<Route> routes = Lists.newArrayList(); + Route route1 = new RouteImpl(); + route1.setEffortNumber(1); + route1.setBeginTime(DateUtil.createDate(12, 54, 12, 12, 1, 2012)); + routes.add(route1); + + Route route2 = new RouteImpl(); + route2.setEffortNumber(2); + route2.setBeginTime(DateUtil.createDate(12, 14, 13, 12, 1, 2012)); + route2.setDeleted(true); + routes.add(route2); + + Route route3 = new RouteImpl(); + route3.setEffortNumber(3); + route3.setBeginTime(DateUtil.createDate(12, 54, 13, 12, 1, 2012)); + routes.add(route3); + + Route route4 = new RouteImpl(); + route4.setEffortNumber(4); + route4.setBeginTime(DateUtil.createDate(12, 55, 13, 12, 1, 2012)); + route4.setDeleted(true); + routes.add(route4); + + Route route5 = new RouteImpl(); + route5.setEffortNumber(5); + route5.setBeginTime(DateUtil.createDate(18, 55, 13, 12, 1, 2012)); + routes.add(route5); + + Route route6 = new RouteImpl(); + route6.setEffortNumber(6); + route6.setBeginTime(DateUtil.createDate(33, 55, 13, 12, 1, 2012)); + route6.setDeleted(true); + routes.add(route6); + + Route route7 = new RouteImpl(); + route7.setEffortNumber(7); + route7.setBeginTime(DateUtil.createDate(12, 54, 14, 12, 1, 2012)); + routes.add(route7); + + Route route8 = new RouteImpl(); + route8.setEffortNumber(8); + route8.setBeginTime(DateUtil.createDate(12, 51, 16, 12, 1, 2012)); + route8.setDeleted(true); + routes.add(route8); + + // In route1 + { + Observation observation = new ObservationImpl(); + observation.setObservationNumber(1); + observation.setObservationTime(DateUtil.createDate(30, 54, 12, 12, 1, 2012)); + + Assert.assertTrue(Observations.inRoute(observation, route1, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route2, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route3, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route4, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route5, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route6, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route7, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route8, routes, false)); + } + + // In route2 + { + Observation observation = new ObservationImpl(); + observation.setObservationNumber(2); + observation.setObservationTime(DateUtil.createDate(30, 14, 13, 12, 1, 2012)); + + Assert.assertFalse(Observations.inRoute(observation, route1, routes, false)); + Assert.assertTrue(Observations.inRoute(observation, route2, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route3, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route4, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route5, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route6, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route7, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route8, routes, false)); + } + + // In route1 because ignore deleted + { + Observation observation = new ObservationImpl(); + observation.setObservationNumber(3); + observation.setObservationTime(DateUtil.createDate(30, 14, 13, 12, 1, 2012)); + + Assert.assertTrue(Observations.inRoute(observation, route1, routes, true)); + Assert.assertTrue(Observations.inRoute(observation, route2, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route3, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route4, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route5, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route6, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route7, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route8, routes, true)); + } + + // In route8 + { + Observation observation = new ObservationImpl(); + observation.setObservationNumber(4); + observation.setObservationTime(DateUtil.createDate(12, 52, 16, 12, 1, 2012)); + + Assert.assertFalse(Observations.inRoute(observation, route1, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route2, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route3, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route4, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route5, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route6, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route7, routes, false)); + Assert.assertTrue(Observations.inRoute(observation, route8, routes, false)); + } + + // In route7 because ignore deleted + { + Observation observation = new ObservationImpl(); + observation.setObservationNumber(5); + observation.setObservationTime(DateUtil.createDate(12, 52, 16, 12, 1, 2012)); + + Assert.assertFalse(Observations.inRoute(observation, route1, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route2, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route3, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route4, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route5, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route6, routes, true)); + Assert.assertTrue(Observations.inRoute(observation, route7, routes, true)); + Assert.assertTrue(Observations.inRoute(observation, route8, routes, true)); + } + + // In route6 + { + Observation observation = new ObservationImpl(); + observation.setObservationNumber(6); + observation.setObservationTime(DateUtil.createDate(33, 55, 13, 12, 1, 2012)); + + Assert.assertFalse(Observations.inRoute(observation, route1, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route2, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route3, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route4, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route5, routes, false)); + Assert.assertTrue(Observations.inRoute(observation, route6, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route7, routes, false)); + Assert.assertFalse(Observations.inRoute(observation, route8, routes, false)); + } + + // In route5 because ignore deleted + { + Observation observation = new ObservationImpl(); + observation.setObservationNumber(7); + observation.setObservationTime(DateUtil.createDate(33, 55, 13, 12, 1, 2012)); + + Assert.assertFalse(Observations.inRoute(observation, route1, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route2, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route3, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route4, routes, true)); + Assert.assertTrue(Observations.inRoute(observation, route5, routes, true)); + Assert.assertTrue(Observations.inRoute(observation, route6, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route7, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route8, routes, true)); + } + + } + + @Test + public void testInRouteFirstDeleted() throws Exception { + + List<Route> routes = Lists.newArrayList(); + Route route1 = new RouteImpl(); + route1.setEffortNumber(1); + route1.setDeleted(true); + route1.setBeginTime(DateUtil.createDate(12, 54, 12, 12, 1, 2012)); + routes.add(route1); + + Route route2 = new RouteImpl(); + route2.setEffortNumber(2); + route2.setDeleted(true); + route2.setBeginTime(DateUtil.createDate(12, 14, 13, 12, 1, 2012)); + routes.add(route2); + + Route route3 = new RouteImpl(); + route3.setEffortNumber(3); + route3.setBeginTime(DateUtil.createDate(12, 54, 13, 12, 1, 2012)); + routes.add(route3); + + Route route4 = new RouteImpl(); + route4.setEffortNumber(4); + route4.setBeginTime(DateUtil.createDate(12, 55, 13, 12, 1, 2012)); + routes.add(route4); + + Observation observation = new ObservationImpl(); + observation.setObservationNumber(1); + observation.setObservationTime(DateUtil.createDate(33, 54, 13, 12, 1, 2012)); + + Assert.assertTrue(Observations.inRoute(observation, route1, routes, true)); + Assert.assertTrue(Observations.inRoute(observation, route2, routes, true)); + Assert.assertTrue(Observations.inRoute(observation, route3, routes, true)); + Assert.assertFalse(Observations.inRoute(observation, route4, routes, true)); + } +} Property changes on: trunk/sammoa-persistence/src/test/java/fr/ulr/sammoa/persistence/ObservationsTest.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java 2012-08-23 10:22:44 UTC (rev 462) @@ -28,12 +28,13 @@ import fr.ulr.sammoa.application.SammoaContext; import fr.ulr.sammoa.application.device.DeviceTechnicalException; import fr.ulr.sammoa.application.device.gps.GpsConfig; +import fr.ulr.sammoa.application.device.gps.GpsHandler; +import fr.ulr.sammoa.application.flightController.FlightController; import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Campaign; import fr.ulr.sammoa.persistence.Flight; import fr.ulr.sammoa.ui.swing.campaign.CampaignUI; import fr.ulr.sammoa.ui.swing.flight.FlightUI; -import fr.ulr.sammoa.ui.swing.flight.FlightUIHandler; import fr.ulr.sammoa.ui.swing.home.HomeUI; import fr.ulr.sammoa.ui.swing.io.input.application.ImportApplicationUI; import fr.ulr.sammoa.ui.swing.io.output.application.ExportApplicationUI; @@ -148,6 +149,8 @@ ui.getBody().remove(currentBody); } + ui.setScreen(screen); + switch (screen) { default: @@ -158,6 +161,7 @@ ui.getBody().add(currentBody); break; + case VALIDATION: case FLIGHT: FlightUI flightUI = new FlightUI(context); Flight flight = flightUI.getModel().getFlight(); @@ -180,7 +184,6 @@ ui.getBody().add(currentBody, BorderLayout.CENTER); break; - case EXPORT_MAP: currentBody = new ExportMapUI(context); context.getSwingSession().add(currentBody); @@ -194,6 +197,7 @@ ui.getBody().setTitle(_("sammoa.title.exportApplication")); ui.getBody().add(currentBody); break; + case IMPORT_APPLICATION: currentBody = new ImportApplicationUI(context); context.getSwingSession().add(currentBody); @@ -201,7 +205,6 @@ ui.getBody().add(currentBody); break; } - ui.setScreen(screen); SammoaUtil.updateBusyState(ui, false); } @@ -285,7 +288,13 @@ @Override public void run() { - context.getFlightUIHandler().initActions(); + + if (SammoaScreen.FLIGHT == ui.getScreen() + || SammoaScreen.VALIDATION == ui.getScreen()) { + + FlightUI flightUI = (FlightUI) currentBody; + flightUI.getHandler().initActions(); + } } }); // categorie raccourcis @@ -320,11 +329,14 @@ @Override public void run() { - FlightUIHandler flightUIHandler = context.getFlightUIHandler(); - if (flightUIHandler != null) { - GpsConfig gpsConfig = context.getConfig().getGpsConfig(); + + if (SammoaScreen.FLIGHT == ui.getScreen()) { + + FlightUI flightUI = (FlightUI) currentBody; + try { - flightUIHandler.getFlightController().openGpsDevice(gpsConfig); + FlightController flightController = flightUI.getHandler().getFlightController(); + flightController.openDeviceManager(GpsHandler.class); } catch (DeviceTechnicalException ex) { logger.error("Error on new GpsHandler", ex); SammoaUtil.showErrorMessage(ui, ex.getMessageWithCause()); @@ -437,7 +449,7 @@ boolean result = true; - if (currentBody instanceof FlightUI) { + if (SammoaScreen.FLIGHT == ui.getScreen()) { FlightUI ui = (FlightUI) currentBody; FlightState state = ui.getModel().getFlightState(); Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaColors.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaColors.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaColors.java 2012-08-23 10:22:44 UTC (rev 462) @@ -63,4 +63,8 @@ public static final Color TRANSECT_WITHOUT_GRAPHIC_BACKGROUND_COLOR = new Color(255, 233, 233); + public static final Color DELETED_ROW_COLOR = Color.GRAY; + + public static final Color VALID_ROW_COLOR = Color.GREEN; + } Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaUIContext.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaUIContext.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaUIContext.java 2012-08-23 10:22:44 UTC (rev 462) @@ -30,7 +30,6 @@ import fr.ulr.sammoa.application.SammoaService; import fr.ulr.sammoa.persistence.Campaign; import fr.ulr.sammoa.persistence.Flight; -import fr.ulr.sammoa.ui.swing.flight.FlightUIHandler; import org.apache.commons.io.IOUtils; import org.nuiton.widget.SwingSession; @@ -46,15 +45,14 @@ protected MainUIHandler mainUIHandler; - @Deprecated - protected FlightUIHandler flightUIHandler; - protected SwingSession swingSession; protected String campaignId; protected String flightId; + protected boolean validationMode; + public static SammoaUIContext newUIContext(SammoaContext context) { Preconditions.checkNotNull(context); uiContext = new SammoaUIContext(context); @@ -96,16 +94,6 @@ this.mainUIHandler = mainUIHandler; } - @Deprecated - public FlightUIHandler getFlightUIHandler() { - return flightUIHandler; - } - - @Deprecated - public void setFlightUIHandler(FlightUIHandler flightUIHandler) { - this.flightUIHandler = flightUIHandler; - } - public SwingSession getSwingSession() { return swingSession; } @@ -157,6 +145,10 @@ mainUIHandler.getUI().getStatus().setStatus(message); } + public boolean isValidationMode() { + return mainUIHandler.getUI().getScreen() == SammoaScreen.VALIDATION; + } + public void open() { context.open(); } Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StopAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StopAction.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StopAction.java 2012-08-23 10:22:44 UTC (rev 462) @@ -53,6 +53,6 @@ @Override protected boolean checkEnabled() { - return getFlightState() == FlightState.OFF_EFFORT; + return getFlight().getEndDate() == null && getFlightState() == FlightState.OFF_EFFORT; } } Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBar.jaxx =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBar.jaxx 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBar.jaxx 2012-08-23 10:22:44 UTC (rev 462) @@ -40,7 +40,7 @@ <FlightBarHandler id='handler' constructorParams='this'/> - <FlightUIModel id='flightUIModel' initializer='getHandler().getFlightUIModel()'/> + <FlightUIModel id='flightUIModel' initializer='getHandler().getParentUI().getModel()'/> <FlightBarModel id='model'/> Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBarHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBarHandler.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBarHandler.java 2012-08-23 10:22:44 UTC (rev 462) @@ -31,6 +31,7 @@ import fr.ulr.sammoa.persistence.Route; import fr.ulr.sammoa.ui.swing.SammoaColors; import fr.ulr.sammoa.ui.swing.SammoaUIContext; +import jaxx.runtime.JAXXUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,37 +44,42 @@ private static final Logger logger = LoggerFactory.getLogger(FlightBarHandler.class); - protected FlightBar view; + protected FlightBar ui; - public FlightBarHandler(FlightBar view) { - this.view = view; + public FlightBarHandler(FlightBar ui) { + this.ui = ui; } - protected FlightBarModel getModel() { - return view.getModel(); + public FlightUI getParentUI() { + return ui.getContextValue(FlightUI.class, JAXXUtil.PARENT); } - @Deprecated - public FlightUIModel getFlightUIModel() { - return SammoaUIContext.getUIContext().getFlightUIHandler().getModel(); + protected FlightBarModel getModel() { + return ui.getModel(); } public void init() { - getFlightUIModel().addPropertyChangeListener(this); + ui.getFlightUIModel().addPropertyChangeListener(this); FlightController flightController = - SammoaUIContext.getUIContext().getFlightUIHandler().getFlightController(); - AudioRecorder audioRecorder = flightController.getAudioRecorder(); - view.getAudioLED().setState(audioRecorder.getState()); - audioRecorder.addDeviceStateListener(view.getAudioLED()); + ui.getContextValue(FlightUIHandler.class).getFlightController(); - GpsHandler gpsHandler = flightController.getGpsHandler(); - view.getGpsLED().setState(gpsHandler.getState()); - gpsHandler.addDeviceStateListener(view.getGpsLED()); - gpsHandler.addGpsLocationListener(getModel()); + if (SammoaUIContext.getUIContext().isValidationMode()) { + // nothing + } else { - if (FlightState.OFF_EFFORT.equals(getFlightUIModel().getFlightState())) { + AudioRecorder audioRecorder = flightController.getDeviceManager(AudioRecorder.class); + ui.getAudioLED().setState(audioRecorder.getState()); + audioRecorder.addDeviceStateListener(ui.getAudioLED()); + + GpsHandler gpsHandler = flightController.getDeviceManager(GpsHandler.class); + ui.getGpsLED().setState(gpsHandler.getState()); + gpsHandler.addDeviceStateListener(ui.getGpsLED()); + gpsHandler.addGpsLocationListener(getModel()); + } + + if (FlightState.OFF_EFFORT.equals(ui.getFlightUIModel().getFlightState())) { getModel().setEffortPanelColor(SammoaColors.ON_EFFORT_BACKGROUND_COLOR); } } @@ -104,7 +110,7 @@ if (route == null || route.getTransectFlight() == null) { // set null will hide label - view.getLblTransect().setText(null); + ui.getLblTransect().setText(null); } } Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUI.jaxx =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUI.jaxx 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUI.jaxx 2012-08-23 10:22:44 UTC (rev 462) @@ -187,6 +187,6 @@ </JSplitPane> - <FlightBar id='flightBar' constraints='BorderLayout.SOUTH'/> + <FlightBar id='flightBar' constructorParams='this' constraints='BorderLayout.SOUTH'/> </JPanel> Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java 2012-08-23 10:22:44 UTC (rev 462) @@ -53,17 +53,23 @@ import fr.ulr.sammoa.application.FlightService; import fr.ulr.sammoa.application.ReferentialService; import fr.ulr.sammoa.application.SammoaConfig; +import fr.ulr.sammoa.application.device.DeviceManager; import fr.ulr.sammoa.application.device.DeviceState; import fr.ulr.sammoa.application.device.DeviceStateEvent; import fr.ulr.sammoa.application.device.DeviceStateListener; import fr.ulr.sammoa.application.device.DeviceTechnicalException; +import fr.ulr.sammoa.application.device.audio.AudioReader; +import fr.ulr.sammoa.application.device.audio.AudioRecorder; +import fr.ulr.sammoa.application.device.gps.GpsHandler; import fr.ulr.sammoa.application.device.gps.GpsLocationEvent; import fr.ulr.sammoa.application.device.gps.GpsLocationListener; import fr.ulr.sammoa.application.flightController.FlightController; -import fr.ulr.sammoa.application.flightController.FlightControllerDefault; import fr.ulr.sammoa.application.flightController.FlightControllerListener; +import fr.ulr.sammoa.application.flightController.FlightControllerOnBoard; +import fr.ulr.sammoa.application.flightController.FlightControllerValidation; import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.application.flightController.ObservationEvent; +import fr.ulr.sammoa.application.flightController.RouteEvent; import fr.ulr.sammoa.application.io.CampaignStorage; import fr.ulr.sammoa.persistence.Campaign; import fr.ulr.sammoa.persistence.Flight; @@ -99,7 +105,9 @@ import fr.ulr.sammoa.ui.swing.transect.TransectUI; import fr.ulr.sammoa.ui.swing.util.ButtonActionTableCellEditorRenderer; import fr.ulr.sammoa.ui.swing.util.ColorTableCellRenderer; +import fr.ulr.sammoa.ui.swing.util.DeletedRowHighlightPredicate; import fr.ulr.sammoa.ui.swing.util.SammoaUtil; +import fr.ulr.sammoa.ui.swing.util.ValidRowHighlightPredicate; import jaxx.runtime.JAXXObject; import jaxx.runtime.SwingUtil; import jaxx.runtime.swing.JAXXWidgetUtil; @@ -110,7 +118,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.swing.*; +import javax.swing.AbstractButton; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JTable; +import javax.swing.KeyStroke; +import javax.swing.ListCellRenderer; +import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; @@ -163,7 +181,6 @@ public FlightUIHandler(SammoaUIContext context, FlightUI ui) { this.context = context; - this.context.setFlightUIHandler(this); this.ui = ui; ui.setContextValue(context); @@ -171,8 +188,12 @@ this.referentialService = context.getService(ReferentialService.class); this.decoratorService = context.getService(UIDecoratorService.class); - //TODO use the correct flightController from the flyMode - this.flightController = context.getService(FlightControllerDefault.class); + if (context.isValidationMode()) { + this.flightController = context.getService(FlightControllerValidation.class); + + } else { + this.flightController = context.getService(FlightControllerOnBoard.class); + } } public FlightController getFlightController() { @@ -225,31 +246,34 @@ startTime = timeLog.log(startTime, "beforeInitUI", "entities are loaded"); - try { - flightController.openGpsDevice(context.getConfig().getGpsConfig()); - } catch (DeviceTechnicalException ex) { - logger.error("Error on GPS init", ex); - SammoaUtil.showErrorMessage(ui, ex.getMessageWithCause()); - SammoaUtil.updateBusyState(context.getMainUIHandler().getUI(), true); - } + flightController.addFlightControllerListener(this); - try { - flightController.openAudioDevice(); - } catch (DeviceTechnicalException ex) { - logger.error("Error on Audio init", ex); - SammoaUtil.showErrorMessage(ui, ex.getMessageWithCause()); - SammoaUtil.updateBusyState(context.getMainUIHandler().getUI(), true); + if (context.isValidationMode()) { + + if (logger.isDebugEnabled()) { + logger.debug("Open devices for VALIDATION"); + } + + openDevice(AudioReader.class); + + } else { + + if (logger.isDebugEnabled()) { + logger.debug("Open devices for ON_BOARD"); + } + + GpsHandler gpsHandler = openDevice(GpsHandler.class); + AudioRecorder audioRecorder = openDevice(AudioRecorder.class); + + gpsHandler.addGpsLocationListener(gpsLocationListener); + gpsHandler.addDeviceStateListener(deviceStateListener); + audioRecorder.addDeviceStateListener(deviceStateListener); } - flightController.addFlightControllerListener(this); - flightController.getGpsHandler().addGpsLocationListener(gpsLocationListener); - flightController.getGpsHandler().addDeviceStateListener(deviceStateListener); - flightController.getAudioRecorder().addDeviceStateListener(deviceStateListener); + FlightUIModel model = new FlightUIModel(); flightController.init(flight); - FlightUIModel model = new FlightUIModel(); - model.setObservers(referentialObservers); model.setFlight(flight); model.setFlightObserverForPositions(observers); @@ -454,17 +478,22 @@ column.setCellRenderer(editorRenderer); } - table.addHighlighter( - SammoaUtil.newColorHighlighter( - new CurrentTransectHighlightPredicate(tableModel), - SammoaColors.CURRENT_TRANSECT_ROW_COLOR) + table.addHighlighter(SammoaUtil.newColorHighlighter( + new CurrentTransectHighlightPredicate(tableModel), + SammoaColors.CURRENT_TRANSECT_ROW_COLOR) ); - - table.addHighlighter( - SammoaUtil.newColorHighlighter( - new NextTransectHighlightPredicate(tableModel), - SammoaColors.NEXT_TRANSECT_ROW_COLOR) + table.addHighlighter(SammoaUtil.newColorHighlighter( + new NextTransectHighlightPredicate(tableModel), + SammoaColors.NEXT_TRANSECT_ROW_COLOR) ); + table.addHighlighter(SammoaUtil.newColorHighlighter( + new DeletedRowHighlightPredicate(getModel().getTransectFlights()), + SammoaColors.DELETED_ROW_COLOR) + ); + table.addHighlighter(SammoaUtil.newColorHighlighter( + new ValidRowHighlightPredicate(getModel().getTransectFlights()), + SammoaColors.VALID_ROW_COLOR) + ); table.setSortable(false); } @@ -519,10 +548,11 @@ } @Override - public void onRouteAdded(Route route) { + public void onCurrentRouteChanged(RouteEvent event) { + Route route = event.getRoute(); getModel().setCurrentRoute(route); - if (route != null) { + if (event.isNew()) { getModel().addRoute(route); } } @@ -696,11 +726,7 @@ getModel().setActionMap(getActionMap()); - initActions(getActionMap(), ui, getInputMap()); -// List<JButton> actionButtons = ui.getTransectTable().getActionButtons(); -// for (JButton actionButton : actionButtons) { -// initAction(getActionMap(), actionButton, getInputMap()); -// } + initActions(ui); } protected void putAction(String actionName, Action action) { @@ -714,38 +740,33 @@ * Récupère tous les composants dans l'appli et regarde s'il ont besoin d'une action. * Si oui, on attache l'action récupérée dans l'actionMap global. */ - public static void initActions(ActionMap actionMap, JAXXObject jaxxObject, InputMap inputMap) { + protected void initActions(JAXXObject jaxxObject) { for (Object object : jaxxObject.get$objectMap().values()) { if (jaxxObject != object && object instanceof JAXXObject) { - initActions(actionMap, (JAXXObject) object, inputMap); + initActions((JAXXObject) object); } if (object instanceof AbstractButton) { AbstractButton abstractButton = (AbstractButton) object; - initAction(actionMap, abstractButton, inputMap); - } - } - } + String actionName = (String) abstractButton.getClientProperty("actionName"); + if (!Strings.isNullOrEmpty(actionName)) { - public static void initAction(ActionMap actionMap, AbstractButton abstractButton, InputMap inputMap) { - String actionName = (String) abstractButton.getClientProperty("actionName"); - if (!Strings.isNullOrEmpty(actionName)) { - if (logger.isDebugEnabled()) { - logger.debug("attach action '" + actionName + "' to button " + abstractButton); + if (logger.isDebugEnabled()) { + logger.debug("attach action '" + actionName + "' to button " + abstractButton); + } + + Action action = getActionMap().get(actionName); + + Preconditions.checkNotNull(action, + "action '" + actionName + "' is not " + + "declared. Declared actions: " + + Arrays.toString(getActionMap().keys())); + + abstractButton.setAction(action); + } } - abstractButton.setAction(getAction(actionMap, actionName)); } } - public static Action getAction(ActionMap actionMap, String actionName) { - Preconditions.checkState(!Strings.isNullOrEmpty(actionName), "action name must not be blank"); - Action action = actionMap.get(actionName); - Preconditions.checkState( - action != null, - "action '" + actionName + "' is not declared. Declared actions: " - + Arrays.toString(actionMap.keys())); - return action; - } - protected void initMap() { OverlayMapPanel overlayMapPanel = ui.getMapPanel(); @@ -903,6 +924,19 @@ } } + protected <T extends DeviceManager> T openDevice(Class<T> deviceManagerClass) { + + try { + flightController.openDeviceManager(deviceManagerClass); + + } catch (DeviceTechnicalException ex) { + logger.error("Error on " + deviceManagerClass.getSimpleName() + " init", ex); + SammoaUtil.showErrorMessage(ui, ex.getMessageWithCause()); + SammoaUtil.updateBusyState(context.getMainUIHandler().getUI(), true); + } + return flightController.getDeviceManager(deviceManagerClass); + } + protected PropertyChangeListener flightObserversListener = new PropertyChangeListener() { @Override Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIModel.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIModel.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIModel.java 2012-08-23 10:22:44 UTC (rev 462) @@ -24,13 +24,11 @@ */ package fr.ulr.sammoa.ui.swing.flight; -import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Flight; import fr.ulr.sammoa.persistence.GeoPoint; import fr.ulr.sammoa.persistence.Observation; -import fr.ulr.sammoa.persistence.Observations; import fr.ulr.sammoa.persistence.Observer; import fr.ulr.sammoa.persistence.Route; import fr.ulr.sammoa.persistence.TransectFlight; @@ -38,7 +36,6 @@ import org.jdesktop.beans.AbstractSerializableBean; import javax.swing.ActionMap; -import java.util.Collections; import java.util.List; /** @@ -231,41 +228,6 @@ setObservationEditBean(observation); fireIndexedPropertyChange(PROPERTY_OBSERVATIONS, index, null, observation); } - - public List<Observation> getObservationsForRoute(Route route) { - - List<Observation> result; - if (route == null) { - result = Collections.emptyList(); - - } else { - - Route nextRoute = getNextRoute(route); - - result = FluentIterable.from(getObservations()) - .filter(Observations.inRoute(route, nextRoute)) - .toImmutableList(); - } - return result; - } - - public Route getNextRoute(Route route) { - - int routeIndex = indexOfRoutes(route); - - Route result; - int nextRouteIndex = routeIndex + 1; - if (nextRouteIndex < sizeRoutes()) { - - result = getRoutes().get(nextRouteIndex); - - } else { - result = null; - } - - return result; - } - public List<Route> getRoutes() { if (routes == null) { routes = Lists.newArrayList(); Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/TransectFlightModel.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/TransectFlightModel.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/TransectFlightModel.java 2012-08-23 10:22:44 UTC (rev 462) @@ -27,11 +27,13 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; +import fr.ulr.sammoa.persistence.Deletable; import fr.ulr.sammoa.persistence.Flight; import fr.ulr.sammoa.persistence.Observer; import fr.ulr.sammoa.persistence.ObserverPosition; import fr.ulr.sammoa.persistence.Position; import fr.ulr.sammoa.persistence.TransectFlight; +import fr.ulr.sammoa.persistence.Validatable; import org.jdesktop.beans.AbstractSerializableBean; /** @@ -39,7 +41,7 @@ * * @author fdesbois <desbois@codelutin.com> */ -public class TransectFlightModel extends AbstractSerializableBean { +public class TransectFlightModel extends AbstractSerializableBean implements Deletable, Validatable { private static final long serialVersionUID = 1L; @@ -91,6 +93,7 @@ firePropertyChange(PROPERTY_TRANSECT, oldValue, transect); } + @Override public boolean isDeleted() { return getSource().isDeleted(); } @@ -101,6 +104,11 @@ getSource().setDeleted(deleted); } + @Override + public boolean isValid() { + return getSource().isValid(); + } + public int getIndex() { return Iterables.indexOf(getFlight().getTransectFlight(), Predicates.equalTo(getSource())); } Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanel.jaxx =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanel.jaxx 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanel.jaxx 2012-08-23 10:22:44 UTC (rev 462) @@ -50,7 +50,7 @@ <SwingListValidatorMessageTableModel id='errorTableModel'/> <FlightUIModel id='flightUIModel' - initializer='handler.getFlightUIModel()'/> + initializer='handler.getParentUI().getModel()'/> <GenericListModel id='navObserversModel' genericType='Observer'/> Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanelHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanelHandler.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanelHandler.java 2012-08-23 10:22:44 UTC (rev 462) @@ -28,6 +28,8 @@ import fr.ulr.sammoa.application.device.DeviceState; import fr.ulr.sammoa.application.device.DeviceStateEvent; import fr.ulr.sammoa.application.device.DeviceStateListener; +import fr.ulr.sammoa.application.device.audio.AudioRecorder; +import fr.ulr.sammoa.application.device.gps.GpsHandler; import fr.ulr.sammoa.application.flightController.FlightController; import fr.ulr.sammoa.persistence.Observation; import fr.ulr.sammoa.persistence.ObservationStatus; @@ -41,6 +43,7 @@ import fr.ulr.sammoa.ui.swing.SammoaUIContext; import fr.ulr.sammoa.ui.swing.UIDecoratorService; import fr.ulr.sammoa.ui.swing.action.CircleBackAction; +import fr.ulr.sammoa.ui.swing.flight.FlightUI; import fr.ulr.sammoa.ui.swing.flight.FlightUIHandler; import fr.ulr.sammoa.ui.swing.flight.FlightUIModel; import fr.ulr.sammoa.ui.swing.observations.action.MoveToNextEditableCellAction; @@ -49,9 +52,12 @@ import fr.ulr.sammoa.ui.swing.observations.action.MoveToPreviousRowEditableAction; import fr.ulr.sammoa.ui.swing.util.AbstractRowHighlightPredicate; import fr.ulr.sammoa.ui.swing.util.ButtonActionTableCellEditorRenderer; +import fr.ulr.sammoa.ui.swing.util.DeletedRowHighlightPredicate; import fr.ulr.sammoa.ui.swing.util.SammoaUtil; import fr.ulr.sammoa.ui.swing.util.TableDataChangeListener; import fr.ulr.sammoa.ui.swing.util.TextCellEditor; +import fr.ulr.sammoa.ui.swing.util.ValidRowHighlightPredicate; +import jaxx.runtime.JAXXUtil; import jaxx.runtime.SwingUtil; import jaxx.runtime.swing.JAXXWidgetUtil; import jaxx.runtime.swing.editor.cell.NumberCellEditor; @@ -68,7 +74,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.swing.*; +import javax.swing.Action; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.ListCellRenderer; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; import javax.swing.border.LineBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; @@ -78,7 +91,8 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; -import java.awt.*; +import java.awt.Color; +import java.awt.Rectangle; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; @@ -107,23 +121,21 @@ protected boolean comboIsAdjusting; + private final SammoaUIContext context; + private final EffortPanel ui; - private final FlightService flightService; - public EffortPanelHandler(EffortPanel ui) { this.ui = ui; - SammoaUIContext context = ui.getContextValue(SammoaUIContext.class); - flightService = context.getService(FlightService.class); + context = ui.getContextValue(SammoaUIContext.class); } - public FlightUIModel getFlightUIModel() { - return SammoaUIContext.getUIContext().getFlightUIHandler().getModel(); + public FlightUI getParentUI() { + return ui.getContextValue(FlightUI.class, JAXXUtil.PARENT); } public void init() { - SammoaUIContext context = ui.getContextValue(SammoaUIContext.class); final UIDecoratorService decoratorService = context.getService(UIDecoratorService.class); @@ -152,12 +164,15 @@ } ); - FlightUIModel flightUIModel = getFlightUIModel(); + FlightUIModel flightUIModel = ui.getFlightUIModel(); + String validatorContext = context.isValidationMode() ? "validation" : "onBoard"; + // init route section { BeanListValidator<Route> validator = ui.getRouteValidator(); + validator.setContext(validatorContext); RouteTableModel tableModel = ui.getRouteTableModel(); @@ -262,7 +277,22 @@ SammoaColors.ROUTE_NO_MODIFICATION_ROW_COLOR) ); + if (context.isValidationMode()) { + dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + + @Override + public void valueChanged(ListSelectionEvent e) { + if (!e.getValueIsAdjusting()) { + int index = SammoaUtil.getLastSelectedRow(ui.getRouteTable()); + Route route = ui.getRouteTableModel().getRow(index); + getParentUI().getHandler().getFlightController().setCurrentRoute(route); + } + } + }); + } + + RouteValidatorDataLocator dataLocator = new RouteValidatorDataLocator(); SwingValidatorUtil.registerListValidator( @@ -276,6 +306,15 @@ NuitonValidatorScope.ERROR, NuitonValidatorScope.WARNING); + dataTable.addHighlighter(SammoaUtil.newColorHighlighter( + new DeletedRowHighlightPredicate(flightUIModel.getRoutes()), + SammoaColors.DELETED_ROW_COLOR) + ); + dataTable.addHighlighter(SammoaUtil.newColorHighlighter( + new ValidRowHighlightPredicate(flightUIModel.getRoutes()), + SammoaColors.VALID_ROW_COLOR) + ); + for (Route route : tableModel.getBean()) { validator.addBean(route); } @@ -285,11 +324,15 @@ { FlightController flightController = - SammoaUIContext.getUIContext().getFlightUIHandler().getFlightController(); + getParentUI().getHandler().getFlightController(); - if (flightController != null) { - flightController.getGpsHandler().addDeviceStateListener(this); - flightController.getAudioRecorder().addDeviceStateListener(this); + if (context.isValidationMode()) { + + // nothing for the moment + + } else { + flightController.getDeviceManager(GpsHandler.class).addDeviceStateListener(this); + flightController.getDeviceManager(AudioRecorder.class).addDeviceStateListener(this); } @@ -321,14 +364,16 @@ logger.debug("Route edition/selection changed, reload observation table data"); ui.getObservationTableModel().fireTableDataChanged(); - FlightUIModel flightUIModel = (FlightUIModel) evt.getSource(); - List<Observation> observations = - flightUIModel.getObservationsForRoute((Route) evt.getNewValue()); + Observation observation = + Observations.findFirstInRoute(flightUIModel.getObservations(), + (Route) evt.getNewValue(), + flightUIModel.getRoutes(), + true); - if (!observations.isEmpty()) { - int firstRowIndex = flightUIModel.indexOfObservations(observations.get(0)); + if (observation != null) { + int firstRowIndex = flightUIModel.indexOfObservations(observation); ui.getObservationTable().scrollRowToVisible(firstRowIndex); } } @@ -438,7 +483,8 @@ @Override public Action get() { - return FlightUIHandler.getAction(getFlightUIModel().getActionMap(), "circleBack"); + FlightUIHandler flightUIHandler = getParentUI().getHandler(); + return flightUIHandler.getActionMap().get("circleBack"); } }, null @@ -449,6 +495,7 @@ column.setCellRenderer(editorRenderer); BeanListValidator<Observation> validator = ui.getObservationValidator(); + validator.setContext(validatorContext); ObservationValidatorDataLocator dataLocator = new ObservationValidatorDataLocator(); @@ -464,6 +511,15 @@ NuitonValidatorScope.ERROR, NuitonValidatorScope.WARNING); + dataTable.addHighlighter(SammoaUtil.newColorHighlighter( + new DeletedRowHighlightPredicate(flightUIModel.getObservations()), + SammoaColors.DELETED_ROW_COLOR) + ); + dataTable.addHighlighter(SammoaUtil.newColorHighlighter( + new ValidRowHighlightPredicate(flightUIModel.getObservations()), + SammoaColors.VALID_ROW_COLOR) + ); + ObservationTableModel tableModel = ui.getObservationTableModel(); for (Observation observation : tableModel.getBean()) { validator.addBean(observation); @@ -516,7 +572,7 @@ public void setObserverByPosition(Observer newValue, Position position) { if (!comboIsAdjusting) { - FlightUIModel flightUIModel = getFlightUIModel(); + FlightUIModel flightUIModel = ui.getFlightUIModel(); Route route = flightUIModel.getRouteEditBean(); if (route != null) { @@ -525,6 +581,7 @@ logger.debug(String.format("Set observer %s for position %s", newValue, position)); } + FlightService flightService = context.getService(FlightService.class); flightService.setRouteObserverByPosition(route, newValue, position); // the method setObserverByPosition could update other positions @@ -563,8 +620,8 @@ @Override public void run() { - Route route = getFlightUIModel().getRouteEditBean(); - int index = getFlightUIModel().indexOfRoutes(route); + Route route = ui.getFlightUIModel().getRouteEditBean(); + int index = ui.getFlightUIModel().indexOfRoutes(route); ui.getRouteTableModel().fireTableRowsUpdated(index, index); } }); @@ -583,13 +640,13 @@ } } - public static void init(final JXTable table, + public void init(final JXTable table, ListSelectionListener selectionListener) { // make tab key to focus only next editable cell table.setSelectionModel(new ForceSelectionSelectionModel()); - table.setSortable(false); + table.setSortable(context.isValidationMode()); table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); @@ -752,48 +809,39 @@ return model.getBean(rowIndex); } } + +// public static class DeletedRowHighlightPredicate<T extends Deletable> extends AbstractRowHighlightPredicate { // -// /** -// * Editeur/renderer des observations sous forme de bouton permettant -// * de rentrer en mode circle back sur l'observation choisie. -// */ -// public static class CircleBackEditorRenderer extends AbstractCellEditor -// implements TableCellRenderer, TableCellEditor { +// protected FlightUIModel UIModel; // -// private static final long serialVersionUID = 1L; +// protected Class<T> referenceClass; // -// -// private final FlightUIModel fligthModel; -// -// public CircleBackEditorRenderer(FlightUIModel fligthModel) { -// this.fligthModel = fligthModel; +// public DeletedRowHighlightPredicate(FlightUIModel UIModel, +// Class<T> referenceClass) { +// this.UIModel = UIModel; +// this.referenceClass = referenceClass; // } // // @Override -// public Object getCellEditorValue() { -// return null; +// protected boolean isHighlighted(int rowIndex) { +// boolean result = getValueAt(rowIndex).isDeleted(); +// return result; // } // // @Override -// public Component getTableCellEditorComponent(JTable table, -// Object value, boolean isSelected, int row, int column) { -// final Observation observation = (Observation) value; -// final JButton result = new JButton(); -// // FIXME-fdesbois-2012-07-08 : improve that, can't do any init... on new button, action is retrieve from actionMap -// if (fligthModel.getActionMap() != null) { -// Action circleBackAction = FlightUIHandler.getAction(fligthModel.getActionMap(), "circleBack"); -// result.setAction(circleBackAction); +// protected T getValueAt(int rowIndex) { +// List<T> list; +// if (Route.class.isAssignableFrom(referenceClass)) { +// list = (List<T>) UIModel.getRoutes(); +// +// } else if (Observation.class.isAssignableFrom(referenceClass)) { +// list = (List<T>) UIModel.getObservations(); +// +// } else { +// throw new IllegalStateException("Not supported type " + referenceClass.getName()); // } -// result.putClientProperty(CircleBackAction.CLIENT_PROPERTY_OBSERVATION, observation); -// return result; +// return list.get(rowIndex); // } -// -// @Override -// public Component getTableCellRendererComponent(JTable table, -// Object value, boolean isSelected, boolean hasFocus, int row, -// int column) { -// return getTableCellEditorComponent(table, value, isSelected, row, column); -// } // } public static class ObservationForSelectedRouteHighlightPredicate extends AbstractRowHighlightPredicate { @@ -812,11 +860,9 @@ boolean result; if (selectedRoute != null) { - Route nextRoute = UIModel.getNextRoute(selectedRoute); - Observation observation = getValueAt(rowIndex); - result = Observations.inRoute(observation, selectedRoute, nextRoute); + result = Observations.inRoute(observation, selectedRoute, UIModel.getRoutes(), true); } else { result = false; Added: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/DeletedRowHighlightPredicate.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/DeletedRowHighlightPredicate.java (rev 0) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/DeletedRowHighlightPredicate.java 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,30 @@ +package fr.ulr.sammoa.ui.swing.util; + +import fr.ulr.sammoa.persistence.Deletable; + +import java.util.List; + +/** + * Created: 22/08/12 + * + * @author fdesbois <florian.desbois@codelutin.com> + */ +public class DeletedRowHighlightPredicate extends AbstractRowHighlightPredicate { + + protected List<? extends Deletable> model; + + public DeletedRowHighlightPredicate(List<? extends Deletable> model) { + this.model = model; + } + + @Override + protected boolean isHighlighted(int rowIndex) { + boolean result = getValueAt(rowIndex).isDeleted(); + return result; + } + + @Override + protected Deletable getValueAt(int rowIndex) { + return model.get(rowIndex); + } +} Property changes on: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/DeletedRowHighlightPredicate.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Added: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/ValidRowHighlightPredicate.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/ValidRowHighlightPredicate.java (rev 0) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/ValidRowHighlightPredicate.java 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,30 @@ +package fr.ulr.sammoa.ui.swing.util; + +import fr.ulr.sammoa.persistence.Validatable; + +import java.util.List; + +/** + * Created: 22/08/12 + * + * @author fdesbois <florian.desbois@codelutin.com> + */ +public class ValidRowHighlightPredicate extends AbstractRowHighlightPredicate { + + protected List<? extends Validatable> model; + + public ValidRowHighlightPredicate(List<? extends Validatable> model) { + this.model = model; + } + + @Override + protected boolean isHighlighted(int rowIndex) { + boolean result = getValueAt(rowIndex).isValid(); + return result; + } + + @Override + protected Validatable getValueAt(int rowIndex) { + return model.get(rowIndex); + } +} Property changes on: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/util/ValidRowHighlightPredicate.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Copied: trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-onBoard-warning-validation.xml (from rev 461, trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-warning-validation.xml) =================================================================== --- trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-onBoard-warning-validation.xml (rev 0) +++ trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-onBoard-warning-validation.xml 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + #%L + SAMMOA :: UI Swing + $Id$ + $HeadURL$ + %% + Copyright (C) 2012 UMS 3462, Code Lutin + %% + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program. If not, see + <http://www.gnu.org/licenses/gpl-3.0.html>. + #L% + --> + + +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="podSize"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <message>sammoa.validator.observation.podSize.invalidMin##${min}</message> + </field-validator> + + </field> + + <field name="species"> + + <field-validator type="required" short-circuit="true"> + <message>sammoa.validator.observation.species.required</message> + </field-validator> + + <field-validator type="speciesCode" short-circuit="true"> + <param name="keys">code</param> + <param name="mode">AT_LEAST_ONE</param> + <param name="useSensitiveContext">true</param> + <param name="expression"> + <![CDATA[ species.code == current.code ]]></param> + <message>sammoa.validator.observation.unknown.species##${species.code}</message> + </field-validator> + + </field> + + <field name="decAngle"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">90</param> + <message>sammoa.validator.observation.decAngle.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="age"> + + <field-validator type="regex" short-circuit="true"> + <param name="expression"> + <![CDATA[ [JIAM] ]]> + </param> + <message>sammoa.validator.observation.age.unkownValue</message> + </field-validator> + + </field> + + <field name="cue"> + + <field-validator type="regex" short-circuit="true"> + <param name="expression"> + <![CDATA[ [UA2-9] ]]> + </param> + <message>sammoa.validator.observation.cue.unkownValue</message> + </field-validator> + + </field> + + <field name="behaviour"> + + <field-validator type="fieldexpression" short-circuit="true"> + <param name="expression"> + <![CDATA[ behaviour in { null, "SW", "MI", "BR", "LO", "FE", "FA", "SB", "OT" } ]]> + </param> + <message>sammoa.validator.observation.behaviour.unkownValue</message> + </field-validator> + + </field> + + <field name="swimDir"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">360</param> + <message>sammoa.validator.observation.swimDir.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + +</validators> Copied: trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-validation-error-validation.xml (from rev 461, trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-warning-validation.xml) =================================================================== --- trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-validation-error-validation.xml (rev 0) +++ trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-validation-error-validation.xml 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + #%L + SAMMOA :: UI Swing + $Id$ + $HeadURL$ + %% + Copyright (C) 2012 UMS 3462, Code Lutin + %% + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program. If not, see + <http://www.gnu.org/licenses/gpl-3.0.html>. + #L% + --> + + +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="podSize"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <message>sammoa.validator.observation.podSize.invalidMin##${min}</message> + </field-validator> + + </field> + + <field name="species"> + + <field-validator type="required" short-circuit="true"> + <message>sammoa.validator.observation.species.required</message> + </field-validator> + + <field-validator type="speciesCode" short-circuit="true"> + <param name="keys">code</param> + <param name="mode">AT_LEAST_ONE</param> + <param name="useSensitiveContext">true</param> + <param name="expression"> + <![CDATA[ species.code == current.code ]]></param> + <message>sammoa.validator.observation.unknown.species##${species.code}</message> + </field-validator> + + </field> + + <field name="decAngle"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">90</param> + <message>sammoa.validator.observation.decAngle.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="age"> + + <field-validator type="regex" short-circuit="true"> + <param name="expression"> + <![CDATA[ [JIAM] ]]> + </param> + <message>sammoa.validator.observation.age.unkownValue</message> + </field-validator> + + </field> + + <field name="cue"> + + <field-validator type="regex" short-circuit="true"> + <param name="expression"> + <![CDATA[ [UA2-9] ]]> + </param> + <message>sammoa.validator.observation.cue.unkownValue</message> + </field-validator> + + </field> + + <field name="behaviour"> + + <field-validator type="fieldexpression" short-circuit="true"> + <param name="expression"> + <![CDATA[ behaviour in { null, "SW", "MI", "BR", "LO", "FE", "FA", "SB", "OT" } ]]> + </param> + <message>sammoa.validator.observation.behaviour.unkownValue</message> + </field-validator> + + </field> + + <field name="swimDir"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">360</param> + <message>sammoa.validator.observation.swimDir.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + +</validators> Property changes on: trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-validation-error-validation.xml ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Deleted: trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-warning-validation.xml =================================================================== --- trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-warning-validation.xml 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Observation-warning-validation.xml 2012-08-23 10:22:44 UTC (rev 462) @@ -1,112 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - #%L - SAMMOA :: UI Swing - $Id$ - $HeadURL$ - %% - Copyright (C) 2012 UMS 3462, Code Lutin - %% - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program. If not, see - <http://www.gnu.org/licenses/gpl-3.0.html>. - #L% - --> - - -<!DOCTYPE validators PUBLIC - "-//Apache Struts//XWork Validator 1.0.3//EN" - "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> -<validators> - - <field name="podSize"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <message>sammoa.validator.observation.podSize.invalidMin##${min}</message> - </field-validator> - - </field> - - <field name="species"> - - <field-validator type="required" short-circuit="true"> - <message>sammoa.validator.observation.species.required</message> - </field-validator> - - <field-validator type="speciesCode" short-circuit="true"> - <param name="keys">code</param> - <param name="mode">AT_LEAST_ONE</param> - <param name="useSensitiveContext">true</param> - <param name="expression"> - <![CDATA[ species.code == current.code ]]></param> - <message>sammoa.validator.observation.unknown.species##${species.code}</message> - </field-validator> - - </field> - - <field name="decAngle"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <param name="max">90</param> - <message>sammoa.validator.observation.decAngle.invalidRange##${min}##${max}</message> - </field-validator> - - </field> - - <field name="age"> - - <field-validator type="regex" short-circuit="true"> - <param name="expression"> - <![CDATA[ [JIAM] ]]> - </param> - <message>sammoa.validator.observation.age.unkownValue</message> - </field-validator> - - </field> - - <field name="cue"> - - <field-validator type="regex" short-circuit="true"> - <param name="expression"> - <![CDATA[ [UA2-9] ]]> - </param> - <message>sammoa.validator.observation.cue.unkownValue</message> - </field-validator> - - </field> - - <field name="behaviour"> - - <field-validator type="fieldexpression" short-circuit="true"> - <param name="expression"> - <![CDATA[ behaviour in { null, "SW", "MI", "BR", "LO", "FE", "FA", "SB", "OT" } ]]> - </param> - <message>sammoa.validator.observation.behaviour.unkownValue</message> - </field-validator> - - </field> - - <field name="swimDir"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <param name="max">360</param> - <message>sammoa.validator.observation.swimDir.invalidRange##${min}##${max}</message> - </field-validator> - - </field> - - -</validators> Deleted: trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-error-validation.xml =================================================================== --- trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-error-validation.xml 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-error-validation.xml 2012-08-23 10:22:44 UTC (rev 462) @@ -1,133 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - #%L - SAMMOA :: UI Swing - $Id$ - $HeadURL$ - %% - Copyright (C) 2012 UMS 3462, Code Lutin - %% - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program. If not, see - <http://www.gnu.org/licenses/gpl-3.0.html>. - #L% - --> - - -<!DOCTYPE validators PUBLIC - "-//Apache Struts//XWork Validator 1.0.3//EN" - "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> -<validators> - - <field name="seaState"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <param name="max">5</param> - <message>sammoa.validator.route.seaState.invalidRange##${min}##${max}</message> - </field-validator> - - </field> - - <field name="swell"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <param name="max">2</param> - <message>sammoa.validator.route.swell.invalidRange##${min}##${max}</message> - </field-validator> - - </field> - - <field name="turbidity"> - - <field-validator type="fieldexpression" short-circuit="true"> - <param name="expression"> - <![CDATA[ turbidity in { 0, 1, 2, 9 } ]]> - </param> - <message>sammoa.validator.route.turbidity.unkownValue</message> - </field-validator> - - </field> - - <field name="cloudCover"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <param name="max">8</param> - <message>sammoa.validator.route.cloudCover.invalidRange##${min}##${max}</message> - </field-validator> - - </field> - - <field name="skyGlint"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <message>sammoa.validator.route.skyGlint.invalidMin##${min}</message> - </field-validator> - - </field> - - <field name="glareFrom"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <param name="max">360</param> - <message>sammoa.validator.route.glareFrom.invalidRange##${min}##${max}</message> - </field-validator> - - </field> - - <field name="glareTo"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <param name="max">360</param> - <message>sammoa.validator.route.glareTo.invalidRange##${min}##${max}</message> - </field-validator> - - </field> - - <field name="glareSeverity"> - - <field-validator type="int" short-circuit="true"> - <param name="min">0</param> - <param name="max">3</param> - <message>sammoa.validator.route.glareSeverity.invalidRange##${min}##${max}</message> - </field-validator> - - </field> - - <field name="subjectiveConditions"> - - <field-validator type="int" short-circuit="true"> - <message>sammoa.validator.route.subjectiveConditions.required</message> - </field-validator> - - <field-validator type="stringlength" short-circuit="true"> - <param name="minLength">2</param> - <param name="maxLength">2</param> - <message>sammoa.validator.route.subjectiveConditions.badLength##${minLength}</message> - </field-validator> - - <field-validator type="regex" short-circuit="true"> - <param name="expression"> - <![CDATA[ [EGMP]{2} ]]> - </param> - <message>sammoa.validator.route.subjectiveConditions.unkownValue</message> - </field-validator> - - </field> - -</validators> Copied: trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-onBoard-error-validation.xml (from rev 461, trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-error-validation.xml) =================================================================== --- trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-onBoard-error-validation.xml (rev 0) +++ trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-onBoard-error-validation.xml 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + #%L + SAMMOA :: UI Swing + $Id$ + $HeadURL$ + %% + Copyright (C) 2012 UMS 3462, Code Lutin + %% + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program. If not, see + <http://www.gnu.org/licenses/gpl-3.0.html>. + #L% + --> + + +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="seaState"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">5</param> + <message>sammoa.validator.route.seaState.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="swell"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">2</param> + <message>sammoa.validator.route.swell.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="turbidity"> + + <field-validator type="fieldexpression" short-circuit="true"> + <param name="expression"> + <![CDATA[ turbidity in { 0, 1, 2, 9 } ]]> + </param> + <message>sammoa.validator.route.turbidity.unkownValue</message> + </field-validator> + + </field> + + <field name="cloudCover"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">8</param> + <message>sammoa.validator.route.cloudCover.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="skyGlint"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <message>sammoa.validator.route.skyGlint.invalidMin##${min}</message> + </field-validator> + + </field> + + <field name="glareFrom"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">360</param> + <message>sammoa.validator.route.glareFrom.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="glareTo"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">360</param> + <message>sammoa.validator.route.glareTo.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="glareSeverity"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">3</param> + <message>sammoa.validator.route.glareSeverity.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="subjectiveConditions"> + + <field-validator type="int" short-circuit="true"> + <message>sammoa.validator.route.subjectiveConditions.required</message> + </field-validator> + + <field-validator type="stringlength" short-circuit="true"> + <param name="minLength">2</param> + <param name="maxLength">2</param> + <message>sammoa.validator.route.subjectiveConditions.badLength##${minLength}</message> + </field-validator> + + <field-validator type="regex" short-circuit="true"> + <param name="expression"> + <![CDATA[ [EGMP]{2} ]]> + </param> + <message>sammoa.validator.route.subjectiveConditions.unkownValue</message> + </field-validator> + + </field> + +</validators> Copied: trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-validation-error-validation.xml (from rev 461, trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-error-validation.xml) =================================================================== --- trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-validation-error-validation.xml (rev 0) +++ trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-validation-error-validation.xml 2012-08-23 10:22:44 UTC (rev 462) @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + #%L + SAMMOA :: UI Swing + $Id$ + $HeadURL$ + %% + Copyright (C) 2012 UMS 3462, Code Lutin + %% + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program. If not, see + <http://www.gnu.org/licenses/gpl-3.0.html>. + #L% + --> + + +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="seaState"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">5</param> + <message>sammoa.validator.route.seaState.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="swell"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">2</param> + <message>sammoa.validator.route.swell.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="turbidity"> + + <field-validator type="fieldexpression" short-circuit="true"> + <param name="expression"> + <![CDATA[ turbidity in { 0, 1, 2, 9 } ]]> + </param> + <message>sammoa.validator.route.turbidity.unkownValue</message> + </field-validator> + + </field> + + <field name="cloudCover"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">8</param> + <message>sammoa.validator.route.cloudCover.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="skyGlint"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <message>sammoa.validator.route.skyGlint.invalidMin##${min}</message> + </field-validator> + + </field> + + <field name="glareFrom"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">360</param> + <message>sammoa.validator.route.glareFrom.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="glareTo"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">360</param> + <message>sammoa.validator.route.glareTo.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="glareSeverity"> + + <field-validator type="int" short-circuit="true"> + <param name="min">0</param> + <param name="max">3</param> + <message>sammoa.validator.route.glareSeverity.invalidRange##${min}##${max}</message> + </field-validator> + + </field> + + <field name="subjectiveConditions"> + + <field-validator type="int" short-circuit="true"> + <message>sammoa.validator.route.subjectiveConditions.required</message> + </field-validator> + + <field-validator type="stringlength" short-circuit="true"> + <param name="minLength">2</param> + <param name="maxLength">2</param> + <message>sammoa.validator.route.subjectiveConditions.badLength##${minLength}</message> + </field-validator> + + <field-validator type="regex" short-circuit="true"> + <param name="expression"> + <![CDATA[ [EGMP]{2} ]]> + </param> + <message>sammoa.validator.route.subjectiveConditions.unkownValue</message> + </field-validator> + + </field> + +</validators> Property changes on: trunk/sammoa-ui-swing/src/main/resources/fr/ulr/sammoa/persistence/Route-validation-error-validation.xml ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/sammoa-ui-swing/src/test/java/fr/ulr/sammoa/ui/swing/BeanValidatorDetectorTest.java =================================================================== --- trunk/sammoa-ui-swing/src/test/java/fr/ulr/sammoa/ui/swing/BeanValidatorDetectorTest.java 2012-08-23 10:21:50 UTC (rev 461) +++ trunk/sammoa-ui-swing/src/test/java/fr/ulr/sammoa/ui/swing/BeanValidatorDetectorTest.java 2012-08-23 10:22:44 UTC (rev 462) @@ -37,10 +37,10 @@ import java.io.File; import java.util.SortedSet; +import java.util.regex.Pattern; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** @@ -54,9 +54,15 @@ } /** La liste des classes avec validation. */ + protected static final Class<?>[] VALIDATOR_CLASSES_ON_BOARD = { + Observation.class, + Route.class + }; + protected static final Class<?>[] VALIDATOR_CLASSES_VALIDATION = { + Observation.class, + Route.class + }; protected static final Class<?>[] VALIDATOR_CLASSES = { - Observation.class, - Route.class, CampaignUIModel.class, RegionUIModel.class, TransectUIModel.class @@ -71,16 +77,32 @@ @Test public void detectAll() { - SortedSet<NuitonValidator<?>> validators = detectValidators( - VALIDATOR_CLASSES); - assertNotNull(validators); - assertEquals(VALIDATOR_CLASSES.length, validators.size()); + { + SortedSet<NuitonValidator<?>> validators = detectValidators( + Pattern.compile("onBoard"), VALIDATOR_CLASSES_ON_BOARD); + assertValidatorSetWithSameContextName( + validators, "onBoard", VALIDATOR_CLASSES_ON_BOARD); + } + + { + SortedSet<NuitonValidator<?>> validators = detectValidators( + Pattern.compile("validation"), VALIDATOR_CLASSES_VALIDATION); + assertValidatorSetWithSameContextName( + validators, "validation", VALIDATOR_CLASSES_VALIDATION); + } + + { + SortedSet<NuitonValidator<?>> validators = detectValidators( + VALIDATOR_CLASSES); + assertEquals(VALIDATOR_CLASSES.length, validators.size()); + } } @Test public void validateEffort() throws Exception { - SortedSet<NuitonValidator<?>> validators = detectValidators(Route.class); + SortedSet<NuitonValidator<?>> validators = detectValidators( + Pattern.compile("onBoard"), Route.class); assertEquals(1, validators.size()); NuitonValidator<Route> validator = (NuitonValidator<Route>) validators.first();