Package org.knopflerfish.bundle.desktop.swing.fwspin

Source Code of org.knopflerfish.bundle.desktop.swing.fwspin.SX

/*
* Copyright (c) 2003, KNOPFLERFISH project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
*   notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
*   copyright notice, this list of conditions and the following
*   disclaimer in the documentation and/or other materials
*   provided with the distribution.
*
* - Neither the name of the KNOPFLERFISH project nor the names of its
*   contributors may be used to endorse or promote products derived
*   from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.knopflerfish.bundle.desktop.swing.fwspin;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.CubicCurve2D;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.Vector;

import javax.swing.JPanel;

import org.knopflerfish.bundle.desktop.swing.Activator;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;

/**
* @author Erik Wistrand
*/
public class Spin extends JPanel implements Runnable, BundleListener, ServiceListener {

  Thread   runner = null;
  boolean  bRun   = false;

  long delay      = 30;
  long targetTime = 1000 / 30;
  long updateTime = 0;
  long totalTime = 0;

  Dimension  size     = null;

  Image      memImage = null;
  Graphics   memG     = null;

  boolean bShowFrameRate    = false;
  boolean bShowBundleLegend = true;
  boolean use2D             = true;
  boolean bShowBundleInfo   = false;
  boolean bShowHelp         = false;
  boolean bShowDeps         = false;
  boolean bStepSize         = false;

  double deltaA = Math.PI * 1.5;
  double aStep  = Math.PI * 2 / 120;

  Map bundles  = new TreeMap();
  Map services = new HashMap();
  Map active   = new HashMap();

  Object paintLock = services;


  double fontSize = 1.0;

  Object alphaHalf = null;

  String searchString = "";
  boolean bSearchMode = false;

  Console console;

  public KeyListener kl = null;

  Color bgColor   = new Color(20, 20, 80);
  Color textColor = bgColor.brighter().brighter().brighter();

  public Spin() {
    super();

    /*
    System.out.println("made spin");
    addFocusListener(new FocusAdapter() {
        public void focusGained(FocusEvent e) {
          System.out.println("got focus");
        }
        public void focusLost(FocusEvent e) {
          System.out.println("lost focus");
        }
      });
    */

    Bundle[] bl = Activator.getTargetBC_getBundles();
    for(int i = 0; bl != null && i < bl.length; i++) {
      bundleChanged(new BundleEvent(BundleEvent.INSTALLED, bl[i]));
    }
    Activator.getTargetBC().addBundleListener(this);

    try {
      ServiceReference [] srl = Activator.getTargetBC_getServiceReferences();
      for(int i = 0; srl != null && i < srl.length; i++) {
        serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, srl[i]));
      }
      Activator.getTargetBC().addServiceListener(this, null);
    } catch (Exception e) {
      e.printStackTrace();
    }

    initFonts();

    addMouseMotionListener(new MouseMotionAdapter() {
        public void mouseDragged(MouseEvent ev) {
        }
        public void mouseMoved(MouseEvent ev) {
          hotX = ev.getX();
          hotY = ev.getY();
          setActive(ev.getX(), ev.getY());
          if(mouseActive != null && (mouseActive instanceof BX)) {
            BX bx = (BX)mouseActive;
            Activator.desktop.setSelected(bx.b);
          }
        }
      });

    addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent ev) {
          requestFocus();
          hotX = ev.getX();
          hotY = ev.getY();
          setActive(ev.getX(), ev.getY());
          if(mouseActive != null && (mouseActive instanceof BX)) {
            BX bx = (BX)mouseActive;
            Activator.desktop.setSelected(bx.b);
          }
        }
      });

    center = new SpinItem() {
        public void    paint(Graphics g) { };
        public void    paintDependencies(Graphics g) { };
        public void    paintInfo(Graphics g, double x, double y) { };
        public boolean isActive() { return false; }
      };

    addKeyListener(kl = new KeyAdapter() {
        public void keyPressed(KeyEvent e) {
          if(bShowConsole) {
            handleConsole(e);
            repaint();
            return;
          }
          if(bSearchMode) {
            switch(e.getKeyCode()) {
            case KeyEvent.VK_PERIOD:
              bSearchMode = false;
              break;
            case KeyEvent.VK_DELETE:
            case KeyEvent.VK_BACK_SPACE:
              if(searchString.length() > 0) {
                searchString = searchString.substring(0, searchString.length() -1);
                doSearch();
              }
              break;
            case KeyEvent.VK_UNDERSCORE:
              searchString = searchString + "_";
              doSearch();
            default:
              searchString = (searchString + e.getKeyChar()).toLowerCase();
              doSearch();
            }
            repaint();
            return;
          }
          switch(e.getKeyCode()) {
          case KeyEvent.VK_SLASH:
          case KeyEvent.VK_PERIOD:
            bSearchMode = true;
            break;
          case KeyEvent.VK_F:
            bShowFrameRate = !bShowFrameRate;
            break;
          case KeyEvent.VK_B:
            bShowBundleLegend = !bShowBundleLegend;
            break;
          case KeyEvent.VK_I:
            bShowBundleInfo = !bShowBundleInfo;
            break;
          case KeyEvent.VK_0:
            {
              if(mouseActive != null) {
                final SpinItem item = mouseActive;
                Runnable run = new Runnable() {
                    public void run() {
                      while(deltaA < 0) deltaA += Math.PI * 2;
                      while(deltaA > -item.getAngle()) {
                        deltaA -= Math.PI / 50;
                        bxNeedRecalc = true;
                        sxNeedRecalc = true;
                        repaint();
                        try {
                          Thread.sleep(20);
                        } catch (Exception e) { }
                      }
                      deltaA = -item.getAngle();
                    }
                  };
                Thread t = new Thread(run, "spin thread");
                t.start();
              }
            }
            break;
          case KeyEvent.VK_8:
            deltaA -= aStep;
            bxNeedRecalc = true;
            sxNeedRecalc = true;
            break;
          case KeyEvent.VK_9:
            deltaA += aStep;
            bxNeedRecalc = true;
            sxNeedRecalc = true;
            break;
          case KeyEvent.VK_LEFT:
            step(-1);
            break;
          case KeyEvent.VK_RIGHT:
            step(1);
            break;
          case KeyEvent.VK_F1:
          case KeyEvent.VK_H:
          case KeyEvent.VK_HELP:
            bShowHelp = !bShowHelp;
            break;
          case KeyEvent.VK_D:
            bShowDeps = !bShowDeps;
            break;
          case KeyEvent.VK_2:
            use2D = !use2D;
            break;
          case KeyEvent.VK_S:
            bStepSize = !bStepSize;
            initFonts();
            break;
          case KeyEvent.VK_4:
            fontSize += .1;
            initFonts();
            break;
          case KeyEvent.VK_3:
            fontSize = Math.max(.2, fontSize - .1);
            initFonts();
            break;
          case KeyEvent.VK_C:
            active.clear();
            depVector = null;
            depActive = null;
            break;
          case KeyEvent.VK_TAB:
            stepDependency();
            break;
          case KeyEvent.VK_F2:
            toggleConsole();
            break;
          case KeyEvent.VK_SPACE:
            if(depActive != null) {
              mouseActive = depActive;
              depActive = null;
              depVector = null;
              active.clear();
            }

            if(mouseActive != null) {
              if(active.containsKey(mouseActive)) {
                active.remove(mouseActive);
              } else {
                active.put(mouseActive, mouseActive);
              }
            }
            break;
          }
          repaint();
        }
      });

  }

  void handleConsole(KeyEvent e) {
  }

  boolean bShowConsole = false;
  int lineCount = 0;

  void toggleConsole() {
    if(console == null) {
      console = new Console(this);
    }

    bShowConsole = !bShowConsole;

    lineCount++;
    console.addLine("count=" + lineCount);
    if(bShowConsole) {
      console.setBounds(10, size.height / 2,
                        size.width - 10, size.height - 10);
    } else {
    }
    repaint();
  }

  Vector depVector   = null;
  int    depPos      = 0;
  SpinItem depActive = null;

  void stepDependency() {
    if(depVector == null && mouseActive != null) {
      depVector = mouseActive.getNext(SpinItem.DIR_FROM | SpinItem.DIR_TO);

      depPos    = 0;
    }
    if(depVector != null && depVector.size() > 0) {
      depPos = (depPos + 1) % depVector.size();
      depActive = (SpinItem)depVector.elementAt(depPos);
      repaint();
    }
  }

  void doSearch() {
    active.clear();
    int hitCount = 0;
    SpinItem hit = null;
    if(searchString.length() > 0) {
      for(Iterator it = bundles.keySet().iterator(); it.hasNext(); ) {
        Long key      = (Long)it.next();
        SpinItem   item = (SpinItem)bundles.get(key);

        if(item.toString().toLowerCase().startsWith(searchString)) {
          active.put(item, item);
          hit = item;
          hitCount++;
        }
      }
    }
    mouseActive = hit;
    depActive = null;
  }


  void step(int delta) {
    if(mouseActive != null && (mouseActive instanceof BX)) {
      BX bx = (BX)mouseActive;
      long id = bx.b.getBundleId();

      BX bx2 = getBX(id + delta);
      if(bx2 != null) {
        mouseActive = bx2;
        repaint();
      }
    }
    if(mouseActive != null && (mouseActive instanceof SX)) {
      SX   sx = (SX)mouseActive;
      Long id = (Long)sx.sr.getProperty("service.id");

      SX sx2 = getSX(id.longValue() + delta);
      if(sx2 != null) {
        mouseActive = sx2;
        repaint();
      }
    }
  }

  int fontMin = 1;
  int fontMax = 11;

  Font[] fonts;
  void initFonts() {
    initFonts("Dialog");
  }


  void initFonts(String name) {
    fonts = new Font[fontMax - fontMin + 1];
    int n = 0;
    for(int i = fontMin; i <= fontMax; i++) {
      int h = (int)(fontSize * i);
      if(bStepSize && i < fontMax) {
        h = (int)(fontMin * fontSize);
      }
      Font f = new Font("Dialog", Font.PLAIN, h);
      fonts[n++] = f;
    }
  }

  SpinItem mouseActive = null;

  void setActive(int x, int y) {
    double minD = 1000000;

    SpinItem nearest = null;

    for(Iterator it = services.keySet().iterator(); it.hasNext(); ) {
      Object key      = it.next();
      SpinItem   item = (SpinItem)services.get(key);

      double dx = x - item.getSX();
      double dy = y - item.getSY();

      double d2 = dx * dx + dy * dy;
      if(d2 < minD) {
        minD = d2;
        nearest = item;
      }
    }

    for(Iterator it = bundles.keySet().iterator(); it.hasNext(); ) {
      Long key      = (Long)it.next();
      SpinItem   item = (SpinItem)bundles.get(key);

      double dx = x - item.getSX();
      double dy = y - item.getSY();

      double d2 = dx * dx + dy * dy;
      if(d2 < minD) {
        minD = d2;
        nearest = item;
      }
    }

    if(nearest != null) {
      mouseActive = nearest;
    }
    repaint();
  }


  Font getFont(double k) {
    int i = (int)(fontMin + (fontMax - fontMin) * k);
    i = Math.max(0, Math.min(fonts.length - 1, i));
    return fonts[i];
  }

  public void forceRepaint() {
    bxNeedRecalc = true;
    sxNeedRecalc = true;
    //    System.out.println("forceRepaint");
    repaint();
  }

  boolean bxNeedRecalc = false;
  boolean sxNeedRecalc = false;

  public void bundleChanged(BundleEvent ev) {
    Long    id = new Long(ev.getBundle().getBundleId());
    synchronized(bundles) {
      BX bx = (BX)bundles.get(id);

      switch(ev.getType()) {
      case BundleEvent.INSTALLED:
        if(bx == null) {
          bx = new BX(this, ev.getBundle());
          bundles.put(id, bx);
          bxNeedRecalc = true;
        }
        break;
      case BundleEvent.UNINSTALLED:
        if(bx != null) {
          bundles.remove(id);
          bxNeedRecalc = true;
        }
        break;
      }
    }
    repaint();
  }

  PackageAdmin pkgAdmin = null;

  public void serviceChanged(ServiceEvent ev) {
    synchronized(services) {
      ServiceReference sr       = ev.getServiceReference();
      String[]         objClass = (String[]) sr.getProperty(Constants.OBJECTCLASS);
      boolean          bRelease = true;
      SX               sx       = (SX)services.get(sr);

      boolean          isPAdmin = false;
      if (objClass !=  null) {
        for (int i=0; i<objClass.length; i++) {
          if (PackageAdmin.class.getName().equals(objClass[i])) {
            isPAdmin = true;
          }
        }
      }

      switch(ev.getType()) {
      case ServiceEvent.REGISTERED:
        if(isPAdmin) {
          if(pkgAdmin == null) {
            pkgAdmin = (PackageAdmin) Activator.getTargetBC_getService(sr);
            bRelease = false;
          }
        }
        if(sx == null) {
          sx = new SX(this,sr);
          services.put(sr, sx);
          sxNeedRecalc = true;
        }
        break;
      case ServiceEvent.UNREGISTERING:
        if(isPAdmin) {
          if(pkgAdmin != null) {
            pkgAdmin = null;
            bRelease = true;
          }
        }
        if(sx != null) {
          services.remove(sr);
          sxNeedRecalc = true;
        }
        break;
      case ServiceEvent.MODIFIED:
        break;
      }
      if(bRelease) {
        Activator.getTargetBC_ungetService(sr);
      }
    }
    repaint();
  }

  void recalcBundlePositions() {
    if(memG == null) {
      System.out.println("recalc - no memG");
      return;
    }
    synchronized(bundles) {
      int i = 0;
      int n = bundles.size();
      int cx = size.width / 2;
      int cy = size.height / 2;
      for(Iterator it = bundles.keySet().iterator(); it.hasNext(); ) {
        Long    id = (Long)it.next();
        BX bx = (BX)bundles.get(id);

        double a = deltaA + i * Math.PI * 2 / n;

        bx.setPos(cx - 20 + cx * .8 * Math.cos(a), cy + cy * .8 * Math.sin(a));
        bx.setAngle(a);
        i++;
      }
    }
  }

  void recalcServicePositions() {
    if(memG == null) {
      System.out.println("sx recalc - no memG");
      return;
    }
    synchronized(services) {
      int cx = size.width  / 2;
      int cy = size.height / 2;

      for(Iterator it = services.keySet().iterator(); it.hasNext(); ) {
        ServiceReference   sr = (ServiceReference)it.next();
        SX                 sx = (SX)services.get(sr);

        BX bx = (BX)bundles.get(sx.bid);
        if(bx == null) {
          System.out.println("No bundle for " + sx);
          continue;
        }
        double x = Math.random() * 10 + bx.x - (bx.x - cx) * .2;
        double y = Math.random() * 10 + bx.y - (bx.y - cy) * .2;

        sx.setPos(x, y);
      }
    }
  }

  int count = 0;


  public void run() {

    try {
      repaint();
      while(memG == null) {
        Thread.sleep(100);
      }
      while(bRun) {

        long startTime = System.currentTimeMillis();
        synchronized(paintLock) {
          updateAll();
          paintAll();
        }
        updateTime = System.currentTimeMillis() - startTime;

        long delta = targetTime - updateTime;
        delay = Math.max(2, delta);

        Thread.sleep(delay);
        totalTime = System.currentTimeMillis() - startTime;
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void updateAll() {
    count++;
  }


  public void paintAll() {
    synchronized(paintLock) {
      Graphics g = getGraphics();

      if(g != null) {
        paint(g);
        g.dispose();
      }
    }
  }

  String indent(int level) {
    StringBuffer sb = new StringBuffer();
    while(level --> 0) sb.append(" ");

    return sb.toString();
  }

  void getDeps(StringBuffer sb, Hashtable lines, SpinItem item, int level) {
    if(item == null) return;

    String line = item.toString();
    if(lines.containsKey(line)) {
      return;
    }

    String s = indent(level);
    //    System.out.println(level + ": " + s + item.toString());
    if(!line.equals("System Bundle")) {
      sb.append(s + item.toString() + "\n");
      lines.put(line, line);
    }
    Vector v = item.getNext(SpinItem.DIR_FROM);
    if(v != null) {
      if(level > 3 && v.size() > 0) {
        sb.append(indent(level) + "...\n");
        return;
      }
      for(int i = 0; i < v.size(); i++) {
        SpinItem next = (SpinItem)v.elementAt(i);

        getDeps(sb, lines, next, level + 1);
      }
    }
  }

  void paintDeps(Graphics g, int x, int y) {
    SpinItem item = getInfoItem();

    if(item == null) return;

    StringBuffer sb = new StringBuffer();
    getDeps(sb, new Hashtable(), item, 0);


    String name = "";
    if(item instanceof SX) {
      name = "(" +
        BX.shortName(((SX)item).sr.getBundle()) +
        ")\n";
    }

    String s = "Imports from:\n" + name + sb.toString();

    paintBox(s, g, Color.white, Color.black, x, y, .8, 200, 200);
  }

  void paintHelp(Graphics g, int x, int y) {

    paintBox("F1/H \t- toggle help\n" +
             "B    \t- toggle legend\n" +
             "I    \t- toggle detail info\n" +
             "D    \t- toggle dependencies\n" +
             "left \t- previous item\n" +
             "right\t- next item\n" +
             "space\t- mark item\n" +
             "C    \t- clear all marked\n" +
             "Tab  \t- step dependencies\n" +
             "2    \t- toggle Graphics2D\n" +
             "S    \t- toggle step font size\n" +
             "3    \t- decrease font size\n" +
             "4    \t- increase font size\n" +
             "8    \t- rotate anti-clockwise\n" +
             "9    \t- rotate clockwise\n" +
             ".    \t- start/stop search mode\n",
             g, Color.white, Color.black, x, y);
  }

  void paintBox(String   s,
                Graphics g,
                Color    bgCol,
                Color    fgCol,
                int      x,
                int      y) {
    paintBox(s, g, bgCol, fgCol, x, y, 1.0, 200, 200);
  }


  void paintBox(String   s,
                Graphics g,
                Color    bgCol,
                Color    fgCol,
                int      x,
                int      y,
                double   size,
                int minWidth, int minHeight) {
    Object oldComp = null;
    if(use2D) {
      Graphics2D g2 = (Graphics2D)g;
      oldComp = g2.getComposite();
      g2.setComposite((AlphaComposite)alphaHalf);
    }

    String[] lines = split(s, "\n");

    int maxCols = 0;
    for(int i = 0; i <lines.length; i++) {
      if(lines[i].length() > maxCols) {
        maxCols = lines[i].length();
      }
    }

    Font font = getFont(size);

    g.setColor(bgCol);

    g.fill3DRect(x, y,
                 Math.max(minWidth, font.getSize() * maxCols / 2 + 30),
                 Math.max(minHeight, (font.getSize() + 3) * lines.length + 10),
                 true);


    g.setFont(font);

    g.setColor(fgCol);

    x += 10;
    y += font.getSize() + 5;

    int x2 = x + font.getSize() * 8;

    if(use2D) {
      if(oldComp != null) {
        Graphics2D g2 = (Graphics2D)g;
        g2.setComposite((AlphaComposite)oldComp);
      }
    }

    for(int i = 0; i <lines.length; i++) {
      int ix = lines[i].indexOf("\t");
      if(ix != -1) {
        g.drawString(lines[i].substring(0, ix),  x, y);
        g.drawString(lines[i].substring(ix + 1), x+font.getSize()*4, y);
      } else {
        g.drawString(lines[i], x, y);
      }
      y += font.getSize() + 3;
    }

  }

  void paintBundles(Graphics g) {
    //    System.out.println("paintBundles()");
    if(bxNeedRecalc) {
      recalcBundlePositions();
      bxNeedRecalc = false;
    }
    synchronized(bundles) {
      for(Iterator it = bundles.keySet().iterator(); it.hasNext(); ) {
        Long    id = (Long)it.next();
        BX bx = (BX)bundles.get(id);
        bx.paint(g);
      }
    }
  }

/**
   * Splits a string into words, using the <code>StringTokenizer</code> class.
   */
  public static String[] split(String s, String sep) {
    StringTokenizer st = new StringTokenizer(s, sep);
    int ntok = st.countTokens();
    String[] res = new String[ntok];
    for (int i = 0; i < ntok; i++) {
      res[i] = st.nextToken();
    }
    return res;
  }

  void zoom() {
    toScreen(center);

    for(Iterator it = bundles.keySet().iterator(); it.hasNext(); ) {
      Long    id = (Long)it.next();
      BX bx = (BX)bundles.get(id);
      toScreen(bx);
    }
    for(Iterator it = services.keySet().iterator(); it.hasNext(); ) {
      ServiceReference   sr = (ServiceReference)it.next();
      SX                 sx = (SX)services.get(sr);
      toScreen(sx);
    }
  }

  void paintServices(Graphics g) {
    //    System.out.println("paintServices()");
    if(sxNeedRecalc) {
      recalcServicePositions();
      sxNeedRecalc = false;
    }
    synchronized(services) {
      for(Iterator it = services.keySet().iterator(); it.hasNext(); ) {
        ServiceReference   sr = (ServiceReference)it.next();
        SX                 sx = (SX)services.get(sr);
        sx.paint(g);
      }
    }
  }

  boolean isActive(SpinItem item) {
    return
      active.containsKey(item)
      || item == mouseActive
      || item == depActive;
  }

  boolean isPainting = false;

  boolean bAntiAlias = true;

  public void setAntiAlias(boolean b) {
    bAntiAlias = b;
  }

  public boolean getAntiAlias() {
    return bAntiAlias;
  }

  long bgTime, spriteTime, fgTime;

  public void update(Graphics g) {
    paint(g);
  }

  public void paint(Graphics _g) {
    //    System.out.println("paint()");
    if(isPainting) return;
    isPainting = true;

    synchronized(paintLock) {
      zoom();

      if(use2D) {
        if(alphaHalf == null) {
          alphaHalf = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .7f);
        }
      }

      Graphics g = _g;

      makeOff(false);

      if(memG == null) return;

      long start = System.currentTimeMillis();
      paintBg(memG);

      bgTime = System.currentTimeMillis() - start;

      if(use2D) {
        ((Graphics2D)memG).
          setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                           bAntiAlias
                           ? RenderingHints.VALUE_ANTIALIAS_ON
                           : RenderingHints.VALUE_ANTIALIAS_OFF);
      }

      paintBundles(memG);
      spriteTime = System.currentTimeMillis() - bgTime - start;

      paintServices(memG);
      fgTime = System.currentTimeMillis() - spriteTime - start;


      if(bShowBundleLegend) {
        paintBundleStateLegend(memG);
      }

      SpinItem infoItem = getInfoItem();

      if(infoItem != null) {
        if(bShowBundleInfo) {
          infoItem.paintInfo(memG, 10, size.height - 100);
        }
      }

      if(bShowConsole) {
        console.paint(memG);
      }


      if(bShowFrameRate) {
        paintFrameRate(memG);
      }

      if(bShowHelp) {
        paintHelp(memG, size.width/2-100, 50);
      }
      if(bShowDeps) {
        paintDeps(memG,
                  (hotX > size.width / 2) ? 40 : (size.width / 2),
                  20);
      }

      if(bSearchMode) {
        paintSearch(memG, 10, size.height - 140);
      }

      if(use2D) {
        ((Graphics2D)memG).
          setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                           RenderingHints.VALUE_ANTIALIAS_OFF);
      }

      g.drawImage(memImage, 0, 0, null);

    }
    isPainting = false;
  }

  public SpinItem getInfoItem() {
    return depActive != null ? depActive : mouseActive;
  }
  public void paintBundleStateLegend(Graphics g) {
    paintCBox(g, 10, 10, BX.getColor(Bundle.INSTALLED),    "Installed");
    paintCBox(g, 10, 25, BX.getColor(Bundle.ACTIVE),       "Active");
    paintCBox(g, 10, 40, BX.getColor(Bundle.RESOLVED),     "Resolved");
    paintCBox(g, 10, 55, BX.getColor(Bundle.UNINSTALLED)"Uninstalled");
    paintCBox(g, 10, 70, BX.getColor(Bundle.STOPPING),     "Stopping");
    paintCBox(g, 10, 85, BX.getColor(Bundle.STARTING),     "Starting");

    paintCBox(g, 10, 105, BX.importsFromColor,              "Imports from");
    paintCBox(g, 10, 120, BX.exportsToColor,                "Exports to");



    paintCBox(g, 10, size.height - 20, bgColor,             "F1 - help");
  }


  public void paintCBox(Graphics g, int x, int y, Color c, String text) {
    int w = 12;
    int h = 12;

    g.setColor(c);
    g.fillRect(x, y, w, h);

    g.setColor(Color.gray);
    g.drawLine(x,   y, x+w, y);
    g.drawLine(x,   y, x,   y+h);

    g.setColor(Color.black);
    g.drawLine(x+w, y,   x+w, y+h);
    g.drawLine(x,   y+h, x+w, y+h);

    g.setColor(textColor);
    g.setFont(getFont(1.0));
    g.drawString(text, x + 30, y + 10);
  }

  public void paintFrameRate(Graphics g) {
    g.setColor(Color.black);
    g.drawString("fps: " + (int)(1000.0 / totalTime), 10, size.height - 5);
    g.drawString("delay: " + delay, 90, size.height - 5);
    g.drawString("bg: "      + bgTime, 10, size.height - 20);
    g.drawString("sprites: " + spriteTime, 10, size.height - 35);
    g.drawString("fg: "      + fgTime, 10, size.height - 50);
  }



  public void paintBg(Graphics g) {
    g.setColor(bgColor);
    g.fillRect(0, 0, size.width, size.height);
  }

  void makeOff(boolean bForce) {
    Dimension d = getSize();
    if(d != null) {
      if(bForce ||
         (size == null || d.width != size.width || d.height != size.height))
        {
          size = d;
          center.setPos(size.width / 2, size.height / 2);
          bxNeedRecalc = true;
          sxNeedRecalc = true;
          memImage = createImage(d.width, d.height);
          memG  = memImage.getGraphics();

        }
    }
  }

  public void start() {
    if(runner != null) {
      return;
    }

    runner = new Thread(this, "fwspin");
    bRun = true;
    runner.start();
  }

  public void stop() {
    Activator.getTargetBC().removeBundleListener(this);
    Activator.getTargetBC().removeServiceListener(this);

    if(runner != null) {
      bRun = false;
      try {
        runner.join(5 * 1000);

      } catch (Exception  e) {
        //
      }
    }
    runner = null;
  }

  int hotX;
  int hotY;

  SpinItem center;

  void toScreen(SpinItem item) {
    double sx = item.getX();
    double sy = item.getY();

    double dx = sx - hotX;
    double dy = sy - hotY;

    double d2 = dx * dx + dy * dy;

    double d  = Math.sqrt(d2);

    double maxDist = 100;

    if(bStepSize) {
      maxDist = 10;
    }

    d = Math.min(d, maxDist);

    double k = d / maxDist;

    k = 1.0  - Math.sqrt(k);

    /*    double m = 100;

    d = Math.max(0.0, Math.min(m, d));
    double k = m / (d + 1) / 10;
    */

    sx += k * dx;
    sy += k * dy;

    item.setSPos((int)sx, (int)sy, k);
  }

  BX getBX(Long id) {
    return (BX)bundles.get(id);
  }

  BX getBX(long id) {
    return getBX(new Long(id));
  }

  SX getSX(long id) {
    for(Iterator it = services.keySet().iterator(); it.hasNext(); ) {
      ServiceReference   sr = (ServiceReference)it.next();
      SX                 sx = (SX)services.get(sr);

      Long sid = (Long)sr.getProperty("service.id");
      if(sid.longValue() == id) {
        return sx;
      }
    }
    return null;
  }

  public void paintSearch(Graphics g, double x, double y) {

    paintBox(searchString, g, Color.white, Color.black, (int)x, (int)y,
             .8, 300, 30);
  }

}


class SX extends SpinItem {
  ServiceReference sr;
  String className;
  String name;
  Long   bid;

  static String ignorePrefix = "com.gatespace.";

  Spin spin;

  public SX(Spin spin, ServiceReference sr) {
    this.sr = sr;
    this.spin = spin;

    bid = new Long(sr.getBundle().getBundleId());

    className = ((String[])sr.getProperty(Constants.OBJECTCLASS))[0]; // TODO: Display all objectclasses?

    if(className.startsWith(ignorePrefix)) {
      className = className.substring(ignorePrefix.length());
    }

    name = className + "/" + sr.getProperty(Constants.SERVICE_ID);

  }

  public void paint(Graphics g) {
    g.setFont(spin.getFont(fac + (isActive() ? 1.0 : .2)));
    g.setColor(isActive() ? Color.white : Color.gray);
    g.drawString(name, sx, sy);

    if(isActive()) {
      paintDependencies(g);
    }
  }



  public void paintInfo(Graphics g, double x, double y) {

    StringBuffer sb = new StringBuffer();

    sb.append("" + sr + "\n");

    String[] keys = sr.getPropertyKeys();
    for(int i = 0; keys != null && i < keys.length; i++) {
      String key = keys[i];
      Object val = sr.getProperty(key);

      if(val.getClass().isArray()) {
        Object[] vals = (Object[])val;
        if(vals.length > 0) {
          sb.append(keys[i] + " = " + vals[0] + "\n");
          for(int j = 1; j < vals.length; j++) {
            sb.append("   " + vals[j] + "\n");
          }
        }
      } else {
        sb.append(keys[i] + " = " + val + "\n");
      }
    }

    spin.paintBox(sb.toString(), g, Color.white, Color.black, (int)x, (int)y,
                  .8, 300, 300);
  }

  Vector getNext(int dir) {

    TreeMap map = new TreeMap();

    if((dir & SpinItem.DIR_FROM) != 0) {
      Bundle[] bl = sr.getUsingBundles();
      for(int i = 0; bl != null && i < bl.length; i++) {
        BX bx = spin.getBX(bl[i].getBundleId());
        if(bx != null) {
          map.put(new Long(bx.b.getBundleId()), bx);
        }
      }
    }

    Vector v = new Vector();
    for(Iterator it = map.keySet().iterator(); it.hasNext(); ) {
      Long key      = (Long)it.next();
      BX   bx       = (BX)map.get(key);
      v.addElement(bx);
    }
    return v;
  }

  public void paintDependencies(Graphics g) {

    BX bx = spin.getBX(sr.getBundle().getBundleId());

    if(bx != null) {
      g.setColor(Color.gray);
      g.drawLine(sx, sy, bx.sx, bx.sy);
    }

    Bundle[] bl = sr.getUsingBundles();
    for(int i = 0; bl != null && i < bl.length; i++) {
      paintUsing(g, bl[i]);
    }

  }

  public boolean isActive() {
    return spin.isActive(this);
  }

  public void paintUsing(Graphics g, Bundle b) {
    BX bx = spin.getBX(b.getBundleId());
    if(bx == null) {
      return;
    }

    double cx = spin.center.getSX();
    double cy = spin.center.getSY();

    g.setColor(BX.exportsToColor);

    if(spin.use2D) {
      CubicCurve2D.Double curve =
        new CubicCurve2D.Double (sx, sy,
                                 cx, cy,
                                 cx, cy,
                                 bx.sx, bx.sy);


      ((Graphics2D)g).draw(curve);
    } else {
      drawSpline(g,
                 sx, sy,
                 cx, cy,
                 cx, cy,
                 bx.sx, bx.sy, 5);
    }
  }
  public String toString() {
    return name;
  }
}


class BX extends SpinItem {
  Bundle b;
  String name;
  Spin   spin;

  public BX(Spin spin, Bundle b) {
    this.b    = b;
    this.spin = spin;

    name = shortName(b);

  }

  public static Color importsFromColor = Color.blue;
  public static Color exportsToColor   = Color.gray;

  public boolean isActive() {
    return spin.isActive(this);
  }


  Vector getNext(int dir) {

    Map map = new TreeMap();

    if(spin.pkgAdmin != null) {

      ExportedPackage[] exp = spin.pkgAdmin.getExportedPackages(b);

      if((dir & SpinItem.DIR_TO) != 0) {
        for(int i = 0; exp != null && i < exp.length; i++) {
          Bundle[] bl =  exp[i].getImportingBundles();
          for(int j = 0; bl != null && j < bl.length; j++) {
            BX bx = spin.getBX(bl[j].getBundleId());
            if(bx != null) {
              map.put(new Long(bx.b.getBundleId()), bx);
            }
          }
        }
      }

      if((dir & SpinItem.DIR_FROM) != 0) {
        for(Iterator it = spin.bundles.keySet().iterator(); it.hasNext(); ) {
          Long key      = (Long)it.next();
          BX   bx       = (BX)spin.bundles.get(key);

          exp = spin.pkgAdmin.getExportedPackages(bx.b);
          boolean done = false;
          for(int i = 0; !done && exp != null && i < exp.length; i++) {
            Bundle[] bl =  exp[i].getImportingBundles();
            for(int j = 0; !done && bl != null && j < bl.length; j++) {
              if(bl[j].getBundleId() == b.getBundleId()) {
                map.put(new Long(bx.b.getBundleId()), bx);
                done = true;
              }
            }
          }
        }
      }
    }

    map.remove(new Long(b.getBundleId()));

    Vector v = new Vector();
    for(Iterator it = map.keySet().iterator(); it.hasNext(); ) {
      Long key      = (Long)it.next();
      BX   bx       = (BX)map.get(key);
      v.addElement(bx);
    }

    return v;
  }


  public void paintDependencies(Graphics g) {
    if(spin.pkgAdmin == null) return;

    ExportedPackage[] exp = spin.pkgAdmin.getExportedPackages(b);

    g.setColor(exportsToColor);

    for(int i = 0; exp != null && i < exp.length; i++) {
      Bundle[] bl =  exp[i].getImportingBundles();
      for(int j = 0; bl != null && j < bl.length; j++) {
        BX bx = spin.getBX(bl[j].getBundleId());
        if(bx != null) {
          paintUsing(g, bx);
        }
      }
    }

    g.setColor(importsFromColor);

    for(Iterator it = spin.bundles.keySet().iterator(); it.hasNext(); ) {
      Long key      = (Long)it.next();
      BX   bx       = (BX)spin.bundles.get(key);

      exp = spin.pkgAdmin.getExportedPackages(bx.b);
      boolean done = false;
      for(int i = 0; !done && exp != null && i < exp.length; i++) {
        Bundle[] bl =  exp[i].getImportingBundles();
        for(int j = 0; !done && bl != null && j < bl.length; j++) {
          if(bl[j].getBundleId() == b.getBundleId()) {
            paintUsing(g, bx);
            done = true;
          }
        }
      }
    }
  }


  public void paintInfo(Graphics g, double x, double y) {

    StringBuffer sb = new StringBuffer();

    sb.append(b.getLocation() + ", id=" + b.getBundleId() + "\n");

    Dictionary headers = b.getHeaders();

    for(Enumeration e = headers.keys(); e.hasMoreElements(); ) {
      String key = (String)e.nextElement();
      String val = (String)headers.get(key);

      sb.append(key + ": " + val + "\n");
    }
    spin.paintBox(sb.toString(), g, Color.white, Color.black, (int)x, (int)y,
                  .8, 300, 300);
  }


  public void paintUsing(Graphics g, BX bx) {

    double cx = spin.center.getSX();
    double cy = spin.center.getSY();

    if(spin.use2D) {
      CubicCurve2D.Double curve =
        new CubicCurve2D.Double (sx, sy,
                                 cx, cy,
                                 cx, cy,
                                 bx.sx, bx.sy);

      ((Graphics2D)g).draw(curve);
    } else {
      drawSpline(g, sx, sy,
                 cx, cy,
                 cx, cy,
                 bx.sx, bx.sy, 5);
    }

  }


  static Color installedColor   = Color.gray;
  static Color uninstalledColor = Color.gray.darker();
  static Color resolvedColor    = new Color(90, 90, 255);
  static Color activeColor      = Color.yellow;
  static Color stoppingColor    = Color.red;
  static Color startingColor    = new Color(255, 0, 255);

  public static Color getColor(int state) {
    switch(state) {
    case Bundle.INSTALLED:
      return installedColor;
    case Bundle.ACTIVE:
      return activeColor;
    case Bundle.RESOLVED:
      return resolvedColor;
    case Bundle.UNINSTALLED:
      return uninstalledColor;
    case Bundle.STARTING:
      return startingColor;
    case Bundle.STOPPING:
      return stoppingColor;
    }

    return Color.black;
  }

  public void paint(Graphics g) {
    g.setFont(spin.getFont(fac + (isActive() ? 1.0 : .8)));

    if(isActive()) {
      g.setColor(Color.white);
    } else {
      g.setColor(getColor(b.getState()));
    }
    g.drawString(name, sx, sy);

    if(isActive()) {
      paintDependencies(g);
    }
  }

  public static String shortName(Bundle b) {
    String s = b.getLocation();
    int ix = s.lastIndexOf("/");
    if(ix == -1) ix = s.lastIndexOf("\\");
    if(ix != -1) {
      s = s.substring(ix + 1);
    }
    if(s.endsWith(".jar")) s = s.substring(0, s.length() - 4);
    return s;
  }

  public String toString() {
    return name;
  }
}
TOP

Related Classes of org.knopflerfish.bundle.desktop.swing.fwspin.SX

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.