/** * Moving Map Navigator Demonstrator Applet * @author Robert J Morton * @version 21 Oct 1997 greatly enhanced 19 Dec 2007 */ /* The central applet class for the Moving Map package. */ import java.awt.*; import javax.swing.*; import java.awt.image.BufferedImage; public class movmap extends JPanel implements Runnable { private static final long serialVersionUID = 8L; // what the hell this is for, I don't know! private boolean FTT = true, // first-time-through flag loadingRoutes = true, // false means routes loader has finished its task Init2started = false, Init2finished = false; /* true when the GUI has been built via the Event Dispatching Thread. */ int ls = 0; /* Load Switch says from where to load image and data files: 0 = from local directory 1 = from jar file 2 = from remote server */ private int // ORIGIN, WIDTH AND HEIGHT OF APPLET PANEL OBJECTS XE, // horizontal extent of window and JFrame. YE, // vertical extent of window and JFrame. Aw=620, Ah=530, // width and height of applet window applet window Am= 15, // applet's border width Nx= 15, Ny= 65, Nw=275, Nh=300, // navigation data names area Vx=153, Vy= 65, Vw=137, Vh=300, // navigation data variables Px= 15, Py=377, Pw=130, Ph=102, // refresh interval selector Sx=160, Sy=377, Sw=130, Sh=102, // map Scale selector panel Lx= 15, Ly=480, Lw=406, Lh= 35, // posn, width, height of message panel Mx=305, My= 65, Mw=300, Mh=300, // map AREA Qx=105, Qy=480, Qw=310, Qh= 35, // message area for loading messages fh, // font height L = 0; // language switch: 0 = English 1 = Portuguese private long tf = 1000, // inter-plot time frame (millisecs) Can be changed by user. t; // future system time at which a new plot is due to begin String cb = ""; // code base for applet and its data files private Container cp; // instance reference of the JApplet's pane private Font // general font used for writing on applet canvas font = new Font("Serif",Font.BOLD,14); private FontMetrics fm; // dimensions of lettering (height, leading etc.) private Color bg = new Color(190,215,255), // background colour fg = new Color(255,255,255); // foreground colour for lettering static BufferedImage AI, IMG1, IMG2, IMG3, IMG4; // for applet background clouds picture private Graphics2D ai = null; // graphics context reference for AI private Thread T; // program thread reference variable aircraft ac; // reference to aircraft object route ROUTE; // object reference of current route bgimg bi; // background image navpanel np; // panel which displays the numeric data butpanel bp; // panel containing the control buttons findroute fr; // find route text box panel routesel rs; // drop-down list choice route selector selwp ws; // drop-down list choice waypoint selector selmap sm; // reference to map scale selection panel refreshrate rr; // reference to refresh rate selection panel airmap am; // reference to air map canvas object msgpanel mp; // instance reference for message display panel imgldr il; // instance reference to the image loader loader ld; // route loader selgeoid gs; // geoidal ellipse selector public movmap(int XE, int YE, int ls, int L, String cb) { this.XE = XE; // horizontal [X] dimension of the JPanel this.YE = YE; // vertical [Y] dimension of the JPanel this.ls = ls; // Load Switch this.cb = cb; // code base (URL) of class, images and data files this.L = L; // language switch setBounds(0,0,XE,YE); // the JPanel fills the whole of the JFrame area setLayout(null); // JPanel has free-form layout [for graph] fm = getFontMetrics(font); // get letter dimensions etc for above font fh = 19; // fm.getHeight(); //get font leading Qy += ((Qh + fh) >> 1); // base height of error message text /* NB: the order of creating the following objects matters for 2 reasons: firstly to optimise the passing of object references (for instance routesel rs needs to be passed the reference to butpanel bp so bp must be created first) and secondly because the order of creation in Swing determines the sandwich level at which it appears on the applet panel (for instance, the background image panel must be created last because it must appear behind everything else). */ cp = this; mp = new msgpanel(this,fg,L); // create a small message panel add(mp); // add it to the applet's contents pane mp.setBounds(Lx,Ly,Lw,Lh); // set its size, locate it at bottom right bp = new butpanel(this,cp,mp,L); // button panel rs = new routesel(this,cp,bp); // route selector fr = new findroute(this,cp,rs,L); // search field mp ws = new selwp(this,cp,mp,bp); // waypoint selector gs = new selgeoid(this,cp); // geoid selector int x = fh + fh - 12, // for positioning the map and y = fh + fh + fh; // refresh-rate selector panels rr = new refreshrate(this); add(rr); rr.setBounds(Px + 7,Py + x,20,y); // refresh rate sm = new selmap(this); add(sm); sm.setBounds(Sx + 7,Sy + x,20,y); // map scale //create an instance of the image loader il = new imgldr(this,mp,ls,L,cb); T = new Thread(this); // creating a run() thread T.start(); // and starting it running // Set finishing time for first pass of applet's run() thread t = System.currentTimeMillis() + tf; } /* Post a request for the method installSwingWidgets2() to be executed on the event-dispatching thread. Don't wait for installSwingWidgets2() to finish execution. Continue immediately on the run() thread T. This loop won't continue with loading the route information until installSwingWidgets2() has finished and set the Init2finished flag to "true". Continuing immediately ensures that the run() thread T will not exceed its normal cycling period. */ private void schedulePhase2init() { Init2started = true; // show phase 2 initialisation has been scheduled try { javax.swing.SwingUtilities.invokeAndWait( new Runnable() { public void run() { installSwingWidgets2(); // create map and nav information panels } } ); } catch(Exception e) { System.out.println("Couldn't create phase 2 of Swing GUI."); } } /* CREATE THE APPLET'S GRAPHICS USER INTERFACE (PHASE 2) NOTE: this must be done as a separate method (in this case installSwingWidgets2()) that is within the scope-space of the applet itself. This code cannot be executed inside the braces {} of the new Runnable above because in there it would not be able to see the applet's local variables. This phase of the initialisation can only be done after the background images have been downloaded from the server. It therefore has to be scheduled to be run later on the Event Dispatching Thread by the run() thread T after the images loader has finished. */ void installSwingWidgets2() { ac = new aircraft(); // create an aircraft object bp.setAircraft(ac); // pass aircraft object ref to button panel /* CREATE THE MAP CANVAS WITH THE APPROPRIATE PART OF THE CLOUDS PHOTO AS BACKGROUND */ /* Create air map panel on which to display the map, add it into the applet's window and morph it to fit map portion of applet window. */ am = new airmap(this,fg,ac,sm); cp.add(am); am.setBounds(Mx,My,Mw,Mh); bp.setAirmap(am); // pass its object reference to the button panel sm.setAirmap(am); // pass airmap reference to the map scale selector ws.setAirmap(am); // pass airmap reference to the waypoint selector /* CREATE THE FLIGHT DATA PANEL WITH ITS APPRO- PRIATE PART OF THE CLOUDS PHOTO AS BACKGROUND */ /* Create a new numeric 'display panel' object, add it into the applet's window, morph it into top left area of applet window and pass its object reference to the button panel. */ np = new navpanel(this,fg,ac); cp.add(np); np.setBounds(Vx,Vy,Vw,Vh); bp.setNavpanel(np); ws.setNavpanel(np); /* Create the background image panel, add it to the applet's content pane and set its size (the size of the applet). */ bi = new bgimg(this,Ny,Am,Sx,Sy,Px,Py,fg,L); cp.add(bi); bi.setBounds(0,0,Aw,Ah); // Change from black lettering to white lettering on the message panel. mp.changeColour(); repaint(); // Repaint the Swing widgets onto the background image /* Create a loader object, pass its reference to the message panel and the route selector, set up airmap reference within loader, set up navpanel reference within loader pass the loader object reference to the waypoint selector */ ld = new loader(ls,L,cb,this,mp,rs,ws,ac,am,np,gs,bp); mp.setLoader(ld); rs.setLoader(ld); am.setLoader(ld); np.setLoader(ld); ws.setLoader(ld); Init2finished = true; } public void run() { // RUN THE AIRCRAFT TRACKING PROGRAM THREAD if(il.awaitingImages()) return; while(T != null) { // loop while thread is alive runLoop(); // see below // Get time left in current time-frame long s = t - System.currentTimeMillis(); if(s < 20) s = 20; // in case machine isn't fast enough try {Thread.sleep(s);} // put thread to sleep for time remaining catch(InterruptedException e) {} // catch possible interrupt from GUI /* Set next update time to current system timeplus the currently appropriate update period. */ t = System.currentTimeMillis() + tf; } } private void runLoop() { if(!il.imagesLoaded()) // wait for background photos finish loading return; if(!Init2finished) { // if initialization phase 2 not yet finished if(!Init2started) // If initialisation phase 2 not yet started schedulePhase2init(); // request for it to be done return; // on the event-dispatching thread } if(!ld.routeDataLoaded()) // bail out if route data and waypoints return; // data not has yet finished loading if(bp.inFlight()) { // if flight currently in progress // if the aircraft is no longer advancing along its track... if(!(route.getCurrent().advance())) mp.showMsg("Reached destination.", true, false); am.atualizar(); // update the Air Map np.atualizar(); // update the nav info panel } } /* RE-LOAD THE BACKGROUND IMAGES: kill the old instance of the image loader create a new instance to try to reload the images. */ void imgReload(){ il.killTracker(); il = new imgldr(this,mp,ls,L,cb); } void setRefreshRate(long x){ // set map update refresh rate from tf = x; // the refresh rate selector } }