alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 * 22:13 09/04/2003
 *
 * Jext.java - A text editor for Java
 * Copyright (C) 1999-2003 Romain Guy
 * Portions copyright (C) 1998-2000 Slava Pestov
 * romain.guy@jext.org
 * www.jext.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package org.jext;

import java.net.*;

import java.lang.reflect.Method;
import java.io.*;
import java.text.*;

import java.util.*;
import java.util.zip.*;

import java.awt.Toolkit;
import java.awt.Window;

import javax.swing.UIManager;
import javax.swing.plaf.metal.MetalLookAndFeel;

import org.gjt.sp.jedit.textarea.DefaultInputHandler;
import org.gjt.sp.jedit.textarea.TextUtilities;

import org.jext.actions.*;
import org.jext.gui.*;
import org.jext.event.JextEvent;
import org.jext.misc.TabSwitcher;
import org.jext.misc.VersionCheck;
import org.jext.oneclick.*;
import org.jext.scripting.dawn.Run;
import org.jext.search.Search;
import org.jext.textarea.*;
import org.jext.xml.OneClickActionsReader;
import org.jext.xml.PyActionsReader;
import org.jext.xml.XPropertiesReader;

import org.python.util.PythonInterpreter;

/**
 * Jext is a fully featured, 100% Pure Java, text editor. It
 * has been mainly designed for programmers, and provides also
 * very useful functions for them (syntax colorization, auto
 * indentation...).
 * @author Romain Guy
 * @version 5.0
 */

public class Jext
{
  //////////////////////////////////////////////////////////////////////////////////////////////
  // PUBLIC CONSTANTS
  //////////////////////////////////////////////////////////////////////////////////////////////

  /* If you change any of the final values here, you'll need to recompile every class that uses them.
   * So some lost their "final" at some point, but mustn't be modified anyway.
   */
  /** Current Jext's release. */
  public static String RELEASE = "5.0 ";
  /**
   * Last Jext's build number. It's used actually only for plugin dependencies, so
   * don't change it for simple bug-fix which don't bump the release number.*/
  public static String BUILD = "05.00.01.00";

  /** If true, Jext will delete user settings if this release is newer */
  public static boolean DELETE_OLD_SETTINGS = true;

  /** Debug mode(not final to avoid it being included in other .class files) */
  public static boolean DEBUG = false;

  /** Available new lines characters */
  public static final String[] NEW_LINE = { "\r", "\n", "\r\n" };

  /** Settings directory. */
  public static final String SETTINGS_DIRECTORY = System.getProperty("user.home") +
                                                  File.separator + ".jext" + File.separator;

  /** Jext home directory. */
  public static final String JEXT_HOME = System.getProperty("user.dir");

  /** Jext server base port number. Used to load all Jext instances with only one JVM. **/
  public static final int JEXT_SERVER_PORT = 49152;

  //////////////////////////////////////////////////////////////////////////////////////////////
  // BEGINNING OF STATIC PART
  //////////////////////////////////////////////////////////////////////////////////////////////
  // STATIC FIELDS
  //////////////////////////////////////////////////////////////////////////////////////////////

  // modes
  public static ArrayList modes;
  public static ArrayList modesFileFilters;
  // selected language
  private static String language = "English";
  private static ZipFile languagePack;
  private static ArrayList languageEntries;
  // GUI option to have, or not flat menus
  private static boolean flatMenus = true;
  // GUI option to have non highlighted buttons
  private static boolean buttonsHighlight = true;
  // server socket
  private static JextLoader jextLoader;
  private static boolean isServerEnabled;
  // plugins specific variables
  private static ArrayList plugins;
  // user properties filename
  public static String usrProps;
  // the splash screen
  private static SplashScreen splash;
  // the properties files
  private static Properties props, defaultProps;
  // contains all the instances of Jext
  // this is an object we synchronize on to avoid window being created concurrently or when is not ready
  // enough(for instance by JextLoader when we didn't call initProperties() yet).
  private static ArrayList instances = new ArrayList(5);
  // contains all the actions
  private static HashMap actionHash;
  // contains all the python actions
  private static HashMap pythonActionHash = new HashMap();
  // auto check
  private static VersionCheck check;
  // input handler
  private static DefaultInputHandler inputHandler;
  // user properties file name
  private static final String USER_PROPS = SETTINGS_DIRECTORY + ".jext-props.xml";
  // this property(set by loadInSingleJVMInstance), if true, says we must not show
  private static boolean runInBg = false;
  private static boolean keepInMemory = false;
  //the default value found during loading must be stored for the option dialog
  private static boolean defaultKeepInMemory = false;
  // when the user runs jext -kill, we store this here and go to kill the server(see 
  // loadInSingleJVMInstance)
  private static boolean goingToKill = false;
  // the text area we pre-build if running in background, that will be shown when Jext is started
  // by the user(so it will be very fast!)
  private static JextFrame builtTextArea = null;

  //////////////////////////////////////////////////////////////////////////////////////////////
  // STATIC METHODS
  //////////////////////////////////////////////////////////////////////////////////////////////

  /**
   * Returns true if highlight buttons should not be highlighted on mouse over.
   */

  public static boolean getButtonsHighlight()
  {
    return buttonsHighlight;
  }

  /**
   * Returns true if menu should be flatened.
   */

  public static boolean getFlatMenus()
  {
    return flatMenus;
  }

  /**
   * Stop the auto check function. We just interrupt the
   * Thread and then 'kill' it.
   */

  public static void stopAutoCheck()
  {
    if (check != null)
    {
      check.interrupt();
      check = null;
    }
  }

  /**
   * Returns the input handler.
   */

  public static DefaultInputHandler getInputHandler()
  {
    return inputHandler;
  }

  /**
   * Add an action listener to the list.
   * @param action The action listener
   */

  public static void addAction(MenuAction action)
  {
    String name = action.getName();
    actionHash.put(name, action);
    String keyStroke = getProperty(name.concat(".shortcut"));

    if (keyStroke != null)
      inputHandler.addKeyBinding(keyStroke, action);
  }

  /**
   * Add a python action listener to the list.
   * @param name Internal action name
   * @param script The python source script
   * @param editAction True if this is an edit action
   */

  public static void addPythonAction(String name, String script, boolean editAction)
  {
    PythonAction action;

    if (!editAction)    
      action = new PythonAction(name, script);
    else
      action = new PythonEditAction(name, script);

    pythonActionHash.put(name, action);
    String keyStroke = getProperty(name.concat(".shortcut"));

    if (keyStroke != null)
      inputHandler.addKeyBinding(keyStroke, action);
  }

  /**
   * Returns a named action.
   * @param action The action
   */

  public static MenuAction getAction(String action)
  {
    Object o = actionHash.get(action);
    if (o == null)
      o = pythonActionHash.get(action);
    return (MenuAction) o;
  }

  /**
   * Load the action listeners.
   */

  private static void initActions()
  {
    actionHash = new HashMap();
    inputHandler = new DefaultInputHandler();
    inputHandler.addDefaultKeyBindings();

    // Python written actions
    loadXMLActions(Jext.class.getResourceAsStream("jext.actions.xml"), "jext.actions.xml");

    // native Java actions
    addAction(new BeginLine());
    addAction(new BoxComment());
    addAction(new CompleteWord());
    addAction(new CompleteWordAll());
    addAction(new CreateTemplate());
    addAction(new EndLine());
    addAction(new JoinAllLines());
    addAction(new JoinLines());
    addAction(new LeftIndent());
    addAction(new OpenUrl());
    addAction(new Print());
//    addAction(new RemoveSpaces());
    addAction(new RemoveWhitespace());
    addAction(new RightIndent());
    addAction(new SimpleComment());
    addAction(new SimpleUnComment());
    addAction(new SpacesToTabs());
    addAction(new TabsToSpaces());
    addAction(new ToLowerCase());
    addAction(new ToUpperCase());
    addAction(new WingComment());
    addAction(new WordCount());

    // init OneClick! actions

    addAction(new OneAutoIndent());
    // One Click !
    loadXMLOneClickActions(Jext.class.getResourceAsStream("jext.oneclickactions.xml"),
                                                          "jext.oneclickactions.xml");
    //    addAction(new OneClickAction("one_paste",             "paste"));
    //    addAction(new OneClickAction("one_reverse_paste",     "reverse_paste"));
    //    addAction(new OneClickAction("one_delete_line",       "delete_line"));
    //    addAction(new OneClickAction("one_join_lines",        "join_lines"));
    //    addAction(new OneClickAction("one_right_indent",      "right_indent"));
    //    addAction(new OneClickAction("one_left_indent",       "left_indent"));
    //    addAction(new OneClickAction("one_simple_comment",    "simple_comment"));
    //    addAction(new OneClickAction("one_simple_uncomment",  "simple_uncomment"));
    //    addAction(new OneClickAction("one_complete_word",     "complete_word"));

    // key bindings
    addJextKeyBindings();
  }

  /**
   * Adds Jext internal key bindings.
   */

  private static void addJextKeyBindings()
  {
    inputHandler.addKeyBinding("CA+UP",           new ScrollUp());
    inputHandler.addKeyBinding("CA+PAGE_UP",      new ScrollPageUp());
    inputHandler.addKeyBinding("CA+DOWN",         new ScrollDown());
    inputHandler.addKeyBinding("CA+PAGE_DOWN",    new ScrollPageDown());
    inputHandler.addKeyBinding("C+UP",            new PrevLineIndent());
    inputHandler.addKeyBinding("C+DOWN",          new NextLineIndent());

    inputHandler.addKeyBinding("ENTER",           new IndentOnEnter());
    inputHandler.addKeyBinding("TAB",             new IndentOnTab());
    inputHandler.addKeyBinding("S+TAB",           new LeftIndent());

    inputHandler.addKeyBinding("C+INSERT",        getAction("copy"));
    inputHandler.addKeyBinding("S+INSERT",        getAction("paste"));

    inputHandler.addKeyBinding("CA+LEFT",         new CsWord(CsWord.NO_ACTION, TextUtilities.BACKWARD));
    inputHandler.addKeyBinding("CA+RIGHT",        new CsWord(CsWord.NO_ACTION, TextUtilities.FORWARD));
    inputHandler.addKeyBinding("CAS+LEFT",        new CsWord(CsWord.SELECT,    TextUtilities.BACKWARD));
    inputHandler.addKeyBinding("CAS+RIGHT",       new CsWord(CsWord.SELECT,    TextUtilities.FORWARD));
    inputHandler.addKeyBinding("CA+BACK_SPACE",   new CsWord(CsWord.DELETE,    TextUtilities.BACKWARD));
    inputHandler.addKeyBinding("CAS+BACK_SPACE",  new CsWord(CsWord.DELETE,    TextUtilities.FORWARD));
    
    if (Utilities.JDK_VERSION.charAt(2) >= '4')
    {
      inputHandler.addKeyBinding("C+PAGE_UP",     new TabSwitcher(false));
      inputHandler.addKeyBinding("C+PAGE_DOWN",   new TabSwitcher(true));
    }//end if JRE 1.4 or above

  }

  /**
   * Loads plugins.
   */

  private static void initPlugins()
  {
    plugins = new ArrayList();
    loadPlugins(JEXT_HOME + File.separator + "plugins");
    loadPlugins(SETTINGS_DIRECTORY + "plugins");
  }

  /**
   * Makes each mode know what plugins to start when it is selected.
   */

  public static void assocPluginsToModes()
  {
    Mode mode;
    String modeName;
    String pluginModes;

    for (int i = 0; i < plugins.size(); i++)
    {
      Plugin plugin = (Plugin) plugins.get(i);
      pluginModes = getProperty("plugin." + plugin.getClass().getName() + ".modes");

      if (pluginModes != null)
      {
        StringTokenizer tok = new StringTokenizer(pluginModes);
        while (tok.hasMoreTokens())
        {
          modeName = tok.nextToken();
          mode = getMode(modeName);
          mode.addPlugin( plugin);
        }
      }
    }
  }

  /**
   * Loads all plugins in a directory.
   * @param directory The directory
   */

  public static void loadPlugins(String directory)
  {
    String[] args = { directory };
    System.out.println(getProperty("jar.scanningdir", args));

    File file = new File(directory);
    if (!(file.exists() || file.isDirectory()))
      return;

    String[] plugins = file.list();
    if (plugins == null)
      return;

    for (int i = 0; i < plugins.length; i++)
    {
      String plugin = plugins[i];
      if (!plugin.toLowerCase().endsWith(".jar"))
        continue;
      try
      {
        new JARClassLoader(directory + File.separator + plugin);
      } catch(IOException io) {
        String[] args2 = { plugin };
        System.err.println(getProperty("jar.error.load", args2));
        io.printStackTrace();
      }
    }
  }

  /**
   * Registers a plugin with the editor. This will also call
   * the start() method of the plugin.
   */

  public static void addPlugin(Plugin plugin)
  {
    plugins.add(plugin);
    try
    {
      plugin.start();
    } catch (Throwable t) {
      System.err.println("#--An exception has occurred while starting plugin:");
      t.printStackTrace();
    }

    if (plugin instanceof SkinFactory)
    {
      //System.out.println("Added a SkinPlugin named: " + plugin.getClass().getName());
      SkinManager.registerSkinFactory((SkinFactory) plugin);
    }
  }

  /**
   * Returns a plugin by it's class name.
   * @param name The plugin to return
   */

  public static Plugin getPlugin(String name)
  {
    for (int i = 0; i < plugins.size(); i++)
    {
      Plugin p = (Plugin) plugins.get(i);
      if (p.getClass().getName().equalsIgnoreCase(name))
        return p;
    }

    return null;
  }

  /**
   * Returns an array of installed plugins.
   */

  public static Plugin[] getPlugins()
  {
    /*Object[] o = plugins.toArray();
    Plugin[] p = new Plugin[o.length];
    for (int i = 0; i < o.length; i++)
      p[i] = (Plugin) o[i];*/
    Plugin[] p = (Plugin[]) plugins.toArray(new Plugin[0]);
    return p;
  }

  /**
   * Opens a new window.
   * @param args Parameters from command line
   */

  public static JextFrame newWindow(String args[])
  {
    return newWindow(args, true);
  }

  /**
   * Opens a new window.
   */

  public static JextFrame newWindow()
  {
    return newWindow(null, true);
  }

  /**
   * Opens a new window, but eventually does not show it.
   * @param args The command line arguments
   * @param toShow When true the frame is shown
   */

  //Note: until code doesn't need it, better leaving it only for the package.
  /*friendly*/ static JextFrame newWindow(String args[], boolean toShow)
  {
    synchronized (instances)
    {
      JextFrame window;
      if (toShow && builtTextArea != null)
      {
        if (args != null)
          for (int i = 0; i < args.length; i++)
            builtTextArea.open(args[i]);
        builtTextArea.setVisible(true);
        window = builtTextArea;
        builtTextArea = null;
      } else {
        window = new JextFrame(args, toShow);
        //if (toShow)
        instances.add(window);
      }

      return window;
    }
  }

  /**
   * Returns amount of opened Jext
   */

  public static int getWindowsCount()
  {
    return instances.size();
  }

  /**
   * Notify all instances of Jext and all properties listeners to reload properties.
   */

  public static void propertiesChanged()
  {
    // we send the event to all the listeners available
    for (int i = 0; i < instances.size(); i++)
      ((JextFrame) instances.get(i)).loadProperties();
  }

  /**
   * Notify all instances of Jext but the one which
   * saved the file to reload recent menu
   * @param The instance which saved a file
   */

  public static void recentChanged(JextFrame instance)
  {
    // we send the event to all the listeners available
    JextFrame listener;
    for (int i = 0; i < instances.size(); i++)
    {
      listener = (JextFrame) instances.get(i);
      if (listener != instance && listener != null)
        listener.reloadRecent();
    }
  }

  /**
   * Some external classes may need to notify
   * each instance of Jext. XTree does.
   * @return A ArrayList containing all instances of Jext
   */

  public static ArrayList getInstances()
  {
    return instances;
  }

  /**
   * Many methods will need to use a Toolkit.
   * This method simply avoid to write too many lines of
   * code.
   * @return The default Toolkit
   */

  public static Toolkit getMyToolkit()
  {
    return Toolkit.getDefaultToolkit();
  }

  /**
   * Jext startup directory is saved during execution.
   * @return Jext's startup directory
   */

  public static String getHomeDirectory()
  {
    return JEXT_HOME;
  }

  /**
   * Store the properties on the HD. After having
   * set up the properties, we need to store'em
   * in a file.
   * @deprecated Use saveXMLProps() instead
   */

  public static void saveProps()
  {
    if (usrProps != null)
    {
      try
      {
        OutputStream out = new FileOutputStream(usrProps);
        props.store(out, "Jext Properties");
        out.close();
      } catch (IOException io) { }
    }
  }

  /**
   * Saves the user's properties to a file using the XML specifications.
   * @param description is a String containing a little
   * description of the properties file. This String is stored on
   * topmost of the user's properties file. Can be set to
   * null.
   */

  public static void saveXMLProps(String description)
  {
    saveXMLProps(usrProps, description);
  }

  /**
   * Saves the user's properties to a file using the XML specifications.
   * @param userProps is the path to the file in which properties will
   * be stored. If it is set to null, properties are not
   * saved at all.
   * @param description is a String containing a little
   * description of the properties file. This String is stored on
   * topmost of the user's properties file. Can be set to
   * null.
   */

  public static void saveXMLProps(String userProps, String description)
  {
    if (userProps != null)
    {
      try
      {
        BufferedWriter out = new BufferedWriter(new FileWriter(userProps));

        String _out = new String("");
        out.write(_out, 0, _out.length());
        out.newLine();

        _out = new String("");
        out.write(_out, 0, _out.length());
        out.newLine();

        _out = "";
        out.write(_out, 0, _out.length());
        out.newLine();

        if (description == null)
          description = new String("Properties");
        description = "";
        out.write(description, 0, description.length());
        out.newLine();
        out.newLine();

        _out = new String("");
        out.write(_out, 0, _out.length());
        out.newLine();

        setProperty("properties.version", BUILD);

        char c = '\0';
        StringBuffer buf;
        Enumeration k = props.keys();
        Enumeration e = props.elements();
        for ( ; e.hasMoreElements(); )
        {
          buf = new StringBuffer("  ");
          //for (int i = 0; i < buf.length(); i++)
          //  out.write(buf.charAt(i));
          out.write(buf.toString(), 0, buf.length());
          out.newLine();
        }
        _out = new String("");
        out.write(_out, 0, _out.length());
        out.close();
      } catch (IOException io) { }
    }
    //JARClassLoader.saveDisabledList();
  }

  /**
   * The XPropertiesHandler needs to get Jext's
   * Properties object to achieve its purpose.
   * @return The current Properties object
   */

  public static Properties getProperties()
  {
    return props;
  }

  /**
   * Load a set of properties from an XML file.
   * This method, and not the caller, will search for the translated version of the XML.
   * @param in An InputStream is specified to load properties from a JAR file
   * @param fileName The XML filename
   */

  public static void loadXMLProps(InputStream in, String fileName)
  {
    XPropertiesReader.read(in, fileName);
  }
  
  /**
   * Load a set of properties from an XML file.
   * It is provided for when the caller already provides the translated file(for instance for the plugin
   * translation); in this case toTranslate must be true, otherwise it will be translated the default way.
   * @param in An InputStream is specified to load properties from a JAR file
   * @param fileName The XML filename
   * @since Jext3.2pre1
   */
   
  public static void loadXMLProps(InputStream in, String fileName, boolean toTranslate)
  {
    XPropertiesReader.read(in, fileName, toTranslate);
  }

  /**
   * Load a set of actions from an XML file.
   * @param in An InputStream is specified to load properties from a JAR file
   * @param fileName The XML filename
   */

  public static void loadXMLActions(InputStream in, String fileName)
  {
    PyActionsReader.read(in, fileName);
  }

  /**
   * Load a set of actions from an XML file.
   * @param in An InputStream is specified to load properties from a JAR file
   * @param fileName The XML filename
   */

  public static void loadXMLOneClickActions(InputStream in, String fileName)
  {
    OneClickActionsReader.read(in, fileName);
  }

  /**
   * Returns an input stream corresponding to selected language.
   * @param in The default stream
   * @param fileName The requested file
   */

  public static InputStream getLanguageStream(InputStream in, String fileName)
  {
    ZipEntry entry;
    if (languagePack != null && (entry = languagePackContains(fileName)) != null)
    {
      try
      {
        return languagePack.getInputStream(entry);
      } catch (IOException ioe) {
        return in;
      }
    } else
      return in;
  }

  // returns a non-null ZipEntry object if current language pack
  // contains requested file

  public static ZipEntry languagePackContains(String fileName)
  {
    for (int i = 0; i < languageEntries.size(); i++)
    {
      ZipEntry entry = (ZipEntry) languageEntries.get(i);
      if (entry.getName().equalsIgnoreCase(fileName))
        return entry;
    }

    return null;
  }

  /**
   * Load a set of properties.
   * @param in An InputStream is specified to load properties from a JAR file
   * @deprecated Maintained only for plugins compliance. Use loadXMLProps()
   * instead of this method.
   */

  public static void loadProps(InputStream in)
  {
    try
    {
      props.load(new BufferedInputStream(in));
      in.close();
    } catch (IOException ioe) { }
  }

  /**
   * Creates the necessary directories.
   */

  public static void initDirectories()
  {
    File dir = new File(SETTINGS_DIRECTORY);
    if (!dir.exists())
    {
      dir.mkdir();

      dir = new File(SETTINGS_DIRECTORY + "plugins" + File.separator);
      if (!dir.exists())
        dir.mkdir();

      dir = new File(SETTINGS_DIRECTORY + "scripts" + File.separator);
      if (!dir.exists())
        dir.mkdir();

      dir = new File(SETTINGS_DIRECTORY + "xinsert" + File.separator);
      if (!dir.exists())
        dir.mkdir();
    }
  }

  /**
   * Init the properties.
   */

  public static void initProperties()
  {
    usrProps = SETTINGS_DIRECTORY + ".jext-props.xml";
    defaultProps = props = new Properties();

    /////////////////////////////////////////////////////////////////
    // DEPRECATED BY THE METHOD loadXMLProps()
    /////////////////////////////////////////////////////////////////
    //    loadProps(Jext.class.getResourceAsStream("jext-gui.keys"));
    //    loadProps(Jext.class.getResourceAsStream("jext-gui.text"));
    //    loadProps(Jext.class.getResourceAsStream("jext.props"));
    //    loadProps(Jext.class.getResourceAsStream("jext.tips"));
    /////////////////////////////////////////////////////////////////

    // loads specified language pack
    File lang = new File(SETTINGS_DIRECTORY + ".lang");

    if (lang.exists())
    {
      try
      {
        BufferedReader reader = new BufferedReader(new FileReader(lang));
        String language = reader.readLine();
        reader.close();

        if (language != null && !language.equals("English"))
        {
          File langPack = new File(JEXT_HOME + File.separator + "lang" +
                                               File.separator + language + "_pack.jar");
          if (langPack.exists())
          {
            languagePack = new ZipFile(langPack);
            languageEntries = new ArrayList();
            Enumeration entries = languagePack.entries();

            while (entries.hasMoreElements())
              languageEntries.add(entries.nextElement());

            setLanguage(language);
          } else
            lang.delete();
        }
      } catch (IOException ioe) { }
    }

    //loadXMLProps(Jext.class.getResourceAsStream("jext.props.xml"), "jext.props.xml");
    loadXMLProps(Jext.class.getResourceAsStream("jext-text.props.xml"), "jext-text.props.xml");
    loadXMLProps(Jext.class.getResourceAsStream("jext-keys.props.xml"), "jext-keys.props.xml");
    loadXMLProps(Jext.class.getResourceAsStream("jext-defs.props.xml"), "jext-defs.props.xml");
    loadXMLProps(Jext.class.getResourceAsStream("jext-tips.props.xml"), "jext-tips.props.xml");

    Properties pyProps = new Properties();
    pyProps.put("python.cachedir", SETTINGS_DIRECTORY + "pythoncache" + File.separator);
    PythonInterpreter.initialize(System.getProperties(), pyProps, new String[0]);

    initPlugins();

    if (usrProps != null)
    {
      props = new Properties(defaultProps);

      try
      {
        loadXMLProps(new FileInputStream(USER_PROPS), ".jext-props.xml");

        if (DELETE_OLD_SETTINGS)
        {
          String pVersion = getProperty("properties.version");
          if (pVersion == null || BUILD.compareTo(pVersion) > 0)
          {
            File userSettings = new File(USER_PROPS);
            if (userSettings.exists())
            {
              userSettings.delete();
              defaultProps = props = new Properties();
              //loadXMLProps(Jext.class.getResourceAsStream("jext.props.xml"), "jext.props.xml");
              loadXMLProps(Jext.class.getResourceAsStream("jext-text.props.xml"), "jext-text.props.xml");
              loadXMLProps(Jext.class.getResourceAsStream("jext-keys.props.xml"), "jext-keys.props.xml");
              loadXMLProps(Jext.class.getResourceAsStream("jext-defs.props.xml"), "jext-defs.props.xml");
              loadXMLProps(Jext.class.getResourceAsStream("jext-tips.props.xml"), "jext-tips.props.xml");
              JARClassLoader.reloadPluginsProperties();
              props = new Properties(defaultProps);
            }
          }
        }

      } catch (FileNotFoundException fnfe) {
      } catch (IOException ioe) { }
    }

    initModes(); //must be here since the user can change the mode filters.
    Search.load();

    if (Utilities.JDK_VERSION.charAt(2) >= '4')
    {
      try
      {
        Class cl = Class.forName("org.jext.JavaSupport");
        Method m = cl.getMethod("initJavaSupport", new Class[0]);
        if (m !=  null)
          m.invoke(null, new Object[0]);
      } catch (Exception e) { }
    }

    // Add our protocols to java.net.URL's list
    System.getProperties().put("java.protocol.handler.pkgs", "org.jext.protocol|" +
                               System.getProperty("java.protocol.handler.pkgs", ""));

    initActions();
    JARClassLoader.initPlugins();
    initUI();
    sortModes();

    assocPluginsToModes();
  }

  /**
   * Sets the current selected language.
   * @param lang The label of the language
   */

  public static void setLanguage(String lang)
  {
    language = lang;
  }

  /**
   * Returns current selected language.
   */

  public static String getLanguage()
  {
    return language;
  }

  /**
   * Execute scripts found in user home directory.
   */

  public static void executeScripts(JextFrame parent)
  {
    String dir = SETTINGS_DIRECTORY + "scripts" + File.separator;
    String[] scripts = Utilities.getWildCardMatches(dir, "*.jext-script", false);
    if (scripts == null)
      return;

    for (int i = 0; i < scripts.length; i++)
      org.jext.scripting.dawn.Run.runScript(dir + scripts[i], parent, false);

    scripts = Utilities.getWildCardMatches(dir, "*.py", false);
    if (scripts == null)
      return;

    for (int i = 0; i < scripts.length; i++)
      org.jext.scripting.python.Run.runScript(dir + scripts[i], parent);
  }

  // sort modes alphabetically

  private static void sortModes()
  {
    String[] modeNames = new String[modes.size()];
    for (int i = 0; i < modeNames.length; i++)
      modeNames[i] = ((Mode) modes.get(i)).getUserModeName();
    Arrays.sort(modeNames);

    ArrayList v = new ArrayList(modeNames.length);

    for (int i = 0; i < modeNames.length; i++)
    {
      int j = 0;
      String name = modeNames[i];

      while (!((Mode) modes.get(j)).getUserModeName().equals(name))
      {
        if (j == modes.size() - 1)
          break;
        else
          j++;
      }

      v.add(modes.get(j));
    }

    modes = v;
    v = null;
  }

  // changes some default UI settings such as trees leaf icons or font size and style...

  private static void initUI()
  {
    /*if (getBooleanProperty("useJextTheme"))
      MetalLookAndFeel.setCurrentTheme(new JextMetalTheme());*/
    SkinManager.applySelectedSkin();

    // check if menus are flat or not
    flatMenus = getBooleanProperty("flatMenus");
    // check if buttons are highlighted or not
    buttonsHighlight = getBooleanProperty("buttonsHighlight");
    // rollover
    JextButton.setRollover(getBooleanProperty("toolbarRollover"));
  }

  /**
   * Initialize syntax colorizing modes.
   */

  private static void initModes()
  {
    StringTokenizer _tok = new StringTokenizer(getProperty("jext.modes"), " ");
    Mode _mode;
    modes = new ArrayList(_tok.countTokens());
    modesFileFilters = new ArrayList(_tok.countTokens());

    for ( ; _tok.hasMoreTokens(); )
    {
      modes.add(_mode = new Mode(_tok.nextToken()));
      modesFileFilters.add(new ModeFileFilter(_mode));
    }
  }

  /**
   * Returns the mode according to its name.
   */

  public static Mode getMode(String modeName)
  {
    for (int i = 0; i < modes.size(); i++)
    {
      Mode _mode = (Mode) modes.get(i);
      if (_mode.getModeName().equalsIgnoreCase(modeName))
        return _mode;
    }

    return null;
  }

  /**
   * Returns modes list.
   */

  public static ArrayList getModes()
  {
    return modes;
  }

  /**
   * Adds a mode to Jext's syntax colorizing modes list
   */

  public static void addMode(Mode mode)
  {
    modes.add(mode);
    modesFileFilters.add(new ModeFileFilter(mode));
  }

  /**
   * Set a property.
   * @param name Property's name
   * @param value The value to store as name
   */

  public static void setProperty(String name, String value)
  {
    if (name == null || value == null)
      return;
    props.put(name, value);
  }

  /**
   * Returns true if the property value equals to "on" or "true"
   * @param name The name of the property to read
   */

  public static boolean getBooleanProperty(String name)
  {
    String p = getProperty(name);
    if (p == null)
      return false;
    else
      return p.equals("on") || p.equals("true");
  }

  /**
   * Returns true if the property value equals to "on" or "true"
   * @param name The name of the property to read
   */

  public static boolean getBooleanProperty(String name, String def)
  {
    String p = getProperty(name, def);
    if (p == null)
      return false;
    else
      return p.equals("on") || p.equals("true");
  }

  /**
   * If we store properties, we need to read them, too !
   * @param name The name of the property to read
   * @return The value of the specified property
   */

  public static String getProperty(String name)
  {
    return props.getProperty(name);
  }

  /**
   * Fetches a property, returning the default value if it's not
   * defined.
   * @param name The property
   * @param def The default value
   */

  public static final String getProperty(String name, String def)
  {
    return props.getProperty(name, def);
  }

  /**
   * Returns the property with the specified name, formatting it with
   * the java.text.MessageFormat.format() method.
   * @param name The property
   * @param args The positional parameters
   */

  public static final String getProperty(String name, Object[] args)
  {
    if (name == null)
      return null;

    if (args == null)
      return props.getProperty(name, name);
    else
      return MessageFormat.format(props.getProperty(name, name), args);
  }

  /**
   * Unsets (clears) a property.
   * @param name The property
   */

  public static void unsetProperty(String name)
  {
    if (defaultProps.get(name) != null)
      props.put(name, "");
    else
      props.remove(name);
  }

  /**
   * Exits Jext by closing all the windows. If backgrounding, it doesn't kill the jext server.
   * This is synchronized because creating two windows at a time can be problematic.
   */

  public static void exit()
  {
    synchronized (instances)
    {
      Object[] o = instances.toArray();

      for (int i = o.length - 1; i >= 0; i--)
      {
        JextFrame instance = ((JextFrame) o[i]);
        /*if (i == 0)
        {
          instance.fireJextEvent(JextEvent.KILLING_JEXT);
          if (!isRunningBg())
            stopPlugins();
        } else
          instance.fireJextEvent(JextEvent.CLOSE_WINDOW);*/
        closeToQuit(instance);
      }
      /*if (isRunningBg())
      {
        builtTextArea = newWindow(null, false);
        //instances.add(builtTextArea);
      } else
        finalCleanupBeforeExit();*/
    }
  }

  /**
   * Do the final cleanup that must be done at the real end of the session(when closing the server if
   * running background server, or after killing the last window if no server is running).
   */
   
  /* friendly*/  static void finalCleanupAndExit() {
    //currently it does almost nothing, but it's used.
    System.exit(0);
  }
  /**
   * Stop plugins.
   */
  /* friendly */ static void stopPlugins() {
    Plugin[] plugins = getPlugins();
    for (int i = 0; i < plugins.length; i++)
      try
      {
        plugins[i].stop();
      } catch (Throwable t) {
        System.err.println("#--An exception has occurred while stopping plugin:");
        t.printStackTrace();
      }
  }

  /**
   * Close a {@link JextFrame} by calling {@link JextFrame#closeToQuit()} and if it it the last window and we are not keeping the server open
   * we close Jext completely.
   */
  public static void closeToQuit(JextFrame frame) {
    closeToQuit(frame,false);
  }
  
  //For JextLoader when it's killing Jext
  /*friendly*/ static void closeToQuit(JextFrame frame, boolean isKillingServer) {
    if (isKillingServer)
      runInBg = false;//so when calling closeWindow(frame), which will happen, it will close completely Jext
    //and stop plugins.
    frame.closeToQuit();
  }
  
  public static void closeWindow(JextFrame frame) {
    synchronized (instances)
    {
      if (getWindowsCount() == 1/* && !isRunningBg()*/)
        frame.fireJextEvent(JextEvent.KILLING_JEXT);
      else
        frame.fireJextEvent(JextEvent.CLOSING_WINDOW);
      frame.closeWindow();

      if (getWindowsCount() == 0)
      {
        if (!isRunningBg())
          stopServer();

        Search.save();

        if (!isRunningBg())
          stopPlugins();

        frame.saveConsole();
        GUIUtilities.saveGeometry(frame, "jext");
        saveXMLProps("Jext v" + Jext.RELEASE + " b" + Jext.BUILD);
        //frame.cleanMemory();
        frame = null;
        System.gc();//this way, the garbage collector should do its work, without any NullPointerEx at all.

        if (isRunningBg())
          builtTextArea = newWindow(null, false);
        else
          System.exit(0);
      }
    }
  }

  /**
   * Returns splash screen
   */

  public static SplashScreen getSplashScreen()
  {
    return splash;
  }

  /**
   * Set the splash screen progress value after
   * having checked if it isn't null (in case of a new window).
   * @param val The new value
   */

  public static void setSplashProgress(int val)
  {
    if (splash != null)
      splash.setProgress(val);
  }

  /**
   * Set the splash screen text value after having checked if it
   * isn't null (in case of a new window).
   * @param text The new text
   */

  public static void setSplashText(String text)
  {
    if (splash != null)
      splash.setText(text);
  }

  /**
   * Kills splash screen
   */

  public static void killSplashScreen()
  {
    if (splash != null)
    {
      splash.dispose();
      splash = null;
    }
  }

  /**
   * Stops the Jext server which loads every Jext instance in the same JVM.
   */

  public static void stopServer()
  {
    if (jextLoader != null)
    {
      jextLoader.stop();
      jextLoader = null;
    }
  }

  /**
   * Returns true if the server is enabled.
   */

  public static boolean isServerEnabled()
  {
    return isServerEnabled;
  }

  /**
   * Returns true if the backgrounding is enabled.
   */

  public static boolean isDefaultKeepInMemory() {
    return defaultKeepInMemory;
  }

  public static void setDefaultKeepInMemory(boolean val) {
    defaultKeepInMemory = val;
    if (val) //TODO:hack to active it from this session onwards
    {
    }
  }
  /**
   * Used by security options panel to remember of the server status.
   * @param on If true, the server will be runned at next start
   */

  public static void setServerEnabled(boolean on)
  {
    isServerEnabled = on;
  }

  /**
   * Attempts to load Jext in a single JVM instance only. If this instance of
   * Jext is the very first to be loaded, then a ServerSocket is opened. Otherwise,
   * this instance attemps to connect on to a specific socket port to tell other
   * Jext instance to create a new window. This avoids to load on JVM for each
   * launch of Jext. Opened port is securised so that no security hole is created.
   * @param args The arguments of the new Jext window
   */

  public static void loadInSingleJVMInstance(String[] args)
  {
    try
    {
      File security = new File(SETTINGS_DIRECTORY + ".security");
      if (!security.exists())
        isServerEnabled = true;
      else
      {
        BufferedReader reader = new BufferedReader(new FileReader(security));
        isServerEnabled = new Boolean(reader.readLine()).booleanValue();
        reader.close();
      }
    } catch (IOException ioe) { }
    
    if (!isServerEnabled && !runInBg)
      return;

    File authorizationKey = new File(SETTINGS_DIRECTORY + ".auth-key");

    // if the authorization key exists, another Jext instance may
    // be running
    if (authorizationKey.exists())
    {
      // we attempt to log onto the other instance of Jext(but only if we are not backgrounding; no
      // more than one bg instance is started, and if we are bg we don't pass anything to the other instance.
      try
      {
        BufferedReader reader = new BufferedReader(new FileReader(authorizationKey));
        int port = Integer.parseInt(reader.readLine());
        String key = reader.readLine();
        reader.close();
      
        Socket client = new Socket("127.0.0.1", JEXT_SERVER_PORT + port);
      
        if (!runInBg)
        { //now that we made sure that the other instance exists, if backgrounding we do
          //nothing
          PrintWriter writer = new PrintWriter(client.getOutputStream());
      
          StringBuffer _args = new StringBuffer();
          if (goingToKill)
          {
            _args.append("kill");
          } else {
            _args.append("load_jext:");
            for (int i = 0; i < args.length; i++)
            {
              _args.append(args[i]);
              if (i != args.length - 1)
                _args.append('?');
            }
          }
          _args.append(':').append(key);
      
          writer.write(_args.toString());
          writer.flush();
          writer.close();
        } else
          System.out.println("Jext is already running, either in background or foreground.");

        client.close();

        System.exit(5);
      } catch (Exception e) {
        // no other jext instance is running, we delete the auth. file
        authorizationKey.delete();
        if (goingToKill) {
          System.err.println("No jext instance found!");
          System.exit(0);
        } else
          jextLoader = new JextLoader();
      }
    } else if (!goingToKill) {
      jextLoader = new JextLoader();
    } else {
      System.err.println("No jext instance found!");
      System.exit(0);
    }
  }

  /**
   * As Jext can be runned in background mode, some operations may need to know wether
   * or not current instance is "up" or "crouched". This is the purpose of this method.
   * @return A true boolean value is returned whenever Jext is running in background mode
   */

  public static boolean isRunningBg()
  {
    return runInBg;
  }

  // check the command line arguments

  private static String[] parseOptions(String [] args)
  {
    // Trap bg flag
    int argLn = args.length;
    ArrayList newArgs = new ArrayList(argLn);

    //First, it checks defaults: if the user actived -showbg by default, read this setting.
    try
    {
      File showbg = new File(SETTINGS_DIRECTORY + ".showBg");
      if (!showbg.exists())
        keepInMemory = false;
      else
      {
        BufferedReader reader = new BufferedReader(new FileReader(showbg));
        keepInMemory = new Boolean(reader.readLine()).booleanValue();
        reader.close();
      }
    } catch (IOException ioe) { }
    defaultKeepInMemory = runInBg = keepInMemory;
    
    //Then, let's read options.
    for (int i = 0; i < argLn; i++)
    {
      //Whenever it encounter an option it resets all contrary ones.
      if ("-bg".equals(args[i]))
      {
        runInBg = true;

        keepInMemory = false;
        goingToKill = false;
      }
      else if ("-kill".equals(args[i]))
      {
        goingToKill = true;

        keepInMemory = false;
        runInBg = false;
      }
      else if ("-showbg".equals(args[i]))
      {
        runInBg = true;
        keepInMemory = true;

        goingToKill = false;
      }
      //This option is unrelated.
      else if ("-debug".equals(args[i]))
        DEBUG = true;
      else
        newArgs.add(args[i]);
    }

    return (String[]) newArgs.toArray(new String[0]);
  }

  //////////////////////////////////////////////////////////////////////////////////////////////
  // END OF STATIC PART
  //////////////////////////////////////////////////////////////////////////////////////////////
  // MAIN ENTRY POINT
  //////////////////////////////////////////////////////////////////////////////////////////////

  /**
   * Start method. Load the property file, set the look and feel, create a new GUI,
   * load the options. If a file name is specified as first argument, we pass it
   * to the window contructor which will construct its full path (because you can
   * specify, for example, ..\..\test.java or ~\jext.props or ...../hello.cpp -
   * both / and \ can be used -)
   */

  public static void main(String args[])
  {
    ///////////////////////////////// DEBUG
    System.setErr(System.out);

    initDirectories();
    args = parseOptions(args);
    synchronized (instances)
    {
      loadInSingleJVMInstance(args);
      initProperties();

      if (!isRunningBg())
      {
        splash = new SplashScreen();
        newWindow(args);
      } else {
        if (keepInMemory)
          splash = new SplashScreen();

        //FIXME:maybe it should ignore arguments when backgrounding.
        builtTextArea = newWindow(args, false);

        if (keepInMemory)
          newWindow(null, true);
      }
    }

    if (getBooleanProperty("check"))
      check = new VersionCheck();
  }
}

// End of Jext.java
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.