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