home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 39 / IOPROG_39.ISO / SOFT / sdkjava40.exe / data1.cab / fg_Samples / Samples / afc11 / JNotepad / src / FeatureTabFileViewer.java < prev    next >
Encoding:
Java Source  |  2000-05-04  |  16.7 KB  |  669 lines

  1. //
  2. // (C) Copyright 1995 - 1999 Microsoft Corporation.  All rights reserved.
  3. //
  4. import java.util.Vector;
  5. import java.util.Enumeration;
  6. import java.io.*;
  7. import java.awt.*;
  8.  
  9. import com.ms.ui.*;
  10. import com.ms.ui.event.*;
  11. import java.awt.event.*;
  12. import java.util.Date;
  13.  
  14. /**
  15. *    FeatureTabFileViewer is an extension of TabFileViewer which supports
  16. *    features. Features are classes which adhere to the IFeature interface.
  17. *    IFeature provides a framework for adding features and functionality to
  18. *    a program without touching the original program at all. It also allows
  19. *    one to mix and match features easily and flexibly. Many of FeatureTabFileViewer's
  20. *    functionality is implemented as features. 
  21. *    <p>
  22. *    FeatureTabFileViewer provides support for:
  23. *    <ul>
  24. *    <li>dirty file marking
  25. *    <li>accelerator keys
  26. *    <li>status bar
  27. *    <li>autosave
  28. *    <li>right-button context menu
  29. *    </ul>
  30. *    
  31. *    @see    IFeature
  32. *    @see    TabFileViewerer
  33. *    @version    1.0, 7/10/97
  34. */
  35.  
  36. public class FeatureTabFileViewer extends TabFileViewer implements IConstants
  37. {
  38.     /**
  39.     *    Thread which automatically saves all open files periodically
  40.     */
  41.     private AutosaveThread autosaveThread;        
  42.     
  43.     /**
  44.     *    Thread which handles and runs feature plugins
  45.     */
  46.     private FeatureThread featureThread;
  47.     
  48.     /**
  49.     *    Feature which handles enabling and disabling of menu items
  50.     */
  51.     protected ICommandFeedback feedbackObj;
  52.  
  53.     /**
  54.     *    Feature which handles command processing
  55.     *    
  56.     */
  57.     protected IComponentFeature    compFeature;
  58.  
  59.     /**
  60.     *    Right button context menu
  61.     */
  62.     protected JNoteContextMenu tabContextMenu;
  63.     
  64.     /**
  65.     *    Creates a new FeatureTabViewer.    
  66.     *    
  67.     *    @param    parFrame    Parent frame window
  68.     *    @param    feedback    ICommandFeedback interface used for command processing
  69.     */
  70.     public FeatureTabFileViewer(UIFrame parFrame, ICommandFeedback feedback, IComponentFeature compFeature)
  71.     {
  72.         this(parFrame, null, feedback, compFeature);
  73.     }
  74.     
  75.     /**
  76.     *    Creates a new FeatureTabViewer.    
  77.     *    
  78.     *    @param    parFrame    Parent frame window
  79.     *    @param    menubar        Menu used as the target of accelerator commands
  80.     *    @param    feedback    ICommandFeedback interface used for command processing
  81.     */
  82.     public FeatureTabFileViewer(UIFrame parFrame, UIBand menubar, ICommandFeedback feedback, IComponentFeature compobj)
  83.     {            
  84.         super(parFrame);
  85.  
  86.         feedbackObj = feedback;
  87.         compFeature = compobj;
  88.         tabContextMenu = null;
  89.         
  90.         autosaveThread = new AutosaveThread(this, 15000);
  91.         //autosaveThread.start();            
  92.         
  93.         featureThread = new FeatureThread(this);
  94.         featureThread.start();
  95.         
  96.         enableAccelerators(menubar);
  97.  
  98.         EnablerFeature enablerFeature = new EnablerFeature(feedbackObj);
  99.         registerListener(enablerFeature);
  100.         
  101.         loadListeners();            
  102.         enablerFeature.checkCommandStatus();
  103.         createTabContextMenu();
  104.     }
  105.     
  106.     /**
  107.     *    Adds a feature to the current file. It is not activated until
  108.     *    the features are loaded via loadListeners(). This calls the registerListeners()
  109.     *    method in the feature thread.
  110.     *
  111.     *    @see    #loadListeners
  112.     *    @see    FeatureThread#registerListener
  113.     *    
  114.     *    @param    fl    The feature to add
  115.     */
  116.     protected void registerListener(IFeature fl)
  117.     {
  118.         featureThread.registerListener(fl);
  119.     }
  120.     
  121.     /**
  122.     *    Loads and enables the current set of features on the current file.    
  123.     *    Calls loadListeners in the feature thread.
  124.     *
  125.     *    @see    FeatureThread#loadListeners
  126.     */
  127.     protected void loadListeners()
  128.     {
  129.         if(getFileTarget()!=null)
  130.             featureThread.loadListeners(getFileTarget());
  131.     }
  132.     
  133.     /**
  134.     *    Unloads all listeners enabled on the current file. Calls removeListeners
  135.     *    in the feature thread.
  136.     *
  137.     *    @see    FeatureThread#removeListeners    
  138.     */
  139.     protected void removeListeners()
  140.     {
  141.         featureThread.removeListeners();
  142.     }
  143.     
  144.     /**
  145.     *    Enables a DirtyFlagFeature on the current file if the file is dirty.
  146.     *    Calls attachDirtyFlagListener in the feature thread.
  147.     *
  148.     *    @see    FeatureThread#attachDirtyFlagListener
  149.     */
  150.     protected void attachDirtyFlagListener()
  151.     {
  152.         featureThread.attachDirtyFlagListener(getFileTarget());
  153.     }
  154.     
  155.     /**
  156.     *    Adds a status bar to a panel and attaches it to the current file's
  157.     *    edit control. Usually used by obtaining the panel the edit control
  158.     *    resides on and passing that panel to this function so that the
  159.     *    status bar is placed below it. The status bar is implemented as
  160.     *    an IFeature feature plugin.
  161.     *    
  162.     *    @parem    panel    UIPanel to place the status bar on. The status bar is placed
  163.     *                    in the south end of this panel.
  164.     */
  165.     private void addStatusBar(UIPanel panel)
  166.     {
  167.         JNoteUIStatus statusbar = new JNoteUIStatus("");
  168.         panel.add(statusbar, "south");
  169.         
  170.         statusbar.init(getFileTarget().getEditControl());
  171.         statusbar.register();            
  172.     }
  173.     
  174.     /**
  175.     *    Adds accelerator support to the system. Creates an AcceleratorFeature object
  176.     *    and loads it with accelerators from the JNoteSettingsObject. The feature is
  177.     *    the registered as a feature.
  178.     *
  179.     *    @param    menubar    The UIComponent to send command events to.
  180.     */
  181.     private void enableAccelerators(UIComponent menubar)
  182.     {
  183.         if (menubar == null)
  184.             return;
  185.         
  186.         AcceleratorFeature accel = new AcceleratorFeature(menubar, feedbackObj);
  187.         
  188.         JNoteAppSettings.getSettingsObj().loadAccelerators(accel);
  189.         
  190.         registerListener(accel);        
  191.     }
  192.     
  193.     /**
  194.     *    Enables or disables a command. Runs the enableCommand method in the
  195.     *    local ICommandFeedback object. Part of the ICommandFeedback interface. 
  196.     */
  197.     protected void enableCommand(String command, boolean on)
  198.     {
  199.         if (feedbackObj != null)
  200.         {
  201.             feedbackObj.enableCommand(command, on);
  202.         }
  203.     }
  204.     
  205.     /**
  206.     *    Adds a new file tab to the viewer. Calls the parent addNewFileTab method,
  207.     *    sets component and command objects on the current edit controls, and adds
  208.     *    a status bar.
  209.     *    
  210.     *    @param    path    Path of file which will be loaded into the new tab
  211.     *    @param    name    Name of file which will be loaded into the new tab
  212.     */    
  213.     public UIPanel addNewFileTab(String path, String name)
  214.     {
  215.         UIPanel panel = null;
  216.         
  217.         if ((panel = super.addNewFileTab(path, name)) != null)
  218.         {                                            
  219.             addStatusBar(panel);
  220.             
  221.             return panel;
  222.         }
  223.         else
  224.         {
  225.             return null;
  226.         }
  227.     }
  228.  
  229.     /*
  230.     public void addClipboardTab()
  231.     {
  232.         System.out.println(feedbackObj);
  233.  
  234.         super.addClipboardTab();
  235.  
  236.         ITextOperationTargetExt editControl = getFileTarget().getEditControl();
  237.  
  238.         editControl.setFeedbackObject(feedbackObj);
  239.         editControl.setCommandObject(compFeature);
  240.     }
  241.     */
  242.  
  243.     protected void initNewTab()
  244.     {
  245.         super.initNewTab();
  246.  
  247.         ITextOperationTargetExt editControl = getFileTarget().getEditControl();
  248.  
  249.         editControl.setFeedbackObject(JNoteAppCommandFeature.getCommandFeedback());
  250.         editControl.setCommandObject(JNoteAppCommandFeature.getCompFeature());
  251.     }
  252.     
  253.     /**
  254.     *    Creates a context menu to be displayed when the user right clicks on
  255.     *    a tab. Also adds the menu to the list of items that compFeature
  256.     *    is listening to for command events.
  257.     */
  258.     private void createTabContextMenu()
  259.     {
  260.  
  261.         UIMenuList ml = new UIMenuList();
  262.         ml.add( JNotePad.loadMenuItem( ResourceIDs.IDS_NEW, ResourceIDs.ID_FILE_NEW ));
  263.         ml.add( JNotePad.loadMenuItem( ResourceIDs.IDS_OPEN, ResourceIDs.ID_FILE_OPEN ));
  264.         ml.add( JNotePad.loadMenuItem( ResourceIDs.IDS_SAVE, ResourceIDs.ID_FILE_SAVE ));
  265.         ml.add(new UILine());                    
  266.         ml.add( JNotePad.loadMenuItem( ResourceIDs.IDS_CLOSE, ResourceIDs.ID_FILE_CLOSE ));
  267.  
  268.         tabContextMenu = new JNoteContextMenu(ml);
  269.         
  270.         compFeature.addTalker(tabContextMenu);
  271.     }
  272.     
  273.     /**
  274.     *    Displays the tab context menu at the specifed screen coordinates.
  275.     *
  276.     *    @param    x    x coordinate of the point to display the menu, relative to the upper left corner of the screen
  277.     *    @param    y    y coordinate of the point to display the menu, relative to the upper left corner of the screen
  278.     */
  279.     protected void showTabContextMenu(int x, int y)
  280.     {            
  281.         Point pt = parentFrame.getLocation();
  282.         Point edit = getLocation(parentFrame);        
  283.  
  284.         tabContextMenu.launchAt(x+pt.x+edit.x, y+pt.y+edit.y, parentFrame);        
  285.     }
  286.     
  287.     /**
  288.     *    Saves all modified open files. Does not save untitled files. Called
  289.     *    by the feature thread.
  290.     *
  291.     *    @see    FeatureThread#run
  292.     */
  293.     public void saveAll()
  294.     {            
  295.         // grabs the tabs in the viewer. 
  296.         UITabList tablist = (UITabList)getComponent(0);    
  297.         UITab tab = null;
  298.         int i = 0;
  299.         
  300.         Enumeration e = loadedFiles.elements();
  301.         
  302.         // go through all the files
  303.         while (e.hasMoreElements())
  304.         {
  305.             IFileOperationTargetExt  fc = (IFileOperationTargetExt )e.nextElement();
  306.             
  307.             // if the file is dirty and has a name we can save under, save it
  308.             if (fc.isDirty() && (fc.getFileName() != null))
  309.             {
  310.                 fc.saveFile();
  311.                 
  312.                 // refresh the tab so the dirty flag gets removed
  313.                 tab = (UITab)tablist.getComponent(i);
  314.                 refreshTab(tab, fc);
  315.             }
  316.             
  317.             ++i;
  318.         }
  319.         
  320.     }
  321.     
  322.     /**
  323.     *    Handles incoming events. Removes and reloads the listeners when the
  324.     *    current tab changes, and displays the context menu when the right button
  325.     *    is pressed. All other events are sent to the paren.
  326.     *
  327.     *    @param    e    Event to handle.    
  328.     */
  329.     public boolean handleEvent(Event e)
  330.     {            
  331.         boolean ret = false;
  332.         
  333.         if ((e.arg instanceof UITab) && (e.id == Event.LIST_SELECT))
  334.         {
  335.             removeListeners();
  336.             
  337.             ret = super.handleEvent(e);
  338.             
  339.             loadListeners();
  340.         }
  341.         else if ((e.id == Event.MOUSE_UP) && (e.modifiers == Event.META_MASK))
  342.         {
  343.             showTabContextMenu(e.x, e.y);            
  344.         }
  345.         else
  346.         {
  347.             return super.handleEvent(e);
  348.         }
  349.         
  350.         return ret;
  351.     }
  352.     
  353.     
  354.     // overriding TabFileViewer's file i/o commands to update the dirty flag listener
  355.     
  356.     /**
  357.     *    Overrides saveFile() to add dirty flag support. Runs the parent's
  358.     *    saveFile method; if the dirty bit changes after the save (from dirty
  359.     *    to clean), attach a dirty flag listener and refresh the tab.
  360.     *    
  361.     *    @see    TabFileViewer#saveFile
  362.     */
  363.     public boolean saveFile()
  364.     {
  365.         boolean bIsDirty = getFileTarget().isDirty();
  366.         
  367.         boolean ret = super.saveFile();
  368.         
  369.         // if dirty bit changed (from dirty to clean), attach a listener
  370.         // The dirty bit can only go from dirty to clean after a save, but
  371.         // may stay dirty if the save was cancelled. It can never go from clean to dirty
  372.         // after a save
  373.         if (bIsDirty != getFileTarget().isDirty())
  374.         {
  375.             attachDirtyFlagListener();
  376.             refreshCurrentTab();
  377.         }
  378.         
  379.         return ret;
  380.     }
  381.     
  382.     /**
  383.     *    Overrides saveFileAs() to add dirty flag support. Runs the parent's
  384.     *    saveFileAs method; if the dirty bit changes after the save (from dirty
  385.     *    to clean), attach a dirty flag listener and refresh the tab.
  386.     *    
  387.     *    @see    TabFileViewer#saveFileAs
  388.     */
  389.     public boolean saveFileAs()
  390.     {
  391.         boolean bIsDirty = getFileTarget().isDirty();
  392.         
  393.         boolean ret = super.saveFileAs();            
  394.         
  395.         // if dirty bit changed (from dirty to clean), attach a listener
  396.         if (bIsDirty != getFileTarget().isDirty())
  397.         {
  398.             attachDirtyFlagListener();
  399.             refreshCurrentTab();
  400.         }
  401.         
  402.         return ret;
  403.     }
  404.     
  405.     /**
  406.     *    Overrides openFile() to add dirty flag and MRU support. Runs the parent's
  407.     *    openFile method and add a dirty flag listener (cause the file is now clean).
  408.     *    Adds the file to the MRU file list.
  409.     *    
  410.     *    @see    TabFileViewer#saveFile
  411.     */    
  412.     public boolean openFile()
  413.     {            
  414.         if (super.openFile())
  415.         {
  416.             attachDirtyFlagListener();                        
  417.             
  418.             return true;
  419.         }
  420.         else
  421.         {
  422.             return false;
  423.         }
  424.     }
  425.  
  426.     /**
  427.     *    Called when a new tab is selected. Refreshes the tab and enables/disables the 
  428.     *    close option as appropriate.
  429.     */
  430.     public void refreshCurrentTab()
  431.     {
  432.         super.refreshCurrentTab();
  433.  
  434.         // we can't close the clipboard, so disable the close option when the clipboard
  435.         // is selected
  436.         if (getFileTarget() instanceof ClipboardControl)
  437.         {
  438.             feedbackObj.enableCommand(JNotePad.loadString(ResourceIDs.IDS_CLOSE), false);
  439.         }
  440.         else
  441.         {
  442.             feedbackObj.enableCommand(JNotePad.loadString(ResourceIDs.IDS_CLOSE), true);
  443.         }
  444.     }
  445.     
  446. }
  447.  
  448.  
  449. /**
  450. *    This thread implements timed save; after so many minutes, all the open
  451. *    files are saved. 
  452. *    <p>
  453. *    This runs the saveAll() method in FeatureTabViewer to save the files.
  454. *    <p>
  455. *    @version    1.0, 7/28/97
  456. */
  457.  
  458. class AutosaveThread extends Thread
  459. {
  460.     /**
  461.     *    The tab viewer which has files to save
  462.     */
  463.     FeatureTabFileViewer featureView;
  464.     
  465.     /**
  466.     *    Time to delay, in milliseconds
  467.     */
  468.     int autosaveTime = 0;
  469.     
  470.     /**
  471.     *    Creates a new AutosaveThread.    
  472.     *    
  473.     *    @param    view    The object which has open files we need to save.
  474.     *    @param    sleeptime    The time (in milliseconds) before a save
  475.     */
  476.     public AutosaveThread(FeatureTabFileViewer view, int sleeptime)
  477.     {
  478.         featureView = view;
  479.         autosaveTime = sleeptime;
  480.     }
  481.     
  482.     /**
  483.     *    Sets the time between automatic saves. The new time takes effect
  484.     *    after the next save.
  485.     *
  486.     *    @param    delay    Time between saves, in seconds.
  487.     */
  488.     public void setDelay(int delay)
  489.     {
  490.         autosaveTime = delay*1000;
  491.     }
  492.     
  493.     /**
  494.     *    Runs the thread. Overrides Thread.run(). Loops infinitely; at each time through
  495.     *    the loop, it sleeps for the correct interval and then calls the
  496.     *    saveAll() method on the featureView object.
  497.     *
  498.     *    @see    FeatureTabFileViewer#saveAll
  499.     */
  500.     public void run()
  501.     {
  502.         while (true)
  503.         {
  504.             try
  505.             {
  506.                 sleep(autosaveTime);
  507.             }
  508.             catch (InterruptedException e)
  509.             {
  510.                 // if we're interrupted, it's okay, we'll
  511.                 // just save now.
  512.             }
  513.             
  514.             // save all open files
  515.             featureView.saveAll();                        
  516.         }                    
  517.     }
  518.     
  519. }
  520.  
  521.  
  522. /**
  523. *    FeatureThread class
  524. *    
  525. *    A private class which runs feature plugins (which adhere to the IFeature
  526. *    interface) in a separate thread. This is done to make the main program
  527. *    a bit faster and more responsive. We don't guaranteed to be synchronized
  528. *    with the main program, but since feature plugins are implemented through
  529. *    listeners (which are by their very nature asynchronous), this isn't a
  530. *    problem.
  531. *
  532. *    This class simply accepts new listeners, adds them to a local Vector,
  533. *    and then registers and unregisters them when asked.
  534. *
  535. *    @version    1.0, 8/17/97
  536. *
  537. *    @see    IFeature
  538. *    @see    FeatureTabFileViewer
  539. */
  540.  
  541. class FeatureThread extends Thread
  542. {
  543.     /**
  544.     *    The list of feature listeners in the system
  545.     */
  546.     private Vector featureListeners;
  547.     
  548.     /**
  549.     *    The dirty flag feature.
  550.     */
  551.     private DirtyFlagFeature dirtyFlagFeature;
  552.     
  553.     /**
  554.     *    Creates a new FeatureThread.
  555.     *
  556.     *    @param    tabTarget    The object to notify when the dirty flag changes.
  557.     */
  558.     public FeatureThread(FeatureTabFileViewer tabTarget)
  559.     {
  560.         init(tabTarget);
  561.     }
  562.     
  563.     /**
  564.     *    Private init function. Initializes variables and inits the DirtyFlagFeature.
  565.     *
  566.     *    @param    tabTarget    The object to notify when the dirty flag changes.
  567.     */
  568.     private void init(FeatureTabFileViewer tabTarget)
  569.     {
  570.         featureListeners = new Vector(10);
  571.         dirtyFlagFeature = new DirtyFlagFeature(tabTarget);            
  572.     }
  573.     
  574.     /**
  575.     *    Adds the feature to the system. This simply adds the feature to the    
  576.     *    featureListeners Vector.
  577.     *
  578.     *    @param    fl    Feature to add
  579.     */
  580.     public void registerListener(IFeature fl)
  581.     {
  582.         featureListeners.addElement(fl);
  583.     }
  584.     
  585.     /**
  586.     *    Loads the features onto the current file. This is done by iterative
  587.     *    through all of the features and running init() and register() on
  588.     *    each one. The dirty flag listener is attached at the end.
  589.     *    
  590.     *    @param    fileObj    The file control to attach features to.
  591.     */
  592.     public void loadListeners(IFileOperationTargetExt fileObj)
  593.     {        
  594.         if (featureListeners == null)
  595.         {
  596.             return;
  597.         }
  598.         
  599.         ITextOperationTargetExt editControl = fileObj.getEditControl();
  600.         
  601.         Enumeration enum = featureListeners.elements();
  602.         while (enum.hasMoreElements())
  603.         {
  604.             ITextFeature fl = (ITextFeature)enum.nextElement();
  605.             
  606.             fl.init(editControl);
  607.             fl.register();                                    
  608.         }
  609.         
  610.         attachDirtyFlagListener(fileObj);
  611.     }
  612.     
  613.     
  614.     /**
  615.     *    Unattaches features from a file. Goes through all of the features and
  616.     *    calls reset() and unregister() on each one. 
  617.     */
  618.     public void removeListeners()
  619.     {
  620.         if (featureListeners == null)
  621.         {
  622.             return;
  623.         }
  624.         
  625.         Enumeration enum = featureListeners.elements();
  626.         while (enum.hasMoreElements())
  627.         {
  628.             IFeature fl = (IFeature)enum.nextElement();
  629.             
  630.             fl.reset();
  631.             fl.unregister();                    
  632.         }
  633.         
  634.         // if the dirty flag feature is still loaded, this will remove it
  635.         dirtyFlagFeature.reset();
  636.     }
  637.     
  638.     /**
  639.     *    Adds a dirty flag listener to the given file. This feature plugin notifies
  640.     *    the tab viewer when a file has been modified. 
  641.     *
  642.     *    @param    fileObj    The file control to listen to for changes
  643.     */
  644.     public void attachDirtyFlagListener(IFileOperationTargetExt  fileObj)
  645.     {            
  646.         if (!fileObj.isDirty() && !fileObj.isReadOnly())
  647.         {
  648.             // attaches the feature to the file control
  649.             dirtyFlagFeature.init(fileObj.getEditControl());
  650.             dirtyFlagFeature.register();
  651.         }            
  652.     }
  653.     
  654.     /**
  655.     *    The thread run method. Since we just wait for our methods to be
  656.     *    called, this method does nothing.
  657.     */
  658.     public void run()
  659.     {
  660.         // we don't need to do anything. We just wait for people
  661.         // to call our public methods. Then our code runs in this
  662.         // thread, not in the caller's thread.            
  663.     }
  664.     
  665. }
  666.  
  667.  
  668.  
  669.