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