1 /*
   2  *
   3  * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  *
   9  *   - Redistributions of source code must retain the above copyright
  10  *     notice, this list of conditions and the following disclaimer.
  11  *
  12  *   - Redistributions in binary form must reproduce the above copyright
  13  *     notice, this list of conditions and the following disclaimer in the
  14  *     documentation and/or other materials provided with the distribution.
  15  *
  16  *   - Neither the name of Oracle nor the names of its
  17  *     contributors may be used to endorse or promote products derived
  18  *     from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 package java2d;
  33 
  34 
  35 import static java.awt.Color.BLACK;
  36 import static java.awt.Color.GREEN;
  37 import static java.awt.Color.LIGHT_GRAY;
  38 import static java.awt.Color.WHITE;
  39 import java.awt.BorderLayout;
  40 import java.awt.Color;
  41 import java.awt.Component;
  42 import java.awt.Dimension;
  43 import java.awt.FlowLayout;
  44 import java.awt.Font;
  45 import java.awt.Graphics;
  46 import java.awt.Image;
  47 import java.awt.Insets;
  48 import java.awt.RenderingHints;
  49 import java.awt.event.ActionEvent;
  50 import java.awt.event.ActionListener;
  51 import java.awt.event.MouseAdapter;
  52 import java.awt.event.MouseEvent;
  53 import java.awt.print.PrinterJob;
  54 import java.text.DecimalFormat;
  55 import java.util.logging.Level;
  56 import java.util.logging.Logger;
  57 import javax.print.attribute.HashPrintRequestAttributeSet;
  58 import javax.print.attribute.PrintRequestAttributeSet;
  59 import javax.swing.Icon;
  60 import javax.swing.ImageIcon;
  61 import javax.swing.JButton;
  62 import javax.swing.JComboBox;
  63 import javax.swing.JLabel;
  64 import javax.swing.JOptionPane;
  65 import javax.swing.JPanel;
  66 import javax.swing.JSlider;
  67 import javax.swing.JToggleButton;
  68 import javax.swing.JToolBar;
  69 import javax.swing.SwingConstants;
  70 import javax.swing.border.EtchedBorder;
  71 import javax.swing.event.ChangeEvent;
  72 import javax.swing.event.ChangeListener;
  73 
  74 
  75 /**
  76  * Tools to control individual demo graphic attributes.  Also, control for
  77  * start & stop on animated demos; control for cloning the demo; control for
  78  * printing the demo.  Expand and collapse the Tools panel with ToggleIcon.
  79  */
  80 @SuppressWarnings("serial")
  81 public final class Tools extends JPanel implements ActionListener,
  82         ChangeListener, Runnable {
  83     private final DemoInstVarsAccessor demoInstVars;
  84     private ImageIcon stopIcon, startIcon;
  85     private Font font = new Font(Font.SERIF, Font.PLAIN, 10);
  86     private Color roColor = new Color(187, 213, 238);
  87     private Surface surface;
  88     private Thread thread;
  89     private JPanel toolbarPanel;
  90     private JPanel sliderPanel;
  91     private JLabel label;
  92     private ToggleIcon bumpyIcon, rolloverIcon;
  93     private DecimalFormat decimalFormat = new DecimalFormat("000");
  94     protected boolean focus;
  95     public JToggleButton toggleB;
  96     public JButton printB;
  97     public JComboBox<String> screenCombo;
  98     public JToggleButton renderB, aliasB;
  99     public JToggleButton textureB, compositeB;
 100     public JButton startStopB;
 101     public JButton cloneB;
 102     public boolean issueRepaint = true;
 103     public JToolBar toolbar;
 104     public JSlider slider;
 105     public boolean doSlider;
 106     public boolean isExpanded;
 107 
 108     @SuppressWarnings("LeakingThisInConstructor")
 109     public Tools(Surface surface, DemoInstVarsAccessor demoInstVars) {
 110         this.surface = surface;
 111         this.demoInstVars = demoInstVars;
 112 
 113         setLayout(new BorderLayout());
 114 
 115         stopIcon = new ImageIcon(DemoImages.getImage("stop.gif", this));
 116         startIcon = new ImageIcon(DemoImages.getImage("start.gif", this));
 117         bumpyIcon = new ToggleIcon(this, LIGHT_GRAY);
 118         rolloverIcon = new ToggleIcon(this, roColor);
 119         toggleB = new JToggleButton(bumpyIcon);
 120         toggleB.addMouseListener(new MouseAdapter() {
 121 
 122             @Override
 123             public void mouseEntered(MouseEvent e) {
 124                 focus = true;
 125                 bumpyIcon.start();
 126             }
 127 
 128             @Override
 129             public void mouseExited(MouseEvent e) {
 130                 focus = false;
 131                 bumpyIcon.stop();
 132             }
 133         });
 134         isExpanded = false;
 135         toggleB.addActionListener(this);
 136         toggleB.setMargin(new Insets(0, 0, -4, 0));
 137         toggleB.setBorderPainted(false);
 138         toggleB.setFocusPainted(false);
 139         toggleB.setContentAreaFilled(false);
 140         toggleB.setRolloverIcon(rolloverIcon);
 141         add("North", toggleB);
 142 
 143         toolbar = new JToolBar();
 144         toolbar.setPreferredSize(new Dimension(5*25, 26));
 145         toolbar.setFloatable(false);
 146 
 147         String s = surface.AntiAlias == RenderingHints.VALUE_ANTIALIAS_ON
 148                 ? "On" : "Off";
 149         aliasB = addTool("A", "Antialiasing " + s, this);
 150 
 151         s = surface.Rendering == RenderingHints.VALUE_RENDER_SPEED
 152                 ? "Speed" : "Quality";
 153         renderB = addTool("R", "Rendering " + s, this);
 154 
 155         s = surface.texture != null ? "On" : "Off";
 156         textureB = addTool("T", "Texture " + s, this);
 157 
 158         s = surface.composite != null ? "On" : "Off";
 159         compositeB = addTool("C", "Composite " + s, this);
 160 
 161         Image printBImg = DemoImages.getImage("print.gif", this);
 162         printB = addTool(printBImg, "Print the Surface", this);
 163 
 164         if (surface instanceof AnimatingSurface) {
 165             Image stopImg = DemoImages.getImage("stop.gif", this);
 166             startStopB = addTool(stopImg, "Stop Animation", this);
 167             toolbar.setPreferredSize(new Dimension(6*25, 26));
 168         }
 169 
 170         screenCombo = new JComboBox<>();
 171         screenCombo.setPreferredSize(new Dimension(100, 18));
 172         screenCombo.setFont(font);
 173         for (String name : GlobalControls.screenNames) {
 174             screenCombo.addItem(name);
 175         }
 176         screenCombo.addActionListener(this);
 177         toolbarPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
 178         toolbarPanel.setLocation(0, 6);
 179         toolbarPanel.setVisible(false);
 180         toolbarPanel.add(toolbar);
 181         toolbarPanel.add(screenCombo);
 182         toolbarPanel.setBorder(new EtchedBorder());
 183         add(toolbarPanel);
 184 
 185         setPreferredSize(new Dimension(200, 8));
 186 
 187         if (surface instanceof AnimatingSurface) {
 188             sliderPanel = new JPanel(new BorderLayout());
 189             label = new JLabel(" Sleep = 030 ms");
 190             label.setForeground(BLACK);
 191             sliderPanel.add(label, BorderLayout.WEST);
 192             slider = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 30);
 193             slider.addChangeListener(this);
 194             sliderPanel.setBorder(new EtchedBorder());
 195             sliderPanel.add(slider);
 196 
 197             addMouseListener(new MouseAdapter() {
 198 
 199                 @Override
 200                 public void mouseClicked(MouseEvent e) {
 201                     if (toolbarPanel.isVisible()) {
 202                         invalidate();
 203                         if ((doSlider = !doSlider)) {
 204                             remove(toolbarPanel);
 205                             add(sliderPanel);
 206                         } else {
 207                             remove(sliderPanel);
 208                             add(toolbarPanel);
 209                         }
 210                         validate();
 211                         repaint();
 212                     }
 213                 }
 214             });
 215         }
 216     }
 217 
 218     public JButton addTool(Image img,
 219             String toolTip,
 220             ActionListener al) {
 221         JButton b = new JButton(new ImageIcon(img)) {
 222 
 223             Dimension prefSize = new Dimension(25, 22);
 224 
 225             @Override
 226             public Dimension getPreferredSize() {
 227                 return prefSize;
 228             }
 229 
 230             @Override
 231             public Dimension getMaximumSize() {
 232                 return prefSize;
 233             }
 234 
 235             @Override
 236             public Dimension getMinimumSize() {
 237                 return prefSize;
 238             }
 239         };
 240         toolbar.add(b);
 241         b.setFocusPainted(false);
 242         b.setSelected(true);
 243         b.setToolTipText(toolTip);
 244         b.addActionListener(al);
 245         return b;
 246     }
 247 
 248     public JToggleButton addTool(String name,
 249             String toolTip,
 250             ActionListener al) {
 251         JToggleButton b = new JToggleButton(name) {
 252 
 253             Dimension prefSize = new Dimension(25, 22);
 254 
 255             @Override
 256             public Dimension getPreferredSize() {
 257                 return prefSize;
 258             }
 259 
 260             @Override
 261             public Dimension getMaximumSize() {
 262                 return prefSize;
 263             }
 264 
 265             @Override
 266             public Dimension getMinimumSize() {
 267                 return prefSize;
 268             }
 269         };
 270         toolbar.add(b);
 271         b.setFocusPainted(false);
 272         if (toolTip.equals("Rendering Quality") || toolTip.equals(
 273                 "Antialiasing On") || toolTip.equals("Texture On") || toolTip.
 274                 equals("Composite On")) {
 275             b.setSelected(true);
 276         } else {
 277             b.setSelected(false);
 278         }
 279         b.setToolTipText(toolTip);
 280         b.addActionListener(al);
 281         return b;
 282     }
 283 
 284     @Override
 285     public void actionPerformed(ActionEvent e) {
 286         Object obj = e.getSource();
 287         if (obj instanceof JButton) {
 288             JButton b = (JButton) obj;
 289             b.setSelected(!b.isSelected());
 290             if (b.getIcon() == null) {
 291                 b.setBackground(b.isSelected() ? GREEN : LIGHT_GRAY);
 292             }
 293         }
 294         if (obj.equals(toggleB)) {
 295             isExpanded = !isExpanded;
 296             if (isExpanded) {
 297                 setPreferredSize(new Dimension(200, 38));
 298             } else {
 299                 setPreferredSize(new Dimension(200, 6));
 300             }
 301             toolbarPanel.setVisible(isExpanded);
 302             if (sliderPanel != null) {
 303                 sliderPanel.setVisible(isExpanded);
 304             }
 305             getParent().validate();
 306             toggleB.getModel().setRollover(false);
 307             return;
 308         }
 309         if (obj.equals(printB)) {
 310             start();
 311             return;
 312         }
 313 
 314         if (obj.equals(startStopB)) {
 315             if (startStopB.getToolTipText().equals("Stop Animation")) {
 316                 startStopB.setIcon(startIcon);
 317                 startStopB.setToolTipText("Start Animation");
 318                 surface.animating.stop();
 319             } else {
 320                 startStopB.setIcon(stopIcon);
 321                 startStopB.setToolTipText("Stop Animation");
 322                 surface.animating.start();
 323             }
 324         } else if (obj.equals(aliasB)) {
 325             if (aliasB.getToolTipText().equals("Antialiasing On")) {
 326                 aliasB.setToolTipText("Antialiasing Off");
 327             } else {
 328                 aliasB.setToolTipText("Antialiasing On");
 329             }
 330             surface.setAntiAlias(aliasB.isSelected());
 331         } else if (obj.equals(renderB)) {
 332             if (renderB.getToolTipText().equals("Rendering Quality")) {
 333                 renderB.setToolTipText("Rendering Speed");
 334             } else {
 335                 renderB.setToolTipText("Rendering Quality");
 336             }
 337             surface.setRendering(renderB.isSelected());
 338         } else if (obj.equals(textureB)) {
 339             if (textureB.getToolTipText().equals("Texture On")) {
 340                 textureB.setToolTipText("Texture Off");
 341                 surface.setTexture(null);
 342                 surface.clearSurface = true;
 343             } else {
 344                 textureB.setToolTipText("Texture On");
 345                 surface.setTexture(demoInstVars.getControls().texturechooser.texture);
 346             }
 347         } else if (obj.equals(compositeB)) {
 348             if (compositeB.getToolTipText().equals("Composite On")) {
 349                 compositeB.setToolTipText("Composite Off");
 350             } else {
 351                 compositeB.setToolTipText("Composite On");
 352             }
 353             surface.setComposite(compositeB.isSelected());
 354         } else if (obj.equals(screenCombo)) {
 355             surface.setImageType(screenCombo.getSelectedIndex());
 356         }
 357 
 358         if (issueRepaint && surface.animating != null) {
 359             if (surface.getSleepAmount() != 0) {
 360                 if (surface.animating.running()) {
 361                     surface.animating.doRepaint();
 362                 }
 363             }
 364         } else if (issueRepaint) {
 365             surface.repaint();
 366         }
 367     }
 368 
 369     @Override
 370     public void stateChanged(ChangeEvent e) {
 371         int value = slider.getValue();
 372         label.setText(" Sleep = " + decimalFormat.format(value) + " ms");
 373         label.repaint();
 374         surface.setSleepAmount(value);
 375     }
 376 
 377     public void start() {
 378         thread = new Thread(this);
 379         thread.setPriority(Thread.MAX_PRIORITY);
 380         thread.setName("Printing " + surface.name);
 381         thread.start();
 382     }
 383 
 384     public synchronized void stop() {
 385         thread = null;
 386         notifyAll();
 387     }
 388 
 389     @Override
 390     public void run() {
 391         boolean stopped = false;
 392         if (surface.animating != null && surface.animating.running()) {
 393             stopped = true;
 394             startStopB.doClick();
 395         }
 396 
 397         try {
 398             PrinterJob printJob = PrinterJob.getPrinterJob();
 399             printJob.setPrintable(surface);
 400             boolean pDialogState = true;
 401             PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
 402 
 403             if (!demoInstVars.getPrintCB().isSelected()) {
 404                 pDialogState = printJob.printDialog(aset);
 405             }
 406             if (pDialogState) {
 407                 printJob.print(aset);
 408             }
 409         } catch (java.security.AccessControlException ace) {
 410             String errmsg = "Applet access control exception; to allow "
 411                     + "access to printer, set\n"
 412                     + "permission for \"queuePrintJob\" in "
 413                     + "RuntimePermission.";
 414             JOptionPane.showMessageDialog(this, errmsg, "Printer Access Error",
 415                     JOptionPane.ERROR_MESSAGE);
 416         } catch (Exception ex) {
 417             Logger.getLogger(Tools.class.getName()).log(Level.SEVERE,
 418                     null, ex);
 419         }
 420 
 421         if (stopped) {
 422             startStopB.doClick();
 423         }
 424         thread = null;
 425     }
 426 
 427 
 428     /**
 429      * Expand and Collapse the Tools Panel with this bumpy button.
 430      */
 431     static class ToggleIcon implements Icon, Runnable {
 432 
 433         private Color shadowColor = new Color(102, 102, 153);
 434         private Color fillColor;
 435         private Tools tools;
 436         private Thread thread;
 437 
 438         public ToggleIcon(Tools tools, Color fillColor) {
 439             this.tools = tools;
 440             this.fillColor = fillColor;
 441         }
 442 
 443         @Override
 444         public void paintIcon(Component c, Graphics g, int x, int y) {
 445             int w = getIconWidth();
 446             int h = getIconHeight();
 447             g.setColor(fillColor);
 448             g.fillRect(0, 0, w, h);
 449             for (; x < w - 2; x += 4) {
 450                 g.setColor(WHITE);
 451                 g.fillRect(x, 1, 1, 1);
 452                 g.fillRect(x + 2, 3, 1, 1);
 453                 g.setColor(shadowColor);
 454                 g.fillRect(x + 1, 2, 1, 1);
 455                 g.fillRect(x + 3, 4, 1, 1);
 456             }
 457         }
 458 
 459         @Override
 460         public int getIconWidth() {
 461             return tools.getSize().width;
 462         }
 463 
 464         @Override
 465         public int getIconHeight() {
 466             return 6;
 467         }
 468 
 469         public void start() {
 470             thread = new Thread(this);
 471             thread.setPriority(Thread.MIN_PRIORITY);
 472             thread.setName("ToggleIcon");
 473             thread.start();
 474         }
 475 
 476         public synchronized void stop() {
 477             if (thread != null) {
 478                 thread.interrupt();
 479             }
 480             thread = null;
 481         }
 482 
 483         @Override
 484         public void run() {
 485             try {
 486                 Thread.sleep(400);
 487             } catch (InterruptedException e) {
 488             }
 489             if (tools.focus && thread != null) {
 490                 tools.toggleB.doClick();
 491             }
 492             thread = null;
 493         }
 494     }
 495 } // End Tools class
 496