Logo Search packages:      
Sourcecode: cacao-oj6 version File versions

Desktop.java

/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest.tool;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;

import com.sun.javatest.InterviewParameters;
import com.sun.javatest.JavaTestError;
import com.sun.javatest.TestSuite;
import com.sun.javatest.util.BackupPolicy;
import com.sun.javatest.util.HTMLWriter;
import com.sun.javatest.util.I18NResourceBundle;
import com.sun.javatest.util.LogFile;
import com.sun.javatest.util.SortedProperties;
import java.awt.print.Printable;
import java.awt.print.PrinterJob;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.ServiceUI;
import javax.print.SimpleDoc;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;

/**
 * Desktop is the host for a series of Tools,
 * which may be displayed as in a number of styles,
 * provided by a DeskView.
 * <p>Much of the functionality of a desktop is provided by the current view,
 * and because of that, many of the methods here simply call through to the
 * underlying current view object.
 * @see DeskView
 */
00104 public class Desktop
{
    /**
     * Create a desktop using a style determined according to the
     * user's preferences.
     */
00110     public Desktop() {
      this(getPreferredStyle());
    }

    /**
     * New desktop, using preferrred style and given context.
     */
00117     public Desktop(CommandContext ctx) {
      this(getPreferredStyle(), ctx);
    }


    public Desktop(int style, CommandContext ctx) {
        commandContext = ctx;

      String val = preferences.getPreference(TTIP_PREF); 
      boolean t = (val == null || val.equalsIgnoreCase("true"));
      setTooltipsEnabled(t);
      
      int delay = getTooltipDelay(preferences);
      setTooltipDelay(delay);
      
      int duration = getTooltipDuration(preferences);
      setTooltipDuration(duration);
      
      String soe = preferences.getPreference(SAVE_ON_EXIT_PREF);
      setSaveOnExit(soe == null || soe.equalsIgnoreCase("true"));

      File f = getDesktopFile();
      firstTime = !(f != null && f.exists());

        if (System.getProperty("systemLAF") != null) {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch(Exception e) {
                System.out.println("Error setting native LAF: " + e);
            }
        }

        uif = new UIFactory(getClass());

      initToolManagers();

      /* defer view initialization in case we do a restore
      initView(style);
      */
      this.style = style;
    }

    /** 
     * Create a desktop using a specified style.
     * @param style a value indicating the desired desktop style.
     * @see #MDI_STYLE
     * @see #SDI_STYLE
     * @see #TAB_STYLE
     */
00166     public Desktop(int style) {
        this(style, null);
    }

    /**
     * Get a value indicating the current style of the desktop.
     * @return a value indicating the current style of the desktop
     * @see #setStyle
     * @see #MDI_STYLE
     * @see #SDI_STYLE
     * @see #TAB_STYLE
     */
00178     public int getStyle() {
      return (currView == null ? style : currView.getStyle());
    }

    /**
     * Get a value indicating the user's preferred desktop style,
     * as recorded in the user's preferences.
     * @return a value indicating the user's preferred desktop style
     * @see #MDI_STYLE
     * @see #SDI_STYLE
     * @see #TAB_STYLE
     */
00190     public static int getPreferredStyle() {
      // would be better(?) to use classname, perhaps
      String prefStyleName = preferences.getPreference(STYLE_PREF);
      int i = indexOf(prefStyleName, styleNames);
      return (i != -1 ? i : TAB_STYLE);
    }

    /**
     * Set the current style of the desktop.
     * @param style a value indicating the current style of the desktop
     * @see #getStyle
     * @see #MDI_STYLE
     * @see #SDI_STYLE
     * @see #TAB_STYLE
     */
00205     public void setStyle(int style) {
      //System.err.println("Desktop.setStyle: " + style);
      if (style == getStyle())
          return;

      if (currView == null) {
          this.style = style;
          return;
      }

      DeskView oldView = currView;
      //System.err.println("DT: creating new desktop (" + style + ")");
      switch (style) {
      case MDI_STYLE:
          currView = new MDIDeskView(oldView);
          break;

      case SDI_STYLE:
          currView = new SDIDeskView(oldView);
          break;

      case TAB_STYLE:
          currView = new TabDeskView(oldView);
          break;

      default:
          throw new IllegalArgumentException();
      }

      //System.err.println("DT: disposing old deskview");
      oldView.dispose();

      //System.err.println("DT: setStyle done ");
    }

    /**
     * Determine if this is the first time that JT Harness has been run.
     * This is determined by checking if a saved desktop exists from
     * a prior run of JT Harness.
     * @return true if this appears to be the first time the user has
     * run JT Harness, and false otherwise
     */
00247     public boolean isFirstTime() {
      return firstTime;
    }

    /**
     * Set the flag indicating whether or not this is the first time 
     * that JT Harness has been run.
     * @param b true if JT Harness should behave as though this is th
     * first time JT Harness has been run
     * @see #isFirstTime
     */
00258     public void setFirstTime(boolean b) {
      firstTime = b;
    }

    /** 
     * Check whether the desktop is empty of any tools.
     * @return true if there are no tools on the desktop, and false otherwise
     */
00266     public boolean isEmpty() {
      return (currView == null ? true : currView.isEmpty());
    }

    /** 
     * Get the set of tools currently on the desktop.
     * @return the set of tools currently on the desktop
     */
00274     public Tool[] getTools() {
      return (currView == null ? new Tool[0] : currView.getTools());
    }

    /**
     * Add a new tool to the desktop.
     * @param t the tool to be added
     * @see #removeTool
     */
00283     public void addTool(Tool t) {
      ensureViewInitialized();
      currView.addTool(t);
    }

    /**
     * Remove a tool from the desktop.
     * @param t the tool to be removed
     * @see #addTool
     */
00293     public void removeTool(Tool t) {
      if (currView != null)
          currView.removeTool(t);
    }

    /**
     * Get the currently selected tool on the desktop.
     * @return the currently selected tool on the desktop
     * @see #setSelectedTool
     */
00303     public Tool getSelectedTool() {
      return (currView == null ? null : currView.getSelectedTool());
    }

    /**
     * Set the currently selected tool on the desktop.
     * @param t the the tool to be selected on the desktop
     * @see #getSelectedTool
     */
00312     public void setSelectedTool(Tool t) {
      ensureViewInitialized();
      currView.setSelectedTool(t);
    }

    /**
     * Add a new default tool to the desktop. The default can be set via the
     * system property "javatest.desktop.defaultTool", which should identify
     * the class name of an appropriate tool manager; if not set, the default
     * is com.sun.javatest.exec.ExecManager.
     * @see #removeTool
     */
00324     public void addDefaultTool() {
      if (!EventQueue.isDispatchThread()) {
          invokeOnEventThread(new Runnable() {
                public void run() {
                  addDefaultTool();
                }
            });
          return;
      }

      for (int i = 0; i < toolManagers.length; i++) {
          ToolManager m = toolManagers[i];
          if (m.getClass().getName().equals(defaultToolManager)) {
            m.startTool();
            return;
          }
      }           
    }


    /**
     * Add a new default tool to the desktop. The default can be set via the
     * system property "javatest.desktop.defaultTool", which should identify
     * the class name of an appropriate tool manager; if not set, the default
     * is com.sun.javatest.exec.ExecManager.
     * @param ip a configuration to be passed to the default tool manager's startTool
     * method
     * @see #removeTool
     */
00353     public void addDefaultTool(InterviewParameters ip) {
      for (int i = 0; i < toolManagers.length; i++) {
          ToolManager mgr = toolManagers[i];
          if (mgr.getClass().getName().equals(defaultToolManager)) {
            try {
                    // this is to avoid a class dependency to exec package, which is
                    // normally not allowed in this package
                Method m = mgr.getClass().getMethod("startTool",
                                            new Class[] { InterviewParameters.class} );
                m.invoke(mgr, new Object[] { ip });
                return;
            }
            catch (NoSuchMethodException e) {
                // ignore??
            }
            catch (IllegalAccessException e) {
                // ignore??
            }
            catch (InvocationTargetException e) {
                // ignore??
            }
          }
      }           
    }

    /** 
     * Check if a tool is present on the desktop.
     * @param t the tool for which to check
     * @return true if the specified tool exists on the desktop, and false otherwise
     */
00383     public boolean containsTool(Tool t) {
      Tool[] tools = getTools();
      for (int i = 0; i < tools.length; i++) {
          if (t == tools[i])
            return true;
      }
      return false;
    }

    /**
     * Get the set of tool managers associated with this desktop.
     * The managers are determined from resource files named
     * "JavaTest.toolMgrs.lst" on the main JT Harness classpath.
     * @return the set of tool managers associated with this desktop
     */
00398     public ToolManager[] getToolManagers() {
      return toolManagers;
    }

    /**
     * Get the instance of a tool manager for this desktop of a specific class.
     * @param c the class of the desired tool manager.
     * @return a tool manager of the desired type, or null if none found
     */
00407     public ToolManager getToolManager(Class c) {
      for (int i = 0; i < toolManagers.length; i++) {
          ToolManager m = toolManagers[i];
          if (c.isInstance(m))
            return m;
      }
      return null;
    }

    /**
     * Get the instance of a tool manager for this desktop of a specific class.
     * @param className the name of the class of the desired tool manager.
     * @return a tool manager of the desired type, or null if none found
     */
00421     public ToolManager getToolManager(String className) {
      for (int i = 0; i < toolManagers.length; i++) {
          ToolManager m = toolManagers[i];
          if (m.getClass().getName().equals(className))
            return m;
      }
      return null;
    }

    /**
     * Get the top level frames that make up this desktop. TAB and MDI style
     * desktops just have a single frame; An SDI style desktop may have more
     * than one frame.
     * @return the top level frames of this desktop
     */
00436     public JFrame[] getFrames() {
      ensureViewInitialized();
      return currView.getFrames();
    }

    /**
     * Get a parent component for a dialog to use.
     * @return Component which can be used as a parent, or null if none
     *         is available.
     */
00446     public Component getDialogParent() {
      ensureViewInitialized();
      return currView.getDialogParent();
    }

    /**
     * Add a file and a corresponding file opener to the file history
     * that appears on the File menu.
     * @param f The file to be added
     * @param fo A FileOpener object to be used to open the file if necessary
     */
00457     public void addToFileHistory(File f, FileOpener fo) {
      // if it is already in the history, remove it
      for (Iterator i = fileHistory.iterator(); i.hasNext(); ) {
          FileHistoryEntry h = (FileHistoryEntry) (i.next());
          if (h.fileOpener == fo && h.file.equals(f)) {
            i.remove();
            break;
          }
      }

      // add it to the front of the list
      fileHistory.addFirst(new FileHistoryEntry(fo, f));

      // throw away old entries in the list
      while (fileHistory.size() > FILE_HISTORY_MAX_SIZE)
          fileHistory.removeLast();
    }

    /**
     * Get a list of the current entries on the file history associated with this desktop.
     * @return  a list of the current entries on the file history associated with this desktop
     * @see #addToFileHistory
     */
00480     List getFileHistory()
    {
      return fileHistory;
    }

    /**
     * Check if the top level windows of the desktop are visible or not.
     * @return true if the top level windows are visible; otherwise, return false
     * @see #setVisible
     */
00490     public boolean isVisible() {
      return (currView == null ? false : currView.isVisible());
    }

    /**
     * Set whether or not the top level windows of the desktop should be visible.
     * @param b If true, the top level windows will be made visible; if false, they
     * will be hidden.
     */
00499     public void setVisible(final boolean b) {
      if (!EventQueue.isDispatchThread()) {
          invokeOnEventThread(new Runnable() {
                public void run() {
                  setVisible(b);
                }
            });
          return;
      }

      ensureViewInitialized();
      currView.setVisible(b);
    }

    /**
     * Create a dialog.
     * @param tool the parent tool for the dialog
     * @param uiKey a string which is to be used as the base name for any
     * resources that may be required
     * @param title the title for the dialog
     * @param menuBar the menu bar for the dialog
     * @param body the body component for the dialog
     * @param bounds the size and position for the dialog
     * @return a JDialog or JInternalDialog built from the supplied values.
     */
00524     public Container createDialog(Tool tool, String uiKey, String title, 
                                 JMenuBar menuBar, Container body,
                                 Rectangle bounds)
    {
      ensureViewInitialized();
      return currView.createDialog(tool, uiKey, title, menuBar, body, bounds);
    }

    /**
     * Check if the tool's parent Window is the owner of a dialog.
     * This may become false if the desktop style is changed after the dialog
     * was created.
     * @param tool the tool from which to determine the parent Window
     * @param dialog the dialog to be checked
     * @return true if the tool's parent Window is the owner of the dialog, and
     * false otherwise.
     */
00541     public boolean isToolOwnerForDialog(Tool tool, Container dialog) {
      ensureViewInitialized();
      return currView.isToolOwnerForDialog(tool, dialog);
    }

    /**
     * Check all the tools on the desktop to see if they have open state
     * that should be saved or processes running. If there is open state
     * or active processes, a confirmation dialog will be displayed.
     * If the user confirms OK, or if there was no need to show the 
     * confirmation dialog, the desktop will be saved and disposed.
     * @param parent A parent frame to be used if a confirmation dialog
     * is necessary
     * @see #isOKToExit
     */
00556     public void checkToolsAndExitIfOK(JFrame parent) {
      if (isOKToExit(parent)) {
          boolean saveOnExit = getSaveOnExit();
          if (saveOnExit)
            save();
          else {
            File f = getDesktopFile();
            if (f != null && f.exists())
                f.delete();
          }

          dispose();
      }
    }

    /**
     * Check if it is OK to close a tool. If the tool has important
     * state that needs to be saved, or any processes running, a confirmation
     * dialog will be shown, to allow the user to cancel the operation if
     * necessary.
     * @param t The tool to be checked
     * @param parent A parent frame to be used if a confirmation dialog
     * is necessary
     * @return true if it is OK to close the tool
     */
00581     public boolean isOKToClose(Tool t, JFrame parent) {
      if (confirmDialog != null) {
          Toolkit.getDefaultToolkit().beep();
          confirmDialog.toFront();
          return false;
      }
      
      String[] alerts = t.getCloseAlerts();
      if (alerts == null || alerts.length == 0)
          return true;
      else
          return isOKToExitOrClose(parent, alerts, CLOSE);
    }

    /**
     * Check if it is OK to close all tools and exit the desktop.
     * If any tools have important state that needs to be saved, or active tasks
     * running, a confirmation dialog will be shown to allow the user to
     * cancel the operation in progress.
     * @param parent A parent frame to be used if a confirmation dialog
     * is necessary
     * @return true if it is OK to exit the desktop, and false otherwise.
     */
00604     public boolean isOKToExit(JFrame parent) {
      if (confirmDialog != null) {
          Toolkit.getDefaultToolkit().beep();
          confirmDialog.toFront();
          return false;
      }

      Vector v = new Vector();

      Tool[] tools = getTools();
      for (int ti = 0; ti < tools.length; ti++) {
          String[] alerts = tools[ti].getCloseAlerts();
          if (alerts != null)
            v.addAll(Arrays.asList(alerts));
      }

      if (v.size() == 0)
          return true;
      else {
          String[] allAlerts = new String[v.size()];
          v.copyInto(allAlerts);
          return isOKToExitOrClose(parent, allAlerts, EXIT);
      }
    }

    private static final int CLOSE = 0;
    private static final int EXIT = 1;
    private JDialog confirmDialog;

    private boolean isOKToExitOrClose(JFrame parent, String[] alerts, int mode) {
      if (confirmDialog != null) {
          Toolkit.getDefaultToolkit().beep();
          confirmDialog.toFront();
          return false;
      }

      Integer m = new Integer(mode);

      if (alerts.length > 0) {
          // protect against reentrant calls by setting confirmDialog 
          // while showing it

          StringWriter sw = new StringWriter();
          try {
            HTMLWriter out = new HTMLWriter(sw, uif.getI18NResourceBundle());
            out.startTag(HTMLWriter.HTML);
            out.startTag(HTMLWriter.BODY);
            out.writeStyleAttr("font-family: SansSerif");
            out.startTag(HTMLWriter.P);
            out.writeStyleAttr("margin-top:0");
            out.startTag(HTMLWriter.B);
            out.writeI18N("dt.confirm.head", m);
            out.endTag(HTMLWriter.B);
            out.endTag(HTMLWriter.P);
            out.startTag(HTMLWriter.P);
            out.startTag(HTMLWriter.I);
            out.writeI18N("dt.confirm.warn", m);
            out.endTag(HTMLWriter.I);
            out.endTag(HTMLWriter.P);
            out.startTag(HTMLWriter.UL);
            out.writeStyleAttr("margin-top:0; margin-bottom:0; margin-left:30");
            for (int i = 0; i < alerts.length; i++) {
                out.startTag(HTMLWriter.LI);
                out.write(alerts[i]);
            }
            out.endTag(HTMLWriter.UL);
            out.startTag(HTMLWriter.P);
            out.writeStyleAttr("margin-top:5");
            out.writeI18N("dt.confirm.warn2", m);
            out.endTag(HTMLWriter.P);
            out.startTag(HTMLWriter.P);
            out.writeStyleAttr("margin-bottom:0");
            out.writeI18N("dt.confirm.tail", m);
            out.endTag(HTMLWriter.P);
            out.endTag(HTMLWriter.BODY);
            out.endTag(HTMLWriter.HTML);
            out.close();
          }
          catch (IOException e) {
            JavaTestError.unexpectedException(e);
          }

          JEditorPane body = new JEditorPane();
          body.setOpaque(false);
          body.setContentType("text/html"); 
          body.setText(sw.toString());
          body.setEditable(false);
          body.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
          body.setSize(new Dimension(5 * uif.getDotsPerInch(), Integer.MAX_VALUE));
          //System.err.println("DT.isOK size=" + body.getSize());
          //System.err.println("DT.isOK psize=" + body.getPreferredSize());
          String title = uif.getI18NString("dt.confirm.title", m);
          // can't use JOptionPane convenience methods because we want to set
          // default option to "No"
          final JOptionPane pane = new JOptionPane(body, JOptionPane.WARNING_MESSAGE);
          ActionListener l = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                  pane.setValue(e.getSource());
                  pane.setVisible(false);
                }
            };
          JButton yesBtn = uif.createButton("dt.confirm.yes", l);
          JButton noBtn = uif.createButton("dt.confirm.no", l);
          pane.setOptions(new JComponent[] { yesBtn, noBtn });
          pane.setInitialValue(noBtn);

          confirmDialog = pane.createDialog(parent, title);
          confirmDialog.setVisible(true);
          confirmDialog.dispose();
          confirmDialog = null;

          if (pane.getValue() != yesBtn)
            return false;
      }

      return true;
    }

    /**
     * Check if it is OK to automatically exit JT Harness.
     * A warning dialog is posted to the user for a reasonable but short while
     * allowing the user to cancel the exit.
     * @return true if the user does not respond within the available time,
     * or if the user allows the request; and false otherwise
     */
00729     public boolean isOKToAutoExit() {
      final int delay = 30/*seconds*/;
      final JTextArea body = new JTextArea();
      body.setOpaque(false);
      body.setText(uif.getI18NString("dt.autoExit.txt", new Integer(delay)));
      body.setEditable(false);
      body.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
      body.setSize(new Dimension(4 * uif.getDotsPerInch(), Integer.MAX_VALUE));

      final JOptionPane pane = new JOptionPane(body, JOptionPane.WARNING_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
      String title = uif.getI18NString("dt.confirm.title", new Integer(EXIT));
      final JDialog dialog = pane.createDialog(null, title);
      
      final Timer timer = new Timer(1000, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (--timeRemaining == 0) {
                  pane.setValue(new Integer(JOptionPane.OK_OPTION));
                  dialog.setVisible(false);
                }
                else
                  body.setText(uif.getI18NString("dt.autoExit.txt", new Integer(timeRemaining)));
            }
            
            private int timeRemaining = delay;
          });

      timer.start();
      dialog.setVisible(true);
      timer.stop();

      Object value = pane.getValue();
      return (value != null && value.equals(new Integer(JOptionPane.OK_OPTION)));
    }


    /**
     * Save the current state of the desktop in the user's standard desktop file.
     */
00767     public void save() {
      save(getDesktopFile());
    }

    /**
     * Save the current state of the desktop in a specified desktop file.
     * @param f the file in which to save the desktop
     */
00775     public void save(File f) {
      //System.err.println("DT: save to " + f);
      if (f == null) 
          return;

      Properties p = new SortedProperties();

      int s = getStyle();
      if (s < NUM_STYLES) {
          p.put("dt.style", styleNames[s]);
          // backwards compatibility for JT3.1.x
          p.put("dt.class", jt31StyleClassNames[s]);
      }  
      
      ensureViewInitialized();
      currView.saveDesktop(p);

      p.put("file.count", String.valueOf(fileHistory.size()));
      int n = 0;
      for (Iterator i = fileHistory.iterator(); i.hasNext(); ) {
          FileHistoryEntry h = (FileHistoryEntry) (i.next());
          p.put("fileHistory." + n + ".type", h.fileOpener.getFileType());
          p.put("fileHistory." + n + ".path", h.file.getPath());
            n++;
        }

      try {
          File dir = f.getParentFile();
          if (dir != null && !dir.exists())
            dir.mkdirs();
          OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
          p.store(out, "JT Harness Desktop");
          out.close();
      }
      catch (IOException e) {
          System.err.println(uif.getI18NString("dt.cantWriteDt.txt", e.getMessage()));
          //System.err.println("Error writing desktop file: " + e);
      }
    }

    /**
     * Restore the desktop from information in a saved desktop file.
     * If no such file exists, or if no tools are successfully started
     * from the info in the file, add a default tool.
     * The work will automatically performed on the main AWT EventQueue
     * thread.
     */
00822     public void restore() {
      restore(getDesktopFile());
    }

    /**
     * Restore the desktop from information in a specified file.
     * If no such file exists, or if no tools are successfully started
     * from the info in the file, add a default tool.
     * The work will automatically performed on the main AWT EventQueue
     * thread.
     * @param file the file from which to load the data
     */
00834     public void restore(final File file) {
      Properties p = getPreviousDesktop(file);
        restore0(p);
    }

    public void restoreHistory() {
        restoreHistory(getPreviousDesktop(getDesktopFile()));
    }

    private void restore0(final Properties p) {
      //System.err.println("DT: restore " + file);
      if (!EventQueue.isDispatchThread()) {
          invokeOnEventThread(new Runnable() {
                public void run() {
                  restore0(p);
                }
            });
          return;
      }

        restoreHistory(p);

      // ALERT!! NEEDS FIXING!
      // should use saved view info
      /*
      String dtClassName = (String) p.getProperty("dt.class");
      if (dtClassName != null) {
          try {
            if (theOne != null)
                theOne.dispose();
            theOne = (Desktop) (Class.forName(dtClassName).newInstance());
          }
          catch (Throwable e) {
            // I18N
            System.err.println("Error loading saved desktop class: " + e);
          }
      }
      */

      if (currView != null) {
          style = currView.getStyle(); // set default in case no valid style in desktop file
          currView.dispose();
      }

      int savedStyle;
      String s = (String) (p.get("dt.style"));
      if (s != null) 
          savedStyle = indexOf(s, styleNames);
      else {
          // javatest 3.1 compatibility
          String c = (String) (p.get("dt.class"));
          savedStyle = (c == null ? -1 : indexOf(c, jt31StyleClassNames));
      }

      if (savedStyle != -1)
          style = savedStyle;

      ensureViewInitialized();
      currView.restoreDesktop(p);

      if (getTools().length == 0) 
          addDefaultTool();

      // select the previously selected tool, if given
      // else a default, if available
      Tool t = getSelectedTool();
      if (t == null) {
          Tool[] tools = getTools();
          if (tools.length > 0)
            t = tools[0];
      }
      if (t != null)
          setSelectedTool(t);

      //System.err.println("DT.restore: set visible");
      setVisible(true);
      //System.err.println("DT: restore done");

    }

    private void restoreHistory(Properties p) {
        HashMap allOpeners = new HashMap();
        for (int i = 0; i < toolManagers.length; i++) {
            ToolManager m = toolManagers[i];
            FileOpener[] mgrOpeners = m.getFileOpeners();
            if (mgrOpeners != null) {
                for (int j = 0; j < mgrOpeners.length; j++) {
                    FileOpener fo = mgrOpeners[j];
                    allOpeners.put(fo.getFileType(), fo);
                }
            }
        }

        try {
            fileHistory.clear();
            String c = (String) (p.get("file.count"));
            if (c != null) {
                int count = Integer.parseInt(c);
                for (int i = 0; i < count; i++) {
                    try {
                        String ft = (String) (p.get("fileHistory." + i + ".type"));
                        FileOpener fo = (FileOpener) (allOpeners.get(ft));
                        if (fo != null) {
                            String path = (String) (p.get("fileHistory." + i + ".path"));
                            if (path != null && path.length() > 0)
                                fileHistory.add(new FileHistoryEntry(fo, new File(path)));
                        }
                    }
                    catch (Throwable e) {
                        // I18N
                        //System.err.println("Error loading saved file: " + e);
                        System.err.println(uif.getI18NString("dt.cantLoadHist.txt"));
                        e.printStackTrace();
                    }
                }
            }
        }
        catch (NumberFormatException ignore) {
            // ignore, for now
        }
    }

    static Properties getPreviousDesktop(File file) {
        if (file == null)
            file = getDesktopFile();

        Properties p = new Properties();

        if (file != null && file.exists()) {
            try {
                InputStream in = new BufferedInputStream(new FileInputStream(file));
                p.load(in);
                in.close();
            }
            catch (IOException e) {
                // I18N
                System.err.println("Error reading desktop file: " + e);
            }
        }

        return p;
    }

    /**
     * Show a Preferences window.
     * @param parent the parent frame to be used for the preferences dialog
     */
00981     public void showPreferences(JFrame parent) {
      if (prefsPane == null)
          prefsPane = new DesktopPrefsPane(this, uif);

      Vector v = new Vector();
      v.addElement(prefsPane);
      for (int i = 0; i < toolManagers.length; i++) {
          ToolManager m = toolManagers[i];
          Preferences.Pane p = m.getPrefsPane();
          if (p != null)
            v.addElement(p);
      }

      Preferences.Pane[] custom = getCustomPreferences();
        if (custom != null)
           for (int i = 0; i < custom.length; i++)
               v.add(custom[i]);

      Preferences.Pane[] panes = new Preferences.Pane[v.size()];
      v.copyInto(panes);
      preferences.showDialog(parent, panes);
    }

    /**
     * Allow for other custom prefs panes.  Current implementation scans
     * test suite properties for one called "prefsPane", which should be a
     * class name referring to a class which subclasses <code>Preferences.Pane</code>.
     * That class will be loaded and instantiated using the test suite's class loader.
     * @return A set of prefs panes, beyond that of the currently active Tools.
     *         Null if none.
     */
01012     private Preferences.Pane[] getCustomPreferences() {
        ArrayList al = new ArrayList();

        HashSet customPrefsClasses = new HashSet();

      Tool[] tools = getTools();
      for (int i = 0; i < tools.length; i++) {
            TestSuite[] tss = tools[i].getLoadedTestSuites();
            if (tss != null && tss.length > 0) {
                for (int j = 0; j < tss.length; j++) {
                    // only process each test suite once
                    if (customPrefsClasses.contains(tss[j].getID()))
                        continue;
                    else
                        customPrefsClasses.add(tss[j].getID());

                    String cls = tss[j].getTestSuiteInfo("prefsPane");
                    try {
                        if (cls != null) {
                            Preferences.Pane pane =
                                (Preferences.Pane)((Class.forName(cls, true,
                                tss[j].getClassLoader())).newInstance());
                            al.add(pane);
                        }
                    }
                    catch (ClassNotFoundException e) {
                        e.printStackTrace();        // XXX rm
                        // should print log entry
                    }
                    catch (InstantiationException e) {
                        e.printStackTrace();        // XXX rm
                        // should print log entry
                    }
                    catch (IllegalAccessException e) {
                        e.printStackTrace();        // XXX rm
                        // should print log entry
                    }   // try
                    finally {
                    }
                }   // inner for j
            }
      }   // for i

        if (al.size() > 0) {
            Preferences.Pane[] panes = new Preferences.Pane[al.size()];
            al.toArray(panes);
            return panes;
        }
        else
            return null;
    }

    /**
     * Get an icon containing the JT Harness logo.
     * @return an icon containing the JT Harness logo
     */
01068     public Icon getLogo() {
      return uif.createIcon("dt.logo");
    }

    /**
     * Dispose of any resources used by this object.
     */
01075     public void dispose() {
      if (currView != null)
          currView.dispose();
    }

    /**
     * Print a text message to the desktop logfile.
     * A single line of text which is as short as possible is highly
     * recommended for readability purposes.
     *
     * @param i18n a resource bundle containing the localized messages
     * @param key a key into the resource bundle for the required message
     *
     * @since 3.0.1
     */
01090     public void log(I18NResourceBundle i18n, String key) {
      ensureLogFileInitialized();
      logFile.log(i18n, key);
    }

    /**
     * Print a text message to the desktop logfile.
     * A single line of text which is as short as possible is highly
     * recommended for readability purposes.
     *
     * @param i18n a resource bundle containing the localized messages
     * @param key a key into the resource bundle for the required message
     * @param arg An argument to be formatted into the specified message.
     *            If this is a <code>Throwable</code>, its stack trace
     *          will be included in the log.
     * @since 3.0.1
     */
01107     public void log(I18NResourceBundle i18n, String key, Object arg) {
      ensureLogFileInitialized();
      logFile.log(i18n, key, arg);
    }

    /**
     * Print a text message to the desktop logfile.
     * A single line of text which is as short as possible is highly
     * recommended for readability purposes.
     *
     * @param i18n a resource bundle containing the localized messages
     * @param key a key into the resource bundle for the required message
     * @param args An array of arguments to be formatted into the specified message.
     *            If the first arg is a <code>Throwable</code>, its stack
     *            trace will be included in the log.
     * @since 3.0.1
     */
01124     public void log(I18NResourceBundle i18n, String key, Object[] args) {
      ensureLogFileInitialized();
      logFile.log(i18n, key, args);
    }

    private void ensureLogFileInitialized() {
      if (logFile == null) {
          File f;
          String s = System.getProperty("javatest.desktop.log");
          if (s == null) {
            File userDir = new File(System.getProperty("user.home"));
            File jtDir = new File(userDir, ".javatest"); // mild uugh
            f = new File(jtDir, "log.txt");
          }
          else if (s.equals("NONE")) {
            f = null;
          }
          else
            f = new File(s);

          try {
            BackupPolicy p = BackupPolicy.simpleBackups(5);
            p.backup(f);
          }
          catch (IOException e) {
            // ignore? or save exception to write to logFile
          }

          logFile = (f == null ? new LogFile() : new LogFile(f));
      }
    }

    // the order of the styles is the presentation order in the preferences panel
    /**
     * A constant to indicate the tabbed-style desktop: 
     * a single window for the desktop, using a tabbed pane for the tools.
     */
01161     public static final int TAB_STYLE = 0;

    /**
     * A constant to indicate the MDI-style desktop:
     * a single window for the desktop, containing multiple internal windows, one per tool.
     */
01167     public static final int MDI_STYLE = 1;

    /**
     * A constant to indicate the SDI-style desktop:
     * multiple top-level windows, one per tool.
     */
01173     public static final int SDI_STYLE = 2;

    static final int NUM_STYLES = 3;
    static final String[] styleNames = {"tab", "mdi", "sdi"};

    private static final String[] jt31StyleClassNames = {
      "com.sun.javatest.tool.TabDesktop",
      "com.sun.javatest.tool.MDIDesktop",
      "com.sun.javatest.tool.SDIDesktop"
    };
    
    /**
     * Check whether or not the desktop will save its state when the VM exits.
     * @return true if the desktop will save its state when the VM exits, and false otherwise
     * @see #setSaveOnExit
     */
01189     public boolean getSaveOnExit() {
      return saveOnExit;
    }

    /**
     * Specify whether or not the desktop will save its state when the VM exits.
     * @param b true if the desktop should save its state when the VM exits, and false otherwise
     * @see #getSaveOnExit
     */
01198     public void setSaveOnExit(boolean b) {
      saveOnExit = b;
    }

    /**
     * Get Tooltip delay from prefs in ms.
     * @return Range is 0-Integer.MAX_VALUE
     */
01206     static int getTooltipDelay(Preferences p) {
      String val = p.getPreference(TTIP_DELAY);
      int result = TTIP_DELAY_DEFAULT;

      try {
          // expected range from prefs in 0-Integer.MAX_VALUE
          result = Integer.parseInt(val);
      }
      catch (NumberFormatException e) {
          // default to no delay
          result = TTIP_DELAY_DEFAULT;
      }

      if (result < 0)
          result = TTIP_DELAY_DEFAULT;;

      return result;
    }

    /**
     * Get tooltip duration from prefs in ms.
     * This is the translated value, so the "forever" value has been
     * transformed into something useful.
     * @return Range is 0-Integer.MAX_VALUE
     */
01231     static int getTooltipDuration(Preferences p) {
      String val = p.getPreference(TTIP_DURATION);
      int result = TTIP_DURATION_DEFAULT;

      try {
          // expected range from prefs in -1-Integer.MAX_VALUE
          result = Integer.parseInt(val);
      }
      catch (NumberFormatException e) {
          // default to no delay
          result = TTIP_DURATION_DEFAULT;
      }

      if (result < 0)
          if (result == TTIP_DURATION_FOREVER)  // indicates forever duration
            result = Integer.MAX_VALUE;
          else                // -2 or less, unknown value
            result = TTIP_DURATION_DEFAULT;
      else { }

      return result;
    }

    // these are here to be shared with DesktopPrefsPane.
    void setTooltipsEnabled(boolean state) {
      ToolTipManager.sharedInstance().setEnabled(state);
    }

    /**
     * Unconditionally set the tooltip delay to the given setting.
     * @param delay Delay time in ms or TTIP_DELAY_NONE.
     */
01263     void setTooltipDelay(int delay) {
      ToolTipManager.sharedInstance().setInitialDelay(delay);
    }

    /**
     * Unconditionally set the tooltip duration to the given setting.
     * @param duration Duration time in ms or TTTIP_DURATION_FOREVER.
     */
01271     void setTooltipDuration(int duration) {
      if (duration == TTIP_DURATION_FOREVER)
          ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE);
      else
          ToolTipManager.sharedInstance().setDismissDelay(duration);
    }

    public void printSetup() {
        ensurePrintAttrsInitialized();
        PrinterJob job = PrinterJob.getPrinterJob();
        job.pageDialog(printAttrs);
    }

    public void print(Printable printable) {
    
        DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);
        
        if(services.length > 0) {
            ensurePrintAttrsInitialized();
            
            Component parent = getDialogParent();
            int x = (int)parent.getLocationOnScreen().getX() + parent.getWidth() / 2 - 250;
            int y = (int)parent.getLocationOnScreen().getY() + parent.getHeight() / 2 - 250;
            
            PrintService service = ServiceUI.printDialog(null, x, y, services, 
                    services[0], flavor, printAttrs);
            if(service != null) {
                DocPrintJob job = service.createPrintJob();
                try {
                    Doc doc = new SimpleDoc(printable, flavor, null);
                
                    job.print(doc, printAttrs);
                }
                catch (PrintException e) {
                    e.printStackTrace();
                }
            }
        }
        
    }
    
    private void ensurePrintAttrsInitialized() {
        if(printAttrs == null) {
            printAttrs = new HashPrintRequestAttributeSet();
        }        
    }

    private void initToolManagers() {
      // locate init file and load up the managers
      //System.err.println("Desktop.initToolManagers");

      try {
          ManagerLoader ml = new ManagerLoader(ToolManager.class, System.err);
          ml.setManagerConstructorArgs(new Class[] { Desktop.class }, new Object[] { this });
          Set s = ml.loadManagers(TOOLMGRLIST);
          toolManagers = (ToolManager[]) (s.toArray(new ToolManager[s.size()]));
      }
      catch (IOException e) {
          throw new JavaTestError(uif.getI18NResourceBundle(), 
                            "dt.cantAccessResource", new Object[] { TOOLMGRLIST, e } );
      }
    }

    private void ensureViewInitialized() {
      if (currView != null)
          return;
      
      switch (style) {
      case MDI_STYLE:
          currView = new MDIDeskView(this);
          break;
          
      case SDI_STYLE:
          currView = new SDIDeskView(this);
          break;
          
      default:
          currView = new TabDeskView(this);
          break;
      }
    }

    private static void appendStrings(StringBuffer sb, String[] msgs) {
      if (msgs != null) {
          for (int i = 0; i < msgs.length; i++) {
            sb.append(msgs[i]);
            if (!msgs[i].endsWith("\n"))
                sb.append('\n');
          }
      }
    }
    
    /**
     * Get the file in which the desktop is (to be) stored.
     * The standard location is the platform equivalent of
     * $HOME/.javatest/desktop
     * It can be overridden by setting the system property
     * "javatest.desktop.file", which can be set to "NONE"
     * to disable the feature.
     */
01372     private static File getDesktopFile() {
      String s = System.getProperty("javatest.desktop.file");
      if (s == null) {
          File userDir = new File(System.getProperty("user.home"));
          File jtDir = new File(userDir, ".javatest"); // mild uugh
          return new File(jtDir, "desktop");
      }
      else if (!s.equals("NONE"))
          return new File(s);
      else
          return null;
    }

    static void addHelpDebugListener(Component c) {
      JComponent root;
      if (c instanceof JFrame)
          root = ((JFrame) c).getRootPane();
      else if (c instanceof JDialog)
          root = ((JDialog) c).getRootPane();
      else
          throw new IllegalArgumentException();

      ActionListener showFocusListener = new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            Component src = (Component) e.getSource();
            Component comp = javax.swing.SwingUtilities.findFocusOwner(src);
            System.err.println("ALT-F2: source=" + src);
            System.err.println("ALT-F2:  focus=" + comp);
          }
      };
      
      root.registerKeyboardAction(showFocusListener,
                            KeyStroke.getKeyStroke("alt F2"),
                            JComponent.WHEN_IN_FOCUSED_WINDOW);
    }

    static void addPreferredSizeDebugListener(Component c) {
      JComponent root;
      if (c instanceof JFrame)
          root = ((JFrame) c).getRootPane();
      else if (c instanceof JDialog)
          root = ((JDialog) c).getRootPane();
      else
          throw new IllegalArgumentException();

      ActionListener showPrefSizeListener = new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            Component src = (Component) e.getSource();
            Component c = javax.swing.SwingUtilities.findFocusOwner(src);
            while (c != null) {
                Dimension d = c.getPreferredSize();
                System.err.println("ALT-1: comp=" + c.getName() + "(" + c.getClass().getName() + ") "
                             + "[w:" + d.width + ",h:" + d.height + "]");
                c = c.getParent();
            }
          }
      };
      
      root.registerKeyboardAction(showPrefSizeListener,
                            KeyStroke.getKeyStroke("alt 1"),
                            JComponent.WHEN_IN_FOCUSED_WINDOW);
    }

    private static void invokeOnEventThread(Runnable r) {
      try {
          EventQueue.invokeAndWait(r);
      }
      catch (InterruptedException e) {
      }
      catch (InvocationTargetException e) {
          Throwable t = e.getTargetException();
          if (t instanceof RuntimeException)
            throw ((RuntimeException) t);
          else
            throw ((Error) t);
      }
    }

    private static int indexOf(String s, String[] a) {
      for (int i = 0; i < a.length; i++) {
          if (s == null ? a[i] == null : s.equals(a[i]))
            return i;
      }
      return -1;
    }

    private final UIFactory uif;
    private CommandContext commandContext;
    private DeskView currView;
    private int style; // used until currView is set, then style comes from that
    private Dimension preferredSize;
    private Preferences.Pane prefsPane;
    private ToolManager[] toolManagers;
    private LogFile logFile;
    private boolean firstTime;
    private boolean saveOnExit;
    private static int frameIndex;
    private PrintRequestAttributeSet printAttrs;

    private LinkedList fileHistory = new LinkedList();
    private static final int FILE_HISTORY_MAX_SIZE = 10;

    private static Preferences preferences = Preferences.access();


    static final String STYLE_PREF = "tool.appearance.style";
    static final String TTIP_PREF = "tool.appearance.ttipToggle";
    static final String TTIP_DELAY= "tool.appearance.ttipDelay";
    static final String TTIP_DURATION = "tool.appearance.ttipDuration";
    static final int TTIP_DURATION_FOREVER = -1;
    static final int TTIP_DELAY_NONE = 0;
    static final int TTIP_DELAY_DEFAULT = 0;
    static final int TTIP_DURATION_DEFAULT = 5000;
    static final String SAVE_ON_EXIT_PREF = "tool.appearance.saveOnExit";

    private static final String TOOLMGRLIST = "JavaTest.toolMgrs.lst";
    private static final String defaultToolManager =
      System.getProperty("javatest.desktop.defaultToolManager", "com.sun.javatest.exec.ExecToolManager");


    //-------------------------------------------------------------------------

    /**
     * A class for an entry on the file history list.
     * It defines a file, and an object to open that file if required.
     */
01498     static class FileHistoryEntry {
      FileHistoryEntry(FileOpener fo, File f) {
          fileOpener = fo;
          file = f;
      }

      FileOpener fileOpener;
      File file;  
    }
}

Generated by  Doxygen 1.6.0   Back to index