/** * Bandscope Receiver Applet 1.0.0 * @author Robert J Morton YE572246C * @version 13 March 2002 revised 03 April 2012 * @copyright Robert J Morton (all rights reserved) */ /* This applet conforms to API 1.1 This applet gets its bandscope data via data files acquired via a web server from an RS232 port server with an AR86000 specific data handling method - all written entirely in Java. */ import javax.swing.*; // swing widgets import java.awt.*; // for graphics operations (GUI) import java.applet.*; // all the gubbins to make the applet work public class bs extends JApplet implements Runnable { private static final int AW = 545, // width of applet panel AH = 295, // height of applet panel GL = 130, // Graph Left: x-co-ordinate of left side of graph area GT = 84, // Graph Top: y-coordinate of top of scope graph GB = 180, // Graph Bottom: panel y-co-ordinate of bottom of graph area GW = 200, // width of scope panel GH = 96, // height of scope signal bar SX = 50; // x-coordinate of left side of S-Meter signal indicator bar boolean JarredImages = true, // true = get the image files from the jar file JarredSearch = true; // true = get search data files from the jar file private boolean Init2started = false, // second phase of initialisation not yet started Init2finished = false, // second phase of initialization not finished FTT = true; // first time through the run() loop private static final Color bg = new Color(244,244,244); // main background colour private static final Font font = new Font("Serif",Font.BOLD,14); // for Choice menus and buttons private long si = 1000, // loop interval T, // time at which to step to the next frequency Pn = 505949278; // Pn bias constant static Image IMG1 = null, // for applet background world map images IMG2 = null, // for scope area background IMG3 = null; // for frequency scale background private String cb; // code base URL: where applet's class file came from private Thread TH; // a separate Internet Data Transfer thread private imgldr il; // instance reference to the image loader private loader ld; // reference to data loader private smeter sm; // instance reference for the S-Meter class private bands bd; // band type and band selectors and their labels private Container cp; // instance reference of the JApplet's pane private msgpanel mp; // message panel reference private update updt; // scan data update frequency and command button // Classes containing: private centrefreq cf; // centre-frequency entry field and button private updown updn; // up and down frequency buttons private freqspan sp; // frequency-span selector private peakhold ph; // the peak hold button and label // Instance references for the private mousefreq mf; // mouse-frequency class private listeningon lo; // listening-on class private worldmap wm; // applet background class public void init() { // CONSTRUCTOR cb = getCodeBase().toString(); // URL (less file name) of the server if(!cb.endsWith("/")) { // Workaround re Hotjava & Microsoft int x = cb.lastIndexOf('/'); // Intranet machine names, where if(x != -1) // getCodeBase() wrongly returns the cb = cb.substring(0,x + 1); // document base (circa Nov 1999). } try { // Attempt Phase 1 of Swing GUI initialisation javax.swing.SwingUtilities.invokeAndWait( new Runnable() { public void run() { init1(); } } ); } catch(Exception e) { showStatus("couldn't create Swing GUI"); } il = new imgldr(this, mp); // create and start the image loader TH = new Thread(this); // thread for downloading data from server } /* THE FIRST PHASE OF INITIALISATION Since this involves the creation and set-up of Swing widgets, it must be done on the Event Dispatching thread. It is invoked from the applet's init() method above. */ private void init1() { setFont( // Set up a font for Text Field, new Font("Serif",Font.PLAIN,12) // Choice Menus and Buttons ); cp = getContentPane(); // content pane of the JApplet cp.setLayout(null); // set its layout mode to allow // the control panels to be laid out manually cp.setFont(font); // set font for writing on the applet pane int W = 355, H = 24; // set width and height of message-panel mp = new msgpanel(bg,font,W,H); // Create a general message panel // at the bottom left of the applet cp.add(mp); // add it to the applet's content pane mp.setBounds(10,260,W,H); // set its position and size. sp = new freqspan(cp,GL,GB,30); // Create the frequency-span selector, cf = new centrefreq(cp,GL,bg,font,mp,sp); // centre-frequency entry field bd = new bands(cp,cf,sp); // and the button and band selector. [safe] sp.setBands(bd); // Pass the instance reference of the Band Selector cf.setBands(bd); // to the frequency-span and centre-frequency classes updt = new update(cp,mp); // Update-Frequency select/command button ph = new peakhold(cp,font); // a Peak-Hold button plus label & buttons updn = new updown(cp); // for inching the frequency up and down H = 96; // Set the height of the S-meter signal bar, sm = new smeter(bg,H); // create an S-meter display panel, cp.add(sm); // add it to the applet's contents pane, sm.setBounds(50,84,20,H); // set its position and size. W = 140; H = 24; // Set width & height of mouse frequency display panel, mf = new mousefreq(this,bg,font,sp,cf,sm,W,H); // create the panel, cp.add(mf); // add it to the applet's content pane, mf.setBounds(10,10,W,H); // set its position and size. [safe ] W = 220; H = 24; // Set width and height of the "listening on" panel lo = new listeningon(bg,font,mf,W,H); // create the panel, cp.add(lo); // add it to the applet's content pane lo.setBounds(160,10,W,H); // set its position and size. [safe] bd.setLo(lo); // inform bands class of listeningon reference cf.setLo(lo); // advise centre-frequency class of reference updn.setLo(lo); // advise up/down buttons class of reference sp.setLo(lo); // advise freqspan class of reference } /* SECOND PHASE OF INITIALISATION This can only be done after the background image for the applet has arrived from the server. Since it involves the creation of a Swing JPanel, it must be executed by the Event Dispatching thread and not the local run() thread from where the process must be invoked. */ private void scheduleInit2() { Init2started = true; // show that phase 2 has been scheduled try { // Attempt to create the map and nav information panels javax.swing.SwingUtilities.invokeAndWait( new Runnable() { public void run() { init2(); } } ); } catch(Exception e) { showStatus("createGUI phase 2 didn't successfully complete"); } } private void init2() { //CREATE THE SCOPE DISPLAY PANEL OBJECT scope sc = new scope(IMG2,sp,bd,cf,mf,lo,GW,GH); cp.add(sc); sc.setBounds(GL,GT,GW,GH); cf.setScope(sc); // advise centre-frequency class of reference mf.setScope(sc); // advise mouse-frequency class of reference lo.setScope(sc); // advise listening-on class of reference sp.setScope(sc); // advise freqspan class of reference //CREATE THE FREQUENCY SCALE FIGURES DISPLAY PANEL int W = 240, H = 20; // width and height of frequency scale text area freqfigs ff = new freqfigs(IMG3,cf,W,H,sp); cp.add(ff); ff.setBounds(110,192,W,H); cf.setFreqFigs(ff); // advise centre-frequency class of reference sp.setFreqFigs(ff); // advise freqspan class instance of reference //CREATE THE SCAN DATA FILES LOADER ld = new loader(this,mp,sc,ff,updt,cb,bd); // Pass the loader's class instance reference to the updt.setLd(ld); // update class bd.setLd(ld); // bands class sc.setLd(ld); // scope class //CREATE THE RECEIVER MODEL-SPECIFIC SCAN DATA INTERPRETER ar86000 rx = new ar86000(ld,sc,mp,sp); // Pass the receiver's class instance reference cf.setAR86000(rx); // to the centre-frequency class of ph.setAR86000(rx); // to the peak hold class sp.setAR86000(rx); // to the freqspan class ld.setAR86000(rx); // to the loader class sc.setAR86000(rx); // to the scope class lo.setAR86000(rx); // to the listening-on class //CREATE THE APPLET'S WORLD MAP BACKGROUND PANEL wm = new worldmap(IMG1,GL,GB,GT,GW,SX); cp.add(wm); wm.setBounds(0,0,AW,AH); ld.load(0,0); // initiate loading of the default scan data Init2finished = true; // phase 2 of the initialization has finished } // CREATE THE 'RUN' THREAD AND START IT RUNNING public void start() { TH = new Thread(this); TH.start(); } public void run() { // MANAGE INTERNET DATA TRANSFERS ON THE RUN THREAD if(il.awaitingImages()) return; // must wait until images have arrived while(TH.isAlive()) { // while this thread exists runLoop(); /* Compute time left in current time-frame, impose a lower limit of 50 milliseconds then put the thread to sleep for this remaining time. */ long s = T - System.currentTimeMillis(); if (s < 50) s = 50; try { Thread.currentThread().sleep(s); } /* Catch any exceptions that may occur during the sleep time but do nothing about them because they will be normal events. Then set the system time at which the next time-frame will expire. */ catch (InterruptedException e) { } T = System.currentTimeMillis() + si; } } private void runLoop() { if(!il.imagesLoaded()) return; // media tracker has not yet terminated if(!Init2finished) { // if second phase of initialization not finished if(!Init2started) // If 2nd phase of initialisation not yet started, scheduleInit2(); // set it to be done on event-dispatching thread. return; // exit if Phase 2 of initialisation not finished } if(ld.scanDataLoaded()) // run through the loader control loop if(FTT) { // If this is 1st time through on applet start-up, repaint(); // call repaint() to displayed everything on top // of the background image. FTT = false; // reset the flag to avoid repreated repaints. } } public void stop() {TH = null;} // Stop and kill the program thread }