products/Sources/formale Sprachen/Isabelle/Tools/jEdit/dist/jEdit/org/gjt/sp/jedit image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: EditBus.java   Sprache: JAVA

Original von: Isabelle©

/*
 * EditBus.java - The EditBus
 * :tabSize=4:indentSize=4:noTabs=false:
 * :folding=explicit:collapseFolds=1:
 *
 * Copyright (C) 1999 Slava Pestov
 *
 * 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.gjt.sp.jedit;

import java.awt.*;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.List;

import org.gjt.sp.util.Log;
import org.gjt.sp.util.ThreadUtilities;

/**
 * jEdit's global event notification mechanism.<p>
 *
 * Plugins register with the EditBus to receive messages reflecting
 * changes in the application's state, including changes in buffers,
 * views and edit panes, changes in the set of properties maintained
 * by the application, and the closing of the application.<p>
 *
 * The EditBus maintains a list of objects that have requested to receive
 * messages. When a message is sent using this class, all registered
 * components receive it in turn. Classes for objects that subscribe to
 * the EditBus must implement the {@link EBComponent} interface, which
 * defines the single method {@link EBComponent#handleMessage(EBMessage)}.<p>
 *
 * Alternatively, since jEdit4.3pre19, EditBus components can be any
 * object. Handlers for EditBus messages are created by annotating
 * methods with the {@link EBHandler} annotation. Such methods should
 * expect a single parameter - an edit bus message of any desired type.
 * If a message matching the type (or any of its super-types, unless the
 * annotation requests exact type matching) is being sent, the annotated
 * method will be called instead of the default {@link
 * EBComponent#handleMessage(EBMessage)}. If a handler exists for a
 * specific message type, the default handler will not be called.<p>
 *
 * A plugin core class that extends the
 * {@link EBPlugin} abstract class (and whose name ends with
 * <code>Plugin</code> for identification purposes) will automatically be
 * added to the EditBus during jEdit's startup routine.  Any other
 * class - for example, a dockable window that needs to receive
 * notification of buffer changes - must perform its own registration by calling
 * {@link #addToBus(Object)} during its initialization.
 * A convenient place to register in a class derived from <code>JComponent</code>
 * would be in an implementation of the <code>JComponent</code> method
 * <code>addNotify()</code>.<p>
 *
 * Message types sent by jEdit can be found in the
 * {@link org.gjt.sp.jedit.msg} package.<p>
 *
 * Plugins can also send their own messages - any object can send a message to
 * the EditBus by calling the static method {@link #send(EBMessage)}.
 * Most plugins, however, only concern themselves with receiving, not
 * sending, messages.
 *
 * @see org.gjt.sp.jedit.EBComponent
 * @see org.gjt.sp.jedit.EBMessage
 *
 * @author Slava Pestov
 * @author John Gellene (API documentation)
 * @version $Id: EditBus.java 24044 2015-09-03 13:34:54Z daleanson $
 *
 * @since jEdit 2.2pre6
 */

public class EditBus
{

 //{{{ EBHandler annotation
 /**
 * This annotation should be used in methods that are to be
 * considered "edit bus message handlers". When registering
 * an object using {@link #addToBus(Object)}, all methods
 * tagged with this annotation will be considered as handlers
 * for specific edit bus messages.<p>
 *
 * Each method should expect a single argument (an object of
 * some type derived from EBMessage, inclusive). When
 * delivering an EBMessage, the bus will search for and invoke
 * all handlers matching the outgoing message type.<p>
 *
 * Since jEdit 4.4pre1, this annotation can also be added to
 * classes extending EditPlugin. This will make the plugin
 * be added to the bus automatically, similarly to how
 * EBPlugin works, but without having to implement the
 * EBComponent interface.
 *
 * @since jEdit 4.3pre19
 */

 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE, ElementType.METHOD})
 public static @interface EBHandler
 {
  /**
 * @return Whether the message should match the exact type of
 * the parameter, instead of a compatible type.
 */

  boolean exact() default false;
 } //}}}

 //{{{ addToBus() method
 /**
 * Adds a component to the bus. It will receive all messages sent
 * on the bus.
 *
 * @param comp The component to add
 */

 public static void addToBus(EBComponent comp)
 {
  addToBus((Object)comp);
 } //}}}

 //{{{ addToBus() method
 /**
 * Adds a component to the bus. Methods annotated with the
 * {@link EBHandler} annotation found in the component will
 * be used as EditBus message handlers if a message of a
 * matching type is sent on the bus.<p>
 *
 * If the component implements {@link EBComponent}, then the
 * {@link EBComponent#handleMessage(EBMessage)} method will be
 * called for every message sent on the bus.
 *
 * @param comp The component to add
 *
 * @since jEdit 4.3pre19
 */

 public static void addToBus(Object comp)
 {
  components.addComponent(comp);
 } //}}}

 //{{{ removeFromBus() method
 /**
 * Removes a component from the bus.
 * @param comp The component to remove
 */

 public static void removeFromBus(EBComponent comp)
 {
  removeFromBus((Object) comp);
 } //}}}

 //{{{ removeFromBus() method
 /**
 * Removes a component from the bus.
 * @param comp The component to remove
 * @since 4.3pre19
 */

 public static void removeFromBus(Object comp)
 {
  components.removeComponent(comp);
 } //}}}

 //{{{ send() method
 /**
 * Sends a message to all components on the bus in turn.
 * The message is delivered to components in the AWT thread,
 * and this method will wait until all handlers receive the
 * message before returning.
 * <p>
 * This method uses {@link ThreadUtilities#runInDispatchThreadNow},
 * read the notes there for possible deadlocks.
 *
 * <p><b>NOTE:</b>
 * If the calling thread is not the AWT thread and the
 * thread is interrupted before or while the call of this
 * method, this method can return before completion of handlers.
 * However, the interruption state is set in this case, so the
 * caller can detect the interruption after the call. If you
 * really need the completion of handlers, you should make sure
 * the call is in the AWT thread or the calling thread is never
 * interrupted. If you don't care about the completion of
 * handlers, it is recommended to use
 * {@link #sendAsync(EBMessage)} instead.
 * </p>
 *
 * @param message The message
 */

 public static void send(EBMessage message)
 {
  Runnable sender = new SendMessage(message);

  if (EventQueue.isDispatchThread())
  {
   sender.run();
  }
  else
  {
   ThreadUtilities.runInDispatchThreadNow(sender);
  }
 } //}}}

 //{{{ sendAsync() method
 /**
 * Schedules a message to be sent on the edit bus as soon as
 * the AWT thread is done processing current events. The
 * method returns immediately (i.e., before the message is
 * sent).
 *
 * @param message The message
 *
 * @since jEdit 4.4pre1
 */

 public static void sendAsync(EBMessage message)
 {
  EventQueue.invokeLater(new SendMessage(message));
 } //}}}

 //{{{ Private members
 private static final HandlerList components = new HandlerList();

 // can't create new instances
 private EditBus() {}

 //{{{ dispatch() method
 private static void dispatch(EBMessageHandler emh,
         EBMessage msg)
  throws Exception
 {
  if (emh.handler != null && emh.comp != null)
   emh.handler.invoke(emh.comp, msg);
  else
  {
   assert (emh.comp instanceof EBComponent);
   ((EBComponent)emh.comp).handleMessage(msg);
  }
 } //}}}

 //{{{ sendImpl() method
 private static void sendImpl(EBMessage message)
 {
  boolean isExact = true;
  Class<?> type = message.getClass();
  while (!type.equals(Object.class))
  {
   List<EBMessageHandler> handlers = components.get(type);
   if (handlers != null)
   {
    try
    {
     for (EBMessageHandler emh : handlers)
     {
      if (!isExact &&
          emh.source != null &&
          emh.source.exact())
      {
       continue;
      }
      if(Debug.EB_TIMER)
      {
       long start = System.nanoTime();
       dispatch(emh, message);
       long time = System.nanoTime() - start;
       if(time >= 1000000)
       {
        Log.log(Log.DEBUG,EditBus.class,emh.comp + ": " + time + " ns");
       }
      }
      else
       dispatch(emh, message);
     }
    }
    catch (InvocationTargetException t)
    {
     Log.log(Log.ERROR,EditBus.class,"Exception"
      + " while sending message on EditBus:");
     Log.log(Log.ERROR, EditBus.class, t.getCause());
    }
    catch(Throwable t)
    {
     Log.log(Log.ERROR,EditBus.class,"Exception"
      + " while sending message on EditBus:");
     Log.log(Log.ERROR,EditBus.class,t);
    }
   }
   type = type.getSuperclass();
   isExact = false;
  }
 } //}}}

 //}}}

 //{{{ EBMessageHandler class
 private static class EBMessageHandler
 {

  EBMessageHandler(Object comp,
     Method handler,
     EBHandler source)
  {
   this.comp = comp;
   this.handler = handler;
   this.source = source;
  }

  Object comp;
  Method handler;
  EBHandler source;
 } //}}}

 //{{{ HandlerList class
 /**
 * A "special" hash map that has some optimizations for use by
 * the EditBus. Notably, it allows setting a "read only" mode
 * where modifications to the map are postponed until the map
 * is unlocked.
 */

 private static class HandlerList
  extends HashMap<Class<?>, List<EBMessageHandler>>
 {

  public List<EBMessageHandler> safeGet(Class<?> type)
  {
   List<EBMessageHandler> lst = super.get(type);
   if (lst == null) {
    lst = new LinkedList<EBMessageHandler>();
    super.put(type, lst);
   }
   return lst;
  }


  public synchronized void lock()
  {
   lock++;
  }


  public synchronized void unlock()
  {
   lock--;
   if (lock == 0)
   {
    for (Object comp : add)
     addComponent(comp);
    for (Object comp : remove)
     removeComponent(comp);
    add.clear();
    remove.clear();
   }
  }


  public synchronized void removeComponent(Object comp)
  {
   if (lock != 0)
   {
    remove.add(comp);
    return;
   }

   for (Map.Entry<Class<?>, List<EBMessageHandler>> entry: entrySet())
   {
    Class<?> msg = entry.getKey();
    List<EBMessageHandler> handlers = entry.getValue();
    if (handlers == null)
     continue;
    for (Iterator<EBMessageHandler> it = handlers.iterator();
         it.hasNext(); )
    {
     EBMessageHandler emh = it.next();
     if (emh.comp == comp)
      it.remove();
    }
   }
  }


  public synchronized void addComponent(Object comp)
  {
   if (lock != 0)
   {
    add.add(comp);
    return;
   }

   for (Method m : comp.getClass().getMethods())
   {
    EBHandler source = m.getAnnotation(EBHandler.class);
    if (source == null)
     continue;

    Class[] params = m.getParameterTypes();

    if (params.length != 1)
    {
     Log.log(Log.ERROR, EditBus.class,
      "Invalid EBHandler method " + m.getName() +
      " in class " + comp.getClass().getName() +
      ": too many parameters.");
     continue;
    }

    if (!EBMessage.class.isAssignableFrom(params[0]))
    {
     Log.log(Log.ERROR, EditBus.class,
      "Invalid parameter " + params[0].getName() +
      " in method " + m.getName() +
      " of class " + comp.getClass().getName());
     continue;
    }

    synchronized (components)
    {
     safeGet(params[0]).add(new EBMessageHandler(comp, m, source));
    }
   }

   /*
 * If the component implements EBComponent, then add the
 * default handler for backwards compatibility.
 */

   if (comp instanceof EBComponent)
    safeGet(EBMessage.class).add(new EBMessageHandler(comp, nullnull));
  }


  private int lock;
  private List<Object> add = new LinkedList<Object>();
  private List<Object> remove = new LinkedList<Object>();
 } //}}}

 //{{{ SendMessage class
 private static class SendMessage implements Runnable
 {

  public SendMessage(EBMessage message)
  {
   this.message = message;
  }


  public void run()
  {
   Log.log(Log.DEBUG,EditBus.class,message.toString());

   components.lock();
   try
   {
    sendImpl(message);
   }
   finally
   {
    components.unlock();
   }
  }

  private EBMessage message;
 } //}}}

}

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤





Download des
Quellennavigators
Download des
sprechenden Kalenders

in der Quellcodebibliothek suchen




Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.


Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.


Bot Zugriff