DesktopGui:

- Remove all static log, context, and instance fields
- Make Main class a RouterApp
- Remove unused ConfigurationManager class
- Translate tooltip, disable tooltip on linux
- Use safer exec call to start i2p
- Remove all images, use itoopie
- Don't start spinner thread in router context
- Handle various startup errors better
- Synchs, finals, javadocs, cleanups
This commit is contained in:
zzz
2016-05-05 13:13:44 +00:00
parent 16ff3e3def
commit 75d6df7789
15 changed files with 240 additions and 246 deletions

View File

@ -5,7 +5,6 @@
<property name="build" value="build"/>
<property name="dist" location="dist"/>
<property name="jar" value="desktopgui.jar"/>
<property name="resources" value="resources"/>
<property name="javadoc" value="javadoc"/>
<property name="javac.compilerargs" value=""/>
<property name="javac.version" value="1.6" />
@ -36,9 +35,6 @@
<pathelement location="../../router/java/build/router.jar" />
</classpath>
</javac>
<copy todir="${build}/desktopgui/${resources}">
<fileset dir="${resources}" />
</copy>
</target>
<target name="bundle" unless="no.bundle">
@ -76,6 +72,8 @@
<target name="jar" depends="compile, bundle, listChangedFiles" unless="jar.uptodate" >
<!-- set if unset -->
<property name="workspace.changes.tr" value="" />
<!-- ideal for linux: 24x24, but transparency doesn't work -->
<copy tofile="${build}/desktopgui/resources/images/logo.png" file="../../installer/resources/themes/console/images/itoopie_xsm.png" />
<jar basedir="${build}" excludes="messages-src/**" destfile="${dist}/${jar}">
<manifest>
<attribute name="Main-Class" value="net.i2p.desktopgui.Main"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -8,14 +8,21 @@ import java.awt.event.ActionListener;
import javax.swing.SwingWorker;
import net.i2p.I2PAppContext;
import net.i2p.desktopgui.router.RouterManager;
import net.i2p.util.Log;
public class ExternalTrayManager extends TrayManager {
/**
* When started before the router, e.g. with
* java -cp i2p.jar:desktopgui.jar net.i2p.desktopgui.Main
*
* No access to context, very limited abilities.
* Not fully supported.
*/
class ExternalTrayManager extends TrayManager {
private final static Log log = new Log(ExternalTrayManager.class);
protected ExternalTrayManager() {}
public ExternalTrayManager(I2PAppContext ctx) {
super(ctx);
}
@Override
public PopupMenu getMainMenu() {

View File

@ -11,13 +11,24 @@ import net.i2p.desktopgui.gui.DesktopguiConfigurationFrame;
import net.i2p.desktopgui.router.RouterManager;
import net.i2p.desktopgui.util.BrowseException;
import net.i2p.desktopgui.util.I2PDesktop;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
public class InternalTrayManager extends TrayManager {
/**
* java -cp i2p.jar:desktopgui.jar net.i2p.desktopgui.Main
*
* Full access to router context.
*/
class InternalTrayManager extends TrayManager {
private final static Log log = new Log(InternalTrayManager.class);
private final RouterContext _context;
private final Log log;
protected InternalTrayManager() {}
public InternalTrayManager(RouterContext ctx) {
super(ctx);
_context = ctx;
log = ctx.logManager().getLog(InternalTrayManager.class);
}
@Override
public PopupMenu getMainMenu() {
@ -56,7 +67,7 @@ public class InternalTrayManager extends TrayManager {
@Override
protected Object doInBackground() throws Exception {
new DesktopguiConfigurationFrame().setVisible(true);
new DesktopguiConfigurationFrame(_context).setVisible(true);
return null;
}
@ -73,7 +84,7 @@ public class InternalTrayManager extends TrayManager {
@Override
protected Object doInBackground() throws Exception {
RouterManager.restart();
RouterManager.restart(_context);
return null;
}
@ -91,7 +102,7 @@ public class InternalTrayManager extends TrayManager {
@Override
protected Object doInBackground() throws Exception {
RouterManager.shutDown();
RouterManager.shutDown(_context);
return null;
}

View File

@ -7,8 +7,15 @@ package net.i2p.desktopgui;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import static net.i2p.app.ClientAppState.*;
import net.i2p.desktopgui.router.RouterManager;
import net.i2p.desktopgui.util.*;
import net.i2p.router.RouterContext;
import net.i2p.router.app.RouterApp;
import net.i2p.util.Log;
import net.i2p.util.Translate;
import net.i2p.util.I2PProperties.I2PPropertyCallback;
@ -16,22 +23,57 @@ import net.i2p.util.I2PProperties.I2PPropertyCallback;
/**
* The main class of the application.
*/
public class Main {
///Manages the lifetime of the tray icon.
private TrayManager trayManager = null;
private final static Log log = new Log(Main.class);
public class Main implements RouterApp {
private final I2PAppContext _appContext;
private final RouterContext _context;
private final ClientAppManager _mgr;
private final Log log;
private ClientAppState _state = UNINITIALIZED;
private TrayManager _trayManager;
/**
* Start the tray icon code (loads tray icon in the tray area).
* @throws Exception
* @since 0.9.26
*/
public void startUp() throws Exception {
trayManager = TrayManager.getInstance();
public Main(RouterContext ctx, ClientAppManager mgr, String args[]) {
_appContext = _context = ctx;
_mgr = mgr;
log = _appContext.logManager().getLog(Main.class);
_state = INITIALIZED;
}
/**
* @since 0.9.26
*/
public Main() {
_appContext = I2PAppContext.getGlobalContext();
if (_appContext instanceof RouterContext)
_context = (RouterContext) _appContext;
else
_context = null;
_mgr = null;
log = _appContext.logManager().getLog(Main.class);
_state = INITIALIZED;
}
/**
* Start the tray icon code (loads tray icon in the tray area).
* @throws AWTException on startup error, including systray not supported
*/
private synchronized void startUp() throws Exception {
final TrayManager trayManager;
if (_context != null)
trayManager = new InternalTrayManager(_context);
else
trayManager = new ExternalTrayManager(_appContext);
trayManager.startManager();
_trayManager = trayManager;
changeState(RUNNING);
if (_mgr != null)
_mgr.register(this);
if(RouterManager.inI2P()) {
RouterManager.getRouterContext().addPropertyCallback(new I2PPropertyCallback() {
if (_context != null) {
_context.addPropertyCallback(new I2PPropertyCallback() {
@Override
public void propertyChanged(String arg0, String arg1) {
@ -45,26 +87,36 @@ public class Main {
}
public static void main(String[] args) {
beginStartup(args);
Main main = new Main();
main.beginStartup(args);
}
/**
* Main method launching the application.
*
* @param args unused
*/
public static void beginStartup(String[] args) {
try {
String headless = System.getProperty("java.awt.headless");
boolean isHeadless = Boolean.parseBoolean(headless);
if(isHeadless) {
log.warn("Headless environment: not starting desktopgui!");
return;
}
}
catch(Exception e) {
private void beginStartup(String[] args) {
changeState(STARTING);
String headless = System.getProperty("java.awt.headless");
boolean isHeadless = Boolean.parseBoolean(headless);
if (isHeadless) {
log.warn("Headless environment: not starting desktopgui!");
changeState(START_FAILED, "Headless environment: not starting desktopgui!", null);
return;
}
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
//UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels();
//for (int i = 0; i < lafs.length; i++) {
// System.out.println("LAF " + i + ": " + lafs[i].getName() + ' ' + lafs[i].getClassName());
//}
String laf = UIManager.getSystemLookAndFeelClassName();
//System.out.println("Default: " + laf);
UIManager.setLookAndFeel(laf);
//laf = UIManager.getCrossPlatformLookAndFeelClassName();
//System.out.println("Cross-Platform: " + laf);
//UIManager.setLookAndFeel(laf);
//UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException ex) {
log.log(Log.ERROR, null, ex);
} catch (InstantiationException ex) {
@ -73,23 +125,28 @@ public class Main {
log.log(Log.ERROR, null, ex);
} catch (UnsupportedLookAndFeelException ex) {
log.log(Log.ERROR, null, ex);
} catch (Error ex) {
// on permissions error (different user)
// Exception in thread "main" java.lang.InternalError: Can't connect to X11 window server using ':0' as the value of the DISPLAY variable.
log.log(Log.ERROR, "No permissions? Different user?", ex);
changeState(START_FAILED, "No permissions? Different user?", new RuntimeException(ex));
return;
}
ConfigurationManager.getInstance().loadArguments(args);
// TODO process args with getopt if needed
final Main main = new Main();
main.launchForeverLoop();
if (_context == null)
launchForeverLoop();
//We'll be doing GUI work, so let's stay in the event dispatcher thread.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
main.startUp();
}
catch(Exception e) {
startUp();
} catch(Exception e) {
log.error("Failed while running desktopgui!", e);
changeState(START_FAILED, "Failed while running desktopgui!", e);
}
}
@ -102,7 +159,7 @@ public class Main {
* Avoids the app terminating because no Window is opened anymore.
* More info: http://java.sun.com/javase/6/docs/api/java/awt/doc-files/AWTThreadIssues.html#Autoshutdown
*/
public void launchForeverLoop() {
private static void launchForeverLoop() {
Runnable r = new Runnable() {
public void run() {
try {
@ -114,9 +171,60 @@ public class Main {
}
}
};
Thread t = new Thread(r);
Thread t = new Thread(r, "DesktopGUI spinner");
t.setDaemon(false);
t.start();
}
/////// ClientApp methods
/** @since 0.9.26 */
public synchronized void startup() {
beginStartup(null);
}
/** @since 0.9.26 */
public synchronized void shutdown(String[] args) {
if (_state == STOPPED)
return;
changeState(STOPPING);
if (_trayManager != null)
_trayManager.stopManager();
changeState(STOPPED);
}
/** @since 0.9.26 */
public synchronized ClientAppState getState() {
return _state;
}
/** @since 0.9.26 */
public String getName() {
return "desktopgui";
}
/** @since 0.9.26 */
public String getDisplayName() {
return "Desktop GUI";
}
/////// end ClientApp methods
/** @since 0.9.26 */
private void changeState(ClientAppState state) {
changeState(state, null, null);
}
/** @since 0.9.26 */
private synchronized void changeState(ClientAppState state, String msg, Exception e) {
_state = state;
if (_mgr != null)
_mgr.notify(this, state, msg, e);
if (_context == null) {
if (msg != null)
System.out.println(state + ": " + msg);
if (e != null)
e.printStackTrace();
}
}
}

View File

@ -8,58 +8,65 @@ import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.net.URL;
import net.i2p.I2PAppContext;
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
import net.i2p.desktopgui.router.RouterManager;
import net.i2p.util.Log;
import net.i2p.util.SystemVersion;
/**
* Manages the tray icon life.
*/
public abstract class TrayManager {
abstract class TrayManager {
private static TrayManager instance = null;
protected final I2PAppContext _appContext;
///The tray area, or null if unsupported
protected SystemTray tray = null;
protected SystemTray tray;
///Our tray icon, or null if unsupported
protected TrayIcon trayIcon = null;
private final static Log log = new Log(TrayManager.class);
protected TrayIcon trayIcon;
/**
* Instantiate tray manager.
*/
protected TrayManager() {}
protected static TrayManager getInstance() {
if(instance == null) {
boolean inI2P = RouterManager.inI2P();
if(inI2P) {
instance = new InternalTrayManager();
}
else {
instance = new ExternalTrayManager();
}
}
return instance;
protected TrayManager(I2PAppContext ctx) {
_appContext = ctx;
}
/**
* Add the tray icon to the system tray and start everything up.
*/
protected void startManager() {
public synchronized void startManager() throws AWTException {
if(SystemTray.isSupported()) {
// TODO figure out how to get menu to pop up on left-click
// left-click does nothing by default
// MouseListener, MouseEvent, ...
tray = SystemTray.getSystemTray();
trayIcon = new TrayIcon(getTrayImage(), "I2P", getMainMenu());
// Windows typically has tooltips; Linux (at least Ubuntu) doesn't
String tooltip = SystemVersion.isWindows() ? _t("I2P: Right-click for menu") : null;
trayIcon = new TrayIcon(getTrayImage(), tooltip, getMainMenu());
trayIcon.setImageAutoSize(true); //Resize image to fit the system tray
try {
tray.add(trayIcon);
} catch (AWTException e) {
log.log(Log.WARN, "Problem creating system tray icon!", e);
}
tray.add(trayIcon);
// 16x16 on Windows, 24x24 on Linux, but that will probably vary
//System.out.println("Tray icon size is " + trayIcon.getSize());
} else {
throw new AWTException("SystemTray not supported");
}
}
/**
* Remove the tray icon from the system tray
*
* @since 0.9.26
*/
public synchronized void stopManager() {
if (tray != null && trayIcon != null) {
tray.remove(trayIcon);
tray = null;
trayIcon = null;
}
}
protected void languageChanged() {
trayIcon.setPopupMenu(getMainMenu());
public synchronized void languageChanged() {
if (trayIcon != null)
trayIcon.setPopupMenu(getMainMenu());
}
/**
@ -71,14 +78,17 @@ public abstract class TrayManager {
/**
* Get tray icon image from the desktopgui resources in the jar file.
* @return image used for the tray icon
* @throws AWTException if image not found
*/
private Image getTrayImage() {
private Image getTrayImage() throws AWTException {
URL url = getClass().getResource("/desktopgui/resources/images/logo.png");
if (url == null)
throw new AWTException("cannot load tray image");
Image image = Toolkit.getDefaultToolkit().getImage(url);
return image;
}
protected static String _t(String s) {
return DesktopguiTranslator._t(s);
protected String _t(String s) {
return DesktopguiTranslator._t(_appContext, s);
}
}

View File

@ -13,8 +13,10 @@ package net.i2p.desktopgui.gui;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
import net.i2p.desktopgui.router.RouterManager;
import net.i2p.router.RouterContext;
/**
*
@ -22,9 +24,12 @@ import net.i2p.desktopgui.router.RouterManager;
*/
public class DesktopguiConfigurationFrame extends javax.swing.JFrame {
private final RouterContext _context;
/** Creates new form ConfigurationFrame */
public DesktopguiConfigurationFrame() {
public DesktopguiConfigurationFrame(RouterContext ctx) {
initComponents();
_context = ctx;
}
/** This method is called from within the constructor to
@ -98,8 +103,8 @@ public class DesktopguiConfigurationFrame extends javax.swing.JFrame {
configureDesktopgui();
}//GEN-LAST:event_okButtonMouseReleased
protected static String _t(String s) {
return DesktopguiTranslator._t(s);
private String _t(String s) {
return DesktopguiTranslator._t(_context, s);
}
private void configureDesktopgui() {
@ -114,7 +119,7 @@ public class DesktopguiConfigurationFrame extends javax.swing.JFrame {
System.out.println("Enabling desktopgui");
}
try {
RouterManager.getRouterContext().router().saveConfig(property, value);
_context.router().saveConfig(property, value);
} catch (Exception ex) {
Logger.getLogger(DesktopguiConfigurationFrame.class.getName()).log(Level.SEVERE, null, ex);
}

View File

@ -7,20 +7,11 @@ public class DesktopguiTranslator {
private static final String BUNDLE_NAME = "net.i2p.desktopgui.messages";
private static I2PAppContext ctx;
private static I2PAppContext getRouterContext() {
if(ctx == null) {
ctx = I2PAppContext.getCurrentContext();
}
return ctx;
}
public static String _t(String s) {
return Translate.getString(s, getRouterContext(), BUNDLE_NAME);
public static String _t(I2PAppContext ctx, String s) {
return Translate.getString(s, ctx, BUNDLE_NAME);
}
public static String _t(String s, Object o) {
return Translate.getString(s, o, getRouterContext(), BUNDLE_NAME);
public static String _t(I2PAppContext ctx, String s, Object o) {
return Translate.getString(s, o, ctx, BUNDLE_NAME);
}
}

View File

@ -16,29 +16,9 @@ import net.i2p.util.Log;
*/
public class RouterManager {
private final static Log log = new Log(RouterManager.class);
private static I2PAppContext context = I2PAppContext.getCurrentContext();
public static I2PAppContext getAppContext() {
return context;
}
public static RouterContext getRouterContext() throws Exception {
if(context.isRouterContext()) {
return (RouterContext) context;
}
else {
throw new Exception("No RouterContext available!");
}
}
private static Router getRouter() {
try {
return getRouterContext().router();
} catch (Exception e) {
log.error("Failed to get router. Why did we request it if no RouterContext is available?", e);
return null;
}
/** @return non-null */
private static I2PAppContext getAppContext() {
return I2PAppContext.getGlobalContext();
}
/**
@ -53,9 +33,10 @@ public class RouterManager {
//TODO: set/get PID
String separator = System.getProperty("file.separator");
String location = getAppContext().getBaseDir().getAbsolutePath();
Runtime.getRuntime().exec(location + separator + "i2psvc " + location + separator + "wrapper.config");
String[] args = new String[] { location + separator + "i2psvc", location + separator + "wrapper.config" };
Runtime.getRuntime().exec(args);
} catch (IOException e) {
Log log = getAppContext().logManager().getLog(RouterManager.class);
log.log(Log.WARN, "Failed to start I2P", e);
}
}
@ -63,17 +44,14 @@ public class RouterManager {
/**
* Restart the running I2P instance.
*/
public static void restart() {
if(inI2P()) {
getRouter().restart();
}
public static void restart(RouterContext ctx) {
ctx.router().restart();
}
/**
* Stop the running I2P instance.
*/
public static void shutDown() {
if(inI2P()) {
public static void shutDown(RouterContext ctx) {
Thread t = new Thread(new Runnable() {
@Override
@ -83,14 +61,6 @@ public class RouterManager {
});
t.start();
getRouter().shutdown(Router.EXIT_HARD);
}
}
/**
* Check if we are running inside I2P.
*/
public static boolean inI2P() {
return context.isRouterContext();
ctx.router().shutdown(Router.EXIT_HARD);
}
}

View File

@ -1,103 +0,0 @@
package net.i2p.desktopgui.util;
import java.util.HashMap;
import java.util.Map;
/**
* Manage the configuration of desktopgui.
* @author mathias
*
*/
public class ConfigurationManager {
private static ConfigurationManager instance;
///Configurations with a String as value
private Map<String, String> stringConfigurations = new HashMap<String, String>();
///Configurations with a Boolean as value
private Map<String, Boolean> booleanConfigurations = new HashMap<String, Boolean>();
private ConfigurationManager() {}
public static ConfigurationManager getInstance() {
if(instance == null) {
instance = new ConfigurationManager();
}
return instance;
}
/**
* Collects arguments of the form --word, --word=otherword and -blah
* to determine user parameters.
* @param args Command line arguments to the application
*/
public void loadArguments(String[] args) {
for(int i=0; i<args.length; i++) {
String arg = args[i];
if(arg.startsWith("--")) {
arg = arg.substring(2);
if(arg.length() < 1) {
continue;
}
int equals = arg.indexOf('=');
if(equals != -1 && equals < arg.length() - 1) { //String configuration
loadStringConfiguration(arg, equals);
}
else { //Boolean configuration
loadBooleanConfiguration(arg);
}
}
else if(arg.startsWith("-")) { //Boolean configuration
loadBooleanConfiguration(arg);
}
}
}
/**
* Add a boolean configuration.
* @param arg The key we wish to add as a configuration.
*/
public void loadBooleanConfiguration(String arg) {
booleanConfigurations.put(arg, Boolean.TRUE);
}
/**
* Add a String configuration which consists a key and a value.
* @param arg String of the form substring1=substring2.
* @param equalsPosition Position of the '=' element.
*/
public void loadStringConfiguration(String arg, int equalsPosition) {
String key = arg.substring(0, equalsPosition);
String value = arg.substring(equalsPosition+1);
stringConfigurations.put(key, value);
}
/**
* Check if a specific boolean configuration exists.
* @param arg The key for the configuration.
* @param defaultValue If the configuration is not found, we use a default value.
* @return The value of a configuration: true if found, defaultValue if not found.
*/
public boolean getBooleanConfiguration(String arg, boolean defaultValue) {
Boolean value = booleanConfigurations.get("startWithI2P");
System.out.println(value);
if(value != null) {
return value;
}
return defaultValue;
}
/**
* Get a specific String configuration.
* @param arg The key for the configuration.
* @param defaultValue If the configuration is not found, we use a default value.
* @return The value of the configuration, or the defaultValue.
*/
public String getStringConfiguration(String arg, String defaultValue) {
String value = stringConfigurations.get(arg);
System.out.println(value);
if(value != null) {
return value;
}
return defaultValue;
}
}

View File

@ -3,12 +3,9 @@ package net.i2p.desktopgui.util;
import java.awt.Desktop;
import java.awt.Desktop.Action;
import java.net.URI;
import net.i2p.util.Log;
public class I2PDesktop {
private final static Log log = new Log(I2PDesktop.class);
public static void browse(String url) throws BrowseException {
if(Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
@ -27,4 +24,4 @@ public class I2PDesktop {
throw new BrowseException();
}
}
}
}