FELIX-159

   - It is now possible to select a log level for each managed remote logger (by right-clicking on the jmxconsole log tree).
   - The log tree is only refreshed upon a click (the font color of the log tree becomes blue if it is not up to date).
   - Console bug correction : if a common plugin is added after a gateway connection, the gateway informations are re-emitted.



git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@478828 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 f0eda8e..6a5300d 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
@@ -49,10 +49,12 @@
       }catch (NumberFormatException nfe) {
         state=new Integer(-1);
       }
-      if (((String) value).equals("??/??/??")) {
-	setBackground(Color.white);
-      } else{
-	setBackground((Color) eventName.get(state));
+      if (value!=null) {
+        if (((String) value).equals("??/??/??")) {
+	  setBackground(Color.white);
+        } else{
+	  setBackground((Color) eventName.get(state));
+        }
       }
     }
     setText((String) value);
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 5e8546b..ecefb60 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
@@ -18,89 +18,117 @@
 package org.apache.felix.mosgi.console.component;
 
 import org.osgi.framework.BundleContext;
-
 import java.awt.Color;
-import javax.swing.JTree;
-import javax.swing.JLabel;
-import java.util.StringTokenizer;
-
-import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.TreeCellRenderer;
 import java.awt.Component;
-import javax.swing.tree.DefaultMutableTreeNode;
 import java.awt.Graphics;
-import java.util.NoSuchElementException;
 import java.awt.Font;
 import java.awt.Dimension;
-
-import javax.swing.ImageIcon;
 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;
 
 public class JtreeCellRenderer extends DefaultTreeCellRenderer {
 
+  private static final String[] LOG_LVL=new String[] {"", "Error", "Warning", "Info", "Debug"};
+
   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.white,Color.white,Color.black};
+  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;
 
-  public JtreeCellRenderer(BundleContext bdlCtx){
+  private RemoteLogger_jtree rl_jtree=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")));
     }
     this.iiOldLog=new ImageIcon(Toolkit.getDefaultToolkit().getImage(bdlCtx.getBundle().getResource("icons/OLDLOG.gif")));
-
   }
 
   public Dimension getPreferredSize() {
     Dimension dim = super.getPreferredSize();
-    //maxL=(isLeaf)?Math.max(maxL,dim.width):maxL;
-    //
-    return (isLeaf)?dim:new Dimension(800/*maxL*/,dim.height);
+    return (isLeaf)?dim:new Dimension(800,dim.height);
   }
 
   public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
     this.isLeaf=leaf;
-
-    super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);
+    //super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);
+    setText(value.toString());
     setOpaque(true);
     setBackground(Color.white);
-    setFont(new Font("Monospaced",Font.BOLD,12));
+    setFont(new Font("Monospaced",Font.BOLD,14));
     setToolTipText(null);
-
+    setIcon(null);
     StringTokenizer st=null;
     DefaultMutableTreeNode dmtn=(DefaultMutableTreeNode)value;
+
     int lvl=dmtn.getLevel(); 
-    if(lvl==3 & dmtn.getChildCount()>0){
-      st=new StringTokenizer(dmtn.getFirstChild().toString()," | ");
-    }
-    if (lvl==4){
-      st=new StringTokenizer(dmtn.toString()," | ");
+    switch (lvl) {
+      case 2: { // port / profilName / logLvl
+        Integer val=rl_jtree.getTreeNodeLogLvl((DefaultMutableTreeNode) value);
+        setText(value+" (log level="+LOG_LVL[val.intValue()]+")");
+	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()," | ");
+        if(st!=null) {	
+          String date=st.nextToken();
+          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>");
+	  }
+	} 
+        break;
+      }
+      case 4: { // icon / date / time / state / logLvl / msg
+        st=new StringTokenizer(dmtn.toString()," | ");
+	setFont(new Font("Monospaced",Font.PLAIN,10));
+        if(st!=null){
+          String date=st.nextToken();
+          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);
+	      }
+	    }
+	  }
+	}
+      break;
+      }
     }
 
-    if(st!=null){
-      String date=st.nextToken();
-      st.nextToken();
-      String state=st.nextToken();
-      for (int i=0 ; i<states.length ; i++){
-        if (state.equals(states[i])){
-          if (lvl==4){
-	    if(!date.equals("??/??/??")){
-	      setIcon(ii[i]);
-	    }else{
-	      setIcon(iiOldLog);
-	    }
-	    setFont(new Font("Monospaced",Font.PLAIN,10));
-          }else{ 
-            StringTokenizer st2 = new StringTokenizer(((DefaultMutableTreeNode)dmtn.getFirstChild()).toString()," | ");
-            setToolTipText("<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()+" : "+st2.nextToken()+"</B></html>");
-            setBackground(colors[i]);
-          }
-	break;
-        }
-      }
-    }	
+    if (tree.getLeadSelectionPath()==null) {
+      setForeground(Color.blue);
+    } else {
+      setForeground(Color.black);
+    }
 	
     return this;
   }	
diff --git a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/MyTree.java b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/MyTree.java
index 4157140..b26d06e 100644
--- a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/MyTree.java
+++ b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/MyTree.java
@@ -21,6 +21,7 @@
 import javax.swing.tree.DefaultTreeModel;
 import javax.swing.ToolTipManager;
 import javax.swing.UIManager;
+import javax.swing.tree.TreePath;
 
 public class MyTree extends JTree{
 
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 ad307f7..a0aa432 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
@@ -25,92 +25,68 @@
 import javax.swing.JButton;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.ListSelectionModel;
+import javax.swing.JFileChooser;
+import javax.swing.table.JTableHeader;
+import javax.swing.JOptionPane;
 import java.awt.Component;
-
+import java.awt.BorderLayout;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
 import javax.management.Notification;
 import javax.management.NotificationListener;
 import javax.management.ObjectName;
 import javax.management.MBeanServerConnection;
-import javax.swing.ListSelectionModel;
-
 import java.util.Hashtable;
 import java.util.StringTokenizer;
-
-import java.beans.PropertyChangeEvent;
-
-import java.awt.BorderLayout;
-import java.awt.event.ActionListener;
-import java.awt.event.ActionEvent;
 import java.util.Vector;
-
+import java.util.Date;
 import java.io.PrintStream;
 import java.io.File;
 import java.io.FileNotFoundException;
-import javax.swing.JFileChooser;
-		
-import java.util.Date;
 import java.text.DateFormat;
 //import java.text.SimpleDateFormat;
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.tree.DefaultMutableTreeNode;
 
-public class RemoteLogger_jtable extends DefaultTableModel implements CommonPlugin, NotificationListener{
+public class RemoteLogger_jtable extends DefaultTableModel implements CommonPlugin, NotificationListener, ActionListener{
 
   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",
+	  "",""};
   private JPanel jbPanel;
   private JPanel jp;
   private Hashtable nodes=new Hashtable();
 
-  public void jb_actionPerformed(ActionEvent e) {
-    String compoName=((Component) e.getSource()).getName();
-	
-    if (compoName.equals("jb_save")){
-      PrintStream ps=System.out;
-      JFileChooser jfc=new JFileChooser();
-      if (jfc.showSaveDialog(null)==JFileChooser.APPROVE_OPTION & jfc.getSelectedFile()!=null){	
-      try{
-        ps=new PrintStream(jfc.getSelectedFile());
-        System.out.println("Save remote log into \""+jfc.getSelectedFile().getName()+"\""); }
-      catch (FileNotFoundException fnfe){
-        System.out.println("err : "+fnfe); }
-      }
-      int col=this.logList.getColumnCount(); // TODO : try this.getColumnCount()
-      int line=this.logList.getRowCount() - 1; // last line always empty
-      //ps.print(col+" "+line);
-      Vector tableData=new Vector();
-      tableData=this.getDataVector();
-      for (int i=0 ; i<line ; i++){
-        ps.print(i+" : ");
-        for (int j=0 ; j<col ; j++){
-	  ps.print((String) ( ((Vector) (tableData.elementAt(i))).elementAt(j) )+" | ");	
-        }
-        ps.print("\n");
-      }
-    }
-  }
-
   public RemoteLogger_jtable (){
     super(new String[]{"Date","Time", "Src", "Id", "Name", "State", "Lvl", "Msg"},1);
     System.out.println("JTable Remote logger");
-   
-    this.jp=new JPanel();
-    this.jp.setLayout(new BorderLayout());
-   
-    this.jbPanel=new JPanel();
-    this.jbPanel.setSize(300,25);
 
-    this.jb_save=new JButton("Save log on file");
-    this.jb_save.setName("jb_save");
+    jp=new JPanel();
+    jp.setLayout(new BorderLayout());
+   
+    jbPanel=new JPanel();
+    jbPanel.setSize(300,25);
 
-    ActionListener al = new ActionListener(){
-        public void actionPerformed(ActionEvent e){
-            jb_actionPerformed(e);
-        }
+    jb_save=new JButton("Save log on file");
+    jb_save.setName("jb_save");
+    jb_save.addActionListener(this);
+    
+    logList=new JTable(this){
+      protected JTableHeader createDefaultTableHeader() {
+        return new JTableHeader(columnModel) {
+          public String getToolTipText(MouseEvent e) {
+            String tip = null;
+            java.awt.Point p = e.getPoint();
+            int index = columnModel.getColumnIndexAtX(p.x);
+            int realIndex = columnModel.getColumn(index).getModelIndex();
+            return columnToolTips[realIndex];
+          }
+        };
+      }
     };
-    this.jb_save.addActionListener(al);
-
-    logList=new JTable(this);
     JtableCellRenderer cellRenderer=new JtableCellRenderer();
     logList.setDefaultRenderer(Object.class,cellRenderer);
 
@@ -126,10 +102,10 @@
     logList.getColumnModel().getColumn(7).setPreferredWidth(180);    
 
     logList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-    logList.getTableHeader().setReorderingAllowed(true);//false); // true c'est sympa pourtant... ?
+    logList.getTableHeader().setReorderingAllowed(true);//false);
     
-    this.jbPanel.add(jb_save);
-    jp.add(this.jbPanel, BorderLayout.NORTH);
+    jbPanel.add(jb_save);
+    jp.add(jbPanel, BorderLayout.NORTH);
     jp.add(new JScrollPane(logList), BorderLayout.CENTER);    
   }
 
@@ -146,7 +122,6 @@
   public void registerServicePlugin(){}
   public void unregisterServicePlugin(){}
 /* fin a supprimer */
-
   
   public void propertyChange(PropertyChangeEvent e){
     if (e.getPropertyName().equals(Plugin.NEW_NODE_CONNECTION)){
@@ -186,5 +161,33 @@
     this.insertRow(0,event); 
     this.fireTableRowsInserted(0, 0);
   }
-  
+ 
+  public void actionPerformed(ActionEvent e) {
+    Object o=e.getSource();
+    if ( o==jb_save){
+      PrintStream ps=System.out;
+      JFileChooser jfc=new JFileChooser();
+      if (jfc.showSaveDialog(null)==JFileChooser.APPROVE_OPTION & jfc.getSelectedFile()!=null){	
+      try{
+        ps=new PrintStream(jfc.getSelectedFile());
+        System.out.println("Save remote log into \""+jfc.getSelectedFile().getName()+"\""); }
+      catch (FileNotFoundException fnfe){
+        System.out.println("err : "+fnfe); }
+      }
+      int col=this.logList.getColumnCount();
+      int line=this.logList.getRowCount() - 1; // last line always empty
+      //ps.print(col+" "+line);
+      Vector tableData=new Vector();
+      tableData=this.getDataVector();
+      for (int i=0 ; i<line ; i++){
+        ps.print(i+" : ");
+        for (int j=0 ; j<col ; j++){
+	  ps.print((String) ( ((Vector) (tableData.elementAt(i))).elementAt(j) )+" | ");	
+        }
+        ps.print("\n");
+      }
+    }
+  }
+
+ 
 }
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 35bdff6..e3423a1 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
@@ -21,68 +21,61 @@
 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.JFrame;
 import javax.swing.JPanel;
-import javax.swing.JFileChooser;
 import javax.swing.JPopupMenu;
 import javax.swing.JMenuItem;
 import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.DefaultTableModel;
+import javax.swing.JScrollBar;
 import javax.swing.JTree;
 import javax.swing.tree.DefaultTreeModel;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.TreePath;
 import javax.swing.JOptionPane;
-
+import javax.swing.JDialog;
 import java.awt.Component;
 import java.awt.BorderLayout;
+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;
 import javax.management.NotificationListener;
 import javax.management.ObjectName;
 import javax.management.MBeanServerConnection;
-import javax.swing.ListSelectionModel;
-
+import javax.management.Attribute;
 import java.util.Hashtable;
 import java.util.StringTokenizer;
 import java.util.Vector;
 import java.util.Date;
+import java.util.Enumeration;
 import java.text.DateFormat;
-
-import java.io.PrintStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-		
-//import java.text.SimpleDateFormat;
 //import org.osgi.service.prefs.Preferences;
 
-public class RemoteLogger_jtree extends DefaultTreeModel implements CommonPlugin, NotificationListener{
+public class RemoteLogger_jtree extends DefaultTreeModel implements CommonPlugin, NotificationListener, MouseListener {
 
-  private static final int OLDLOG_THIS_TIME = 0;
-  private static final int OLDLOG_ALWAYS = 1;
-  private static final int OLDLOG_NEVER = 2;
+  private static final String OLDLOG_THIS_TIME     ="This time";
+  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 int oldLogChoice=OLDLOG_THIS_TIME;
+  private static final String[] LOG_LVL=new String[] {"Error", "Warning", "Info", "Debug"};
+  private Hashtable logLvlHt=new Hashtable(); // treeNode/logLvl
+
   private MyTree logTree;
-  private MouseListener ml;
   private TreePath selPath;
   private JPanel jp;
   private DefaultMutableTreeNode rootNode=new DefaultMutableTreeNode("root");
   private Hashtable eventName=new Hashtable();
-  private Hashtable nodes=new Hashtable();
+
+  private Hashtable nodes=new Hashtable();    // connString/mbsc
 
   public RemoteLogger_jtree (BundleContext bdlCtx){
+    //super(rootNode);
     super(null);
     setRoot(rootNode);
     System.out.println("JTree Remote logger"); 
@@ -91,36 +84,21 @@
     this.jp.setLayout(new BorderLayout());
    
     this.logTree=new MyTree(this);
-    JtreeCellRenderer treeCellRenderer=new JtreeCellRenderer(bdlCtx);
+    JtreeCellRenderer treeCellRenderer=new JtreeCellRenderer(bdlCtx, this);
     this.logTree.setCellRenderer(treeCellRenderer);
     this.logTree.setLargeModel(true);
-    //this.logTree.setToggleClickCount(2); 
+    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...
+    // this create an invisible tree, even if I use "expand" so...
     // I use expand after the first insert into the tree
-
-    MouseListener ml = new MouseAdapter() {
-      public void mousePressed(MouseEvent e) {
-        int selRow = logTree.getRowForLocation(e.getX(), e.getY());
-        selPath = logTree.getPathForLocation(e.getX(), e.getY());
-        if ( selRow!=-1 & e.getButton()>1 ) {
-	  String nodeString="\""+((DefaultMutableTreeNode) selPath.getLastPathComponent()).getUserObject()+"\"";
-	  JMenuItem itemm=new JMenuItem("Delete logs "+nodeString);
-	  itemm.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e){
-	      removeNodeFromParent((DefaultMutableTreeNode) selPath.getLastPathComponent());
-	    }
-	  });
-	  JPopupMenu jpopup=new JPopupMenu();
-	  jpopup.add(itemm);
-          jpopup.show(jp, e.getX(), e.getY());
-        }
-      }
-    };
-    this.logTree.addMouseListener(ml);
+   
+    this.logTree.addMouseListener(this);
 
     jp.add(new JScrollPane(logTree), 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   ");
@@ -129,84 +107,128 @@
     eventName.put(new Integer(Bundle.UNINSTALLED),"UNINSTALLED");
   }
 
+  /////////////////////////////////////////////////////
+  //           Mouse Listener Interface              //
+  /////////////////////////////////////////////////////
+  public void mouseEntered(MouseEvent e){}
+  public void mouseClicked(MouseEvent e) {}
+  public void mouseExited(MouseEvent e){}
+  public void mouseReleased(MouseEvent e){} 
+  public void mousePressed(MouseEvent e) {
+    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()+"\"";
+      JPopupMenu jpopup=new JPopupMenu();
+      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();
+        }	
+      });
+      jpopup.add(jmiRemove);
+      if (selPath.getPath().length==3) {
+        JMenuItem jmiLogLvl=new JMenuItem("Set log lvl");
+        jmiLogLvl.addActionListener(new ActionListener(){
+          public void actionPerformed(ActionEvent e){
+            setLogLvl(selPath);
+          }
+        });
+        jpopup.add(jmiLogLvl);
+      }
+      jpopup.show(jp, e.getX()-horizontalJsb.getValue(), e.getY()-verticalJsb.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();
+    }
+  }
+
   /////////////////////////////////////
-  //  Plugin Interface ////////////////
+  //        Plugin Interface         //
   /////////////////////////////////////
   public String getName(){ return "JTree Remote Logger";}
   public Component getGUI(){return this.jp;}
 
-/* a supprimer si on enleve l'heritage CommonPlugin -> Plugin */
+  /* a supprimer si on enleve l'heritage CommonPlugin -> Plugin */
   public String pluginLocation(){
     return null;
   }
   public void registerServicePlugin(){}
   public void unregisterServicePlugin(){}
-/* fin a supprimer */
+  /* fin a supprimer */
  
   public void propertyChange(PropertyChangeEvent e){
-    //System.out.println("PCE : "+e.getPropertyName());
+    // TODO : DEBUG
+    // Sometimes ???
+    //   *1)  when stay with "return" key pressed => JoptionPane miss getValue()
+    //   *2)  when commonPanel started after a new_node_connection event.
+    //        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{
-        MBeanServerConnection mbs=(MBeanServerConnection)e.getNewValue();
-        if (nodes.get(mbs)==null){
-          //System.out.println("RemoteLogger_jtree add a notification listener on this Remote Logger : "+mbs);
-	  ((MBeanServerConnection)e.getNewValue()).addNotificationListener(new ObjectName("OSGI:name=Remote Logger"), this, null, e.getOldValue());
-          nodes.put(mbs, "ok");
-	  if (oldLogChoice==OLDLOG_THIS_TIME | oldLogChoice==JOptionPane.CLOSED_OPTION ) {
-	    oldLogChoice=JOptionPane.showOptionDialog(jp,"Do you want old log from gateway :\n"+((String) e.getOldValue())+" ?","Old log management",JOptionPane.DEFAULT_OPTION,JOptionPane.QUESTION_MESSAGE,null,new Object[] {"This time", "Always", "Never"},"This time");
-	  }
-          switch (oldLogChoice) {
-            case (OLDLOG_ALWAYS) : { 
+        MBeanServerConnection mbsc=(MBeanServerConnection)e.getNewValue();
+	if ( !nodes.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);
+          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");
+	    //dialog.setModal(true);
+	    dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+	    dialog.show();
+	    oldLogChoice = (String) jop.getValue();
+	    if (oldLogChoice==JOptionPane.UNINITIALIZED_VALUE) {
+              oldLogChoice=OLDLOG_THIS_TIME; // *1)
 	    }
-	    case (OLDLOG_THIS_TIME) : {
-	    }
-	    case (JOptionPane.CLOSED_OPTION) : {
-	      mbs.invoke(new ObjectName("OSGI:name=Remote Logger"), "sendOldLog", new Object[]{}, new String[]{});
-              break;
-	    }
-	    case (OLDLOG_NEVER) : { 
-	    }
+	  } 
+          if (oldLogChoice==OLDLOG_THIS_TIME | oldLogChoice==OLDLOG_ALWAYS) {
+            mbsc.invoke(new ObjectName("OSGI:name=Remote Logger"), "sendOldLog", new Object[]{}, new String[]{});
 	  }
         }
       } catch(Exception ex){
-        ex.printStackTrace();
+        System.out.println("[RemoteLogger_jtree] error : "+ex);
       }
     }
   }
-
-  private DefaultMutableTreeNode createIfNeed(String nodeToCreateAndGet, DefaultMutableTreeNode parent, boolean isOldLog){
-    int childNumber=this.getChildCount(parent);
-    DefaultMutableTreeNode theNode=null;
-    for (int i=0 ; i<childNumber ; i++){ // is node even exist ?
-      String string_pool=((DefaultMutableTreeNode)(this.getChild(parent, i))).toString();
-      if (string_pool.equals(nodeToCreateAndGet)){
-        theNode=(DefaultMutableTreeNode) (this.getChild(parent, i));
-        break;
-      }
-    }
-    if (theNode==null){ // create the node
-      theNode=new DefaultMutableTreeNode(nodeToCreateAndGet);
-      // Unable to set tree expand whithout a first node so :
-      if (rootNode.getChildCount()==0){
-        this.insertNodeInto(theNode, parent, 0);
-        logTree.expandPath(new TreePath(rootNode.getPath()));
-      } else{
-        if(isOldLog){
-          this.insertNodeInto(theNode, parent, parent.getChildCount());
-        } else {
-          this.insertNodeInto(theNode, parent, 0);
-        }
-      }
-    }
-    return theNode;
-  }
-
+ 
+  ///////////////////////////////////////////////////
+  //       NotificationListener implementation     //  
+  ///////////////////////////////////////////////////
   public void handleNotification(Notification notification, Object handback) {
+    TreePath treeP=logTree.getLeadSelectionPath();
     StringTokenizer st=new StringTokenizer(handback.toString(),":");
     boolean isOldLog=false;
     String ip=st.nextToken();
     String ref=st.nextToken();
-    
+  
     st = new StringTokenizer(notification.getMessage(),"*");
     long ts=notification.getTimeStamp();
     String time="??:??:??";
@@ -228,13 +250,140 @@
     String lvl=st.nextToken();
     String msg=st.nextToken();
     // Get and maybe create parents nodes : ip / ref / idname
-    DefaultMutableTreeNode dmtn_ip=createIfNeed(ip, rootNode, isOldLog);
-    DefaultMutableTreeNode dmtn_ref=createIfNeed(ref, dmtn_ip, isOldLog);
-    DefaultMutableTreeNode dmtn_idname=createIfNeed(idname, dmtn_ref, isOldLog);
+    DefaultMutableTreeNode dmtn_ip=createIfNeed(ip, rootNode);
+    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);
-    this.insertNodeInto(dmtn, dmtn_idname, (isOldLog)?dmtn_idname.getChildCount():0);
-    this.reload(dmtn_idname);
+    this.insertNodeInto(dmtn, dmtn_idname, 0);
+
+    TreePath selectedPath=this.logTree.getLeadSelectionPath();
+    if (selectedPath!=null) {
+      this.logTree.setSelectionRow(-1);
+      this.logTree.repaint();
+    }
   }
-  
+
+  //////////////////////////////////////////
+  //     MBean attribute manipulation     //
+  //////////////////////////////////////////
+  private Integer getLogLvl(String connString) {
+    Integer val=new Integer(0);
+    try {
+      MBeanServerConnection mb=(MBeanServerConnection) nodes.get(connString);
+      val=(Integer) mb.getAttribute(new ObjectName("OSGI:name=Remote Logger"), "LogLvl");
+    } catch (Exception exc) {
+      System.out.println("errrrror : "+exc);
+    }
+    return val;
+  }
+
+  private void setLogLvl(TreePath tp) {
+    Object[] o=tp.getPath();
+    String connS=""+o[1]+":"+o[2];
+    MBeanServerConnection mb=(MBeanServerConnection) nodes.get(connS);
+    try {
+      Integer curentVal=(Integer) mb.getAttribute(new ObjectName("OSGI:name=Remote Logger"), "LogLvl");
+
+      JOptionPane jop = new JOptionPane("Select a log level for \""+connS+"\" :", JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, LOG_LVL, LOG_LVL[curentVal.intValue()-1]);
+      JDialog dialog = jop.createDialog(jp, "Log level");
+      dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+      dialog.show();
+      String choice = (String) jop.getValue();
+      Integer newVal=new Integer(4);
+      if (choice.equals("Error")) {newVal=new Integer(1);}
+      else if (choice.equals("Warning")) {newVal=new Integer(2);}
+      else if (choice.equals("Info")) {newVal=new Integer(3);}
+      else if (choice.equals("Debug")) {newVal=new Integer(4);}
+
+      mb.setAttribute(new ObjectName("OSGI:name=Remote Logger"), new Attribute("LogLvl", newVal));
+      DefaultMutableTreeNode ddmmttnn=(DefaultMutableTreeNode) tp.getLastPathComponent();
+      logLvlHt.put(ddmmttnn, newVal);
+    } catch (Exception ex) {
+      JOptionPane.showMessageDialog(jp,"Error with \""+connS+"\" :\n"+ex, "Error :", JOptionPane.ERROR_MESSAGE);
+    }
+  }
+
+  //////////////////////////////////////////
+  //         PRIVATE TOOLS                //
+  //////////////////////////////////////////
+  private void removeLog_actionPerformed() {
+    //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 ) {
+        removeNodeFromParent(selectedDmtn);
+      }
+    } 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);
+      }
+    } 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);
+        }
+      }
+    }
+  }
+
+  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;
+    for (int i=0 ; i<childNumber ; i++){ // is node even exist ?
+      String string_pool=((DefaultMutableTreeNode)(this.getChild(parent, i))).toString();
+      if (string_pool.equals(nodeToCreateAndGet)){
+        theNode=(DefaultMutableTreeNode) (this.getChild(parent, i));
+        break;
+      }
+    }
+    if (theNode==null){ // create the node
+      theNode=new DefaultMutableTreeNode(nodeToCreateAndGet);
+      this.insertNodeInto(theNode, parent, 0);
+    }
+    return theNode;
+  }
+ 
+  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.gui/src/main/java/org/apache/felix/mosgi/console/gui/Activator.java b/mosgi.console.gui/src/main/java/org/apache/felix/mosgi/console/gui/Activator.java
index 69714b4..f57ff90 100644
--- a/mosgi.console.gui/src/main/java/org/apache/felix/mosgi/console/gui/Activator.java
+++ b/mosgi.console.gui/src/main/java/org/apache/felix/mosgi/console/gui/Activator.java
@@ -45,7 +45,7 @@
   protected BundleContext m_context = null;
 
   protected ArrayList m_pluginList = null;
-  protected ArrayList m_commonpluginList = null; //TODO To I need this table ?
+  protected ArrayList m_commonpluginList = null;  //TODO Do I need this table ?
   private EventListenerList m_listenerList = null;
   
   private JFrame m_frame = null;
@@ -57,6 +57,9 @@
     m_listenerList = new EventListenerList();
   }
 
+  ///////////////////////////////////////
+  //         BundleActivator           //
+  ///////////////////////////////////////
   public void start(BundleContext context) {
     m_context = context;
 
@@ -72,9 +75,6 @@
               if(svcObj instanceof CommonPlugin){
                 m_commonpluginList.add(svcObj);
                 firePropertyChangedEvent(CommonPlugin.COMMON_PLUGIN_ADDED, null, svcObj);
-		//evite d'attendre le Thread pr que le common plugin remotelogger_jtree/jtable chope le MBean remote logger :
-		//nodesTree.tryToConnectAllNodes();
-		//createDefaultNodes(false);
               }else if (svcObj instanceof Plugin){
                 m_pluginList.add(svcObj);
                 firePropertyChangedEvent(Plugin.PLUGIN_ADDED, null, svcObj);
@@ -117,7 +117,7 @@
       m_frame.setIconImage(Toolkit.getDefaultToolkit().getImage(m_context.getBundle().getResource("images/logo.gif")));
       //m_frame.setResizable(false);
       //m_frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-      //add a windowListener to save screen size preference
+      // TODO : add a windowListener and use a Preferences service to save screen size
       m_frame.addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
           JFrame jf=(JFrame) we.getWindow();
@@ -129,8 +129,6 @@
         }
       });
 	    
-      //Dimension wndSize = m_frame.getToolkit().getScreenSize();
-      //m_frame.setBounds(wndSize.width / 8, wndSize.height / 8, 1000, 700);
       Dimension maxdim = m_frame.getToolkit().getScreenSize();
       int m_width=maxdim.width-100;
       int m_height=maxdim.height-100;
@@ -152,13 +150,25 @@
 
     // Now try to manually initialize the plugin list
     // since some might already be available.
-    //initializePlugins();
-    this.nodesTree.runDiscovery();
-
+    // initializePlugins();
+    
     m_frame.setVisible(true);
+    this.nodesTree.runDiscovery();
+  }
+ 
+  public void stop(BundleContext context) {
+    if (m_frame != null) {
+      this.nodesTree.stop();
+      m_frame.setVisible(false);
+      m_frame.dispose();
+      m_frame = null;
+    }
   }
 
-  private synchronized void initializePlugins() { // Never used ?
+  ////////////////////////////////////
+  //
+  ////////////////////////////////////
+  /*private synchronized void initializePlugins() { // Never used ?
     System.out.println("??? private synchronized void initializePlugins() ???");
     try {
       // Get all model services.
@@ -171,7 +181,6 @@
           if (!m_pluginList.contains(svcObj)) {
             m_pluginList.add(svcObj);
             firePropertyChangedEvent(Plugin.PLUGIN_ADDED, null, (Plugin)svcObj);
-	    //this.nodesTree.valueChanged(null);
           }
         }
       }
@@ -183,7 +192,6 @@
           if (!m_commonpluginList.contains(svcObj)) {
             m_commonpluginList.add(svcObj);
             firePropertyChangedEvent(CommonPlugin.COMMON_PLUGIN_ADDED, null, (CommonPlugin)svcObj);
-	    //this.nodesTree.valueChanged(null);
           }
         }
       }
@@ -192,16 +200,7 @@
       System.err.println("ShellGuiActivator: " + ex);
       ex.printStackTrace();
     }
-  }
-
-  public void stop(BundleContext context) {
-    if (m_frame != null) {
-      this.nodesTree.stop();
-      m_frame.setVisible(false);
-      m_frame.dispose();
-      m_frame = null;
-    }
-  }
+  }*/
 
   //////////////////////////////
   // Event methods.           //
@@ -215,22 +214,11 @@
   }
 
   public void firePropertyChangedEvent(String name, Object oldValue, Object newValue) {
+    //System.out.println("[Gui Activator] fire PCE("+name+","+oldValue+","+newValue+")");
     PropertyChangeEvent event = null;
     // Guaranteed to return a non-null array
     Object[] listeners = m_listenerList.getListenerList();
 
-/* a supprimer de ici
-    String mb="";
-    //System.out.println("name="+name);
-    if(name.equals("pluggin_added") | name.equals("pluggin_removed")){
-      mb="java.awt.Component";
-    } else {
-      mb=newValue.toString();
-      mb=mb.substring((mb.indexOf("$")==-1)?0:mb.indexOf("$")+1,mb.length());
-    }
-    System.out.println("console.gui whill firePCE "+(int)(listeners.length/2)+"* : (this,"+name+","+oldValue+","+mb+")");
-/* a ici */
-
     // Process the listeners last to first, notifying
     // those that are interested in this event 
     for (int i = listeners.length - 2; i >= 0; i -= 2) {
diff --git a/mosgi.console.gui/src/main/java/org/apache/felix/mosgi/console/gui/NodesTree.java b/mosgi.console.gui/src/main/java/org/apache/felix/mosgi/console/gui/NodesTree.java
index 48a7534..f099311 100644
--- a/mosgi.console.gui/src/main/java/org/apache/felix/mosgi/console/gui/NodesTree.java
+++ b/mosgi.console.gui/src/main/java/org/apache/felix/mosgi/console/gui/NodesTree.java
@@ -18,14 +18,14 @@
  */
 package org.apache.felix.mosgi.console.gui;
 
-//import java.awt.GridLayout;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import javax.swing.JOptionPane;
-
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTree;
@@ -41,6 +41,7 @@
 import java.util.Enumeration;
 import org.osgi.framework.BundleContext;
 import org.apache.felix.mosgi.console.ifc.Plugin;
+import org.apache.felix.mosgi.console.ifc.CommonPlugin;
 import org.apache.felix.framework.cache.BundleCache;
 
 import javax.management.MBeanServerConnection;
@@ -55,7 +56,7 @@
 
 //import javax.jmdns.ServiceInfo;
 
-public class NodesTree extends JPanel implements TreeSelectionListener, NotificationListener, ActionListener {
+public class NodesTree extends JPanel implements TreeSelectionListener, NotificationListener, ActionListener, PropertyChangeListener {
 
   static String TOP_NAME="Servers";
   static int POOLING_TIME=2000;
@@ -84,7 +85,6 @@
 
   public NodesTree(Activator a,BundleContext bc) {
     super(new BorderLayout());
-    //super(new GridLayout(1, 0));
     this.a=a;
     this.bc=bc;
     this.pt=new PoolingThread();
@@ -108,8 +108,20 @@
     poolThread.start();
   }
 
-
-
+  //////////////////////////////////////////////////
+  //          PropertyChangeListener              //
+  //////////////////////////////////////////////////
+  public void propertyChange(PropertyChangeEvent event) {
+    if (event.getPropertyName().equals(CommonPlugin.COMMON_PLUGIN_ADDED)) {
+      Enumeration enu=connectedNodes.keys();
+      while (enu.hasMoreElements()) {
+        // Common plugin added after a gateway connection so firePCE(Plugin.NEW_NODE_CONNECTION, connString , mbsc) again :
+        String key=(String) enu.nextElement();
+        System.out.println("   "+key+"="+connectedNodes.get(key));
+        a.firePropertyChangedEvent(Plugin.NEW_NODE_CONNECTION, key, connectedNodes.get(key));
+      }
+    }
+  }
 
   //////////////////////////////////////////////////////
   //               TreeSelectionListener              //
@@ -160,8 +172,9 @@
   }
 
   public void actionPerformed(ActionEvent e) {
+    // TODO : 
     Object object = e.getSource();
-    if (object==addNodeButton) {
+    if (object==addNodeButton) { // Add a new node into tree
       String connString = JOptionPane.showInputDialog("Please input a connection string : ", "127.0.0.1:1099/vosgi");
       TreePath tp=tree.getSelectionPath();
       if (connString!=null) {
@@ -170,7 +183,7 @@
 	isAllNodesConnected=false;
 	tree.setSelectionPath(tp);
       }
-    } else if (object==removeNodeButton) {
+    } else if (object==removeNodeButton) { // Remove a nod from tree
       DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
       String connString=(String) node.getUserObject();
       if (connString!=null){
@@ -270,13 +283,12 @@
       }catch(MalformedObjectNameException e){
         e.printStackTrace();
       }catch(Exception e){
-        //e.printStackTrace();
+	//use one thread per node to avoid being freeze by a timeOutConnection
 	System.out.println("gui.NodesTree.connectToNode("+connString+") : "+e);
 	System.out.println("  => Delete this node ? to implement... ?");
 
       }
     }else{
-      // a.firePCE(NEW_NODE_CONNECTION, connString, ls) inutile maintenant je sais plus pourqouoi ca l'etait d'ailleur ???
       return true;
     }
   return false;
diff --git a/mosgi.jmx.remotelogger/src/main/java/org/apache/felix/mosgi/jmx/remotelogger/Logger.java b/mosgi.jmx.remotelogger/src/main/java/org/apache/felix/mosgi/jmx/remotelogger/Logger.java
index ef35567..ef44cfc 100644
--- a/mosgi.jmx.remotelogger/src/main/java/org/apache/felix/mosgi/jmx/remotelogger/Logger.java
+++ b/mosgi.jmx.remotelogger/src/main/java/org/apache/felix/mosgi/jmx/remotelogger/Logger.java
@@ -39,6 +39,7 @@
 
 import java.io.Serializable;
 import java.util.Enumeration;
+import java.util.Vector;
 
 public class Logger extends NotificationBroadcasterSupport implements LogListener,BundleActivator,ServiceListener, LoggerMBean, Serializable{
 
@@ -51,24 +52,42 @@
 
   private Object logMutex=new Object();
 
-  private boolean debugLogFlag=true;
-  private boolean errorLogFlag=true;
-  private boolean infoLogFlag=true;
-  private boolean warningLogFlag=true;
+  private static final String[] LOG_LVL=new String[] {"","ERROR  ","WARNING ","INFO   ","DEBUG  "};
+  private Integer logLvl=new Integer(4);
 
   private MBeanServer agent=null;
   private ObjectName remoteLoggerON=null;
 
-//LogerMBean Interface
+  /////////////////////////////////
+  //     LogerMBean Interface    //
+  /////////////////////////////////
   public void sendOldLog(){
-    System.out.println("mosgi.jmx.remoteLogger.Logger : send old log");
+    System.out.println("[remoteLogger.Logger] send old log");
     Enumeration oldLog = this.lrs.getLog();
+    Vector invert=new Vector();
     while(oldLog.hasMoreElements()) {
-      logged((LogEntry)(oldLog.nextElement()),true);
+      LogEntry le=(LogEntry) (oldLog.nextElement());
+      invert.insertElementAt(le,0);
+    }
+    for (int i=0 ; i<invert.size() ; i++) {
+      logged( (LogEntry) invert.elementAt(i), true );
     }
   }
 
-//ServiceListener Interface
+  public void setLogLvl(Integer lvl) {
+    this.logLvl=lvl;
+    String logLvlToString=(new String[] {"Error", "Warning", "Info", "Debug"})[lvl.intValue()-1];
+    this.log(LogService.LOG_INFO, "Log level is now \""+logLvlToString+"\".");
+    System.out.println("[Logger] : modification of log lvl : logLvl="+logLvl+" ("+logLvlToString+")");
+  }
+
+  public Integer getLogLvl() {
+    return logLvl;
+  }
+
+  ///////////////////////////////////////
+  //      ServiceListener Interface    //
+  ///////////////////////////////////////
   public void serviceChanged(ServiceEvent serviceevent) {
     ServiceReference servicereference= serviceevent.getServiceReference();
     String as[]=(String[])servicereference.getProperty("objectClass");
@@ -90,69 +109,44 @@
     }
   }
 
-
-//LogListener Interface
+  /////////////////////////////////////////
+  //      LogListener Interface          //
+  /////////////////////////////////////////
   public void logged(LogEntry log){
     logged(log, false);
   }
+
   public void logged(LogEntry log, boolean oldLog){
-    String reg=new String("*");
-    StringBuffer message=new StringBuffer();
-    //System.out.print("mosgi.jmx.remotelogger : new log : ");
-
     synchronized (logMutex){
-      try{
-        long id=log.getBundle().getBundleId();
-	if (id<10) {
-	  message.append(" "+id);
-	} else{
-          message.append(""+id);
-	}
-      }catch(NullPointerException e){
-        message.append("Unknown source");
-      }
+      if (log.getLevel() <= logLvl.intValue() & this.agent!=null) {
+        String reg=new String("*");
+        StringBuffer message=new StringBuffer();
+        try{
+          long id=log.getBundle().getBundleId();
+	  message.append( ((id<10)?" ":"")+id );
+        } catch(NullPointerException e){
+          message.append("Unknown source");
+        }
      
-      String lSymbolicName=log.getBundle().getSymbolicName();
-      if(lSymbolicName != null){
-        message.append(reg+lSymbolicName);
-      }else {
-        message.append(reg+"\"null\"");
-      }
+        String lSymbolicName=log.getBundle().getSymbolicName();
+        message.append( reg+ ((lSymbolicName!=null)?lSymbolicName:"\"null\"") );
 
-      message.append(reg+log.getBundle().getState());
+        message.append(reg+log.getBundle().getState());
 
-      int lLevel=log.getLevel();
-      if(debugLogFlag && lLevel==LogService.LOG_DEBUG){
-        message.append(reg+"DEBUG  ");
-      }else if (errorLogFlag && lLevel==LogService.LOG_ERROR){
-        message.append(reg+"ERROR  ");
-      }else if(infoLogFlag && lLevel==LogService.LOG_INFO){
-        message.append(reg+"INFO   ");
-      }else if(warningLogFlag && lLevel==LogService.LOG_WARNING){
-        message.append(reg+"WARNING");
-      }else {
-        message.append(reg+"NOLEVEL");
-      }
+	message.append(reg+LOG_LVL[log.getLevel()]);
 	 
-      // into log.getMessage() replaceAll regex char by an other
-      String msg=log.getMessage();
-      if (msg!=null){
-	message.append(reg+msg.replace('*','X'));
-      } else {
-	message.append(reg+"\"null\"");
+        // into log.getMessage() replaceAll regex char by an other
+        String msg=log.getMessage();
+        message.append( reg+ ((msg!=null)?msg.replace('*','X'):"\"null\"") );
+
+        this.sendNotification(new  AttributeChangeNotification(this.remoteLoggerON, 0, (oldLog)?0:System.currentTimeMillis(), message.toString(), null, "Log", null, null));
       }
     }
-    //System.out.println(message.toString());
-    if (this.agent!=null){ // On envoie tous les logs a un MBeanServer
-      //System.out.println("this.agent != null => remoteLogger.Logger.sendNotifiaction(...."+message.toString());
-      //System.out.println("RemoteLogger send notification : "+oldLog+" : "+message.toString()); 
-      this.sendNotification(new  AttributeChangeNotification(this.remoteLoggerON, 0, 
-						             (oldLog)?0:System.currentTimeMillis(),
-						             message.toString(), null, "Log", null, null));
-    }
   }
 
-//BundleActivator Interface
+  //////////////////////////////////
+  //  BundleActivator Interface   //
+  //////////////////////////////////
   public void start(BundleContext bc) throws Exception{
     this.version=(String)bc.getBundle().getHeaders().get(Constants.BUNDLE_VERSION);
     this.bc=bc;
@@ -177,28 +171,29 @@
     if (sr2!=null){
       this.registerToAgent(sr2);
     }
-    this.log(LogService.LOG_INFO, "Remote Logger started "+version);
-
+    this.log(LogService.LOG_INFO, "Remote Logger started (logLvl="+logLvl+")"+version);
   }
      
   public void stop(BundleContext bc) throws Exception{
-   this.log(LogService.LOG_INFO, "Stopping remote Logger "+version);
-   if (this.lrs==null){
-      System.out.println("ERROR : Logger.stop : there is no logger or reader to stop");
-   } else {
-     this.lrs.removeLogListener(this);
-     this.bc.removeServiceListener(this);
-   }
-   if (this.agent!=null){
-     this.unRegisterFromAgent();
-   }
-   this.agent=null;
-   this.lrs=null; 
-   this.log(LogService.LOG_INFO, "Remote Logger stopped"+version);
-   this.bc=null;
- }
+    this.log(LogService.LOG_INFO, "Stopping remote Logger "+version);
+    if (this.lrs==null){
+       System.out.println("ERROR : Logger.stop : there is no logger or reader to stop");
+    } else {
+      this.lrs.removeLogListener(this);
+      this.bc.removeServiceListener(this);
+    }
+    if (this.agent!=null){
+      this.unRegisterFromAgent();
+    }
+    this.agent=null;
+    this.lrs=null; 
+    this.log(LogService.LOG_INFO, "Remote Logger stopped"+version);
+    this.bc=null;
+  }
 
-//private methods 
+  //////////////////////////////
+  //     private methods      //
+  //////////////////////////////
   private void registerLogReaderService(ServiceReference sr) {
     //System.out.println("mosgi.jmx.remoteLogger.Logger.registerLogReaderService("+sr.toString()+") : oldLog=");
     this.lrs=(LogReaderService)this.bc.getService(sr);
diff --git a/mosgi.jmx.remotelogger/src/main/java/org/apache/felix/mosgi/jmx/remotelogger/LoggerMBean.java b/mosgi.jmx.remotelogger/src/main/java/org/apache/felix/mosgi/jmx/remotelogger/LoggerMBean.java
index 33d67ee..f2fb5cb 100644
--- a/mosgi.jmx.remotelogger/src/main/java/org/apache/felix/mosgi/jmx/remotelogger/LoggerMBean.java
+++ b/mosgi.jmx.remotelogger/src/main/java/org/apache/felix/mosgi/jmx/remotelogger/LoggerMBean.java
@@ -21,5 +21,7 @@
 public interface LoggerMBean{
 
   public void sendOldLog();
+  public void setLogLvl(Integer lvl);
+  public Integer getLogLvl();
 
 }