001 /*
002 * $Id: McIdasImageSequenceControl.java,v 1.22 2012/02/19 17:35:38 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2012
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 *
012 * All Rights Reserved
013 *
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.
016 *
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 *
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025 * GNU Lesser Public License for more details.
026 *
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program. If not, see http://www.gnu.org/licenses.
029 */
030
031 package edu.wisc.ssec.mcidasv.control;
032
033 import java.awt.Color;
034 import java.awt.Component;
035 import java.awt.Dimension;
036 import java.awt.Font;
037 import java.awt.FontMetrics;
038 import java.awt.GridBagConstraints;
039 import java.awt.GridBagLayout;
040 import java.awt.Image;
041 import java.awt.event.ActionEvent;
042 import java.awt.event.ActionListener;
043 import java.awt.event.ItemEvent;
044 import java.awt.event.ItemListener;
045 import java.awt.event.KeyAdapter;
046 import java.awt.event.KeyEvent;
047 import java.awt.event.MouseAdapter;
048 import java.awt.event.MouseEvent;
049 import java.io.BufferedReader;
050 import java.io.DataInputStream;
051 import java.io.InputStreamReader;
052 import java.net.URLEncoder;
053 import java.rmi.RemoteException;
054 import java.util.ArrayList;
055 import java.util.Hashtable;
056 import java.util.List;
057 import java.util.StringTokenizer;
058
059 import javax.swing.BorderFactory;
060 import javax.swing.JCheckBox;
061 import javax.swing.JComponent;
062 import javax.swing.JLabel;
063 import javax.swing.JPanel;
064 import javax.swing.JScrollBar;
065 import javax.swing.JScrollPane;
066 import javax.swing.JTabbedPane;
067 import javax.swing.JTextField;
068 import javax.swing.JTextPane;
069 import javax.swing.ScrollPaneConstants;
070 import javax.swing.SwingUtilities;
071 import javax.swing.border.EmptyBorder;
072 import javax.swing.text.BadLocationException;
073 import javax.swing.text.Style;
074 import javax.swing.text.StyleConstants;
075 import javax.swing.text.StyledDocument;
076
077 import visad.VisADException;
078 import visad.georef.MapProjection;
079
080 import ucar.unidata.data.DataChoice;
081 import ucar.unidata.data.DataContext;
082 import ucar.unidata.data.DataSource;
083 import ucar.unidata.data.DataSourceImpl;
084 import ucar.unidata.idv.ControlContext;
085 import ucar.unidata.idv.IntegratedDataViewer;
086 import ucar.unidata.idv.MapViewManager;
087 import ucar.unidata.idv.control.ControlWidget;
088 import ucar.unidata.idv.control.ImageSequenceControl;
089 import ucar.unidata.idv.control.WrapperWidget;
090 import ucar.unidata.ui.colortable.ColorTableManager;
091 import ucar.unidata.util.ColorTable;
092 import ucar.unidata.util.GuiUtils;
093 import ucar.unidata.util.Misc;
094
095 import edu.wisc.ssec.mcidasv.data.FrameDirtyInfo;
096 import edu.wisc.ssec.mcidasv.data.McIdasFrame;
097 import edu.wisc.ssec.mcidasv.data.McIdasXDataSource;
098 import edu.wisc.ssec.mcidasv.data.McIdasXInfo;
099 import edu.wisc.ssec.mcidasv.ui.McIdasFrameDisplay;
100
101 /**
102 * A DisplayControl for handling McIDAS-X image sequences
103 */
104 public class McIdasImageSequenceControl extends ImageSequenceControl {
105
106 private JLabel runningThreads;
107 private JCheckBox navigatedCbx;
108 private JPanel frameNavigatedContent;
109 private McIdasFrameDisplay frameDisplay;
110 private Dimension frameSize;
111 private JTextField inputText;
112 private JScrollPane outputPane;
113 private StyledDocument outputText;
114 private Font outputFont = new Font("Monospaced", Font.BOLD, 12);
115 private ArrayList commandHistory = new ArrayList();
116 private int commandHistoryIdx = -1;
117 private boolean commandHistoryMode = true;
118
119 /** McIDAS-X handles */
120 private McIdasXInfo mcidasxInfo;
121 private McIdasXDataSource mcidasxDS;
122
123 private int threadCount = 0;
124
125 private static DataChoice dc=null;
126 private static Integer frmI;
127
128 /** Holds frame component information */
129 private FrameComponentInfo frameComponentInfo;
130 private List frameDirtyInfoList = new ArrayList();
131 private List frameNumbers = new ArrayList();
132
133 /**
134 * Default ctor; sets the attribute flags
135 */
136 public McIdasImageSequenceControl() {
137 setAttributeFlags(FLAG_COLORTABLE | FLAG_DISPLAYUNIT);
138 initFrameComponentInfo();
139 this.mcidasxInfo = null;
140 this.mcidasxDS = null;
141
142 setDisplayId("bridgecontrol");
143 setHelpUrl("idv.controls.bridgecontrol");
144
145 setExpandedInTabs(true);
146 }
147
148 /**
149 * Creates, if needed, the frameComponentInfo member.
150 */
151 private void initFrameComponentInfo() {
152 if (this.frameComponentInfo == null) {
153 this.frameComponentInfo = new FrameComponentInfo(true, true, true, false, true, false);
154 }
155 }
156
157 /**
158 * Initializes the frameDirtyInfoList member.
159 */
160 private void initFrameDirtyInfoList() {
161 this.frameDirtyInfoList.clear();
162 Integer frameNumber;
163 FrameDirtyInfo frameDirtyInfo;
164 for (int i=0; i<this.frameNumbers.size(); i++) {
165 frameNumber = (Integer)this.frameNumbers.get(i);
166 frameDirtyInfo = new FrameDirtyInfo(frameNumber.intValue(), false, false, false);
167 this.frameDirtyInfoList.add(frameDirtyInfo);
168 }
169 }
170
171 /**
172 * Sets the frameDirtyInfoList member based on frame number
173 */
174 private void setFrameDirtyInfoList(int frameNumber, boolean dirtyImage, boolean dirtyGraphics, boolean dirtyColorTable) {
175 FrameDirtyInfo frameDirtyInfo;
176 for (int i=0; i<this.frameDirtyInfoList.size(); i++) {
177 frameDirtyInfo = (FrameDirtyInfo)frameDirtyInfoList.get(i);
178 if (frameDirtyInfo.getFrameNumber() == frameNumber) {
179 frameDirtyInfo.setDirtyImage(dirtyImage);
180 frameDirtyInfo.setDirtyGraphics(dirtyGraphics);
181 frameDirtyInfo.setDirtyColorTable(dirtyColorTable);
182 this.frameDirtyInfoList.set(i, frameDirtyInfo);
183 }
184 }
185 }
186
187 /**
188 * Override the base class method that creates request properties
189 * and add in the appropriate frame component request parameters.
190 * @return table of properties
191 */
192 protected Hashtable getRequestProperties() {
193 Hashtable props = super.getRequestProperties();
194 props.put(McIdasComponents.IMAGE, new Boolean(this.frameComponentInfo.getIsImage()));
195 props.put(McIdasComponents.GRAPHICS, new Boolean(this.frameComponentInfo.getIsGraphics()));
196 props.put(McIdasComponents.COLORTABLE, new Boolean(this.frameComponentInfo.getIsColorTable()));
197 props.put(McIdasComponents.ANNOTATION, new Boolean(this.frameComponentInfo.getIsAnnotation()));
198 props.put(McIdasComponents.FAKEDATETIME, new Boolean(this.frameComponentInfo.getFakeDateTime()));
199 props.put(McIdasComponents.DIRTYINFO, this.frameDirtyInfoList);
200 return props;
201 }
202
203 /**
204 * A helper method for constructing the ui.
205 * This fills up a list of {@link ControlWidget}
206 * (e.g., ColorTableWidget) and creates a gridded
207 * ui with them.
208 *
209 * @return The ui for the widgets
210 */
211 protected JComponent doMakeWidgetComponent() {
212
213 JPanel framePanel = new JPanel();
214 try {
215 framePanel = GuiUtils.top(doMakeFramePanel());
216 } catch (Exception e) {
217 System.err.println("doMakeContents exception: " + e);
218 }
219
220 JComponent settingsPanel = GuiUtils.top(super.doMakeWidgetComponent());
221
222 JTabbedPane tabbedPane = new JTabbedPane();
223 tabbedPane.add("Frames", framePanel);
224 tabbedPane.add("Settings", settingsPanel);
225
226 return tabbedPane;
227
228 }
229
230 /**
231 * Get control widgets specific to this control.
232 *
233 * @param controlWidgets list of control widgets from other places
234 *
235 * @throws RemoteException Java RMI error
236 * @throws VisADException VisAD Error
237 */
238 public void getControlWidgets(List controlWidgets)
239 throws VisADException, RemoteException {
240
241 super.getControlWidgets(controlWidgets);
242
243 // Navigated checkbox
244 navigatedCbx = new JCheckBox("Display data in main 3D panel", false);
245 navigatedCbx.setToolTipText("Set to send navigated data to the main 3D display in addition to this 2D display");
246 navigatedCbx.addItemListener(new ItemListener() {
247 public void itemStateChanged(ItemEvent e) {
248 JCheckBox myself = (JCheckBox)e.getItemSelectable();
249 GuiUtils.enableTree(frameNavigatedContent, myself.isSelected());
250 updateVImage();
251 }
252 });
253 JPanel frameNavigatedCbx =
254 GuiUtils.hflow(Misc.newList(navigatedCbx), 2, 0);
255 controlWidgets.add(
256 new WrapperWidget( this, GuiUtils.rLabel("Data:"), frameNavigatedCbx));
257
258 // Navigated options
259 JPanel frameComponentsPanel =
260 GuiUtils.hflow(Misc.newList(doMakeImageBox(), doMakeGraphicsBox(), doMakeAnnotationBox()), 2, 0);
261 JPanel frameOrderPanel =
262 GuiUtils.hflow(Misc.newList(doMakeFakeDateTimeBox()), 2, 0);
263 JPanel frameProjectionPanel =
264 GuiUtils.hflow(Misc.newList(doMakeResetProjectionBox()), 2, 0);
265 frameNavigatedContent =
266 GuiUtils.vbox(frameComponentsPanel, frameOrderPanel, frameProjectionPanel);
267 GuiUtils.enableTree(frameNavigatedContent, false);
268 controlWidgets.add(
269 new WrapperWidget( this, GuiUtils.rLabel(""), frameNavigatedContent));
270
271 }
272
273 /**
274 * Get frame control widgets specific to this control.
275 *
276 * @throws RemoteException Java RMI error
277 * @throws VisADException VisAD Error
278 */
279 private JPanel doMakeFramePanel()
280 throws VisADException, RemoteException {
281 frameSize = new Dimension(640, 480);
282
283 JPanel framePanel = new JPanel(new GridBagLayout());
284 GridBagConstraints c = new GridBagConstraints();
285 c.gridwidth = GridBagConstraints.REMAINDER;
286
287 frmI = new Integer(0);
288 ControlContext controlContext = getControlContext();
289 List dss = ((IntegratedDataViewer)controlContext).getDataSources();
290 for (int i=0; i<dss.size(); i++) {
291 DataSourceImpl ds = (DataSourceImpl)dss.get(i);
292 if (ds instanceof McIdasXDataSource) {
293 frameNumbers.clear();
294 ds.setProperty(DataSource.PROP_AUTOCREATEDISPLAY, false);
295 mcidasxDS = (McIdasXDataSource)ds;
296 DataContext dataContext = mcidasxDS.getDataContext();
297 ColorTableManager colorTableManager =
298 ((IntegratedDataViewer)dataContext).getColorTableManager();
299 ColorTable ct = colorTableManager.getColorTable("McIDAS-X");
300 setColorTable(ct);
301 this.mcidasxInfo = mcidasxDS.getMcIdasXInfo();
302 this.dc = getDataChoice();
303 String choiceStr = this.dc.toString();
304 if (choiceStr.equals("Frame Sequence")) {
305 frameNumbers = mcidasxDS.getFrameNumbers();
306 } else {
307 StringTokenizer tok = new StringTokenizer(choiceStr);
308 String str = tok.nextToken();
309 if (str.equals("Frame")) {
310 frmI = new Integer(tok.nextToken());
311 frameNumbers.add(frmI);
312 } else {
313 frmI = new Integer(1);
314 frameNumbers.add(frmI);
315 }
316 }
317 break;
318 }
319 }
320 initFrameDirtyInfoList();
321
322 // McIDAS-X frame display
323 frameDisplay = new McIdasFrameDisplay(frameNumbers, frameSize);
324 for (int i=0; i<frameNumbers.size(); i++) {
325 updateXImage((Integer)frameNumbers.get(i));
326 if (i==0) showXImage((Integer)frameNumbers.get(i));
327 }
328 framePanel.add(GuiUtils.hflow(Misc.newList(frameDisplay)), c);
329
330 // McIDAS-X text stuff
331 outputPane = doMakeOutputText();
332 inputText = doMakeCommandLine();
333 JPanel commandLinePanel =
334 GuiUtils.vbox(outputPane, doMakeSpacer(), inputText);
335 commandLinePanel.setBorder(BorderFactory.createLineBorder(Color.black));
336 framePanel.add(GuiUtils.hflow(Misc.newList(commandLinePanel)), c);
337
338 // McIDAS-X commands that are running
339 runningThreads = GuiUtils.lLabel("Running: " + this.threadCount);
340 framePanel.add(GuiUtils.hflow(Misc.newList(runningThreads)), c);
341
342 // Create a sensible title and tell McIDAS-X to stop looping and go to the first frame
343 String title = "";
344 if (frameNumbers.size() == 1) {
345 title = "McIDAS-X Frame " + (Integer)frameNumbers.get(0);
346 }
347 else {
348 Integer first = (Integer)frameNumbers.get(0);
349 Integer last = (Integer)frameNumbers.get(frameNumbers.size() - 1);
350 if (last - first == frameNumbers.size() - 1) {
351 title = "McIDAS-X Frames " + first + "-" + last;
352 }
353 else {
354 title = "McIDAS-X Frames " + (Integer)frameNumbers.get(0);
355 for (int i=1; i<frameNumbers.size(); i++) {
356 title += ", " + (Integer)frameNumbers.get(i);
357 }
358 }
359 }
360 sendCommandLine("TERM L OFF; SF " + (Integer)frameNumbers.get(0), false);
361
362 setNameFromUser(title);
363
364 // Give inputText the focus whenever anything is clicked on...
365 framePanel.addMouseListener(new MouseAdapter() {
366 public void mouseClicked(MouseEvent me) {
367 if (me.getButton() == me.BUTTON1) {
368 inputText.requestFocus();
369 }
370 }
371 });
372
373 return framePanel;
374 }
375
376 /**
377 * Make the frame component check boxes.
378 * @return Check box for Images
379 */
380 protected Component doMakeImageBox() {
381 JCheckBox newBox = new JCheckBox("Image", frameComponentInfo.getIsImage());
382 newBox.setToolTipText("Set to import image data");
383 newBox.addItemListener(new ItemListener() {
384 public void itemStateChanged(ItemEvent e) {
385 JCheckBox myself = (JCheckBox)e.getItemSelectable();
386 frameComponentInfo.setIsImage(myself.isSelected());
387 updateVImage();
388 }
389 });
390 return newBox;
391 }
392
393 /**
394 * Make the frame component check boxes.
395 * @return Check box for Graphics
396 */
397 protected Component doMakeGraphicsBox() {
398 JCheckBox newBox = new JCheckBox("Graphics", frameComponentInfo.getIsGraphics());
399 newBox.setToolTipText("Set to import graphics data");
400 newBox.addItemListener(new ItemListener() {
401 public void itemStateChanged(ItemEvent e) {
402 JCheckBox myself = (JCheckBox)e.getItemSelectable();
403 frameComponentInfo.setIsGraphics(myself.isSelected());
404 updateVImage();
405 }
406 });
407 return newBox;
408 }
409
410 /**
411 * Make the frame component check boxes.
412 * @return Check box for Color table
413 */
414 protected Component doMakeColorTableBox() {
415 JCheckBox newBox = new JCheckBox("Color table", frameComponentInfo.getIsColorTable());
416 newBox.setToolTipText("Set to import color table data");
417 newBox.addItemListener(new ItemListener() {
418 public void itemStateChanged(ItemEvent e) {
419 JCheckBox myself = (JCheckBox)e.getItemSelectable();
420 frameComponentInfo.setIsColorTable(myself.isSelected());
421 updateVImage();
422 }
423 });
424 return newBox;
425 }
426
427 /**
428 * Make the frame component check boxes.
429 * @return Check box for Annotation line
430 */
431 protected Component doMakeAnnotationBox() {
432 JCheckBox newBox = new JCheckBox("Annotation line", frameComponentInfo.getIsAnnotation());
433 newBox.setToolTipText("Set to import annotation line");
434 newBox.addItemListener(new ItemListener() {
435 public void itemStateChanged(ItemEvent e) {
436 JCheckBox myself = (JCheckBox)e.getItemSelectable();
437 frameComponentInfo.setIsAnnotation(myself.isSelected());
438 updateVImage();
439 }
440 });
441 return newBox;
442 }
443
444 /**
445 * Make the frame behavior check boxes.
446 * @return Check box for Fake date/time
447 */
448 protected Component doMakeFakeDateTimeBox() {
449 JCheckBox newBox =
450 new JCheckBox("Use McIDAS-X frame order to override data time with frame number",
451 frameComponentInfo.getFakeDateTime());
452 newBox.setToolTipText("Set to preserve frame order");
453 newBox.addItemListener(new ItemListener() {
454 public void itemStateChanged(ItemEvent e) {
455 JCheckBox myself = (JCheckBox)e.getItemSelectable();
456 frameComponentInfo.setFakeDateTime(myself.isSelected());
457 updateVImage();
458 }
459 });
460 return newBox;
461 }
462
463 /**
464 * Make the frame behavior check boxes.
465 * @return Check box for Projection reset
466 */
467 protected Component doMakeResetProjectionBox() {
468 JCheckBox newBox =
469 new JCheckBox("Use McIDAS-X data projection",
470 frameComponentInfo.getResetProjection());
471 newBox.setToolTipText("Set to reset projection when data is refreshed");
472 newBox.addItemListener(new ItemListener() {
473 public void itemStateChanged(ItemEvent e) {
474 JCheckBox myself = (JCheckBox)e.getItemSelectable();
475 frameComponentInfo.setResetProjection(myself.isSelected());
476 updateVImage();
477 }
478 });
479 return newBox;
480 }
481
482 private void resetCommandHistory() {
483 commandHistory = new ArrayList();
484 resetCommandHistoryIdx();
485 }
486
487 private void resetCommandHistoryIdx() {
488 commandHistoryIdx = -1;
489 }
490
491 protected JTextField doMakeCommandLine() {
492 final JTextField commandLine = new JTextField(0);
493 commandLine.setFont(outputFont);
494 commandLine.setBackground(Color.black);
495 commandLine.setForeground(Color.cyan);
496 commandLine.setCaretColor(Color.cyan);
497
498 FontMetrics metrics = commandLine.getFontMetrics(outputFont);
499 Dimension d = new Dimension(frameSize.width, metrics.getHeight());
500 commandLine.setSize(d);
501 commandLine.setPreferredSize(d);
502 commandLine.setMinimumSize(d);
503 commandLine.setMaximumSize(d);
504
505 resetCommandHistory();
506
507 commandLine.addActionListener(new ActionListener() {
508 public void actionPerformed(ActionEvent ae) {
509 String line = commandLine.getText().trim();
510 if (line.equals("")) return;
511 commandLine.setText("");
512 sendCommandLineThread(line, true);
513
514 // Add it to the head of commandHistory list
515 commandHistory.add(0, line);
516 resetCommandHistoryIdx();
517 }
518 });
519 commandLine.addKeyListener(new KeyAdapter() {
520 public void keyTyped(KeyEvent ke) {
521 char keyChar = ke.getKeyChar();
522 if (commandLine.getText().trim().equals("") && commandHistory.size() > 0) {
523 commandHistoryMode = true;
524 }
525 if (commandHistoryMode) {
526 if (keyChar == '&') {
527 commandHistoryIdx = Math.min(commandHistoryIdx+1,commandHistory.size()-1);
528 if (commandHistoryIdx < 0) {
529 resetCommandHistoryIdx();
530 commandLine.setText("");
531 }
532 else {
533 commandLine.setText((String)commandHistory.get(commandHistoryIdx));
534 }
535 ke.consume();
536 }
537 else if (keyChar == '^') {
538 commandHistoryIdx--;
539 if (commandHistoryIdx < 0) {
540 resetCommandHistoryIdx();
541 commandLine.setText("");
542 }
543 else {
544 commandLine.setText((String)commandHistory.get(commandHistoryIdx));
545 }
546 ke.consume();
547 }
548 else {
549 commandHistoryMode = false;
550 }
551 }
552 if (Character.isLowerCase(keyChar))
553 keyChar = Character.toUpperCase(keyChar);
554 else
555 keyChar = Character.toLowerCase(keyChar);
556 ke.setKeyChar(keyChar);
557 }
558 });
559 commandLine.setBorder(new EmptyBorder(0,0,0,0));
560 return commandLine;
561 }
562
563 private Component doMakeSpacer() {
564 JPanel spacer = new JPanel();
565 Color backgroundColor = new Color(0, 128, 128);
566 spacer.setBackground(backgroundColor);
567 FontMetrics metrics = inputText.getFontMetrics(outputFont);
568 Dimension d = new Dimension(frameSize.width, metrics.getHeight());
569 spacer.setSize(d);
570 spacer.setPreferredSize(d);
571 spacer.setMinimumSize(d);
572 spacer.setMaximumSize(d);
573 spacer.setBorder(new EmptyBorder(0,0,0,0));
574 return spacer;
575 }
576
577 protected JScrollPane doMakeOutputText() {
578 JTextPane outputPane = new JTextPane() {
579 public void setSize(Dimension d) {
580 if (d.width < getParent().getSize().width)
581 d.width = getParent().getSize().width;
582 super.setSize(d);
583 }
584 public boolean getScrollableTracksViewportWidth() {
585 return false;
586 }
587 };
588 outputPane.setFont(outputFont);
589 outputPane.setEditable(false);
590 outputPane.setBackground(Color.black);
591 outputPane.setForeground(Color.lightGray);
592 JScrollPane outputScrollPane = new JScrollPane(outputPane,
593 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
594 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
595
596 FontMetrics metrics = outputPane.getFontMetrics(outputFont);
597 Dimension d = new Dimension(frameSize.width, metrics.getHeight() * 8);
598 outputScrollPane.setSize(d);
599 outputScrollPane.setPreferredSize(d);
600 outputScrollPane.setMinimumSize(d);
601 outputScrollPane.setMaximumSize(d);
602
603 outputText = (StyledDocument)outputPane.getDocument();
604 outputScrollPane.setBorder(new EmptyBorder(0,0,0,0));
605
606 return outputScrollPane;
607 }
608
609 /**
610 * Send the given commandline to McIDAS-X over the bridge
611 * @param line
612 * @param showprocess
613 */
614 private void sendCommandLine(String line, boolean showprocess) {
615
616 // The user might have moved to another frame...
617 // Ask the image display which frame we are on
618 int frameCur = 1;
619 if (frameDisplay != null)
620 frameCur = frameDisplay.getFrameNumber();
621
622 line = line.trim();
623 if (line.length() < 1) return;
624 String encodedLine = line;
625 try {
626 encodedLine = URLEncoder.encode(line,"UTF-8");
627 } catch (Exception e) {
628 System.out.println("sendCommandLine URLEncoder exception: " + e);
629 }
630
631 DataInputStream inputStream = mcidasxInfo.getCommandInputStream(encodedLine, frameCur);
632 if (!showprocess) {
633 try { inputStream.close(); }
634 catch (Exception e) {}
635 return;
636 }
637 // appendTextLineItalics(line);
638 appendTextLineCommand(line);
639 try {
640 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
641 String responseType = null;
642 String ULine = null;
643 StringTokenizer tok;
644 boolean inList = false;
645 boolean doUpdate = false;
646 boolean dirtyImage, dirtyGraphics, dirtyColorTable;
647 // Burn the session key header line
648 String lineOut = br.readLine();
649 lineOut = br.readLine();
650 while (lineOut != null) {
651 // System.out.println("sendCommandLine processing: " + lineOut);
652 tok = new StringTokenizer(lineOut, " ");
653 responseType = tok.nextToken();
654 if (responseType.equals("U")) {
655 Integer frameInt = (Integer)Integer.parseInt(tok.nextToken());
656 inList = false;
657 dirtyImage = dirtyGraphics = dirtyColorTable = false;
658 // Don't pay attention to anything outside of our currently loaded frame list
659 for (int i=0; i<frameNumbers.size(); i++) {
660 if (frameInt.compareTo((Integer)frameNumbers.get(i)) == 0) inList = true;
661 }
662 if (inList) {
663 ULine = tok.nextToken();
664 // System.out.println(" Frame " + frameInt + " status line: " + ULine);
665 if (Integer.parseInt(ULine.substring(1,2)) != 0) dirtyImage = true;
666 if (Integer.parseInt(ULine.substring(3,4)) != 0) dirtyGraphics = true;
667 if (Integer.parseInt(ULine.substring(5,6)) != 0) dirtyColorTable = true;
668 if (dirtyImage || dirtyGraphics || dirtyColorTable) {
669 doUpdate = true;
670 updateXImage(frameInt);
671 }
672 setFrameDirtyInfoList(frameInt, dirtyImage, dirtyGraphics, dirtyColorTable);
673 }
674 } else if (responseType.equals("C")) {
675 appendTextLineCommand(lineOut.substring(6));
676 } else if (responseType.equals("T")) {
677 // appendTextLine(" " + lineOut.substring(6));
678 appendTextLineNormal(lineOut.substring(6));
679
680 } else if (responseType.equals("M") ||
681 responseType.equals("S")) {
682 // appendTextLine(" * " + lineOut.substring(6));
683 appendTextLineError(lineOut.substring(6));
684
685 } else if (responseType.equals("R")) {
686 // appendTextLine(" ! " + lineOut.substring(6));
687 appendTextLineError(lineOut.substring(6));
688 } else if (responseType.equals("V")) {
689 // System.out.println("Viewing frame status line: " + lineOut);
690 frameCur = Integer.parseInt(tok.nextToken());
691 } else if (responseType.equals("H") ||
692 responseType.equals("K")) {
693 /* Don't do anything with these response types */
694 } else {
695 /* Catch any unparsed line... */
696 System.err.println("Could not parse bridge response: " + lineOut);
697 }
698 lineOut = br.readLine();
699 }
700 showXImage(frameCur);
701 if (doUpdate) {
702 updateVImage();
703 }
704
705 } catch (Exception e) {
706 System.out.println("sendCommandLine exception: " + e);
707 try { inputStream.close(); }
708 catch (Exception ee) {}
709 }
710
711 }
712
713 /*
714 private void appendTextLine(String line) {
715 outputText.append(line + "\n");
716 outputText.setCaretPosition(outputText.getDocument().getLength());
717 }
718 */
719
720 private void appendTextLineNormal(String line) {
721 Style style = outputText.addStyle("Normal", null);
722 StyleConstants.setForeground(style, Color.lightGray);
723 try {
724 outputText.insertString(outputText.getLength(), line + "\n", style);
725 } catch (BadLocationException e) { }
726 scrollTextLineToBottom();
727 }
728
729 private void appendTextLineCommand(String line) {
730 Style style = outputText.addStyle("Command", null);
731 StyleConstants.setForeground(style, Color.green);
732 try {
733 outputText.insertString(outputText.getLength(), line + "\n", style);
734 } catch (BadLocationException e) { }
735 scrollTextLineToBottom();
736 }
737
738 private void appendTextLineError(String line) {
739 Style style = outputText.addStyle("Error", null);
740 StyleConstants.setForeground(style, Color.yellow);
741 try {
742 outputText.insertString(outputText.getLength(), line + "\n", style);
743 } catch (BadLocationException e) { }
744 scrollTextLineToBottom();
745 }
746
747 private void scrollTextLineToBottom() {
748 SwingUtilities.invokeLater(new Runnable() {
749 public void run() {
750 JScrollBar vBar = outputPane.getVerticalScrollBar();
751 vBar.setValue(vBar.getMaximum());
752 }
753 });
754 }
755
756 private void updateXImage(int inFrame) {
757 if (mcidasxDS == null || frameDisplay == null) return;
758 try {
759 McIdasFrame frm = mcidasxDS.getFrame(inFrame);
760 Image imageGIF = frm.getGIF();
761 frameDisplay.setFrameImage(inFrame, imageGIF);
762 } catch (Exception e) {
763 System.out.println("updateXImage exception: " + e);
764 }
765 }
766
767 private void showXImage(int inFrame) {
768 if (frameDisplay == null) return;
769 try {
770 frameDisplay.showFrameNumber(inFrame);
771 } catch (Exception e) {
772 System.out.println("showXImage exception: " + e);
773 }
774 }
775
776 private void updateVImage() {
777 try {
778 getRequestProperties();
779 resetData();
780 } catch (Exception e) {
781 System.out.println("updateVImage exception: " + e);
782 }
783 }
784
785 public boolean init(DataChoice choice)
786 throws VisADException, RemoteException {
787 setShowProgressBar(false);
788 boolean ret = super.init(choice, false);
789 return ret;
790 }
791
792 /**
793 * This gets called when the control has received notification of a
794 * dataChange event.
795 *
796 * @throws RemoteException Java RMI problem
797 * @throws VisADException VisAD problem
798 */
799 protected void resetData() throws VisADException, RemoteException {
800 // Do not attempt to load any data unless the checkbox is set...
801 if (!navigatedCbx.isSelected()) return;
802
803 super.resetData();
804
805 if (frameComponentInfo.getResetProjection()) {
806 MapProjection mp = getDataProjection();
807 if (mp != null) {
808 MapViewManager mvm = getMapViewManager();
809 mvm.setMapProjection(mp, false);
810 }
811 }
812 }
813
814 /**
815 * Try my hand at creating a thread
816 */
817 private class McIdasCommandLine implements Runnable {
818 private String line;
819 private boolean showprocess;
820 public McIdasCommandLine() {
821 this.line = "";
822 this.showprocess = true;
823 }
824 public McIdasCommandLine(String line, boolean showprocess) {
825 this.line = line;
826 this.showprocess = showprocess;
827 }
828 public void run() {
829 notifyThreadStart();
830 sendCommandLine(this.line, this.showprocess);
831 notifyThreadStop();
832 }
833 }
834
835 /**
836 * Threaded sendCommandLine
837 * @param line
838 * @param showprocess
839 */
840 private void sendCommandLineThread(String line, boolean showprocess) {
841 McIdasCommandLine mcCmdLine = new McIdasCommandLine(line, showprocess);
842 Thread t = new Thread(mcCmdLine);
843 t.start();
844 }
845
846 private void notifyThreadStart() {
847 this.threadCount++;
848 notifyThreadCount();
849 }
850 private void notifyThreadStop() {
851 this.threadCount--;
852 notifyThreadCount();
853 }
854 private void notifyThreadCount() {
855 runningThreads.setText("Running: " + this.threadCount);
856 }
857
858 }