From 305fc7314f2da4cc26196d86c53f6cd6d2e93f12 Mon Sep 17 00:00:00 2001
From: mathiasdm <mathiasdm@mail.i2p>
Date: Sat, 11 Apr 2009 13:35:22 +0000
Subject: [PATCH] Added text explaining the different speeds. Tray icon colours
 indicates active peers (and tooltip indicates reachability). The menu now
 uses Swing instead of Awt, so it looks a lot better.

---
 .../desktopgui/resources/logo/logo_green.jpg  | Bin 0 -> 1328 bytes
 .../desktopgui/resources/logo/logo_orange.jpg | Bin 0 -> 1302 bytes
 .../desktopgui/resources/logo/logo_red.jpg    | Bin 0 -> 1233 bytes
 .../src/gui/GeneralConfiguration.form         | 103 ++++++++++
 .../src/gui/GeneralConfiguration.java         | 106 +++++++++++
 apps/desktopgui/src/gui/JPopupTrayIcon.java   | 176 ++++++++++++++++++
 apps/desktopgui/src/gui/SpeedSelector.form    |   1 +
 apps/desktopgui/src/gui/SpeedSelector2.form   |   7 +-
 apps/desktopgui/src/gui/SpeedSelector2.java   |   6 +-
 apps/desktopgui/src/gui/SpeedSelector3.form   |   2 +-
 apps/desktopgui/src/gui/SpeedSelector3.java   |   6 +-
 apps/desktopgui/src/gui/Tray.java             |  65 +++++--
 .../gui/resources/SpeedSelector.properties    |   2 +-
 .../gui/resources/SpeedSelector2.properties   |   2 +-
 .../gui/resources/SpeedSelector3.properties   |   2 +-
 .../src/router/configuration/PeerHelper.java  | 165 ++++++++++++++++
 16 files changed, 614 insertions(+), 29 deletions(-)
 create mode 100644 apps/desktopgui/desktopgui/resources/logo/logo_green.jpg
 create mode 100644 apps/desktopgui/desktopgui/resources/logo/logo_orange.jpg
 create mode 100644 apps/desktopgui/desktopgui/resources/logo/logo_red.jpg
 create mode 100644 apps/desktopgui/src/gui/GeneralConfiguration.form
 create mode 100644 apps/desktopgui/src/gui/GeneralConfiguration.java
 create mode 100644 apps/desktopgui/src/gui/JPopupTrayIcon.java
 create mode 100644 apps/desktopgui/src/router/configuration/PeerHelper.java

diff --git a/apps/desktopgui/desktopgui/resources/logo/logo_green.jpg b/apps/desktopgui/desktopgui/resources/logo/logo_green.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9a29b6d1c3e10d658683a91c89fcfe106e538028
GIT binary patch
literal 1328
zcmex=<NpH&0WUXCHwH#VMur3+WcYuZ!5PG(2!ITs$N-S${|6WZIT%D3B$*kN7?=bZ
znFSgDA7PMUU|?cmW<UmP?3}C|TtGQ>0S2HH6B8pd3seOQD>EBA69*$FgNRs!ppe8h
z$!XJp3MCjBn1LQf0<3JDU?Y?TfkrSgFfy~kq?uWmSlJkb**OFmghWIY#sA-8-~p;&
z5@Z%+uxIEBDt9j`ZYrPcxi0zP%U}92zhl>aeXV-lxa;ZBZt1A3xlNtXYi&2F#nsOI
zd`<J;d!zHEzmrrJ%QOnsh_}c6RZSKPUo*G&?Pb0bg4g!ly|CenSbJ<<?2TKuc|v}d
zzgg3I=!Y!lQLa~}GxyG6yVfyd%R@`{EAvi9`9E~mxW0Yo;e?)BUxcsTJ+=PY8T(sy
z4+|eEau)w*NUGhCDs`i7b<6wta%E+cmPa%+GNhl8d~3F?Gkb!`9L<JMZ9kr<qQ;D+
z6NTol-hH<`@3Ow^jyv1$EIWJ4_ib?%TVbc>1;?(N6CaDbW;T1XGHY{Yjtrk*ahd2r
z-NyE3d#*gp);PL<c81x(#qm$3al|F8oN&DAX6Ajrm5MVLWNO{AHF|k>_foT6=Zz<A
zcI%toWqj(^ET2P;d#+{W-0OIhy0&2=$Ni}x>F57`UoJBBhkx9=`ZF4elh5vq4R&4=
zDa-t8b8haZ8K<*;ap|dC*IK#4C_{h2&Fr^12@-R?8x)*&URoLFo3XMw`y0o3netmq
z8|3yy{`x)dW!C4v60g35TfOaLKJhzbrZ~H@uG0yxdY*?nu7|AO>K(XAJLct$`mhB*
z7AVx4t^F6ax9*?Y;{Oc3m+P1OS>zvExBt!EtFOP#p1kkO-OqbW-4lJ|3yx%m-q&H-
zzSGnDy!6z3!Jpes2&rxon{|Lo^r^|hsE5Hy0<%8J_S+k@sQb-7`ftlWo5cB_qWHi5
zXXulAbn)B#8CSmR<a~Yc{)O)Q$(y||$(5^VT}jc3ys~(O*}K(FtzQp3|E<h-T>D6X
z1iykgv!8Z}|GXCg-x4R?m@HGXuO~|9>bq(CuFAWl-igq9z3-G|aCr9lSEg!9d1YTL
zKkdwSS@GAe7Yv_bH*U08t+;7==VKr3a;?IjYDu~7uA8TpU&vZ|Vbzjr@57z_qpsX8
zJt=c)=bFtoPiM?@R+_(C<k=Frm6?;KpJ{NNq<ShpV%PP#5eIfWzgu;9#k8j}K9AO2
z_C2{Gv|H+)4wGWxABT#G3_6D&6@5CzaGrUpe3O$(W7@}aoJ;yAe)!qqzU&fbx{z4Y
zo6H-P^|p?;?OEr2)-&b(+0ZQ`Y!}L++WoBMPj^q^{1Xo)K9zEZui)xiAglUg;-*jk
zjw;4P^m_AK9rn3DYft2ZsLyJOTJbiVPa>RI{<(4-?)&*Ke&&;tUF)7!-W4}qKj%_<
z+M@HXJTyCdN<11FoQtM~i?8KqYhl`25Nt4wFZGlHBfrX>g<^bydu#0E+01U|Z%UWT
zY>!T=bKY{Z<FNYt%5!CDmP?H$)jqd8zpH3^o#nZj{|t65J6=!ImAuV%v+`Q{C4<}T
h+P(&UpXa>fIr!XY8c^lAGn1$6K36>7{`~s?HvwflBewtm

literal 0
HcmV?d00001

diff --git a/apps/desktopgui/desktopgui/resources/logo/logo_orange.jpg b/apps/desktopgui/desktopgui/resources/logo/logo_orange.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..137a25e7a033e632799ebb118a73c3044fedc0ee
GIT binary patch
literal 1302
zcmex=<NpH&0WUXCHwH#VMur3+WcYuZ!5PG(2!ITs$N-S${|6WZIT%D3B$*kN7?=bZ
znFSgDA7PMUU|?cmW<UmP?3}C|TtGQZ0S2HH6B8p7D=S0+3oA1lI}-;3Bd3U%kg$Yg
zc*L~nSFZt;N-#1o1HFs{*f=;@Sb;K1f<QwU85miB1Oza%01adlW)~C^Vc<{{{eO#r
z2PnrR$SlZU&(I+BT|TF<wLIT-{gbB5S^ROkeOEt_46C1eeeIcusF2Y3z}H*1m#I9E
zO{x0WG=I0xraOPHE%Gs3F-iPrMTYIisV$LyTfa$fbN{B&x3lb2cbC#;%hxMp+t$tR
zmCyMjy5UEh^P=sG?i|}>wyEjbSz)%qbB<TTCxwet1)nl~yUt*L&k=$8NV8MNV?O#%
zu3dHikdtu0KF8ky$D3Z%EpK@*CzDq*Yjsppp=0V9%{SksWv;$pG{@2*T-%OE@>65R
zQh%ZK$6_Dt-SW~r@A})_`=V3cynD5GE5G&8tMP}ru1<cumHo|Z!{yrNQtJ;~6gRWm
zqr1Y<c0oqQ)h&ze^K6>&+j-wf9ktsJ3okygO}{+fzcBOcLz8)V`X0Mx`<0}<Hrcr^
z*i*-+B6P;NQ%9c#^IZ?Ul4%=w<#bk~_Qdr{C*v+Z`DWEuYB%}$@xryaf2T%WxOTug
zQtLtgEa&<qj%RZtQ-uCa+wOF+sB&K^%aciJ#y)p7w)eKZUMK25b>1K26SCh@<|s36
zdNA|fgiWmrXEj;(Rvl$LQoF{b`|z{lJ{tv=U)ESB`cxtE=ao0v;X8};H%*b{cyjpN
z#r-AoTI&N|{AbuwQvc(=#_PxT7jBDt`k*X7uUfU_{6^8}pWSbNY%SXV_0jDZ)n(7m
zp4`^;<8%n;<QrW9KSUCQ&UI%shOBVPKE)<f=aE#h{#WMf=^xnC|7k6%U-)7BH&Oko
zb=k}3CEWS<;CsQ=?ID-_FJ;UNi9B&5;`%A~W#)y`FDUO`@BN=)QR0iD50gwd->|L7
zzFH};ePLeRi4vJNCC;}`sF|HhGmd=wYqsGf!SC9&QJLG%v-e**QY>xsk)xxtBtCbO
zghA>Wt%!eaN*{YFe!bndpe%6K?BEM)j@;G1TJ&OTk@oiP&gJVeQa9b3lp1sGX3o*g
z0ZTje=kjEGo)6ox)9aaov!~Eo`?a=3=W`TpudrZKci*P{C|-10Rb8mdnj7JTHkQ}t
z9ufBpXgT4h))1&L{Y6po7mt*4Ciiw8Hko57C#SslrIn)2t)%<6r22o_eOi3As@wWm
zOqTT9rsa*sPeYs{=4IVKvE!I@b>GxA7Sj(LQoNQiW2Z`{zWn91pDS;?s^~9s{o0#w
zlJQYWOG2G?@Pne5t>0AFW|l5Yi`*A7XVtg(`9a1dY@26ZT=62*#pKJ=ohkv1iW|MP
z59o2U6}RlHD3;feIW;AKNq)|rg<^byyMI(vp3U4gFJbMj(|l&tKlv`ZDf38u78EX;
zacw7OWk<))xNGw>I==s_%a2T*%rMorKx>2c2d>u~2@ILS#v%f)Q9PxcGw1he3%)o0
I^XLCf07gg~1^@s6

literal 0
HcmV?d00001

diff --git a/apps/desktopgui/desktopgui/resources/logo/logo_red.jpg b/apps/desktopgui/desktopgui/resources/logo/logo_red.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1da898381264bae953ddc628254788cbd4137433
GIT binary patch
literal 1233
zcmex=<NpH&0WUXCHwH#VMur3+WcYuZ!5PG(2!ITs$N-S${|6WZIT%D3B$*kN7?=bZ
znFSgDA7PMUU|?cmW<Un4Y#hv-TtGQZ0S2HH6C)!VJ5-*9m5G^+k)44<NJLaD?252>
z@Z>2|uY!zWWME`vL^g$)i3Mm7$QVUIpfQXfYhVhPSs0mE+1Q1E4iZ*0{C|sq2P7}Z
zEXZKb@LWai%mvZ@ch4IivR>Z%dfly?rO(1`XSh|SZRa#*SsgO%fS1~d%bbgH^Adht
zoys47xOvw>C+Qj9^9oD<-QTEuQ}pZlyeA(NjPpC&&Pwh$G1H3edvP{rliAie!BL%w
zK5OTjP1$o}jaWi4!|7^oD{oHu=r>nO-^E|~cJjVi(O&Tt|8DJ{mD#hjuysNf!?bma
zZ?^pC<hdy%^-FhqN5AiqLzi-vR7B?}|C{|q%WT&7*xBoEt6Fa{Te!iiTf(|d#V=Z9
zZNI9oD_7+li&f?VyS9}C9u1E@bZb>@?WdH#Z=UzfV^)YiadcU9%jr|Q4|sc~mEEkd
zQaN?bD0_uzcj=__$7XF@x$g74g&SlfbTjrg3SPXgxw(Dy_8%e5c23U&-~VZuuDkYf
zp>@SR-J?%RcU;-ics=dQt-IXT9@?9)l*xIl{A8goTXg5nbQh~TkE;$cipTqLGX%cU
z-sy8>=Ud4HtBup-H5ZGDO`E8lF!%nWSd)n@jNhLxKR%Chv&#~zF3IZZ);+tq6@9L?
zWSZQ{KOgV^pCLY_zUA<reocFalEd@v9kAz^ccO6i0r%R9T{2OvTmACSaGIs|AK6))
z&2h>0-a+mxndG4DJVBE?&Y7G!aZ$0%|5Km;%bMq3vi@B^`rW!l&Ti^v{@BI)X8UnY
z_#9=m)6~bV^VES0`zHFa&z?DrlPA53Y0DPAkH)VJWq-_k^q=AMewBi(@0Ga~r`4yv
z{CO|gUETYfO*-Qf=P$Fi>HXNg)#B=olA_W|y|OKGUYGlCoQ`VGD9cR>D6{cldU#>N
z&QnQ7lH6A^X5RYju<p%|uys{0Cb8+X^Eu8*F*ch%g~8>{fm`eKE-{O}ysOQ=EFfyS
zeb@Q<&Ly(t*H7H$mtJIT@>5k?B2fDET=8R*ot90?>b-KV<n9sOez8!?>vpP~#mCj#
zTmLf7*s(-uqMSavOy4A9NA18#+@AeGt}g|>e;?huQZTyq_~(b(%a^)MsG6l8dS_)+
z(Vf*fp=)mXe9QE7>`;-k44oa>y0p6gi`+GXy`IMTeHTu~g;<9_{cPEDLwu@nJ}Xz^
z<@UmDp}u0`8K-y3&F0$F*uE^qPv*APie)?fXN2-8y?@pwzexV={qJ&eawd9yfhUXQ
zjctyq{Ek`bnI!b>KZD)->aN_(Umg8BXU>0qnoG{<{iezB*7`eMe=fcv!|4+6vTU+%
epv##9(?iSM82Z%GlA4!h3me<V7u(zazX<?U)!mW+

literal 0
HcmV?d00001

diff --git a/apps/desktopgui/src/gui/GeneralConfiguration.form b/apps/desktopgui/src/gui/GeneralConfiguration.form
new file mode 100644
index 0000000000..070e201382
--- /dev/null
+++ b/apps/desktopgui/src/gui/GeneralConfiguration.form
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+    <Property name="name" type="java.lang.String" value="Form" noResource="true"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace max="32767" attributes="0"/>
+              <Component id="jTabbedPane1" min="-2" pref="478" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace max="32767" attributes="0"/>
+              <Component id="jTabbedPane1" min="-2" pref="369" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JTabbedPane" name="jTabbedPane1">
+      <Properties>
+        <Property name="name" type="java.lang.String" value="jTabbedPane1" noResource="true"/>
+      </Properties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel1">
+          <Properties>
+            <Property name="name" type="java.lang.String" value="jPanel1" noResource="true"/>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="tab1">
+                <Property name="tabTitle" type="java.lang.String" resourceKey="jPanel1.TabConstraints.tabTitle"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <EmptySpace min="0" pref="474" max="32767" attributes="0"/>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <EmptySpace min="0" pref="338" max="32767" attributes="0"/>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel2">
+          <Properties>
+            <Property name="name" type="java.lang.String" value="jPanel2" noResource="true"/>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="tab2">
+                <Property name="tabTitle" type="java.lang.String" resourceKey="jPanel2.TabConstraints.tabTitle"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <EmptySpace min="0" pref="474" max="32767" attributes="0"/>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <EmptySpace min="0" pref="338" max="32767" attributes="0"/>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/apps/desktopgui/src/gui/GeneralConfiguration.java b/apps/desktopgui/src/gui/GeneralConfiguration.java
new file mode 100644
index 0000000000..b9c7403813
--- /dev/null
+++ b/apps/desktopgui/src/gui/GeneralConfiguration.java
@@ -0,0 +1,106 @@
+/*
+ * GeneralConfiguration.java
+ *
+ * Created on 10 april 2009, 19:04
+ */
+
+package gui;
+
+/**
+ *
+ * @author  mathias
+ */
+public class GeneralConfiguration extends javax.swing.JFrame {
+
+    /** Creates new form GeneralConfiguration */
+    public GeneralConfiguration() {
+        initComponents();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jTabbedPane1 = new javax.swing.JTabbedPane();
+        jPanel1 = new javax.swing.JPanel();
+        jPanel2 = new javax.swing.JPanel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        setName("Form"); // NOI18N
+
+        jTabbedPane1.setName("jTabbedPane1"); // NOI18N
+
+        jPanel1.setName("jPanel1"); // NOI18N
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 474, Short.MAX_VALUE)
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 338, Short.MAX_VALUE)
+        );
+
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(GeneralConfiguration.class);
+        jTabbedPane1.addTab(resourceMap.getString("jPanel1.TabConstraints.tabTitle"), jPanel1); // NOI18N
+
+        jPanel2.setName("jPanel2"); // NOI18N
+
+        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
+        jPanel2.setLayout(jPanel2Layout);
+        jPanel2Layout.setHorizontalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 474, Short.MAX_VALUE)
+        );
+        jPanel2Layout.setVerticalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 338, Short.MAX_VALUE)
+        );
+
+        jTabbedPane1.addTab(resourceMap.getString("jPanel2.TabConstraints.tabTitle"), jPanel2); // NOI18N
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 478, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 369, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    /**
+    * @param args the command line arguments
+    */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                new GeneralConfiguration().setVisible(true);
+            }
+        });
+    }
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JPanel jPanel2;
+    private javax.swing.JTabbedPane jTabbedPane1;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/apps/desktopgui/src/gui/JPopupTrayIcon.java b/apps/desktopgui/src/gui/JPopupTrayIcon.java
new file mode 100644
index 0000000000..83872e4a51
--- /dev/null
+++ b/apps/desktopgui/src/gui/JPopupTrayIcon.java
@@ -0,0 +1,176 @@
+/*
+* Created on Sep 15, 2008  5:51:33 PM
+*/
+
+/*
+ * This class is part of fishfarm project: https://fishfarm.dev.java.net/
+ * It is licensed under the GPL version 2.0 with Classpath Exception.
+ * 
+ * Copyright (C) 2008  Michael Bien
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ */
+
+package gui;
+
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.PopupMenu;
+import java.awt.TrayIcon;
+import java.awt.Window;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JWindow;
+import javax.swing.RootPaneContainer;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+
+
+
+/**
+ * JPopupMenu compatible TrayIcon based on Alexander Potochkin's JXTrayIcon
+ * (http://weblogs.java.net/blog/alexfromsun/archive/2008/02/jtrayicon_updat.html)
+ * but uses a JWindow instead of a JDialog to workaround some bugs on linux.
+ *
+ * @author Michael Bien
+ */
+public class JPopupTrayIcon extends TrayIcon {
+
+    private JPopupMenu menu;
+    
+    private Window window;
+    private PopupMenuListener popupListener;
+    
+    private final static boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("windows");
+
+    public JPopupTrayIcon(Image image) {
+        super(image);
+        init();
+    }
+
+    public JPopupTrayIcon(Image image, String tooltip) {
+        super(image, tooltip);
+        init();
+    }
+
+    public JPopupTrayIcon(Image image, String tooltip, PopupMenu popup) {
+        super(image, tooltip, popup);
+        init();
+    }
+
+    public JPopupTrayIcon(Image image, String tooltip, JPopupMenu popup) {
+        super(image, tooltip);
+        init();
+        setJPopupMenu(popup);
+    }
+
+
+    private final void init() {
+
+
+        popupListener = new PopupMenuListener() {
+
+            @Override
+            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+//                System.out.println("popupMenuWillBecomeVisible");
+            }
+
+            @Override
+            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+//                System.out.println("popupMenuWillBecomeInvisible");
+                if(window != null) {
+                    window.dispose();
+                    window = null;
+                }
+            }
+
+            @Override
+            public void popupMenuCanceled(PopupMenuEvent e) {
+//                System.out.println("popupMenuCanceled");
+                if(window != null) {
+                    window.dispose();
+                    window = null;
+                }
+            }
+        };
+
+        addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+//                System.out.println(e.getPoint());
+                showJPopupMenu(e);
+            }
+
+            @Override
+            public void mouseReleased(MouseEvent e) {
+//                System.out.println(e.getPoint());
+                showJPopupMenu(e);
+            }
+        });
+
+    }
+
+    private final void showJPopupMenu(MouseEvent e) {
+        if(e.isPopupTrigger() && menu != null) {
+            if (window == null) {
+
+                if(IS_WINDOWS) {
+                    window = new JDialog((Frame)null);
+                    ((JDialog)window).setUndecorated(true);
+                }else{
+                    window = new JWindow((Frame)null);
+                }
+                window.setAlwaysOnTop(true);
+                Dimension size = menu.getPreferredSize();
+
+                Point centerPoint = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
+                if(e.getY() > centerPoint.getY())
+                    window.setLocation(e.getX(), e.getY() - size.height);
+                else
+                    window.setLocation(e.getX(), e.getY());
+
+                window.setVisible(true);
+                
+                menu.show(((RootPaneContainer)window).getContentPane(), 0, 0);
+
+                // popup works only for focused windows
+                window.toFront();
+
+            }
+        }
+    }
+
+
+    public final JPopupMenu getJPopupMenu() {
+        return menu;
+    }
+
+    public final void setJPopupMenu(JPopupMenu menu) {
+        if (this.menu != null) {
+            this.menu.removePopupMenuListener(popupListener);
+        }
+        this.menu = menu;
+        menu.addPopupMenuListener(popupListener);
+    }
+
+}
diff --git a/apps/desktopgui/src/gui/SpeedSelector.form b/apps/desktopgui/src/gui/SpeedSelector.form
index 6ccf414b5b..79d25ae965 100644
--- a/apps/desktopgui/src/gui/SpeedSelector.form
+++ b/apps/desktopgui/src/gui/SpeedSelector.form
@@ -22,6 +22,7 @@
     <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
     <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
     <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,56,0,0,2,102"/>
   </AuxValues>
 
   <Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
diff --git a/apps/desktopgui/src/gui/SpeedSelector2.form b/apps/desktopgui/src/gui/SpeedSelector2.form
index 215d407f0f..5c305de19b 100644
--- a/apps/desktopgui/src/gui/SpeedSelector2.form
+++ b/apps/desktopgui/src/gui/SpeedSelector2.form
@@ -26,6 +26,7 @@
     <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
     <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
     <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,2,105"/>
   </AuxValues>
 
   <Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
@@ -82,7 +83,7 @@
       </Properties>
       <Constraints>
         <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
-          <AbsoluteConstraints x="40" y="130" width="-1" height="40"/>
+          <AbsoluteConstraints x="40" y="120" width="-1" height="40"/>
         </Constraint>
       </Constraints>
     </Component>
@@ -97,7 +98,7 @@
       </Properties>
       <Constraints>
         <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
-          <AbsoluteConstraints x="40" y="80" width="-1" height="40"/>
+          <AbsoluteConstraints x="40" y="70" width="-1" height="40"/>
         </Constraint>
       </Constraints>
     </Component>
@@ -108,7 +109,7 @@
       </Properties>
       <Constraints>
         <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
-          <AbsoluteConstraints x="30" y="190" width="530" height="50"/>
+          <AbsoluteConstraints x="30" y="170" width="530" height="70"/>
         </Constraint>
       </Constraints>
     </Component>
diff --git a/apps/desktopgui/src/gui/SpeedSelector2.java b/apps/desktopgui/src/gui/SpeedSelector2.java
index d929e4ccd2..1177b57258 100644
--- a/apps/desktopgui/src/gui/SpeedSelector2.java
+++ b/apps/desktopgui/src/gui/SpeedSelector2.java
@@ -85,19 +85,19 @@ public class SpeedSelector2 extends javax.swing.JFrame {
         browseButton.setActionCommand(resourceMap.getString("browseButton.actionCommand")); // NOI18N
         browseButton.setName("browseButton"); // NOI18N
         getContentPane().add(browseButton);
-        browseButton.setBounds(40, 130, 520, 40);
+        browseButton.setBounds(40, 120, 520, 40);
 
         buttonGroup1.add(downloadButton);
         downloadButton.setText(resourceMap.getString("downloadButton.text")); // NOI18N
         downloadButton.setActionCommand(resourceMap.getString("downloadButton.actionCommand")); // NOI18N
         downloadButton.setName("downloadButton"); // NOI18N
         getContentPane().add(downloadButton);
-        downloadButton.setBounds(40, 80, 499, 40);
+        downloadButton.setBounds(40, 70, 499, 40);
 
         jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
         jLabel1.setName("jLabel1"); // NOI18N
         getContentPane().add(jLabel1);
-        jLabel1.setBounds(30, 190, 530, 50);
+        jLabel1.setBounds(30, 170, 530, 70);
 
         pack();
     }// </editor-fold>//GEN-END:initComponents
diff --git a/apps/desktopgui/src/gui/SpeedSelector3.form b/apps/desktopgui/src/gui/SpeedSelector3.form
index ec26972216..9c6ef533aa 100644
--- a/apps/desktopgui/src/gui/SpeedSelector3.form
+++ b/apps/desktopgui/src/gui/SpeedSelector3.form
@@ -329,7 +329,7 @@
       </Properties>
       <Constraints>
         <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
-          <AbsoluteConstraints x="20" y="200" width="600" height="40"/>
+          <AbsoluteConstraints x="20" y="180" width="600" height="70"/>
         </Constraint>
       </Constraints>
     </Component>
diff --git a/apps/desktopgui/src/gui/SpeedSelector3.java b/apps/desktopgui/src/gui/SpeedSelector3.java
index 8115acb2bc..1f523befda 100644
--- a/apps/desktopgui/src/gui/SpeedSelector3.java
+++ b/apps/desktopgui/src/gui/SpeedSelector3.java
@@ -122,12 +122,12 @@ public class SpeedSelector3 extends javax.swing.JFrame {
         uploadUsageLabel.setText(resourceMap.getString("uploadUsageLabel.text")); // NOI18N
         uploadUsageLabel.setName("uploadUsageLabel"); // NOI18N
         getContentPane().add(uploadUsageLabel);
-        uploadUsageLabel.setBounds(20, 150, 141, 30);
+        uploadUsageLabel.setBounds(20, 150, 19, 30);
 
         downloadUsageLabel.setText(resourceMap.getString("downloadUsageLabel.text")); // NOI18N
         downloadUsageLabel.setName("downloadUsageLabel"); // NOI18N
         getContentPane().add(downloadUsageLabel);
-        downloadUsageLabel.setBounds(340, 150, 162, 30);
+        downloadUsageLabel.setBounds(340, 150, 19, 30);
 
         uploadField.setText(resourceMap.getString("uploadField.text")); // NOI18N
         uploadField.setMinimumSize(new java.awt.Dimension(77, 27));
@@ -236,7 +236,7 @@ public class SpeedSelector3 extends javax.swing.JFrame {
         explanation.setText(resourceMap.getString("explanation.text")); // NOI18N
         explanation.setName("explanation"); // NOI18N
         getContentPane().add(explanation);
-        explanation.setBounds(20, 200, 600, 40);
+        explanation.setBounds(20, 180, 600, 70);
 
         pack();
     }// </editor-fold>//GEN-END:initComponents
diff --git a/apps/desktopgui/src/gui/Tray.java b/apps/desktopgui/src/gui/Tray.java
index bf3cd28c87..5a8da78db9 100644
--- a/apps/desktopgui/src/gui/Tray.java
+++ b/apps/desktopgui/src/gui/Tray.java
@@ -9,9 +9,6 @@ import desktopgui.*;
 import java.awt.AWTException;
 import java.awt.Desktop;
 import java.awt.Image;
-import java.awt.MenuItem;
-import java.awt.Menu;
-import java.awt.PopupMenu;
 import java.awt.SystemTray;
 import java.awt.Toolkit;
 import java.awt.TrayIcon;
@@ -23,8 +20,12 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
 import router.RouterHandler;
 import router.RouterHelper;
+import router.configuration.PeerHelper;
 
 /**
  *
@@ -41,12 +42,13 @@ public class Tray {
 
         Image image = Toolkit.getDefaultToolkit().getImage("desktopgui/resources/logo/logo.jpg");
 
-        PopupMenu popup = new PopupMenu();
+        final JPopupMenu popup = new JPopupMenu();
 
         //Create menu items to put in the popup menu
-        MenuItem browserLauncher = new MenuItem("Launch browser");
+        JMenuItem browserLauncher = new JMenuItem("Launch browser");
         browserLauncher.addActionListener(new ActionListener() {
 
+            @Override
             public void actionPerformed(ActionEvent arg0) {
                 if(Desktop.isDesktopSupported()) {
                     Desktop desktop = Desktop.getDesktop();
@@ -66,9 +68,10 @@ public class Tray {
             }
 
         });
-        MenuItem howto = new MenuItem("How to use I2P");
+        JMenuItem howto = new JMenuItem("How to use I2P");
         howto.addActionListener(new ActionListener() {
 
+            @Override
             public void actionPerformed(ActionEvent arg0) {
                 if(Desktop.isDesktopSupported()) {
                     Desktop desktop = Desktop.getDesktop();
@@ -84,18 +87,20 @@ public class Tray {
             }
             
         });
-        Menu config = new Menu("Configuration");
-        MenuItem speedConfig = new MenuItem("Speed");
+        JMenu config = new JMenu("Configuration");
+        JMenuItem speedConfig = new JMenuItem("Speed");
         speedConfig.addActionListener(new ActionListener() {
 
+            @Override
             public void actionPerformed(ActionEvent arg0) {
                 (new SpeedSelector()).setVisible(true);
             }
             
         });
-        MenuItem advancedConfig = new MenuItem("Advanced Configuration");
+        JMenuItem advancedConfig = new JMenuItem("Advanced Configuration");
         advancedConfig.addActionListener(new ActionListener() {
 
+            @Override
             public void actionPerformed(ActionEvent arg0) {
                 if(Desktop.isDesktopSupported()) {
                     Desktop desktop = Desktop.getDesktop();
@@ -110,7 +115,7 @@ public class Tray {
             }
 
         });
-        MenuItem viewLog = new MenuItem("View log");
+        JMenuItem viewLog = new JMenuItem("View log");
         viewLog.addActionListener(new ActionListener() {
 
             @Override
@@ -119,17 +124,21 @@ public class Tray {
             }
             
         });
-        MenuItem shutdown = new MenuItem("Shutdown I2P");
+        JMenuItem shutdown = new JMenuItem("Shutdown I2P");
         shutdown.addActionListener(new ActionListener() {
 
+            @Override
             public void actionPerformed(ActionEvent arg0) {
                 RouterHandler.setStatus(RouterHandler.SHUTDOWN_GRACEFULLY);
                 long shutdownTime = RouterHelper.getGracefulShutdownTimeRemaining();
                 System.out.println(shutdownTime);
-                if(shutdownTime>0)
-                    trayIcon.displayMessage("Shutting down...", "Shutdown time remaining: " + shutdownTime/1000 + " seconds.", TrayIcon.MessageType.INFO);
-                else
+                if(shutdownTime>0) {
+                    trayIcon.displayMessage("Shutting down...", "Shutdown time remaining: " + shutdownTime/1000 + " seconds."
+                            + System.getProperty("line.separator") + "Shutdown will not happen immediately, because we are still participating in the network.", TrayIcon.MessageType.INFO);
+                }
+                else {
                     trayIcon.displayMessage("Shutting down...", "Shutting down immediately.", TrayIcon.MessageType.INFO);
+                }
             }
 
         });
@@ -147,7 +156,31 @@ public class Tray {
         popup.add(shutdown);
 
         //Add tray icon
-        trayIcon = new TrayIcon(image, "I2P: the anonymous network", popup);
+        trayIcon = new JPopupTrayIcon(image, "I2P: the anonymous network", popup);
+        PeerHelper.addReachabilityListener(new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent arg0) {
+                trayIcon.setToolTip("I2P Network status: " + PeerHelper.getReachability());
+            }
+            
+        });
+        PeerHelper.addActivePeerListener(new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent arg0) {
+                int activePeers = PeerHelper.getActivePeers();
+                if(activePeers == 0)
+                    trayIcon.setImage(Toolkit.getDefaultToolkit().getImage("desktopgui/resources/logo/logo_red.jpg"));
+                else if(activePeers < 10)
+                    trayIcon.setImage(Toolkit.getDefaultToolkit().getImage("desktopgui/resources/logo/logo_orange.jpg"));
+                else
+                    trayIcon.setImage(Toolkit.getDefaultToolkit().getImage("desktopgui/resources/logo/logo_green.jpg"));
+                
+            }
+            
+        });
+        
         try {
             tray.add(trayIcon);
         } catch (AWTException ex) {
@@ -156,6 +189,6 @@ public class Tray {
     }
     
     private SystemTray tray = null;
-    private TrayIcon trayIcon = null;
+    private JPopupTrayIcon trayIcon = null;
     
 }
diff --git a/apps/desktopgui/src/gui/resources/SpeedSelector.properties b/apps/desktopgui/src/gui/resources/SpeedSelector.properties
index 03b04286f6..00eb6c973d 100644
--- a/apps/desktopgui/src/gui/resources/SpeedSelector.properties
+++ b/apps/desktopgui/src/gui/resources/SpeedSelector.properties
@@ -3,4 +3,4 @@ Form.title=I2P Speed Configuration
 nextButton.text=Next
 uploadLabel.text=What is your maximum upload speed?
 downloadLabel.text=What is your maximum download speed?
-speedExplanation.text=Explanation about speeds...
+speedExplanation.text=<html>The maximum speed is set by your provider. It can be given in <b>kilobit (kbps)</b> or <b>kilobyte (kBps)</b>.<br />One kilobyte equals eight kilobit.</html>
diff --git a/apps/desktopgui/src/gui/resources/SpeedSelector2.properties b/apps/desktopgui/src/gui/resources/SpeedSelector2.properties
index 54424ed051..909518ada2 100644
--- a/apps/desktopgui/src/gui/resources/SpeedSelector2.properties
+++ b/apps/desktopgui/src/gui/resources/SpeedSelector2.properties
@@ -6,4 +6,4 @@ downloadButton.text=Downloading: I want to use I2P for downloads and filesharing
 nextButton.text=Next
 browseButton.actionCommand=Browsing
 downloadButton.actionCommand=Downloading
-jLabel1.text=Text explaining ...
+jLabel1.text=<html>I2P can be used for many different purposes. Here, we present two possible descriptions. If you use a lot of bandwidth in I2P (for example using downloading), please check the <b>downloading</b> option. If your bandwidth usage is limited, please check the <b>browsing</b> option.</html>
diff --git a/apps/desktopgui/src/gui/resources/SpeedSelector3.properties b/apps/desktopgui/src/gui/resources/SpeedSelector3.properties
index 9d0718f8db..6dca3ca516 100644
--- a/apps/desktopgui/src/gui/resources/SpeedSelector3.properties
+++ b/apps/desktopgui/src/gui/resources/SpeedSelector3.properties
@@ -14,4 +14,4 @@ downloadBurstField.text=jTextField5
 uploadMonth.text=jTextField1
 downloadMonth.text=jTextField2
 settingsInfo.text=The profile information your entered, indicates that these are your optimal settings:
-explanation.text=Text explaining ...
+explanation.text=<html>We give a suggested upload and download speed. If your provider imposes a monthly bandwidth limit (usually given in <b>gigabyte (GB)</b>), please enter a value lower than that limit. If you run I2P only 50% of the time, you can double the bandwidth limit to use the same amount as when you are online 100% of the time.</html>
diff --git a/apps/desktopgui/src/router/configuration/PeerHelper.java b/apps/desktopgui/src/router/configuration/PeerHelper.java
new file mode 100644
index 0000000000..2272456f8d
--- /dev/null
+++ b/apps/desktopgui/src/router/configuration/PeerHelper.java
@@ -0,0 +1,165 @@
+package router.configuration;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import net.i2p.data.RouterAddress;
+import net.i2p.router.CommSystemFacade;
+import net.i2p.router.RouterContext;
+import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
+import net.i2p.router.transport.ntcp.NTCPAddress;
+import router.RouterHelper;
+
+/**
+ * Part of the code imported and adapted from the I2P Router Console (which is licensed as public domain)
+ */
+public class PeerHelper {
+    public static String getReachability() {
+        RouterContext context = RouterHelper.getContext();
+        if (context.router().getUptime() > 60*1000
+                && (!context.router().gracefulShutdownInProgress())
+                && !context.clientManager().isAlive())
+            return "ERROR: Client Manager I2CP Error - check logs";  // not a router problem but the user should know
+        if (!context.clock().getUpdatedSuccessfully())
+            return "ERROR: ClockSkew";
+        if (context.router().isHidden())
+            return "Hidden";
+
+        int status = context.commSystem().getReachabilityStatus();
+        switch (status) {
+            case CommSystemFacade.STATUS_OK:
+                RouterAddress ra = context.router().getRouterInfo().getTargetAddress("NTCP");
+                if (ra == null || (new NTCPAddress(ra)).isPubliclyRoutable())
+                    return "OK";
+                return "ERROR: Private TCP Address";
+            case CommSystemFacade.STATUS_DIFFERENT:
+                return "ERROR: You are behind a symmetric NAT.";
+            case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
+                if (context.router().getRouterInfo().getTargetAddress("NTCP") != null)
+                    return "WARNING: You are behind a firewall and have Inbound TCP Enabled";
+                if (((FloodfillNetworkDatabaseFacade)context.netDb()).floodfillEnabled())
+                    return "WARNING: You are behind a firewall and are a floodfill router";
+                if (context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0)
+                    return "WARNING: You are behind a firewall and are a fast router";
+                return "Firewalled";
+            case CommSystemFacade.STATUS_HOSED:
+                return "ERROR: The UDP port is already in use. Set i2np.udp.internalPort=xxxx to a different value in the advanced config and restart";
+            case CommSystemFacade.STATUS_UNKNOWN: // fallthrough
+            default:
+                ra = context.router().getRouterInfo().getTargetAddress("UDP");
+                if (ra == null && context.router().getUptime() > 5*60*1000) {
+                    if (context.getProperty(PROP_I2NP_NTCP_HOSTNAME) == null ||
+                        context.getProperty(PROP_I2NP_NTCP_PORT) == null)
+                        return "ERROR: UDP is disabled and the inbound TCP host/port combination is not set";
+                    else
+                        return "WARNING: You are behind a firewall and have UDP Disabled";
+                }
+                return "Testing";
+        }
+    }
+    
+    /**
+     * How many peers we are talking to now
+     *
+     */
+    public static int getActivePeers() {
+        RouterContext context = RouterHelper.getContext();
+        if (context == null) 
+            return 0;
+        else
+            return context.commSystem().countActivePeers();
+    }
+    
+    public static void addActivePeerListener(ActionListener listener) {
+        synchronized(activePeerListeners) {
+            activePeerListeners.add(listener);
+            if(activePeerTimer == null) {
+                activePeerTimer = new Timer();
+                TimerTask t = new TimerTask() {
+                    private int activePeers = 0;
+
+                    @Override
+                    public void run() {
+                        int newActivePeers = getActivePeers();
+                        if(!(activePeers == newActivePeers)) {
+                            synchronized(activePeerListeners) {
+                                for(int i=0; i<activePeerListeners.size(); i++) {
+                                    activePeerListeners.get(i).actionPerformed(new ActionEvent(this, 0, ""));
+                                }
+                            }
+                            activePeers = newActivePeers;
+                        }
+                    }
+                };
+                activePeerTimer.schedule(t, 60*1000);
+            }
+        }
+    }
+    
+    public static void removeActivePeerListener(ActionListener listener) {
+        synchronized(activePeerListeners) {
+            activePeerListeners.remove(listener);
+            if(activePeerListeners.size() == 0) {
+                activePeerTimer.cancel();
+                activePeerTimer = null;
+            }
+        }
+    }
+    
+    
+    
+    public static void addReachabilityListener(ActionListener listener) {
+        synchronized(reachabilityListeners) {
+            reachabilityListeners.add(listener);
+            if(reachabilityTimer == null) {
+                reachabilityTimer = new Timer();
+                TimerTask t = new TimerTask() {
+                    
+                    private String reachability = "";
+
+                    @Override
+                    public void run() {
+                        String newReachability = getReachability();
+                        if(!reachability.equals(newReachability)) {
+                            synchronized(reachabilityListeners) {
+                                for(int i=0; i<reachabilityListeners.size(); i++) {
+                                    reachabilityListeners.get(i).actionPerformed(new ActionEvent(this, 0, ""));
+                                }
+                            }
+                            reachability = newReachability;
+                        }
+                    }
+                    
+                };
+                reachabilityTimer.schedule(t, 60*1000);
+            }
+        }
+    }
+    
+    public static void removeReachabilityListener(ActionListener listener) {
+        synchronized(reachabilityListeners) {
+            reachabilityListeners.remove(listener);
+            if(reachabilityListeners.size() == 0) {
+                reachabilityTimer.cancel();
+                reachabilityTimer = null;
+            }
+        }
+    }
+    
+    private static List<ActionListener> reachabilityListeners = new ArrayList<ActionListener>();
+    private static Timer reachabilityTimer = null;
+    
+    private static List<ActionListener> activePeerListeners = new ArrayList<ActionListener>();
+    private static Timer activePeerTimer = null;
+    
+    /** copied from various private components */
+    public final static String PROP_I2NP_UDP_PORT = "i2np.udp.port";
+    public final static String PROP_I2NP_INTERNAL_UDP_PORT = "i2np.udp.internalPort";
+    public final static String PROP_I2NP_NTCP_HOSTNAME = "i2np.ntcp.hostname";
+    public final static String PROP_I2NP_NTCP_PORT = "i2np.ntcp.port";
+    public final static String PROP_I2NP_NTCP_AUTO_PORT = "i2np.ntcp.autoip";
+    public final static String PROP_I2NP_NTCP_AUTO_IP = "i2np.ntcp.autoport";
+}
-- 
GitLab