[gui-dev] A console tab for LimeWire

Jens-Uwe Mager <[email protected]> Fri, 24 Jun 2005 19:11:34 +0100
Newsgroups gmane.network.gnutella.limewire.gui.devel
Message-ID <[email protected]>
--AGBBLMjITsWHeOTZ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

I did submit a patch a while ago to add a console tab to LimeWire.
Recently there was some discussion about adding something like a
console, so I reworked the patch to be relative to the newest CVS and
also to use log4j instead of what was previously the preferred logger.
This console patch does do the following things:

* adding a new tab that displays the console window (not shown unless
  enabled, like the connection view)
* adds statements to log4j.properties to be able to redirect log
  messages to the console window.
* being based on the BeanShell JConsole window, also add BeanShell
  scripting to LimeWire.

The scripting feature does warrent more explanation. The JConsole window
is actually a feature of BeanShell (www.beanshell.org), and the file
bsh-2.0b4.jar needs to be put into lib/jars for the patch to work. The
result ist that you can simply type java style expressions into the
console window and let BeanShell evaluate it and print the results, this
is really handy to inspect all the variables of the running LimeWire.
Part of the evaluation can also be arbitrary method calls, so you can
also trigger Java code to be run. You can also set variables, that
allows easy experimentation with parameters without recompiling LimeWire
or adding settings for them.

Part of the initialization of the BeanShell tab is also evaluating the
file LimeWire.bsh (if it exists) in the preferences directory. This can
be used to add some handy functions or other customizations to the
console. It can also be used to modify LimeWire's behaviour in various
ways, I have included an example LimeWire.bsh file that adds a BeanShell
menu that allows to refresh the logging preferences besides other play
things.

As BeanShell pretty much supports nearly all of the Java syntax and some
more loosely typed scripting extensions it is also a nice tool to
prototype new functionality that can be later simply compiled into
classes.
-- 
Jens-Uwe Mager	<pgp-mailto:F476EBC2>

--AGBBLMjITsWHeOTZ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="BeanShell.patch"

Index: lib/jars/bsh-2.0b4.jar
===================================================================
Binary files /dev/null and lib/jars/bsh-2.0b4.jar differ
Index: gui/com/limegroup/gnutella/gui/BeanShellAppender.java
===================================================================
--- /dev/null	Fri Jun 24 16:13:56 2005
+++ gui/com/limegroup/gnutella/gui/BeanShellAppender.java	Fri Apr 30 23:42:19 2004
@@ -0,0 +1,17 @@
+package com.limegroup.gnutella.gui;
+
+import java.io.*;
+import java.net.*;
+import org.apache.log4j.*;
+import com.limegroup.gnutella.gui.tabs.BeanShellTab;
+import bsh.util.JConsole;
+
+public class BeanShellAppender extends WriterAppender {
+
+    public BeanShellAppender() {
+        setWriter(createWriter(((JConsole)BeanShellTab.getInstance().getComponent()).getErr()));
+    }
+
+    protected final void closeWriter() {
+    }
+}
Index: gui/com/limegroup/gnutella/gui/images/beanshell.gif
===================================================================
Binary files /dev/null and gui/com/limegroup/gnutella/gui/images/beanshell.gif differ
Index: gui/com/limegroup/gnutella/gui/tabs/BeanShellTab.java
===================================================================
--- /dev/null	Fri Jun 24 16:13:56 2005
+++ gui/com/limegroup/gnutella/gui/tabs/BeanShellTab.java	Fri Aug  6 22:34:36 2004
@@ -0,0 +1,69 @@
+package com.limegroup.gnutella.gui.tabs;
+
+import com.limegroup.gnutella.gui.*; 
+import com.limegroup.gnutella.settings.*; 
+import com.limegroup.gnutella.util.CommonUtils; 
+import com.limegroup.gnutella.gui.tables.ComponentMediator;
+import java.io.*;
+import javax.swing.*;
+import java.awt.*;
+import bsh.*;
+import bsh.util.*;
+import bsh.classpath.*;
+
+/**
+ * This class contains all elements of the tab for the BeanShell
+ * console.
+ */
+public final class BeanShellTab extends AbstractTab {
+
+	private JConsole console;
+        private Interpreter interpreter;
+        private static BeanShellTab instance;
+
+	/**
+	 * Constructs the tab for the BeanShell console
+	 *
+	 */
+	private BeanShellTab() {
+            super("BEANSHELL", GUIMediator.BEANSHELL_INDEX, "beanshell");
+            GUIMediator.setSplashScreenString(
+                GUIMediator.getStringResource("SPLASH_STATUS_BEANSHELL"));
+            console = new JConsole();
+            interpreter = new Interpreter(console);
+            NameCompletionTable nct = new NameCompletionTable();
+            nct.add(interpreter.getNameSpace());
+            try {
+                BshClassManager bcm = interpreter.getClassManager();
+                if (bcm != null)
+                    nct.add(((ClassManagerImpl)bcm).getClassPath());
+            } catch (ClassPathException ex) {}
+            console.setNameCompletion(nct);
+            SwingUtilities.invokeLater(new Runnable() {
+                public void run() {
+                    try {
+                        interpreter.source(CommonUtils.getUserSettingsDir() +
+                            "/LimeWire.bsh");
+                    } catch (FileNotFoundException ex) {
+                    } catch (Throwable ex) {
+                        console.print(ex, Color.RED);
+                    }
+                    new Thread(interpreter, "BeanShell").start();
+                }
+            });
+	}
+
+        public static BeanShellTab getInstance() {
+            if (instance == null)
+                instance = new BeanShellTab();
+            return instance;
+        }
+
+	public void storeState(boolean visible) {
+            ApplicationSettings.BEANSHELL_VIEW_ENABLED.setValue(visible);
+	}
+
+	public JComponent getComponent() {
+            return console;
+	}
+}
Index: lib/messagebundles/MessagesBundle.properties
===================================================================
RCS file: /cvs/lib/messagebundles/MessagesBundle.properties,v
retrieving revision 1.224
diff -u -r1.224 MessagesBundle.properties
--- lib/messagebundles/MessagesBundle.properties	23 Jun 2005 22:44:34 -0000	1.224
+++ lib/messagebundles/MessagesBundle.properties	24 Jun 2005 14:12:33 -0000
@@ -178,6 +178,7 @@
 STATS_TITLE=Statistics
 DOWNLOAD_TITLE=Downloads
 UPLOAD_TITLE=Uploads
+BEANSHELL_TITLE=BeanShell
 
 ################################################################################
 # Key/value pairs for the tooltips of the main windows
@@ -186,6 +187,7 @@
 MONITOR_TIP=View Searches and Uploads
 CONNECTIONS_TIP=Show Connections to Other Clients
 LIBRARY_TIP=View Repository of Saved Files
+BEANSHELL_TIP=BeanShell Console
 
 ################################################################################
 # Key/Value pairs for the pull-down menus in the main window
@@ -239,6 +241,9 @@
 MENU_NAV_LIB=Library
 MENU_NAV_LIB_MNEMONIC=L
 MENU_NAV_LIB_ACCESSIBLE=Display the Library Screen
+MENU_NAV_BEAN=BeanShell
+MENU_NAV_BEAN_MNEMONIC=B
+MENU_NAV_BEAN_ACCESSIBLE=Show BeanShell Console
 
 MENU_VIEW_TITLE=View
 MENU_VIEW_TITLE_MNEMONIC=V
@@ -260,6 +265,9 @@
 MENU_VIEW_LIBRARY=Library
 MENU_VIEW_LIBRARY_MNEMONIC=L
 MENU_VIEW_LIBRARY_ACCESSIBLE=Show Library Window
+MENU_VIEW_BEANSHELL=BeanShell
+MENU_VIEW_BEANSHELL_MNEMONIC=B
+MENU_VIEW_BEANSHELL_ACCESSIBLE=Show BeanShell Console
 MENU_VIEW_THEMES_TITLE=Apply Skins
 MENU_VIEW_THEMES_TITLE_MNEMONIC=A
 MENU_VIEW_THEMES_GET_MORE=Get More Skins
@@ -1063,6 +1078,7 @@
 SPLASH_STATUS_PLAYLIST_WINDOW=Loading playlist window...
 SPLASH_STATUS_MENUS=Loading menus...
 SPLASH_STATUS_MESSAGE_SERVICE=Loading messages...
+SPLASH_STATUS_BEANSHELL=Loading BeanShell...
 SPLASH_STATUS_ICONS=Loading icons...
 SPLASH_STATUS_I18N=Loading internationalization support...
 SPLASH_STATUS_DAAP=Loading Digital Audio Access Protocol...
Index: core/com/limegroup/gnutella/settings/ApplicationSettings.java
===================================================================
RCS file: /cvs/core/com/limegroup/gnutella/settings/ApplicationSettings.java,v
retrieving revision 1.15
diff -u -r1.15 ApplicationSettings.java
--- core/com/limegroup/gnutella/settings/ApplicationSettings.java	8 Mar 2005 17:53:56 -0000	1.15
+++ core/com/limegroup/gnutella/settings/ApplicationSettings.java	24 Jun 2005 14:12:41 -0000
@@ -147,6 +147,12 @@
 	 */    
     public static final BooleanSetting SHOPPING_VIEW_ENABLED =
         FACTORY.createBooleanSetting("SHOPPING_VIEW_ENABLED", true);
+
+    /**
+	 * Sets whether or not BeanShell Tab should be enabled.
+	 */    
+    public static final BooleanSetting BEANSHELL_VIEW_ENABLED =
+        FACTORY.createBooleanSetting("BEANSHELL_VIEW_ENABLED", false);
     
     /**
 	 * Sets the name of the jar file to load on startup, which is read
Index: gui/log4j.properties
===================================================================
RCS file: /cvs/gui/log4j.properties,v
retrieving revision 1.49
diff -u -r1.49 log4j.properties
--- gui/log4j.properties	23 Jun 2005 16:30:39 -0000	1.49
+++ gui/log4j.properties	24 Jun 2005 14:12:42 -0000
@@ -17,7 +17,7 @@
 ########
 
 # Set the root loggers
-log4j.rootLogger=OFF, stdout, TextFile, XMLFile,socket
+log4j.rootLogger=OFF, stdout, TextFile, XMLFile,socket, BeanShell
 
 
 ######
@@ -89,6 +89,12 @@
 log4j.appender.stdout.layout.ConversionPattern=%-6r %-5p [%t] %c{2}.%M[%L] - %m%n
 
 
+# An appender using the BeanShell console window.
+log4j.appender.BeanShell=org.apache.log4j.varia.NullAppender
+#log4j.appender.BeanShell=com.limegroup.gnutella.gui.BeanShellAppender
+#log4j.appender.BeanShell.layout=org.apache.log4j.PatternLayout
+#log4j.appender.BeanShell.layout.ConversionPattern=%-6r %-5p [%t] %c{2}.%M - %m%n
+
 ###  To set the value for specific classes/packages, use the following format:
 ## log4j.logger.<package.class>=LEVEL
 # log4j.logger.com.limegroup.gnutella.gui=INFO
Index: gui/com/limegroup/gnutella/gui/GUIMediator.java
===================================================================
RCS file: /cvs/gui/com/limegroup/gnutella/gui/GUIMediator.java,v
retrieving revision 1.175
diff -u -r1.175 GUIMediator.java
--- gui/com/limegroup/gnutella/gui/GUIMediator.java	21 Jun 2005 21:43:55 -0000	1.175
+++ gui/com/limegroup/gnutella/gui/GUIMediator.java	24 Jun 2005 14:12:43 -0000
@@ -107,6 +107,13 @@
 	public static final int LIBRARY_INDEX = 3;
 
 	/**
+	 * Constant for the index of the BeanShell tab in the main application
+	 * window.
+	 */
+	public static final int BEANSHELL_INDEX = 4;
+
+
+	/**
 	 * Constant specifying whether or not the user has donated to the LimeWire
 	 * project.
 	 */
Index: gui/com/limegroup/gnutella/gui/MainFrame.java
===================================================================
RCS file: /cvs/gui/com/limegroup/gnutella/gui/MainFrame.java,v
retrieving revision 1.234
diff -u -r1.234 MainFrame.java
--- gui/com/limegroup/gnutella/gui/MainFrame.java	10 Jun 2005 15:38:56 -0000	1.234
+++ gui/com/limegroup/gnutella/gui/MainFrame.java	24 Jun 2005 14:12:44 -0000
@@ -34,6 +34,7 @@
 import com.limegroup.gnutella.gui.search.MagnetClipboardListener;
 import com.limegroup.gnutella.gui.search.SearchMediator;
 import com.limegroup.gnutella.gui.statistics.StatisticsMediator;
+import com.limegroup.gnutella.gui.tabs.BeanShellTab;
 import com.limegroup.gnutella.gui.tabs.ConnectionsTab;
 import com.limegroup.gnutella.gui.tabs.LibraryPlayListTab;
 import com.limegroup.gnutella.gui.tabs.MonitorUploadTab;
@@ -243,6 +244,8 @@
             this.setTabVisible(GUIMediator.CONNECTIONS_INDEX, false);
         if (!ApplicationSettings.LIBRARY_VIEW_ENABLED.getValue())
             this.setTabVisible(GUIMediator.LIBRARY_INDEX, false);
+        if (!ApplicationSettings.BEANSHELL_VIEW_ENABLED.getValue())
+            this.setTabVisible(GUIMediator.BEANSHELL_INDEX, false);
 
         FRAME.setJMenuBar(MENU_MEDIATOR.getMenuBar());
         JPanel contentPane = new JPanel();
@@ -304,11 +307,12 @@
      * Build the Tab Structure based on advertising mode and Windows
      */
     private void buildTabs() {
-        TABS = new Tab[4];
+        TABS = new Tab[5];
         TABS[0]=new SearchDownloadTab(SEARCH_MEDIATOR, DOWNLOAD_MEDIATOR);
         TABS[1]=new MonitorUploadTab(MONITOR_VIEW, UPLOAD_MEDIATOR);
         TABS[2]=new ConnectionsTab(CONNECTION_MEDIATOR);
         TABS[3]=new LibraryPlayListTab(LIBRARY_MEDIATOR, PLAYLIST_MEDIATOR);
+        TABS[4]=BeanShellTab.getInstance();
     }
 
     
Index: gui/com/limegroup/gnutella/gui/menu/NavMenu.java
===================================================================
RCS file: /cvs/gui/com/limegroup/gnutella/gui/menu/NavMenu.java,v
retrieving revision 1.14
diff -u -r1.14 NavMenu.java
--- gui/com/limegroup/gnutella/gui/menu/NavMenu.java	12 Oct 2004 21:45:34 -0000	1.14
+++ gui/com/limegroup/gnutella/gui/menu/NavMenu.java	24 Jun 2005 14:12:46 -0000
@@ -50,6 +50,11 @@
 		item = addMenuItem("NAV_LIB", NAV_LISTENER);
 		item.putClientProperty(NAV_PROPERTY,
 		    new Integer(GUIMediator.LIBRARY_INDEX));
+
+		item = addMenuItem("NAV_BEAN", NAV_LISTENER);
+		item.putClientProperty(NAV_PROPERTY,
+		    new Integer(GUIMediator.BEANSHELL_INDEX));
+
 	}
 
 	
Index: gui/com/limegroup/gnutella/gui/menu/ShowHideMenu.java
===================================================================
RCS file: /cvs/gui/com/limegroup/gnutella/gui/menu/ShowHideMenu.java,v
retrieving revision 1.9
diff -u -r1.9 ShowHideMenu.java
--- gui/com/limegroup/gnutella/gui/menu/ShowHideMenu.java	12 Oct 2004 21:45:34 -0000	1.9
+++ gui/com/limegroup/gnutella/gui/menu/ShowHideMenu.java	24 Jun 2005 14:12:46 -0000
@@ -38,6 +38,10 @@
                     new ViewListener(GUIMediator.LIBRARY_INDEX), 
                     ApplicationSettings.LIBRARY_VIEW_ENABLED.getValue());
                     
+        addToggleMenuItem("VIEW_BEANSHELL", 
+                    new ViewListener(GUIMediator.BEANSHELL_INDEX), 
+                    ApplicationSettings.BEANSHELL_VIEW_ENABLED.getValue());
+
         MENU.add(new SearchMenu("VIEW_SEARCH").getMenu());
     }
 

--AGBBLMjITsWHeOTZ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="LimeWire.bsh"

// Enable access to private fields and methods.
setAccessibility(true);

// Import most of the LimeWire name space for easy typing.
import com.limegroup.gnutella.gui.*;
import com.limegroup.gnutella.gui.menu.*;
import com.limegroup.gnutella.gui.download.*;
import com.limegroup.gnutella.gui.search.*;
import com.limegroup.gnutella.gui.tables.*;
import com.limegroup.gnutella.gui.tabs.*;
import com.limegroup.gnutella.*;
import com.limegroup.gnutella.settings.*;
import com.limegroup.gnutella.util.*;
import com.limegroup.gnutella.uploader.*;
import com.limegroup.gnutella.downloader.*;
import com.limegroup.gnutella.connection.*;

// Define a function for scripting searches, This will open a new search
// tab.
void addSearchTab(String stext, MediaType type) {
    byte[] guid = RouterService.newQueryGUID();
    SearchInformation info = SearchInformation.createKeywordSearch(stext, null, type);
    ResultPanel rp = SearchMediator.addResultTab(new GUID(guid), info);
    RouterService.query(guid, stext);
}

// Define a function to clear all completed downloads. That differs from
// the inactive button as it will only clear 100% complete downloads.
void clearCompleted() {
    DataLineModel dm = DownloadMediator.instance().DATA_MODEL;
    boolean didOne;
    do {
        didOne = false;
        for (int i = 0; i < dm.getRowCount(); i++) {
            DownloadDataLine dd = (DownloadDataLine)dm.get(i);
            if (dd._state == Downloader.COMPLETE) {
                //print("Delete " + i + " " + dd);
                dm.remove(i);
                didOne = true;
                break;
            }
        }
    } while (didOne);
}

// Wait until we have a connection before starting searches
class ConnWaiter extends ManagedThread {
    ConnWaiter() {
        super("ConnWaiter");
    }
    public void managedRun() {
        try {
            while (!RouterService.isConnected())
                Thread.sleep(1000);
            // add search tabs
            addSearchTab("LimeWire", MediaType.getAnyTypeMediaType());
            addSearchTab("Beatles", MediaType.getAudioMediaType());
            addSearchTab("ufo", MediaType.getVideoMediaType());
        } catch (Throwable ex) {
            error(ex);
        }
    }
}
new ConnWaiter().start();
print("ConnWaiter started");

// Re-read the logging properties
reReadLogProperties() {
    org.apache.log4j.PropertyConfigurator.configure("log4j.properties");
}

// Define a new menu named "BeanShell" for easy access to BeanShell
// functions.
bshMenu = new JMenu("BeanShell");

JMenuItem simpleMenu(name, func) {
    void actionPerformed(event) {
        try {
            eval(func);
        } catch (Throwable ex) {
            error(ex);
        }
    }
    item = new JMenuItem(name);
    item.addActionListener(this);
    return item;
}

bshMenu.add(simpleMenu("test doit", "print(\"doit\");print(event)"));
bshMenu.add(simpleMenu("open prefs", "GUIMediator.launchFile(CommonUtils.getUserSettingsDir())"));
bshMenu.add(simpleMenu("clear completed downloads", "clearCompleted()"));
bshMenu.add(simpleMenu("refresh log properties", "reReadLogProperties()"));
bshMenu.add(simpleMenu("shutdown", "GUIMediator.shutdown()"));

MenuMediator.instance().MENU_BAR.add(bshMenu);

// make the queue monitor a bit larger by default
GUIMediator.instance().getMainFrame().TABS[1].SPLIT_PANE.setDividerLocation(140);

print("LimeWire.bsh done " + new Date());

--AGBBLMjITsWHeOTZ
Content-Type: image/gif
Content-Disposition: attachment; filename="beanshell.gif"
Content-Transfer-Encoding: base64

R0lGODlhDgAOAPcAMf//////zP//mf//Zv//M///AP/M///MzP/Mmf/MZv/MM//MAP+Z//+Z
zP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9mZv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8A
zP8Amf8AZv8AM/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zMAMyZ/8yZ
zMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz/8wzzMwzmcwzZswzM8wzAMwA/8wA
zMwAmcwAZswAM8wAAJn//5n/zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZ
zJmZmZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkzZpkzM5kzAJkA/5kA
zJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZ
zGaZmWaZZmaZM2aZAGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA/2YA
zGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPMzDPMmTPMZjPMMzPMADOZ/zOZ
zDOZmTOZZjOZMzOZADNm/zNmzDNmmTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMA
zDMAmTMAZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDMMwDMAACZ/wCZ
zACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBmAAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAA
zAAAmQAAZgAAM2srKGorKGorJ2oqJ////f/69cVqQtOYfr1dNcmGa7poS/rbz7hQLK9cQqdO
N9uhkvzk3v3m4JdDNOKyqYk6LppUSq53b30yK2MsJ10qJXI1MIpGQHUwLGosKFklI3s7OHMq
Km0rK1MiIWorK2UqKl0oKGguLgAAAAAAACH5BAEAAAAALAAAAAAOAA4AAAilAAEIFHhOnTl1
4gYqBABu3Lp588q1W7itYTl59ua5uzdxoLdx48qxswev3r1r5wZ2C8lOHqJ89+7p6yguZLiR
/PK5gyhPoLlvN+XpywdvXbp59gSC63YzXk537sohVdqNnNB8OtOVw8dOoDdyOPO9S0duHb4u
PsmVc4d1ntZ5+2QIRKeWbb515ezhm8dtILh12sSuW3dvX8eB7Orl27fO3bueAgMCADs=

--AGBBLMjITsWHeOTZ
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
gui-dev mailing list
[email protected]
http://www.limewire.org/mailman/listinfo/gui-dev

--AGBBLMjITsWHeOTZ--