/app/src/de/georg_gruetter/xhsi/HSI.java

https://github.com/breidh/xhsi · Java · 347 lines · 254 code · 62 blank · 31 comment · 42 complexity · 699a70a4a396a85d9a2a6c2b46e07d48 MD5 · raw file

  1. /**
  2. * HSI.java
  3. *
  4. * Main class starting and controlls the UI and all threads of the horizontal
  5. * situation indicator display.
  6. *
  7. * Copyright (C) 2007 Georg Gruetter (gruetter@gmail.com)
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. */
  23. package de.georg_gruetter.xhsi;
  24. import java.awt.Color;
  25. import java.awt.event.ActionEvent;
  26. import java.awt.event.ActionListener;
  27. import java.awt.event.KeyEvent;
  28. import java.lang.reflect.InvocationHandler;
  29. import java.lang.reflect.Method;
  30. import java.lang.reflect.Proxy;
  31. import java.net.InetAddress;
  32. import java.util.ArrayList;
  33. import java.util.logging.ConsoleHandler;
  34. import java.util.logging.FileHandler;
  35. import java.util.logging.Handler;
  36. import java.util.logging.Level;
  37. import java.util.logging.Logger;
  38. import javax.swing.JFrame;
  39. import javax.swing.JMenu;
  40. import javax.swing.JMenuBar;
  41. import javax.swing.JMenuItem;
  42. import javax.swing.JOptionPane;
  43. import de.georg_gruetter.xhsi.model.xplane.XPlaneDataPacketDecoder;
  44. import de.georg_gruetter.xhsi.model.xplane.XPlaneFlightSessionPlayer;
  45. import de.georg_gruetter.xhsi.model.xplane.XPlaneFlightSessionRecorder;
  46. import de.georg_gruetter.xhsi.model.xplane.XPlaneModelFactory;
  47. import de.georg_gruetter.xhsi.model.xplane.XPlaneNavigationObjectBuilder;
  48. import de.georg_gruetter.xhsi.model.xplane.XPlaneSimDataRepository;
  49. import de.georg_gruetter.xhsi.model.xplane.XPlaneUDPReceiver;
  50. import de.georg_gruetter.xhsi.panel.HSIComponent;
  51. import de.georg_gruetter.xhsi.panel.UIHeartbeat;
  52. import de.georg_gruetter.xhsi.util.XHSILogFormatter;
  53. public class HSI implements ActionListener {
  54. private static final String RELEASE = "1.0 Beta 6";
  55. private static final String MODE_REPLAY = "replay";
  56. private static final String MODE_RECEIVE = "receive";
  57. public static final String ACTION_QUIT = "Quit";
  58. public static final String ACTION_PREFERENCES = "Preferences";
  59. public static final String ACTION_ABOUT = "About XHSI";
  60. private HSIPreferences preferences;
  61. private ArrayList running_threads;
  62. private HSIComponent hsi_ui;
  63. private JFrame hsi_frame;
  64. private JFrame preferences_frame;
  65. private JFrame nob_progress_frame;
  66. private static Logger logger = Logger.getLogger("de.georg_gruetter.xhsi");
  67. public static void main(String args[]) throws Exception {
  68. Handler handler = new ConsoleHandler();
  69. handler.setLevel(Level.ALL);
  70. handler.setFormatter(new XHSILogFormatter());
  71. handler.setFilter(null);
  72. logger.addHandler(handler);
  73. handler = new FileHandler("XHSI.log");
  74. handler.setLevel(Level.ALL);
  75. handler.setFormatter(new XHSILogFormatter());
  76. handler.setFilter(null);
  77. logger.addHandler(handler);
  78. logger.setLevel(Level.ALL);
  79. logger.setUseParentHandlers(false);
  80. logger.config("XHSI " + HSI.RELEASE + " started");
  81. HSIStatus.status = HSIStatus.STATUS_STARTUP;
  82. if ((args.length >= 2) && (args[0].equals("--record"))) {
  83. logger.fine("recording flight session to '" + args[1] + "' ...");
  84. int recording_rate = 1;
  85. if (args.length == 3)
  86. recording_rate = Integer.parseInt(args[2]);
  87. XPlaneFlightSessionRecorder recorder = new XPlaneFlightSessionRecorder(args[1],recording_rate);
  88. XPlaneUDPReceiver udp_receiver = new XPlaneUDPReceiver(49001);
  89. udp_receiver.add_reception_observer(recorder);
  90. recorder.start();
  91. udp_receiver.start();
  92. } else if ((args.length == 2) && (args[0].equals("--replay"))) {
  93. new HSI(MODE_REPLAY, args[1]);
  94. } else if ((args.length == 1) && (args[0].equals("--help"))) {
  95. display_usage_info();
  96. } else if ((args.length == 1) && (args[0].equals("--version"))) {
  97. System.out.println("Version of XHSI is " + HSI.RELEASE);
  98. } else if (args.length == 0) {
  99. new HSI(MODE_RECEIVE);
  100. } else {
  101. display_usage_info();
  102. }
  103. }
  104. public static void display_usage_info() {
  105. System.out.println(
  106. "Usage: java -jar XHSI.jar [--options]\n\n" +
  107. "where options include:\n" +
  108. " --record <filename> [<frame_rate>] to record the current datastream\n" +
  109. " received from X-Plane in the file\n" +
  110. " <filename>. If <frame_rate>\n" +
  111. " is given, records every <frame_rate>'th\n" +
  112. " received data frame to save space.\n" +
  113. " --replay <filename> to replay the recording stored\n" +
  114. " in <filename>\n" +
  115. " --version to display the version of XHSI\n" +
  116. " --help to display this help\n"
  117. );
  118. }
  119. public HSI(String mode, String filename) throws Exception {
  120. init();
  121. if (mode.equals(MODE_REPLAY)) {
  122. logger.fine("playing flight session recording from '" + filename + "' ...");
  123. XPlaneFlightSessionPlayer player = new XPlaneFlightSessionPlayer(filename,Long.parseLong(this.preferences.get_preference(HSIPreferences.PREF_REPLAY_DELAY_PER_FRAME)));
  124. XPlaneDataPacketDecoder decoder = new XPlaneDataPacketDecoder();
  125. player.add_sim_data_observer(decoder);
  126. this.running_threads.add(player);
  127. XPlaneSimDataRepository.source_is_recording = true;
  128. HSIStatus.status = HSIStatus.STATUS_PLAYING_RECORDING;
  129. player.start();
  130. }
  131. }
  132. public HSI(String mode) throws Exception {
  133. init();
  134. if (mode.equals(MODE_RECEIVE)) {
  135. XPlaneUDPReceiver udp_receiver = new XPlaneUDPReceiver(Integer.parseInt(preferences.get_preference(HSIPreferences.PREF_PORT)));
  136. XPlaneDataPacketDecoder decoder = new XPlaneDataPacketDecoder();
  137. udp_receiver.add_reception_observer(decoder);
  138. XPlaneSimDataRepository.source_is_recording = false;
  139. this.running_threads.add(udp_receiver);
  140. HSIStatus.status = HSIStatus.STATUS_RECEIVING;
  141. udp_receiver.start();
  142. }
  143. }
  144. private void init() throws Exception {
  145. this.running_threads = new ArrayList();
  146. // load properties and create a new properties file, if none exists
  147. this.preferences = HSIPreferences.get_instance();
  148. // set loglevel
  149. logger.config("Selected loglevel: " + this.preferences.get_preference(HSIPreferences.PREF_LOGLEVEL));
  150. logger.setLevel(Level.parse(this.preferences.get_preference(HSIPreferences.PREF_LOGLEVEL)));
  151. // create user interface
  152. create_UI();
  153. // load X-Plane Earth nav databases
  154. XPlaneNavigationObjectBuilder nob = new XPlaneNavigationObjectBuilder(this.preferences.get_preference(HSIPreferences.PREF_XPLANE_DIR));
  155. HSIPreferences.get_instance().add_subsciption(nob, HSIPreferences.PREF_XPLANE_DIR);
  156. nob.set_progress_observer((ProgressObserver) this.nob_progress_frame);
  157. if (HSIStatus.nav_db_status.equals(HSIStatus.STATUS_NAV_DB_NOT_FOUND) == false) {
  158. nob.read_all_tables();
  159. HSIStatus.nav_db_status = HSIStatus.STATUS_NAV_DB_LOADED;
  160. }
  161. // add ui update watchdog
  162. UIHeartbeat ui_heartbeat = new UIHeartbeat(this.hsi_ui, 1000);
  163. ui_heartbeat.start();
  164. this.running_threads.add(ui_heartbeat);
  165. }
  166. private void shutdown_threads() {
  167. StoppableThread thread;
  168. HSIStatus.status = HSIStatus.STATUS_SHUTDOWN;
  169. for (int i=0;i<this.running_threads.size();i++) {
  170. thread = (StoppableThread) this.running_threads.get(i);
  171. thread.signal_stop();
  172. try {
  173. thread.join(1000);
  174. } catch (Exception e) {
  175. logger.warning("Could not shutdown thread. (" + e.toString());
  176. }
  177. }
  178. }
  179. private boolean isMac() {
  180. return (System.getProperty("mrj.version") != null);
  181. }
  182. private void create_UI() throws Exception {
  183. boolean ui_specialization = true;
  184. if (isMac()) {
  185. logger.config("Mac detected. Create Menubar with Mac look and feel");
  186. System.setProperty("apple.laf.useScreenMenuBar", "true");
  187. System.setProperty("com.apple.mrj.application.apple.menu.about.name","XHSI");
  188. // try to load apple specific classes dynamically in order to avoid
  189. // compilation problems on non-mac platforms
  190. try {
  191. Class Application = Class.forName("com.apple.eawt.Application");
  192. Class ApplicationListener = Class.forName("com.apple.eawt.ApplicationListener");
  193. Class ApplicationEvent = Class.forName("com.apple.eawt.ApplicationEvent");
  194. Method getApplication = Application.getMethod("getApplication", new Class[0]);
  195. Method addApplicationListener = Application.getMethod("addApplicationListener", new Class[] { ApplicationListener });
  196. final Method setHandled = ApplicationEvent.getMethod("setHandled", new Class[] { Boolean.TYPE });
  197. Method setEnabledPreferencesMenu = Application.getMethod("setEnabledPreferencesMenu", new Class[] { Boolean.TYPE });
  198. InvocationHandler listenerHandler = new InvocationHandler() {
  199. public Object invoke(Object proxy, Method method, Object[] args) {
  200. String name = method.getName();
  201. if (name.equals("handleAbout")) {
  202. actionPerformed(new ActionEvent(this,0, HSI.ACTION_ABOUT));
  203. } else if (name.equals("handlePreferences")) {
  204. actionPerformed(new ActionEvent(this,0, HSI.ACTION_PREFERENCES));
  205. } else if (name.equals("handleQuit")) {
  206. actionPerformed(new ActionEvent(this,0, HSI.ACTION_QUIT));
  207. } else {
  208. return null;
  209. }
  210. try {
  211. setHandled.invoke(args[0], new Object[] { Boolean.TRUE });
  212. } catch (Exception ex) {
  213. // Ignore
  214. }
  215. return null;
  216. }
  217. };
  218. Object application = getApplication.invoke(null, (Object[]) null);
  219. setEnabledPreferencesMenu.invoke(application, new Object[] { Boolean.TRUE });
  220. Object listener = Proxy.newProxyInstance(HSI.class.getClassLoader(),
  221. new Class[] { ApplicationListener },
  222. listenerHandler);
  223. addApplicationListener.invoke(application, new Object[] { listener });
  224. } catch (Exception e) {
  225. logger.warning("Could not create Mac specific UI! (" + e.toString() + ")");
  226. ui_specialization = false;
  227. }
  228. }
  229. this.hsi_frame = new JFrame("XHSI " + HSI.RELEASE + " on " + InetAddress.getLocalHost());
  230. if ((isMac() == false) || (ui_specialization == false)) {
  231. this.hsi_frame.setJMenuBar(createMenu());
  232. }
  233. this.hsi_ui = new HSIComponent(new XPlaneModelFactory());
  234. XPlaneSimDataRepository.get_instance().add_observer(hsi_ui);
  235. this.hsi_frame.getContentPane().add(hsi_ui);
  236. this.hsi_frame.pack();
  237. this.hsi_frame.setBackground(Color.BLACK);
  238. this.hsi_frame.setVisible(true);
  239. this.preferences_frame = new PreferencesDialog();
  240. this.nob_progress_frame = new ProgressDialog(this.hsi_frame);
  241. }
  242. private JMenuBar createMenu() {
  243. JMenuBar menu_bar = new JMenuBar();
  244. JMenu big_hsi_menu = new JMenu("XHSI");
  245. JMenuItem menu_item = new JMenuItem("About XHSI");
  246. menu_item.addActionListener(this);
  247. menu_item.setMnemonic(KeyEvent.VK_A);
  248. big_hsi_menu.add(menu_item);
  249. big_hsi_menu.addSeparator();
  250. menu_item = new JMenuItem("Preferences");
  251. menu_item.addActionListener(this);
  252. menu_item.setMnemonic(KeyEvent.VK_S);
  253. big_hsi_menu.add(menu_item);
  254. big_hsi_menu.addSeparator();
  255. menu_item = new JMenuItem("Quit");
  256. menu_item.setMnemonic(KeyEvent.VK_Q);
  257. menu_item.addActionListener(this);
  258. big_hsi_menu.add(menu_item);
  259. menu_bar.add(big_hsi_menu);
  260. return menu_bar;
  261. }
  262. public void actionPerformed(ActionEvent event) {
  263. if (event.getActionCommand().equals(ACTION_QUIT)) {
  264. logger.fine("stopping threads");
  265. shutdown_threads();
  266. logger.fine("clean exit from threads");
  267. System.exit(0);
  268. } else if (event.getActionCommand().equals(ACTION_PREFERENCES)) {
  269. // choose X-Plane directory
  270. this.preferences_frame.setVisible(true);
  271. this.preferences_frame.pack();
  272. } else if (event.getActionCommand().equals(ACTION_ABOUT)) {
  273. JOptionPane.showMessageDialog(this.hsi_frame,
  274. "XHSI " + HSI.RELEASE +
  275. "\nby Georg Gruetter in 2007" +
  276. "\n\ngruetter@users.sourceforge.net" +
  277. "\nhttp://www.g16g.de/x-plane\n\n" +
  278. "Special thanks for beta testing to\n" +
  279. "Ansorg, Brandon, Elvis, Mark Steele,\n" +
  280. "Mueli and Schleich!",
  281. "About XHSI",
  282. JOptionPane.INFORMATION_MESSAGE);
  283. }
  284. }
  285. }