001    // This file is part of the program FRYSK.
002    //
003    // Copyright 2005, 2007, 2008, Red Hat Inc.
004    //
005    // FRYSK is free software; you can redistribute it and/or modify it
006    // under the terms of the GNU General Public License as published by
007    // the Free Software Foundation; version 2 of the License.
008    //
009    // FRYSK is distributed in the hope that it will be useful, but
010    // WITHOUT ANY WARRANTY; without even the implied warranty of
011    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012    // General Public License for more details.
013    // 
014    // You should have received a copy of the GNU General Public License
015    // along with FRYSK; if not, write to the Free Software Foundation,
016    // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
017    // 
018    // In addition, as a special exception, Red Hat, Inc. gives You the
019    // additional right to link the code of FRYSK with code not covered
020    // under the GNU General Public License ("Non-GPL Code") and to
021    // distribute linked combinations including the two, subject to the
022    // limitations in this paragraph. Non-GPL Code permitted under this
023    // exception must only link to the code of FRYSK through those well
024    // defined interfaces identified in the file named EXCEPTION found in
025    // the source code files (the "Approved Interfaces"). The files of
026    // Non-GPL Code may instantiate templates or use macros or inline
027    // functions from the Approved Interfaces without causing the
028    // resulting work to be covered by the GNU General Public
029    // License. Only Red Hat, Inc. may make changes or additions to the
030    // list of Approved Interfaces. You must obey the GNU General Public
031    // License in all respects for all of the FRYSK code and other code
032    // used in conjunction with FRYSK except the Non-GPL Code covered by
033    // this exception. If you modify this file, you may extend this
034    // exception to your version of the file, but you are not obligated to
035    // do so. If you do not wish to provide this exception without
036    // modification, you must delete this exception statement from your
037    // version and license this file solely under the GPL without
038    // exception.
039    
040    
041    package frysk.gui.register;
042    
043    import java.util.HashMap;
044    import org.gnu.glade.LibGlade;
045    import org.gnu.gtk.event.LifeCycleEvent;
046    import org.gnu.gtk.event.LifeCycleListener;
047    import frysk.proc.Proc;
048    import frysk.proc.Task;
049    import frysk.stepping.SteppingEngine;
050    import frysk.config.Prefix;
051    
052    /**
053     * Factory for creating RegisterWindows - allows multiple RegisterWindows to be
054     * instantiated for different processes, and disallows multiple windows on the
055     * same process. Uses a ProcBlockCounter to co-ordinate the un-blocking of the
056     * process between the Memory and SourceWindows if the other two are also 
057     * running on that process. A singleton class dynamically creating RegisterWindows.
058     */
059    public class RegisterWindowFactory
060    {
061    
062      /* Instance of this class used by the SourceWindow to ensure singularity */
063      public static RegisterWindow regWin = null;
064    
065      /* Keeps track of which RegisterWindows belong to which Task. */
066      private static HashMap map = new HashMap();
067      
068      private static HashMap seMap = new HashMap();
069      
070      private final static String REG_GLADE = "registerwindow.glade";
071    
072      /**
073       * Performs checks to ensure no other RegisterWindow is running on this Task;
074       * if not, assigns a ProcBlockCounter and attaches an Observer if there is
075       * no other Window already running on this Task.
076       * 
077       * @param proc    The Proc to be examined by the new RegisterWindow.
078       */
079      public static void createRegisterWindow (Proc proc, SteppingEngine steppingEngine)
080      {
081        RegisterWindow rw = (RegisterWindow) map.get(proc);
082    
083        /* Check if there is already a RegisterWindow running on this task */
084        if (rw != null)
085          {
086            rw = (RegisterWindow) map.get(proc);
087            steppingEngine.addObserver(rw.getLockObserver());
088            rw.showAll();
089            return;
090          }
091    
092        LibGlade glade;
093        try {
094            glade = new LibGlade(Prefix.gladeFile(REG_GLADE).getAbsolutePath(), null);
095        } catch (Exception e) {
096            throw new RuntimeException(e);
097        }
098    
099        rw = new RegisterWindow(glade);
100        steppingEngine.addObserver(rw.getLockObserver());
101        rw.finishRegWin(proc);
102        rw.setObservable(steppingEngine.getSteppingObserver());
103    
104        map.put(proc, rw);
105        seMap.put(rw, steppingEngine);
106        rw.addListener(new RegWinListener());
107        rw.grabFocus();
108      }
109    
110      /**
111             * Used by the SourceWindow to assign the static regWin object which it
112             * uses to ensure there is only one RegisterWindow running for its Task.
113             * 
114             * @param proc The Proc used to find the RegisterWindow representing it.
115             */
116      public static void setRegWin (Proc proc)
117      {
118        regWin = (RegisterWindow) map.get(proc);
119      }
120    
121      /**
122       * A wrapper for LifeCycleListener which cleans up when the RegisterWindow 
123       * is closed.
124       */
125      private static class RegWinListener
126          implements LifeCycleListener
127      {
128    
129        public void lifeCycleEvent (LifeCycleEvent arg0)
130        {
131        }
132    
133        /**
134         * If the RegisterWindow is closed, let the Task know that it isn't being
135         * examined anymore and then hide the window.
136         * 
137         * @param arg0  The LifeCycleEvent affecting this window.
138         */
139        public boolean lifeCycleQuery (LifeCycleEvent arg0)
140        {
141    
142          /*
143           * If the window is closing we want to remove it and it's task from the
144           * map, so that we know to create a new instance next time
145           */
146          if (arg0.isOfType(LifeCycleEvent.Type.DELETE)
147              || arg0.isOfType(LifeCycleEvent.Type.DESTROY)
148              || arg0.isOfType(LifeCycleEvent.Type.HIDE))
149            {
150              RegisterWindow rw = (RegisterWindow) arg0.getSource();
151              Task t = rw.getMyTask();
152              Proc p = t.getProc();
153              
154              SteppingEngine se = (SteppingEngine) seMap.get(rw);
155              se.removeObserver(rw.getLockObserver(), p, true);
156              map.remove(p);
157              seMap.remove(rw);
158              
159              rw.hideAll();
160              return true;
161            }
162    
163          return false;
164        }
165    
166      }
167    }