def addApplicationCheckbox(app, app_id, ap): checkbox = JCheckBox("{} ({})".format(app.capitalize(), app_id), actionPerformed= ap) checkbox.setActionCommand(app) checkbox.setSelected(True) checkbox.setVisible(False) checkbox.setActionCommand(app_id) return checkbox
def addDeviceCheckbox(device, ap, visible=False): checkbox = JCheckBox(device, actionPerformed=ap) checkbox.setActionCommand(device) checkbox.setSelected(True) checkbox.setVisible(visible) return checkbox
class CumulusUI(JFrame): '''Java Swing used to create a JFrame UI. On init the objects will be populated with information derived from URL requests to CUMULUS and the open CWMS watershed. ''' def __init__(self, arg_dict): super(CumulusUI, self).__init__() # Load argument from the command line self.start_time = arg_dict['start_time'] self.end_time = arg_dict['end_time'] self.dss_path = arg_dict['dss_path'] self.cwms_home = arg_dict['cwms_home'] self.config = arg_dict['config'] # Get the DSS Path if one was saved in the "cumulus.config" file if os.path.isfile(self.config): with open(os.path.join(APPDATA, "cumulus.config")) as f: self.dss_path = f.read() # Get the basins and products, load JSON, create lists for JList, and create dictionaries self.basin_download = json.loads(self.http_get(url_basins)) self.jlist_basins = ["{}:{}".format(b['office_symbol'], b['name']) for b in self.basin_download] self.basin_meta = dict(zip(self.jlist_basins, self.basin_download)) self.jlist_basins.sort() self.product_download = json.loads(self.http_get(url_products)) self.jlist_products = ["{}".format(p['name'].replace("_", " ").title()) for p in self.product_download] self.product_meta = dict(zip(self.jlist_products, self.product_download)) self.jlist_products.sort() btn_submit = JButton() lbl_start_date = JLabel() lbl_end_date = JLabel() self.txt_select_file = JTextField() btn_select_file = JButton() lbl_origin = JLabel() lbl_extent = JLabel() lbl_select_file = JLabel() self.txt_start_time = JTextField() self.txt_end_time = JTextField() jScrollPane1 = JScrollPane() self.lst_product = JList() self.lst_product = JList(self.jlist_products, valueChanged = self.choose_product) jScrollPane2 = JScrollPane() self.lst_watershed = JList() self.lst_watershed = JList(self.jlist_basins, valueChanged = self.choose_watershed) self.cwms_dssname = JCheckBox() self.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE) self.setTitle("Cumulus CAVI UI") self.setLocation(Point(10, 10)) self.setLocationByPlatform(True) self.setName("CumulusCaviUi") self.setResizable(False) btn_submit.setFont(Font("Tahoma", 0, 18)) btn_submit.setText("Submit") btn_submit.actionPerformed = self.submit lbl_start_date.setText("Start Date/Time") lbl_end_date.setText("End Date/Time") self.txt_select_file.setToolTipText("FQPN to output file (.dss)") btn_select_file.setText("...") btn_select_file.setToolTipText("Select File...") btn_select_file.actionPerformed = self.select_file lbl_origin.setText("Minimum (x,y):") lbl_extent.setText("Maximum (x,y):") lbl_select_file.setText("Output File Location") self.txt_start_time.setToolTipText("Start Time") self.txt_end_time.setToolTipText("End Time") self.lst_product.setBorder(BorderFactory.createTitledBorder(None, "Available Products", TitledBorder.CENTER, TitledBorder.TOP, Font("Tahoma", 0, 14))) self.lst_product.setFont(Font("Tahoma", 0, 14)) jScrollPane1.setViewportView(self.lst_product) self.lst_product.getAccessibleContext().setAccessibleName("Available Products") self.lst_product.getAccessibleContext().setAccessibleParent(jScrollPane2) self.lst_watershed.setBorder(BorderFactory.createTitledBorder(None, "Available Watersheds", TitledBorder.CENTER, TitledBorder.TOP, Font("Tahoma", 0, 14))) self.lst_watershed.setFont(Font("Tahoma", 0, 14)) self.lst_watershed.setSelectionMode(ListSelectionModel.SINGLE_SELECTION) jScrollPane2.setViewportView(self.lst_watershed) self.cwms_dssname.setText("CWMS DSS filename") self.cwms_dssname.setToolTipText("Parameter.yyyy.mm.dss") self.cwms_dssname.setVisible(False) layout = GroupLayout(self.getContentPane()); self.getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, False) .addComponent(lbl_select_file) .addComponent(jScrollPane1) .addComponent(jScrollPane2) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(btn_submit) .addComponent(self.txt_select_file, GroupLayout.PREFERRED_SIZE, 377, GroupLayout.PREFERRED_SIZE)) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addComponent(btn_select_file)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(lbl_start_date) .addComponent(self.txt_start_time, GroupLayout.PREFERRED_SIZE, 170, GroupLayout.PREFERRED_SIZE)) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(self.txt_end_time, GroupLayout.PREFERRED_SIZE, 170, GroupLayout.PREFERRED_SIZE) .addComponent(lbl_end_date)))) .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ) layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(25, 25, 25) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(lbl_start_date) .addComponent(lbl_end_date)) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(self.txt_start_time, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(self.txt_end_time, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) .addComponent(jScrollPane2, GroupLayout.PREFERRED_SIZE, 201, GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 201, GroupLayout.PREFERRED_SIZE) .addGap(18, 18, Short.MAX_VALUE) .addComponent(lbl_select_file) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(self.txt_select_file, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(btn_select_file)) .addGap(18, 18, 18) .addComponent(btn_submit) .addContainerGap()) ) self.txt_select_file.setText(self.dss_path) self.txt_start_time.setText(self.start_time) self.txt_end_time.setText(self.end_time) self.pack() self.setLocationRelativeTo(None) def http_get(self, url): '''Return java.lang.String JSON Input: java.lang.String URL ''' start_timer = System.currentTimeMillis() try: url = URL(url) urlconnect = url.openConnection() br = BufferedReader( InputStreamReader( urlconnect.getInputStream(), "UTF-8" ) ) s = br.readLine() br.close() except MalformedURLException() as ex: cumulus_logger.error(str(ex)) MessageBox.showError(str(ex), "Exception") raise except IOException as ex: cumulus_logger.error(str(ex)) MessageBox.showError(str(ex), "Exception") raise end_timer = System.currentTimeMillis() cumulus_logger.debug( "HTTP GET (milliseconds): {}".format( (end_timer - start_timer) ) ) return s def http_post(self, json_string, url): '''Return java.lang.String JSON Input: java.lang.String JSON, java.lang.String URL ''' start_timer = System.currentTimeMillis() try: # Get a connection and set the request properties url = URL(url) urlconnect = url.openConnection() urlconnect.setDoOutput(True) urlconnect.setRequestMethod("POST") urlconnect.setRequestProperty("Content-Type", "application/json; UTF-8") urlconnect.setRequestProperty("Accept", "application/json") # Write to the body bw = BufferedWriter( OutputStreamWriter( urlconnect.getOutputStream() ) ) bw.write(json_string) bw.flush() bw.close() # Read the result from the POST br = BufferedReader( InputStreamReader( urlconnect.getInputStream(), "UTF-8" ) ) s = br.readLine() br.close() except MalformedURLException() as ex: cumulus_logger.error(str(ex)) MessageBox.showError(str(ex), "Exception") raise Exception(ex) except IOException as ex: cumulus_logger.error(str(ex)) MessageBox.showError(str(ex), "Exception") raise Exception(ex) end_timer = System.currentTimeMillis() cumulus_logger.debug( "HTTP GET (milliseconds): {}".format( (end_timer - start_timer) ) ) return s def json_build(self): '''Return JSON string or 'None' if failed The returning JSON string is from the UI and used when POSTing to the Cumulus API. ''' conf = { 'datetime_start': None, 'datetime_end': None, 'watershed_id': None, 'product_id': None, } try: tf = TimeFormatter() tz = tf.zid st = tf.parse_zoned_date_time(self.txt_start_time.getText(), tz) et = tf.parse_zoned_date_time(self.txt_end_time.getText(), tz) conf['datetime_start'] = st.format(tf.iso_instant()) conf['datetime_end'] = et.format(tf.iso_instant()) except DateTimeParseException as ex: MessageBox.showWarning(ex, "Exception") selected_watershed = self.lst_watershed.getSelectedValue() selected_products = self.lst_product.getSelectedValues() if selected_watershed is not None: watershed_id = self.basin_meta[selected_watershed]['id'] conf['watershed_id'] = watershed_id else: MessageBox.showWarning( "No Watershed Selected", "Exception" ) return None product_ids = list() if len(selected_products) > 0: for p in selected_products: product_ids.append(self.product_meta[p]['id']) conf['product_id'] = product_ids else: MessageBox.showWarning( "No Products Selected", "Exception" ) return None return json.dumps(conf) def choose_product(self, event): '''The event here is a javax.swing.event.ListSelectionEvent because it comes from a Jlist. Use getValueIsAdjusting() to only get the mouse up value. ''' output_str = '''{name} After: {after} Before: {before} Parameter: {para} Unit: {u} ''' index = self.lst_product.selectedIndex if not event.getValueIsAdjusting(): pnames = self.lst_product.getSelectedValues() for pname in pnames: cumulus_logger.info("~" * 50) cumulus_logger.info("Product: {}".format(pname)) cumulus_logger.info( "After time: {}".format(self.product_meta[pname]['after'])) cumulus_logger.info( "Before time: {}".format(self.product_meta[pname]['before'])) cumulus_logger.info( "Parameter: {}".format(self.product_meta[pname]['parameter'])) cumulus_logger.info( "unit: {}".format(self.product_meta[pname]['unit'])) def choose_watershed(self, event): '''The event here is a javax.swing.event.ListSelectionEvent because it comes from a Jlist. Use getValueIsAdjusting() to only get the mouse up value. ''' index = self.lst_watershed.selectedIndex if not event.getValueIsAdjusting(): _dict = self.basin_meta[self.lst_watershed.getSelectedValue()] def select_file(self, event): '''Provide the user a JFileChooser to select the DSS file data is to download to. Event is a java.awt.event.ActionEvent ''' fc = FileChooser(self.txt_select_file) fc.title = "Select Output DSS File" _dir = os.path.dirname(self.dss_path) fc.set_current_dir(File(_dir)) fc.show() def submit(self, event): '''Collect user inputs and initiate download of DSS files to process. Event is a java.awt.event.ActionEvent ''' start_timer = end_timer = System.currentTimeMillis() # Build the JSON from the UI inputs and POST if we have JSON json_string = self.json_build() cumulus_logger.debug("JSON String Builder: {}".format(json_string)) if json_string is not None: cumulus_logger.info("*" * 50) cumulus_logger.info("Initiated Cumulus Product Request") cumulus_logger.info("*" * 50) post_result = self.http_post(json_string, url_downloads) json_post_result = json.loads(post_result) id = json_post_result['id'] max_timeout = 180 while max_timeout > 0: get_result = self.http_get("/".join([url_downloads, id])) if get_result is not None: json_get_result = json.loads(get_result) progress = json_get_result['progress'] #100% stat = json_get_result['status'] #SUCCESS fname = json_get_result['file'] # not null cumulus_logger.info("Status: {:>10}; Progress: {:>4.1f}%; Timeout: {:>4}".format(stat, progress, max_timeout)) if stat == 'FAILED': cumulus_logger.error("Failed to load grid products.") MessageBox.showError( "Failed to load grid products.", "Failed Download" ) break if int(progress) == 100 and stat == 'SUCCESS' and fname is not None: dest_dssfile = self.txt_select_file.getText() cumulus_logger.debug("DSS Download Filname: {}".format(fname)) downloaded_dssfile = download_dss(fname) if downloaded_dssfile is not None: cumulus_logger.info("DSS file downloaded.") merged_dssfiles = merge_dss(downloaded_dssfile, dest_dssfile) if len(merged_dssfiles) > 0: end_timer = System.currentTimeMillis() msg = "DSS file downloaded and merged to: {}".format( '\n'.join([f for f in merged_dssfiles]) ) cumulus_logger.info(msg) MessageBox.showInformation(msg, "Successful Processing" ) else: msg = "DSS file merge unsuccessful" cumulus_logger.warning(msg) MessageBox.showWarning(msg, "Unsuccessful Merge" ) else: msg = "Downloading and processing the DSS file failed!" cumulus_logger.error(msg) MessageBox.showError(msg, "Failed Processing" ) break else: Thread.sleep(2000) max_timeout -= 1 cumulus_logger. info( "Submit time duration (milliseconds): {}".format( (end_timer - start_timer) ) ) # Try to clean up any dss6 and dss7 files in the temp try: tempdir = tempfile.gettempdir() dss_temp_files = os.listdir(tempdir) for f in dss_temp_files: if (f.endswith(".dss") or f.endswith(".dss")): os.remove(os.path.join(tempdir, f)) except OSError as ex: cumulus_logger.warning(str(ex))