001/* A panel for controlling the format of a plotter. 002 003 Copyright (c) 1998-2018 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.plot; 028 029import java.awt.BorderLayout; 030import java.awt.Container; 031import java.awt.Frame; 032import java.util.ArrayList; 033import java.util.Enumeration; 034import java.util.Vector; 035 036import javax.swing.JPanel; 037 038import ptolemy.gui.ComponentDialog; 039import ptolemy.gui.Query; 040import ptolemy.gui.QueryListener; 041 042/////////////////////////////////////////////////////////////////// 043//// PlotFormatter 044 045/** 046 047 PlotFormatter is a panel that controls the format of a plotter object 048 passed to the constructor. 049 050 @see Plot 051 @see PlotBox 052 @author Edward A. Lee 053 @version $Id$ 054 @since Ptolemy II 1.0 055 @Pt.ProposedRating Yellow (eal) 056 @Pt.AcceptedRating Red (cxh) 057 */ 058@SuppressWarnings("serial") 059public class PlotFormatter extends JPanel { 060 /** Construct a plot formatter for the specified plot object. 061 * @param plot The specified plot object. 062 */ 063 public PlotFormatter(PlotBox plot) { 064 super(); 065 _plot = plot; 066 067 setLayout(new BorderLayout()); 068 _wideQuery = new Query(); 069 add(_wideQuery, BorderLayout.WEST); 070 _narrowQuery = new Query(); 071 add(_narrowQuery, BorderLayout.EAST); 072 073 // Populate the wide query. 074 _wideQuery.setTextWidth(20); 075 _originalTitle = plot.getTitle(); 076 _wideQuery.addLine("title", "Title", _originalTitle); 077 078 _originalCaptions = plot.getCaptions(); 079 StringBuffer captionsString = new StringBuffer(); 080 for (Enumeration captions = _originalCaptions.elements(); captions 081 .hasMoreElements();) { 082 if (captionsString.length() > 0) { 083 captionsString.append('\n'); 084 } 085 captionsString.append((String) captions.nextElement()); 086 } 087 _wideQuery.addTextArea("caption", "Caption", captionsString.toString()); 088 089 _originalXLabel = plot.getXLabel(); 090 _wideQuery.addLine("xlabel", "X Label", _originalXLabel); 091 _originalYLabel = plot.getYLabel(); 092 _wideQuery.addLine("ylabel", "Y Label", _originalYLabel); 093 _originalXRange = plot.getXRange(); 094 _wideQuery.addLine("xrange", "X Range", 095 "" + _originalXRange[0] + ", " + _originalXRange[1]); 096 _originalYRange = plot.getYRange(); 097 _wideQuery.addLine("yrange", "Y Range", 098 "" + _originalYRange[0] + ", " + _originalYRange[1]); 099 100 String[] marks = { "none", "points", "dots", "various", "bigdots", 101 "pixels" }; 102 _originalMarks = "none"; 103 104 if (plot instanceof Plot) { 105 _originalMarks = ((Plot) plot).getMarksStyle(); 106 _wideQuery.addRadioButtons("marks", "Marks", marks, _originalMarks); 107 } 108 109 _originalXTicks = plot.getXTicks(); 110 _originalXTicksSpec = ""; 111 112 if (_originalXTicks != null) { 113 StringBuffer buffer = new StringBuffer(); 114 Vector positions = _originalXTicks[0]; 115 Vector labels = _originalXTicks[1]; 116 117 for (int i = 0; i < labels.size(); i++) { 118 if (buffer.length() > 0) { 119 buffer.append(", "); 120 } 121 122 buffer.append(labels.elementAt(i).toString()); 123 buffer.append(" "); 124 buffer.append(positions.elementAt(i).toString()); 125 } 126 127 _originalXTicksSpec = buffer.toString(); 128 } 129 130 _wideQuery.addLine("xticks", "X Ticks", _originalXTicksSpec); 131 132 _originalYTicks = plot.getYTicks(); 133 _originalYTicksSpec = ""; 134 135 if (_originalYTicks != null) { 136 StringBuffer buffer = new StringBuffer(); 137 Vector positions = _originalYTicks[0]; 138 Vector labels = _originalYTicks[1]; 139 140 for (int i = 0; i < labels.size(); i++) { 141 if (buffer.length() > 0) { 142 buffer.append(", "); 143 } 144 145 buffer.append(labels.elementAt(i).toString()); 146 buffer.append(" "); 147 buffer.append(positions.elementAt(i).toString()); 148 } 149 150 _originalYTicksSpec = buffer.toString(); 151 } 152 153 _wideQuery.addLine("yticks", "Y Ticks", _originalYTicksSpec); 154 155 _originalGrid = plot.getGrid(); 156 _narrowQuery.addCheckBox("grid", "Grid", _originalGrid); 157 _originalStems = false; 158 _originalConnected = null; 159 160 if (plot instanceof Plot) { 161 _originalStems = ((Plot) plot).getImpulses(); 162 _narrowQuery.addCheckBox("stems", "Stems", _originalStems); 163 _saveConnected(); 164 _narrowQuery.addCheckBox("connected", "Connect", 165 ((Plot) plot).getConnected()); 166 } 167 168 _originalColor = plot.getColor(); 169 _narrowQuery.addCheckBox("color", "Use Color", _originalColor); 170 171 if (plot instanceof Plot) { 172 // This method is also called by Histogram, 173 // and Histogram does not have getLineStyles() 174 _originalLineStyles = ((Plot) plot).getLineStyles(); 175 _narrowQuery.addCheckBox("lineStyles", "Use Line Styles", 176 _originalLineStyles); 177 } 178 179 // FIXME: setXLog() and setYLog() cause problems with 180 // dropped data if they are toggled after data is read in. 181 // This is because the log axis facility modifies the datasets 182 // in addPlotPoint() in Plot.java. When this is fixed 183 // we can add the XLog and YLog facility to the Format menu 184 // 185 // _originalXLog = plot.getXLog(); 186 //_narrowQuery.addCheckBox("xlog", "X Log", _originalXLog); 187 //if (_originalXTicks != null) { 188 // _narrowQuery.setBoolean("xlog", false); 189 // _narrowQuery.setEnabled("xlog", false); 190 //} 191 // _originalYLog = plot.getYLog(); 192 //_narrowQuery.addCheckBox("ylog", "Y Log", _originalYLog); 193 //if (_originalYTicks != null) { 194 // _narrowQuery.setBoolean("ylog", false); 195 // _narrowQuery.setEnabled("ylog", false); 196 //} 197 // Attach listeners. 198 _wideQuery.addQueryListener(new QueryListener() { 199 @Override 200 public void changed(String name) { 201 if (name.equals("title")) { 202 _plot.setTitle(_wideQuery.getStringValue("title")); 203 } else if (name.equals("caption")) { 204 _plot.clearCaptions(); 205 String newCaption = _wideQuery.getStringValue("caption"); 206 String[] captionsArray = newCaption.split("\\n"); 207 for (String element : captionsArray) { 208 _plot.read("captions: " + element); 209 } 210 } else if (name.equals("xlabel")) { 211 _plot.setXLabel(_wideQuery.getStringValue("xlabel")); 212 } else if (name.equals("ylabel")) { 213 _plot.setYLabel(_wideQuery.getStringValue("ylabel")); 214 } else if (name.equals("xrange")) { 215 _plot.read( 216 "XRange: " + _wideQuery.getStringValue("xrange")); 217 } else if (name.equals("xticks")) { 218 String spec = _wideQuery.getStringValue("xticks").trim(); 219 _plot.read("XTicks: " + spec); 220 221 // FIXME: log axis format temporarily 222 // disabled, see above. 223 // if (spec.equals("")) { 224 // _narrowQuery.setEnabled("xlog", true); 225 // } else { 226 // _narrowQuery.setBoolean("xlog", false); 227 // _narrowQuery.setEnabled("xlog", false); 228 // } 229 } else if (name.equals("yticks")) { 230 String spec = _wideQuery.getStringValue("yticks").trim(); 231 _plot.read("YTicks: " + spec); 232 233 // FIXME: log axis format temporarily 234 // disabled, see above. 235 // if (spec.equals("")) { 236 // _narrowQuery.setEnabled("ylog", true); 237 // } else { 238 // _narrowQuery.setBoolean("ylog", false); 239 // _narrowQuery.setEnabled("ylog", false); 240 // } 241 } else if (name.equals("yrange")) { 242 _plot.read( 243 "YRange: " + _wideQuery.getStringValue("yrange")); 244 } else if (name.equals("marks")) { 245 ((Plot) _plot) 246 .setMarksStyle(_wideQuery.getStringValue("marks")); 247 } 248 249 _plot.repaint(); 250 } 251 }); 252 253 _narrowQuery.addQueryListener(new QueryListener() { 254 @Override 255 public void changed(String name) { 256 if (name.equals("grid")) { 257 _plot.setGrid(_narrowQuery.getBooleanValue("grid")); 258 } else if (name.equals("stems")) { 259 ((Plot) _plot) 260 .setImpulses(_narrowQuery.getBooleanValue("stems")); 261 _plot.repaint(); 262 } else if (name.equals("color")) { 263 _plot.setColor(_narrowQuery.getBooleanValue("color")); 264 265 // FIXME: log axis format temporarily 266 // disabled, see above. 267 // } else if (name.equals("xlog")) { 268 // _plot.setXLog(_narrowQuery.getBooleanValue("xlog")); 269 // } else if (name.equals("ylog")) { 270 // _plot.setYLog(_narrowQuery.getBooleanValue("ylog")); 271 } else if (name.equals("connected")) { 272 _setConnected(_narrowQuery.getBooleanValue("connected")); 273 } else if (name.equals("lineStyles")) { 274 ((Plot) _plot).setLineStyles( 275 _narrowQuery.getBooleanValue("lineStyles")); 276 } 277 278 _plot.repaint(); 279 } 280 }); 281 } 282 283 /////////////////////////////////////////////////////////////////// 284 //// public methods //// 285 286 /** Apply currently specified values to the associated plot. 287 * This requests a repaint of the plot. 288 */ 289 public void apply() { 290 // Apply current values. 291 _plot.setTitle(_wideQuery.getStringValue("title")); 292 _plot.setXLabel(_wideQuery.getStringValue("xlabel")); 293 _plot.setYLabel(_wideQuery.getStringValue("ylabel")); 294 _plot.read("XRange: " + _wideQuery.getStringValue("xrange")); 295 _plot.read("YRange: " + _wideQuery.getStringValue("yrange")); 296 _plot.setGrid(_narrowQuery.getBooleanValue("grid")); 297 _plot.setColor(_narrowQuery.getBooleanValue("color")); 298 // FIXME: log axis format temporarily disable, see above. 299 // _plot.setXLog(_narrowQuery.getBooleanValue("xlog")); 300 // _plot.setYLog(_narrowQuery.getBooleanValue("ylog")); 301 if (_plot instanceof Plot) { 302 // This method is also called by Histogram, 303 // and Histogram does not have lineStyles 304 Plot cplot = (Plot) _plot; 305 cplot.setLineStyles(_narrowQuery.getBooleanValue("lineStyles")); 306 cplot.setMarksStyle(_wideQuery.getStringValue("marks")); 307 cplot.setImpulses(_narrowQuery.getBooleanValue("stems")); 308 _setConnected(_narrowQuery.getBooleanValue("connected")); 309 } 310 311 // FIXME: log axis format temporarily disable, see above. 312 // String spec = _wideQuery.getStringValue("xticks").trim(); 313 // _plot.read("XTicks: " + spec); 314 // if (spec.equals("")) { 315 // _narrowQuery.setEnabled("xlog", true); 316 // } else { 317 // _narrowQuery.setBoolean("xlog", false); 318 // _narrowQuery.setEnabled("xlog", false); 319 // } 320 // spec = _wideQuery.getStringValue("yticks").trim(); 321 // _plot.read("YTicks: " + spec); 322 // if (spec.equals("")) { 323 // _narrowQuery.setEnabled("ylog", true); 324 // } else { 325 // _narrowQuery.setBoolean("ylog", false); 326 // _narrowQuery.setEnabled("ylog", false); 327 // } 328 _plot.repaint(); 329 } 330 331 /** Open a format control window as a top-level, modal dialog. 332 */ 333 public void openModal() { 334 String[] buttons = { "Apply", "Cancel" }; 335 336 // NOTE: If the plot is in a top-level container that is a Frame 337 // (as opposed to an applet), then tell the dialog that the Frame 338 // owns the dialog. 339 Container toplevel = _plot.getTopLevelAncestor(); 340 Frame frame = null; 341 342 if (toplevel instanceof Frame) { 343 frame = (Frame) toplevel; 344 } 345 346 ComponentDialog dialog = new ComponentDialog(frame, "Set plot format", 347 this, buttons); 348 349 if (dialog.buttonPressed().equals("Apply")) { 350 apply(); 351 } else { 352 restore(); 353 } 354 } 355 356 /** Restore the original configuration of the plot, and request a 357 * a redraw. 358 */ 359 public void restore() { 360 // Restore _original values. 361 _plot.setTitle(_originalTitle); 362 _plot.setCaptions(_originalCaptions); 363 _plot.setXLabel(_originalXLabel); 364 _plot.setYLabel(_originalYLabel); 365 _plot.setXRange(_originalXRange[0], _originalXRange[1]); 366 _plot.setYRange(_originalYRange[0], _originalYRange[1]); 367 _plot.setGrid(_originalGrid); 368 _plot.setColor(_originalColor); 369 // FIXME: log axis format temporarily disable, see above. 370 // _plot.setXLog(_originalXLog); 371 // _plot.setYLog(_originalYLog); 372 if (_plot instanceof Plot) { 373 // This method is also called by Histogram, 374 // and Histogram does not have lineStyles 375 Plot cplot = (Plot) _plot; 376 cplot.setLineStyles(_originalLineStyles); 377 cplot.setMarksStyle(_originalMarks); 378 cplot.setImpulses(_originalStems); 379 _restoreConnected(); 380 } 381 382 // FIXME: log axis format temporarily disabled, see above. 383 // _plot.read("XTicks: " + _originalXTicksSpec); 384 // if (_originalXTicksSpec.equals("")) { 385 // _narrowQuery.setEnabled("xlog", true); 386 // } else { 387 // _narrowQuery.setBoolean("xlog", false); 388 // _narrowQuery.setEnabled("xlog", false); 389 // } 390 // _plot.read("YTicks: " + _originalYTicksSpec); 391 // if (_originalYTicksSpec.equals("")) { 392 // _narrowQuery.setEnabled("ylog", true); 393 // } else { 394 // _narrowQuery.setBoolean("ylog", false); 395 // _narrowQuery.setEnabled("ylog", false); 396 // } 397 _plot.repaint(); 398 } 399 400 /////////////////////////////////////////////////////////////////// 401 //// protected variables //// 402 403 /** The plot object controlled by this formatter. */ 404 protected final PlotBox _plot; 405 406 /////////////////////////////////////////////////////////////////// 407 //// private methods //// 408 // Save the current connected state of all the point currently in the 409 // plot. NOTE: This method reaches into the protected members of 410 // the Plot class, taking advantage of the fact that this class is 411 // in the same package. 412 private void _saveConnected() { 413 ArrayList<ArrayList<PlotPoint>> points = ((Plot) _plot)._points; 414 _originalConnected = new boolean[points.size()][]; 415 _originalPoints = new PlotPoint[points.size()][]; 416 417 for (int dataset = 0; dataset < points.size(); dataset++) { 418 ArrayList<PlotPoint> pts = points.get(dataset); 419 _originalConnected[dataset] = new boolean[pts.size()]; 420 _originalPoints[dataset] = new PlotPoint[pts.size()]; 421 422 for (int i = 0; i < pts.size(); i++) { 423 PlotPoint pt = pts.get(i); 424 _originalConnected[dataset][i] = pt.connected; 425 _originalPoints[dataset][i] = pt; 426 } 427 } 428 } 429 430 // Set the current connected state of all the point in the 431 // plot. NOTE: This method reaches into the protected members of 432 // the Plot class, taking advantage of the fact that this class is 433 // in the same package. 434 private void _setConnected(boolean value) { 435 //ArrayList<ArrayList<PlotPoint>> points = ((Plot) _plot)._points; 436 437 // Make sure the default matches. 438 ((Plot) _plot).setConnected(value); 439 440 // We don't change the individual points anymore, but when the 441 // we plot points we'll both look at the global connected state and 442 // the one of the individual points (both will be and'ed). 443 /* 444 boolean[][] result = new boolean[points.size()][]; 445 446 for (int dataset = 0; dataset < points.size(); dataset++) { 447 ArrayList<PlotPoint> pts = points.get(dataset); 448 result[dataset] = new boolean[pts.size()]; 449 450 boolean first = true; 451 452 for (int i = 0; i < pts.size(); i++) { 453 PlotPoint pt = pts.get(i); 454 pt.connected = value && !first; 455 first = false; 456 } 457 } 458 */ 459 } 460 461 // Restore the connected state of all the point that were in the 462 // plot when their connected state was saved. 463 // NOTE: This method reaches into the protected members of 464 // the plot class, taking advantage of the fact that this class is 465 // in the same package. 466 private void _restoreConnected() { 467 for (int dataset = 0; dataset < _originalPoints.length; dataset++) { 468 for (int i = 0; i < _originalPoints[dataset].length; i++) { 469 PlotPoint pt = _originalPoints[dataset][i]; 470 pt.connected = _originalConnected[dataset][i]; 471 } 472 } 473 } 474 475 /////////////////////////////////////////////////////////////////// 476 //// private variables //// 477 // Query widgets. 478 private Query _wideQuery; 479 480 /////////////////////////////////////////////////////////////////// 481 //// private variables //// 482 // Query widgets. 483 private Query _narrowQuery; 484 485 // Original configuration of the plot. 486 private String _originalTitle; 487 488 // Original configuration of the plot. 489 private Vector _originalCaptions; 490 491 // Original configuration of the plot. 492 private String _originalXLabel; 493 494 // Original configuration of the plot. 495 private String _originalYLabel; 496 497 // Original configuration of the plot. 498 private String _originalMarks; 499 500 // Original configuration of the plot. 501 private String _originalXTicksSpec; 502 503 // Original configuration of the plot. 504 private String _originalYTicksSpec; 505 506 private double[] _originalXRange; 507 508 private double[] _originalYRange; 509 510 private Vector[] _originalXTicks; 511 512 private Vector[] _originalYTicks; 513 514 private boolean _originalGrid; 515 516 private boolean _originalLineStyles; 517 518 private boolean _originalStems; 519 520 private boolean _originalColor; 521 522 private boolean[][] _originalConnected; 523 524 private PlotPoint[][] _originalPoints; 525}