FELIX-151
---------
Improve the remote logger console component.


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@553129 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/JtableCellRenderer.java b/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/JtableCellRenderer.java
index 6a5300d..c67958d 100644
--- a/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/JtableCellRenderer.java
+++ b/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/JtableCellRenderer.java
@@ -32,12 +32,12 @@
 
   public JtableCellRenderer() {
     super();
-    eventName.put(new Integer( Bundle.ACTIVE      ), Color.green  );
-    eventName.put(new Integer( Bundle.INSTALLED   ), Color.orange );
-    eventName.put(new Integer( Bundle.RESOLVED    ), Color.red    );
+    eventName.put(new Integer( Bundle.UNINSTALLED ), Color.black  );
+    eventName.put(new Integer( Bundle.INSTALLED   ), Color.red    );
+    eventName.put(new Integer( Bundle.RESOLVED    ), Color.orange );
     eventName.put(new Integer( Bundle.STARTING    ), Color.gray   );
     eventName.put(new Integer( Bundle.STOPPING    ), Color.gray   );
-    eventName.put(new Integer( Bundle.UNINSTALLED ), Color.black  );
+    eventName.put(new Integer( Bundle.ACTIVE      ), Color.green  );
   }
 
   public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
@@ -50,7 +50,7 @@
         state=new Integer(-1);
       }
       if (value!=null) {
-        if (((String) value).equals("??/??/??")) {
+        if (((String) value).equals(JtreeCellRenderer.UNKNOWN_DATE)) {
 	  setBackground(Color.white);
         } else{
 	  setBackground((Color) eventName.get(state));
diff --git a/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/JtreeCellRenderer.java b/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/JtreeCellRenderer.java
index ecefb60..453191d 100644
--- a/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/JtreeCellRenderer.java
+++ b/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/JtreeCellRenderer.java
@@ -20,40 +20,65 @@
 import org.osgi.framework.BundleContext;
 import java.awt.Color;
 import java.awt.Component;
-import java.awt.Graphics;
 import java.awt.Font;
 import java.awt.Dimension;
 import java.awt.Toolkit;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.JTree;
-import javax.swing.JLabel;
 import javax.swing.ImageIcon;
 import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.TreeCellRenderer;
-import javax.swing.tree.TreePath;
 import java.util.StringTokenizer;
-import java.util.NoSuchElementException;
 import java.lang.StringBuffer;
+import java.util.Hashtable;
 
 public class JtreeCellRenderer extends DefaultTreeCellRenderer {
 
-  private static final String[] LOG_LVL=new String[] {"", "Error", "Warning", "Info", "Debug"};
+  public static final String UNKNOWN_DATE="??/??/??";
+  public static final String UNKNOWN_TIME="??:??:??:???";
+  public static Hashtable ht_num2string=new Hashtable();
 
   private boolean isLeaf=false;
-
-  private String[] states=new String[]{"ACTIVE","INSTALLED","RESOLVED","STARTING","STOPPING","UNINSTALLED"};
-  private Color[] colors=new Color[]{Color.green,Color.orange,Color.red,Color.gray,Color.gray,Color.black};
-  private ImageIcon[] ii=new ImageIcon[6];
-  private ImageIcon iiOldLog=null;
-
   private RemoteLogger_jtree rl_jtree=null;
+  private static final Font FONT_BIG=new Font("Monospaced",Font.BOLD,14);
+  private static final Font FONT_SMALL=new Font("Monospaced",Font.PLAIN,10);
 
-  public JtreeCellRenderer(BundleContext bdlCtx, RemoteLogger_jtree rl_jtree){
+  private static Hashtable ht_string2color=new Hashtable();
+  private static Hashtable ht_string2icon=new Hashtable();
+  private static ImageIcon iiOldLog=null;
+  private static ImageIcon iiNewLog=null;
+  private static ImageIcon iiNull=null;
+  
+  public JtreeCellRenderer(BundleContext bdlCtx, RemoteLogger_jtree rl_jtree) {
     this.rl_jtree=rl_jtree;
-    for (int i=0 ; i<states.length ; i++){
-      this.ii[i]=new ImageIcon(Toolkit.getDefaultToolkit().getImage(bdlCtx.getBundle().getResource("icons/"+states[i]+".gif")));
-    }
+    
+    String[] states=new String[] {
+      "Uninstalled",
+      "Installed  ",
+      "Resolved   ",
+      "Starting   ",
+      "Stopping   ",
+      "Active     "
+    };
+
+    Color[] colors=new Color[] {
+      Color.black,
+      Color.red,
+      Color.orange,
+      Color.gray,
+      Color.gray,
+      Color.green
+    };
+    
     this.iiOldLog=new ImageIcon(Toolkit.getDefaultToolkit().getImage(bdlCtx.getBundle().getResource("icons/OLDLOG.gif")));
+    this.iiNewLog=new ImageIcon(Toolkit.getDefaultToolkit().getImage(bdlCtx.getBundle().getResource("icons/NEWLOG.gif")));
+    this.iiNull=new ImageIcon(Toolkit.getDefaultToolkit().getImage(bdlCtx.getBundle().getResource("icons/NULL.gif")));
+    
+    for (int i=0 ; i<states.length ; i++) {
+      ht_num2string.put(new Integer((int) Math.pow(2, i)), states[i]);
+      ht_string2color.put(states[i].trim(), colors[i]);
+      ht_string2icon.put(states[i].trim(), new ImageIcon(Toolkit.getDefaultToolkit().getImage(bdlCtx.getBundle().getResource("icons/"+states[i].trim()+".gif"))));
+    }
+
   }
 
   public Dimension getPreferredSize() {
@@ -67,70 +92,77 @@
     setText(value.toString());
     setOpaque(true);
     setBackground(Color.white);
-    setFont(new Font("Monospaced",Font.BOLD,14));
+    setFont(FONT_BIG);
     setToolTipText(null);
-    setIcon(null);
     StringTokenizer st=null;
     DefaultMutableTreeNode dmtn=(DefaultMutableTreeNode)value;
 
+    if (rl_jtree.v_ul.contains(dmtn)) {
+      setIcon(iiNewLog);
+    } else {
+      setIcon(iiNull);
+    }
+
     int lvl=dmtn.getLevel(); 
     switch (lvl) {
       case 2: { // port / profilName / logLvl
-        Integer val=rl_jtree.getTreeNodeLogLvl((DefaultMutableTreeNode) value);
-        setText(value+" (log level="+LOG_LVL[val.intValue()]+")");
+        setText(value+" (log level="+rl_jtree.getLogLvl(dmtn)+")");
 	break;
       }
       case 3: { // bundleId / symbolic name / children count
-        // TODO : create a bundleNodeUserObject (getText, getTtt, getStateColor, setNewValues(test,ttt,stateColor))
-        st=new StringTokenizer(dmtn.getFirstChild().toString()," | ");
+        st=new StringTokenizer(dmtn.getFirstChild().toString(),"|");
         if(st!=null) {	
-          String date=st.nextToken();
+          String date=st.nextToken().trim();
           st.nextToken();
-          String state=st.nextToken();
-	  if (tree.getLeadSelectionPath()!=null) {
-	    for (int i=0; i<states.length ; i++) {
-	      if (state.equals(states[i])) {
-	        setBackground(colors[i]);
-	      }
-	    }
-	    StringTokenizer st2 = new StringTokenizer(((DefaultMutableTreeNode)dmtn.getFirstChild()).toString()," | ");
-	    StringBuffer ttt=new StringBuffer("<html><B>IP = </B>"+/*IP=<ip> Profil=<port>/<profil>*/dmtn.getParent().getParent()+"<B> Profil =</B>"+dmtn.getParent()+"<br><B>Bundle : </B>"+/*Bundle : Id=<bundleId> : <bundleSymbolicName>*/dmtn+"<br><B>Date : </B>"+/*<date> - <time>*/st2.nextToken()+" - "+st2.nextToken()+"<br><B>State : "+/*<bundleState>*/st2.nextToken()+"<br>Event "+/*Event <eventNumber> : <logLevel> : <message>*/dmtn.getChildCount()+" : "+st2.nextToken()+" : </B><br>");
-	    while (st2.hasMoreTokens()) {
-	      ttt.append(st2.nextToken()+" ");
-	    }
-	    setToolTipText(ttt+"</html>");
+          String state=st.nextToken().trim();
+	  setBackground((Color) ht_string2color.get(state));
+	  StringTokenizer st2 = new StringTokenizer(((DefaultMutableTreeNode)dmtn.getFirstChild()).toString()," | ");
+	  StringBuffer ttt=new StringBuffer(
+	    "<html><B>IP = </B>"+/*IP=<ip> Profil=<port>/<profil>*/dmtn.getParent().getParent()+"<B> Profil =</B>"+dmtn.getParent()+
+	    "<br><B>Bundle : </B>"+/*Bundle : Id=<bundleId> : <bundleSymbolicName>*/dmtn+
+	    "<br><B>Date : </B>"+/*<date> - <time>*/st2.nextToken()+" - "+st2.nextToken()+
+	    "<br><B>State on last log : "+/*<bundleState>*/st2.nextToken()+
+	      "<br>Event "+/*Event <eventNumber> : <logLevel> : <message>*/dmtn.getChildCount()+" : "+st2.nextToken()+" : </B><br>");
+	  while (st2.hasMoreTokens()) {
+	    ttt.append(st2.nextToken()+" ");
 	  }
+	  setToolTipText(ttt+"</html>");
 	} 
         break;
       }
       case 4: { // icon / date / time / state / logLvl / msg
-        st=new StringTokenizer(dmtn.toString()," | ");
-	setFont(new Font("Monospaced",Font.PLAIN,10));
+        st=new StringTokenizer(dmtn.toString(),"|");
+	setFont(FONT_SMALL);
         if(st!=null){
-          String date=st.nextToken();
+          String time=st.nextToken().trim();
           st.nextToken();
-	  String state=st.nextToken();
-	  for (int i=0 ; i<states.length ; i++){
-	    if (state.equals(states[i])){
-	      if(!date.equals("??/??/??")){
-	        setIcon(ii[i]);
-	      } else{
-	        setIcon(iiOldLog);
-	      }
-	    }
+	  String state=st.nextToken().trim();
+	  ImageIcon ii=(ImageIcon) ht_string2icon.get(state);
+	  if (time.equals(UNKNOWN_TIME)) {
+	    ii=iiOldLog;
 	  }
+	  setIcon(ii);
 	}
       break;
       }
-    }
 
-    if (tree.getLeadSelectionPath()==null) {
-      setForeground(Color.blue);
-    } else {
-      setForeground(Color.black);
-    }
-	
+    }	
     return this;
   }	
 
 }
+
+  /*
+    // Introspection technique :
+    java.lang.Class class_bundle=org.osgi.framework.Bundle.class;
+    java.lang.reflect.Field[] fields=class_bundle.getFields();
+    for (int i=0 ; i<fields.length ; i++) {
+	try {
+		String name=fields[i].getName();
+		int value=fields[i].getInt(null);
+		System.out.println("Cst # "+i+" \""+name+"\" = "+value);
+	}catch (Exception oups) {
+		oups.printStackTrace();
+	}
+  }
+  */
diff --git a/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtable.java b/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtable.java
index f95abdc..912fd54 100644
--- a/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtable.java
+++ b/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtable.java
@@ -54,7 +54,7 @@
   private JTable logList;
   private JButton jb_save;
   private String[] columnToolTips=new String[]{"","","","","",
-          "<html><pre> 1 UNINSTALLED black<br> 2 INSTALLED   orange<br> 4 RESOLVED    red<br> 8 STARTING    gray<br>16 STOPPING    gray<br>32 ACTIVE      green",
+          "<html><pre> 1 UNINSTALLED black<br> 2 INSTALLED   red<br> 4 RESOLVED    orange<br> 8 STARTING    gray<br>16 STOPPING    gray<br>32 ACTIVE      green",
 	  "",""};
   private JPanel jbPanel;
   private JPanel jp;
@@ -142,8 +142,8 @@
     StringTokenizer st = new StringTokenizer(notification.getMessage(),"*");
     
     long ts=notification.getTimeStamp();
-    String date="??/??/??";
-    String time="??/??/??";
+    String date=JtreeCellRenderer.UNKNOWN_DATE; //"??/??/??";
+    String time=JtreeCellRenderer.UNKNOWN_TIME; //"??/??/??";
     if (ts!=0){ // means it's not an old log
       Date d=new Date(ts);
       //DateFormat dateFormat = new SimpleDateFormat("hh'h'mm dd-MM-yy");
diff --git a/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtree.java b/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtree.java
index e3423a1..813ef83 100644
--- a/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtree.java
+++ b/mosgi/console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtree.java
@@ -20,15 +20,12 @@
 import org.apache.felix.mosgi.console.ifc.Plugin;
 import org.apache.felix.mosgi.console.component.MyTree;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.Bundle;
 import java.beans.PropertyChangeEvent;
-import javax.swing.JButton;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JMenuItem;
 import javax.swing.JScrollPane;
 import javax.swing.JScrollBar;
-import javax.swing.JTree;
 import javax.swing.tree.DefaultTreeModel;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.TreePath;
@@ -39,7 +36,6 @@
 import java.awt.Dimension;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseListener;
-import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.ActionEvent;
 import javax.management.Notification;
@@ -53,6 +49,7 @@
 import java.util.Date;
 import java.util.Enumeration;
 import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 //import org.osgi.service.prefs.Preferences;
 
 public class RemoteLogger_jtree extends DefaultTreeModel implements CommonPlugin, NotificationListener, MouseListener {
@@ -61,24 +58,23 @@
   private static final String OLDLOG_NOT_THIS_TIME ="Not this time";
   private static final String OLDLOG_ALWAYS        ="Always";
   private static final String OLDLOG_NEVER         ="Never";
-  private String oldLogChoice=OLDLOG_THIS_TIME;
-  
   private static final String[] LOG_LVL=new String[] {"Error", "Warning", "Info", "Debug"};
-  private Hashtable logLvlHt=new Hashtable(); // treeNode/logLvl
+  
+  private String oldLogChoice=OLDLOG_THIS_TIME;
+  private Hashtable ht_connectedGateway=new Hashtable(); // connString/mbsc
+  protected Hashtable ht_logLvl=new Hashtable(); // DefaultMutableTreeNode/Integer_logLvl
+  protected Vector v_ul=new Vector(); // tree node containing not visible log yet  (placer ce vecteur dans le renderer ???)
 
   private MyTree logTree;
   private TreePath selPath;
   private JPanel jp;
-  private DefaultMutableTreeNode rootNode=new DefaultMutableTreeNode("root");
-  private Hashtable eventName=new Hashtable();
-
-  private Hashtable nodes=new Hashtable();    // connString/mbsc
+  private DefaultMutableTreeNode rootNode=new DefaultMutableTreeNode("");
+  private JScrollBar jsb_horizontal=null;
+  private JScrollBar jsb_vertical=null;
 
   public RemoteLogger_jtree (BundleContext bdlCtx){
-    //super(rootNode);
     super(null);
     setRoot(rootNode);
-    System.out.println("JTree Remote logger"); 
 
     this.jp=new JPanel();
     this.jp.setLayout(new BorderLayout());
@@ -89,22 +85,15 @@
     this.logTree.setLargeModel(true);
     this.logTree.setToggleClickCount(-1); 
     this.logTree.setScrollsOnExpand(false);
-    //this.jp.setToolTipText("Select a node to refresh"); // not visible
-    this.logTree.setRootVisible(false);
-    // this create an invisible tree, even if I use "expand" so...
-    // I use expand after the first insert into the tree
-   
+    // if I do this.logTree.setRootVisible(false) => Create an invisible tree, even if I use an "expand"
+    // then need to expand after the first insert into the tree so i give up with root not visible.
     this.logTree.addMouseListener(this);
 
-    jp.add(new JScrollPane(logTree), BorderLayout.CENTER);    
+    JScrollPane jsp=new JScrollPane(logTree);
+    this.jsb_horizontal=jsp.getHorizontalScrollBar();
+    this.jsb_vertical=jsp.getVerticalScrollBar();
+    jp.add(jsp, BorderLayout.CENTER);    
     jp.setMinimumSize(new Dimension(500,25));
-
-    eventName.put(new Integer(Bundle.ACTIVE),     "ACTIVE     ");
-    eventName.put(new Integer(Bundle.INSTALLED),  "INSTALLED  ");
-    eventName.put(new Integer(Bundle.RESOLVED),   "RESOLVED   ");
-    eventName.put(new Integer(Bundle.STARTING),   "STARTING   ");
-    eventName.put(new Integer(Bundle.STOPPING),   "STOPPING   ");
-    eventName.put(new Integer(Bundle.UNINSTALLED),"UNINSTALLED");
   }
 
   /////////////////////////////////////////////////////
@@ -115,11 +104,8 @@
   public void mouseExited(MouseEvent e){}
   public void mouseReleased(MouseEvent e){} 
   public void mousePressed(MouseEvent e) {
-    int selRow = logTree.getRowForLocation(e.getX(), e.getY());
+    final int selRow = logTree.getRowForLocation(e.getX(), e.getY());
     selPath = logTree.getPathForLocation(e.getX(), e.getY());
-    JScrollPane jsp_tmp=(JScrollPane) logTree.getParent().getParent();
-    JScrollBar horizontalJsb=jsp_tmp.getHorizontalScrollBar();
-    JScrollBar verticalJsb=jsp_tmp.getVerticalScrollBar();
 
     if ( e.getClickCount()==1 & selRow!=-1 & e.getButton()>1 ) { // show JPopupMenu
       String nodeString="\""+((DefaultMutableTreeNode) selPath.getLastPathComponent()).getUserObject()+"\"";
@@ -127,7 +113,7 @@
       JMenuItem jmiRemove=new JMenuItem("Remove logs \""+nodeString.substring(0,Math.min(15,nodeString.length()))+((nodeString.length()>15)?"...\"":"\""));
       jmiRemove.addActionListener(new ActionListener(){
         public void actionPerformed(ActionEvent e){
-	  removeLog_actionPerformed();
+	  removeLog_actionPerformed(selRow);
         }	
       });
       jpopup.add(jmiRemove);
@@ -140,40 +126,50 @@
         });
         jpopup.add(jmiLogLvl);
       }
-      jpopup.show(jp, e.getX()-horizontalJsb.getValue(), e.getY()-verticalJsb.getValue());
-    } else if ( e.getClickCount()==2 & selPath!=null) { // expand selected path
+      jpopup.show(jp, e.getX()-jsb_horizontal.getValue(), e.getY()-jsb_vertical.getValue());
+    /*} else if ( e.getClickCount()==2 & selPath!=null) { // expand selected path
       if (logTree.isExpanded(selPath)) {
         logTree.collapsePath(selPath);
       } else {
         logTree.expandPath(selPath);
-      }
+      } */
     } else if ( e.getClickCount()==1 & selPath!=null ) { // reload logTree and let selected path location
-      int horizontal_jsb_init_value=horizontalJsb.getValue();
-      int vertical_jsb_init_value=verticalJsb.getValue();
-      int row_y_init_loc=(int) ((logTree.getRowBounds(selRow)).getY());
-      Enumeration enu=logTree.getExpandedDescendants(new TreePath(rootNode));
-      reload();
-      if (enu!=null) {
-        while (enu.hasMoreElements()) {
-	  logTree.expandPath((TreePath) enu.nextElement());
-        }
-      }
-      // without next line if scrollbar_value=scrollbar_max it's generate a bad shift (may be vertical scrollbar height)
-      logTree.scrollPathToVisible(selPath);
-      int row_y_new_loc=(int) ((logTree.getRowBounds(logTree.getRowForPath(selPath))).getY());
-      int vertical_jsb_new_value=vertical_jsb_init_value+(row_y_new_loc-row_y_init_loc);
-      verticalJsb.setValue(vertical_jsb_new_value);
-      horizontalJsb.setValue(horizontal_jsb_init_value);
-      logTree.setSelectionPath(selPath);
-      logTree.repaint();
+      reloadTree(selRow);
     }
   }
+  
+  private void reloadTree(int selRow) {
+    int horizontal_jsb_init_value = jsb_horizontal.getValue();
+    int vertical_jsb_init_value = jsb_vertical.getValue();
+    int row_y_init_loc = (int) ((logTree.getRowBounds(selRow)).getY());
+    Enumeration enu = logTree.getExpandedDescendants(new TreePath(rootNode));
+    reload();
+    if ( enu != null ) { // necessaire ce test ?
+      while (enu.hasMoreElements()) {
+        logTree.expandPath((TreePath) enu.nextElement());
+      }
+    }
+    // Redefini tous les noeuds rmiport/profilName comme a jour
+    this.v_ul.removeAllElements();
+    // without next line if scrollbar_value=scrollbar_max it's generate a bad shift (may be vertical scrollbar height)
+    logTree.scrollPathToVisible(selPath);
+    int row_y_new_loc = (int) ((logTree.getRowBounds(logTree.getRowForPath(selPath))).getY());
+    int vertical_jsb_new_value = vertical_jsb_init_value+(row_y_new_loc-row_y_init_loc);
+    jsb_vertical.setValue(vertical_jsb_new_value);
+    jsb_horizontal.setValue(horizontal_jsb_init_value);
+    logTree.setSelectionPath(selPath);
+    logTree.repaint();
+  }
 
   /////////////////////////////////////
   //        Plugin Interface         //
   /////////////////////////////////////
-  public String getName(){ return "JTree Remote Logger";}
-  public Component getGUI(){return this.jp;}
+  public String getName(){
+    return "JTree Remote Logger";
+  }
+  public Component getGUI(){
+    return this.jp;
+  }
 
   /* a supprimer si on enleve l'heritage CommonPlugin -> Plugin */
   public String pluginLocation(){
@@ -191,13 +187,20 @@
     //        Slow or slowed (by a key pressed for exemple) computer.
     //        => gui.NodesTree fireNewNodeConnection after each PCE_common_plugin_added for each connected nodes
     if (e.getPropertyName().equals(Plugin.NEW_NODE_CONNECTION)){
-      try{
+      try {
         MBeanServerConnection mbsc=(MBeanServerConnection)e.getNewValue();
-	if ( !nodes.containsValue(mbsc) ) {
+	if ( !ht_connectedGateway.containsValue(mbsc) ) {
 	  String connString=(String) e.getOldValue();
 	  mbsc.addNotificationListener(new ObjectName("OSGI:name=Remote Logger"), this, null, connString);
-	  nodes.put(connString, mbsc);
-	  this.addNodesIpRef(connString);
+	  ht_connectedGateway.put(connString, mbsc);
+	  // At gateway connection time : add into the tree an rmiport/profileName node under an ip node
+          String ip=connString.split(":")[0];
+          String ref=connString.split(":")[1];
+          DefaultMutableTreeNode dmtn_ip=createIfNeed(ip, rootNode);
+          DefaultMutableTreeNode dmtn_ref=createIfNeed(ref, dmtn_ip);
+          Integer lL=this.getLogLvl(connString);
+          ht_logLvl.put(dmtn_ref, lL);
+          // ask for old log management choice :
           if (oldLogChoice==OLDLOG_THIS_TIME | oldLogChoice==OLDLOG_NOT_THIS_TIME) {
             JOptionPane jop = new JOptionPane("Do you want old log from gateway :\n"+connString+" ?", JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, new String[] {OLDLOG_THIS_TIME, OLDLOG_NOT_THIS_TIME, OLDLOG_ALWAYS, OLDLOG_NEVER}, OLDLOG_THIS_TIME);
             JDialog dialog = jop.createDialog(jp, "Old log management");
@@ -223,30 +226,29 @@
   //       NotificationListener implementation     //  
   ///////////////////////////////////////////////////
   public void handleNotification(Notification notification, Object handback) {
-    TreePath treeP=logTree.getLeadSelectionPath();
-    StringTokenizer st=new StringTokenizer(handback.toString(),":");
-    boolean isOldLog=false;
+    StringTokenizer st=new StringTokenizer(handback.toString(), ":");
     String ip=st.nextToken();
     String ref=st.nextToken();
   
-    st = new StringTokenizer(notification.getMessage(),"*");
+    st = new StringTokenizer(notification.getMessage(), "*");
     long ts=notification.getTimeStamp();
-    String time="??:??:??";
-    String date="??/??/??";
-    if (ts==0) {
-      isOldLog=true;
-    } else {
+    String time=JtreeCellRenderer.UNKNOWN_TIME;
+    String date=JtreeCellRenderer.UNKNOWN_DATE;
+    if (ts!=0) {
       Date timeDate=new Date(ts);
-      //DateFormat dateFormat = new SimpleDateFormat("hh'h'mm dd-MM-yy");
-      DateFormat df = DateFormat.getTimeInstance(DateFormat.MEDIUM); // use local date format
-      DateFormat df2 = DateFormat.getDateInstance(DateFormat.SHORT);
-      time=df.format(timeDate);
-      date=df2.format(timeDate);
+      DateFormat dateFormat = new SimpleDateFormat("dd-MM-yy");
+      DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss:SSS");
+      // if I use local date format there are indentations problems
+      //DateFormat df = DateFormat.getTimeInstance(DateFormat.MEDIUM);
+      //DateFormat df2 = DateFormat.getDateInstance(DateFormat.SHORT);
+      time=timeFormat.format(timeDate);
+      date=dateFormat.format(timeDate);
     }
     String id=st.nextToken();
     String name=st.nextToken();
     String idname=new String(id+" : "+name);
-    String state=""+eventName.get(new Integer((int) Integer.parseInt(st.nextToken())));
+    // bundle state juste after remote loger received a the log entry (in old log case do state="")
+    String state=(String) JtreeCellRenderer.ht_num2string.get(new Integer((int) Integer.parseInt(st.nextToken())));
     String lvl=st.nextToken();
     String msg=st.nextToken();
     // Get and maybe create parents nodes : ip / ref / idname
@@ -254,14 +256,20 @@
     DefaultMutableTreeNode dmtn_ref=createIfNeed(ref, dmtn_ip);
     DefaultMutableTreeNode dmtn_idname=createIfNeed(idname, dmtn_ref);
     // insert the leaf with message under id/ref/idname
-    DefaultMutableTreeNode dmtn=new DefaultMutableTreeNode(date+" | "+time+" | "+state+" | "+lvl+" | "+msg,false);
+    DefaultMutableTreeNode dmtn=new DefaultMutableTreeNode(time+" | "+date+" | "+state+" | "+lvl+" | "+msg,false);
     this.insertNodeInto(dmtn, dmtn_idname, 0);
-
-    TreePath selectedPath=this.logTree.getLeadSelectionPath();
-    if (selectedPath!=null) {
-      this.logTree.setSelectionRow(-1);
-      this.logTree.repaint();
+    // if usefull save nodes which contains new log
+    if ( !v_ul.contains(dmtn_ip) ) {
+	v_ul.add(dmtn_ip);
+	v_ul.add(dmtn_ref);
+	v_ul.add(dmtn_idname);
+    } else if ( !v_ul.contains(dmtn_ref) ) {
+	v_ul.add(dmtn_ref);
+	v_ul.add(dmtn_idname);
+    } else if ( !v_ul.contains(dmtn_idname) ) {
+	v_ul.add(dmtn_idname);
     }
+    this.logTree.repaint();
   }
 
   //////////////////////////////////////////
@@ -270,10 +278,10 @@
   private Integer getLogLvl(String connString) {
     Integer val=new Integer(0);
     try {
-      MBeanServerConnection mb=(MBeanServerConnection) nodes.get(connString);
+      MBeanServerConnection mb=(MBeanServerConnection) ht_connectedGateway.get(connString);
       val=(Integer) mb.getAttribute(new ObjectName("OSGI:name=Remote Logger"), "LogLvl");
     } catch (Exception exc) {
-      System.out.println("errrrror : "+exc);
+      exc.printStackTrace();
     }
     return val;
   }
@@ -281,7 +289,7 @@
   private void setLogLvl(TreePath tp) {
     Object[] o=tp.getPath();
     String connS=""+o[1]+":"+o[2];
-    MBeanServerConnection mb=(MBeanServerConnection) nodes.get(connS);
+    MBeanServerConnection mb=(MBeanServerConnection) ht_connectedGateway.get(connS);
     try {
       Integer curentVal=(Integer) mb.getAttribute(new ObjectName("OSGI:name=Remote Logger"), "LogLvl");
 
@@ -298,21 +306,20 @@
 
       mb.setAttribute(new ObjectName("OSGI:name=Remote Logger"), new Attribute("LogLvl", newVal));
       DefaultMutableTreeNode ddmmttnn=(DefaultMutableTreeNode) tp.getLastPathComponent();
-      logLvlHt.put(ddmmttnn, newVal);
+      ht_logLvl.put(ddmmttnn, newVal);
     } catch (Exception ex) {
       JOptionPane.showMessageDialog(jp,"Error with \""+connS+"\" :\n"+ex, "Error :", JOptionPane.ERROR_MESSAGE);
+      ex.printStackTrace();
     }
   }
 
   //////////////////////////////////////////
   //         PRIVATE TOOLS                //
   //////////////////////////////////////////
-  private void removeLog_actionPerformed() {
+  private void removeLog_actionPerformed(int selRow) {
     //System.out.println("selected path="+this.selPath);
     Object[] o= this.selPath.getPath();
     DefaultMutableTreeNode selectedDmtn=(DefaultMutableTreeNode) this.selPath.getLastPathComponent();
-    // Select root to avoid remove the selection and generate select=-1 which generate blue font
-    logTree.setSelectionRow(0);
     if (o.length==5) {
       // Can't remove first child of a bundle to avoid modify tree node color
       if ( ((DefaultMutableTreeNode) selectedDmtn.getParent()).getFirstChild()!=selectedDmtn ) {
@@ -321,50 +328,29 @@
     } else if (o.length==4) {
       removeNodeFromParent(selectedDmtn);
     } else if (o.length==3) {
-      Enumeration enume=selectedDmtn.children();
-      Vector v=new Vector();
-      while (enume.hasMoreElements()) {
-        v.add(enume.nextElement()); // modification on an enumeration element destroy the enumeration
-      }
-      for (int i=0; i<v.size() ; i++) {
-        DefaultMutableTreeNode ddmtn_tmp=(DefaultMutableTreeNode) v.elementAt(i);
-        removeNodeFromParent(ddmtn_tmp);
-      }
+      selectedDmtn.removeAllChildren();
+      reloadTree(selRow);
     } else if (o.length==2) {
       Enumeration enu_1=selectedDmtn.children();
       while (enu_1.hasMoreElements()) {
         DefaultMutableTreeNode dmtn_child=(DefaultMutableTreeNode) enu_1.nextElement();
-        Enumeration enu_2=dmtn_child.children();
-        Vector v=new Vector();
-        while (enu_2.hasMoreElements()) {
-          v.add(enu_2.nextElement());
-        }
-        for (int i=0; i<v.size() ; i++) {
-          DefaultMutableTreeNode ddmtn_tmp=(DefaultMutableTreeNode) v.elementAt(i);
-          removeNodeFromParent(ddmtn_tmp);
-        }
+	dmtn_child.removeAllChildren();
       }
+      reloadTree(selRow);
+    } else if (o.length==1) {
+      Enumeration enume=rootNode.children();
+      while (enume.hasMoreElements()) {
+        DefaultMutableTreeNode dmtn_child=(DefaultMutableTreeNode) enume.nextElement();
+	Enumeration enume2=dmtn_child.children();
+        while (enume2.hasMoreElements()) {
+          DefaultMutableTreeNode dmtn_child_child=(DefaultMutableTreeNode) enume2.nextElement();
+	  dmtn_child_child.removeAllChildren();
+	}
+      }
+      reloadTree(selRow); 
     }
   }
 
-  private void addNodesIpRef(String connString) {
-    String ip=connString.split(":")[0];
-    String ref=connString.split(":")[1];
-    DefaultMutableTreeNode dmtn_ip=createIfNeed(ip, rootNode);
-    DefaultMutableTreeNode dmtn_ref=createIfNeed(ref, dmtn_ip);
-    Integer lL=this.getLogLvl(connString);
-    logLvlHt.put(dmtn_ref, lL);
-    logTree.setSelectionRow(-1);
-    // Unable to set tree expand whithout a first node so :
-    logTree.expandPath(new TreePath(rootNode.getPath()));
-    logTree.repaint();
-  }
-
-  protected Integer getTreeNodeLogLvl(DefaultMutableTreeNode dmtn) {
-    // used by treeCellRenderer
-    return (Integer) logLvlHt.get(dmtn);
-  }
-
   private DefaultMutableTreeNode createIfNeed(String nodeToCreateAndGet, DefaultMutableTreeNode parent) {
     int childNumber=this.getChildCount(parent);
     DefaultMutableTreeNode theNode=null;
@@ -378,9 +364,18 @@
     if (theNode==null){ // create the node
       theNode=new DefaultMutableTreeNode(nodeToCreateAndGet);
       this.insertNodeInto(theNode, parent, 0);
+      if ( parent==rootNode ) {
+        v_ul.add(rootNode);
+      }
     }
+    
     return theNode;
   }
+
+  protected String getLogLvl(DefaultMutableTreeNode dmtn) {
+    // used by treeCellRenderer
+    return LOG_LVL[ ((Integer) ht_logLvl.get(dmtn)).intValue() - 1 ];
+  }
  
   protected void fireTreeNodesInserted(Object source, Object path[], int childIndices[], Object children[]) {
     // Do nothing to avoid refresh jtree after each log.
diff --git a/mosgi/console.component/src/main/resources/icons/Active.gif b/mosgi/console.component/src/main/resources/icons/Active.gif
new file mode 100644
index 0000000..643b161
--- /dev/null
+++ b/mosgi/console.component/src/main/resources/icons/Active.gif
Binary files differ
diff --git a/mosgi/console.component/src/main/resources/icons/Installed.gif b/mosgi/console.component/src/main/resources/icons/Installed.gif
new file mode 100644
index 0000000..4af4e95
--- /dev/null
+++ b/mosgi/console.component/src/main/resources/icons/Installed.gif
Binary files differ
diff --git a/mosgi/console.component/src/main/resources/icons/NEWLOG.gif b/mosgi/console.component/src/main/resources/icons/NEWLOG.gif
new file mode 100644
index 0000000..8e16a8d
--- /dev/null
+++ b/mosgi/console.component/src/main/resources/icons/NEWLOG.gif
Binary files differ
diff --git a/mosgi/console.component/src/main/resources/icons/NULL.gif b/mosgi/console.component/src/main/resources/icons/NULL.gif
new file mode 100644
index 0000000..4a1b481
--- /dev/null
+++ b/mosgi/console.component/src/main/resources/icons/NULL.gif
Binary files differ
diff --git a/mosgi/console.component/src/main/resources/icons/Resolved.gif b/mosgi/console.component/src/main/resources/icons/Resolved.gif
new file mode 100644
index 0000000..5006a97
--- /dev/null
+++ b/mosgi/console.component/src/main/resources/icons/Resolved.gif
Binary files differ
diff --git a/mosgi/console.component/src/main/resources/icons/Starting.gif b/mosgi/console.component/src/main/resources/icons/Starting.gif
new file mode 100644
index 0000000..3b600b8
--- /dev/null
+++ b/mosgi/console.component/src/main/resources/icons/Starting.gif
Binary files differ
diff --git a/mosgi/console.component/src/main/resources/icons/Stopping.gif b/mosgi/console.component/src/main/resources/icons/Stopping.gif
new file mode 100644
index 0000000..3b600b8
--- /dev/null
+++ b/mosgi/console.component/src/main/resources/icons/Stopping.gif
Binary files differ
diff --git a/mosgi/console.component/src/main/resources/icons/Uninstalled.gif b/mosgi/console.component/src/main/resources/icons/Uninstalled.gif
new file mode 100644
index 0000000..5e60dbb
--- /dev/null
+++ b/mosgi/console.component/src/main/resources/icons/Uninstalled.gif
Binary files differ