From 0be061fddf6776f2e8f654cc1e75e94f207a07c1 Mon Sep 17 00:00:00 2001 From: romanman Date: Thu, 29 May 2014 12:05:18 +0300 Subject: [PATCH] Redesign SerpentEditors controls 1. Introduced side vertical toolbar 2. 5 tool actions included (Open/Save file, Compile/Deploy/Call contract) 3. Convenient shortcuts ctrl + o, ctrl +s, ctrl + F9, ctrl + shift + F9, ctrl + F8 --- .../ethereum/gui/ContractSubmitDialog.java | 13 +- .../java/org/ethereum/gui/SerpentEditor.java | 260 ++++++++++++++---- .../src/main/resources/buttons/call.png | Bin 0 -> 1578 bytes .../src/main/resources/buttons/compile.png | Bin 0 -> 2440 bytes .../src/main/resources/buttons/deploy.png | Bin 0 -> 1596 bytes .../src/main/resources/buttons/open-file.png | Bin 0 -> 1314 bytes .../src/main/resources/buttons/save-file.png | Bin 0 -> 1257 bytes 7 files changed, 216 insertions(+), 57 deletions(-) create mode 100644 ethereumj-core/src/main/resources/buttons/call.png create mode 100644 ethereumj-core/src/main/resources/buttons/compile.png create mode 100644 ethereumj-core/src/main/resources/buttons/deploy.png create mode 100644 ethereumj-core/src/main/resources/buttons/open-file.png create mode 100644 ethereumj-core/src/main/resources/buttons/save-file.png diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java b/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java index c634e104..5bf2c4a9 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java @@ -234,12 +234,6 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{ public void submitContract(){ - ClientPeer peer = MainData.instance.getActivePeer(); - if (peer == null) { - dialog.alertStatusMsg("Not connected to any peer"); - return; - } - AddressState addressState = ((AddressStateWraper)creatorAddressCombo.getSelectedItem()).getAddressState(); byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes(); @@ -265,6 +259,13 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{ contractAddrInput.setText(Hex.toHexString(tx.getContractAddress())); + + ClientPeer peer = MainData.instance.getActivePeer(); + if (peer == null) { + dialog.alertStatusMsg("Not connected to any peer"); + return; + } + // SwingWorker DialogWorker worker = new DialogWorker(tx, this); worker.execute(); diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/SerpentEditor.java b/ethereumj-core/src/main/java/org/ethereum/gui/SerpentEditor.java index 86051eae..098b0789 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/SerpentEditor.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/SerpentEditor.java @@ -8,6 +8,8 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -66,10 +68,11 @@ public class SerpentEditor extends JFrame { private static final long serialVersionUID = 1L; final JSplitPane splitPanel; final JTextArea result; + final JPanel contentPane; public SerpentEditor() { - final JPanel cp = new JPanel(new BorderLayout()); + contentPane = new JPanel(new BorderLayout()); final JFrame mainWindow = this; java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png"); @@ -86,12 +89,13 @@ public class SerpentEditor extends JFrame { codeArea.setCodeFoldingEnabled(true); codeArea.setAntiAliasingEnabled(true); codeArea.setText(codeSample3); + changeStyleProgrammatically(); RTextScrollPane sp = new RTextScrollPane(codeArea); sp.setFoldIndicatorEnabled(true); - cp.setLayout(new BorderLayout()); + contentPane.setLayout(new BorderLayout()); splitPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT); splitPanel.setOneTouchExpandable(true); @@ -99,7 +103,7 @@ public class SerpentEditor extends JFrame { splitPanel.setContinuousLayout(true); - cp.add(splitPanel, BorderLayout.CENTER); + contentPane.add(splitPanel, BorderLayout.CENTER); splitPanel.add(sp); result = new JTextArea(); @@ -113,59 +117,19 @@ public class SerpentEditor extends JFrame { FlowLayout fl = new FlowLayout(FlowLayout.CENTER, 10, 5); // fl.setAlignment(FlowLayout.RIGHT); controlsPanel.setLayout(fl); + controlsPanel.setMaximumSize(new Dimension(10000, 20)); + controlsPanel.setPreferredSize(new Dimension(600, 20)); + controlsPanel.setMinimumSize(new Dimension(1, 20)); - JButton buildButton = new JButton("Build"); - JButton sendButton = new JButton("Send"); - JButton callButton = new JButton("Call"); + contentPane.add(controlsPanel, BorderLayout.SOUTH); - callButton.addActionListener(new ActionListener() { + createToolBar(); - public void actionPerformed(ActionEvent e) { - ContractCallDialog payOutDialog = - new ContractCallDialog((Frame)SwingUtilities.getAncestorOfClass(JFrame.class, - cp)); - - } - }); - - - sendButton.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent e) { - - byte[] machineCode = prepareCodeForSend(); - if (machineCode == null) return; - - ContractSubmitDialog payOutDialog = - new ContractSubmitDialog((Frame)SwingUtilities.getAncestorOfClass(JFrame.class, - cp), machineCode); - } - }); - - - buildButton.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent e) { - - compileCode(); - }}); - - - controlsPanel.add(callButton, FlowLayout.LEFT); - - - - controlsPanel.add(sendButton); - controlsPanel.add(buildButton); - - cp.add(controlsPanel, BorderLayout.SOUTH); - - - setContentPane(cp); + setContentPane(contentPane); setTitle("Serpent Editor"); -// setDefaultCloseOperation(EXIT_ON_CLOSE); + + pack(); -// setLocationRelativeTo(null); } @@ -273,6 +237,200 @@ public class SerpentEditor extends JFrame { } + public void createToolBar(){ + + + JToolBar toolbar = new JToolBar(SwingConstants.VERTICAL); + toolbar.putClientProperty("JToolBar.isRollover", Boolean.TRUE); + toolbar.setFloatable(false); + final JPanel mainContentPane = SerpentEditor.this.contentPane; + + + + { + + java.net.URL url = ClassLoader.getSystemResource("buttons/open-file.png"); + Toolkit kit = Toolkit.getDefaultToolkit(); + Image img = kit.createImage(url); + ImageIcon imageIcon = new ImageIcon(img); + final JButton button = new JButton(imageIcon); + button.setToolTipText("Open File < Ctrl + O >"); + + Action openFile = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + button.doClick(); + } + }; + + mainContentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW). + put(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK), + "OpenFileButton"); + + mainContentPane.getActionMap().put("OpenFileButton",openFile); + + button.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.out.println("open file"); + } + } + ); + + toolbar.add(button); + } + + { + java.net.URL url = ClassLoader.getSystemResource("buttons/save-file.png"); + Toolkit kit = Toolkit.getDefaultToolkit(); + Image img = kit.createImage(url); + ImageIcon imageIcon = new ImageIcon(img); + final JButton button = new JButton(imageIcon); + button.setToolTipText("Save File < Ctrl + S >"); + + Action saveFile = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + button.doClick(); + } + }; + + mainContentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW). + put(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), + "OpenSaveButton"); + + mainContentPane.getActionMap().put("OpenSaveButton",saveFile); + + button.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.out.println("save file"); + } + } + ); + + toolbar.add(button); + } + + + toolbar.addSeparator(); + + { + + java.net.URL url = ClassLoader.getSystemResource("buttons/compile.png"); + Toolkit kit = Toolkit.getDefaultToolkit(); + Image img = kit.createImage(url); + ImageIcon imageIcon = new ImageIcon(img); + final JButton button = new JButton(imageIcon); + button.setToolTipText("Compile the contract < Ctrl + F9 >"); + + Action compile = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + button.doClick(); + } + }; + + mainContentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW). + put(KeyStroke.getKeyStroke(KeyEvent.VK_F9, InputEvent.CTRL_DOWN_MASK), + "CompileButton"); + + mainContentPane.getActionMap().put("CompileButton",compile); + + + button.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + compileCode(); + } + } + ); + toolbar.add(button); + } + + { + + java.net.URL url = ClassLoader.getSystemResource("buttons/deploy.png"); + Toolkit kit = Toolkit.getDefaultToolkit(); + Image img = kit.createImage(url); + ImageIcon imageIcon = new ImageIcon(img); + final JButton button = new JButton(imageIcon); + button.setToolTipText("Deploy contract to the chain < Ctrl + Shift + F9 >"); + + Action deploy = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + button.doClick(); + } + }; + + mainContentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW). + put(KeyStroke.getKeyStroke(KeyEvent.VK_F9, + InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK), + "DeployButton"); + + mainContentPane.getActionMap().put("DeployButton",deploy); + + + button.addActionListener(new ActionListener() { + + public void actionPerformed(ActionEvent e) { + + byte[] machineCode = prepareCodeForSend(); + if (machineCode == null) return; + + ContractSubmitDialog payOutDialog = + new ContractSubmitDialog((Frame) SwingUtilities.getAncestorOfClass(JFrame.class, + contentPane), machineCode); + } + }); + toolbar.add(button); + } + + { + + java.net.URL url = ClassLoader.getSystemResource("buttons/call.png"); + Toolkit kit = Toolkit.getDefaultToolkit(); + Image img = kit.createImage(url); + ImageIcon imageIcon = new ImageIcon(img); + final JButton button = new JButton(imageIcon); + button.setToolTipText("Call contract "); + + Action call = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + button.doClick(); + } + }; + + mainContentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW). + put(KeyStroke.getKeyStroke(KeyEvent.VK_F8, + InputEvent.CTRL_DOWN_MASK), + "CallButton"); + + mainContentPane.getActionMap().put("CallButton", call); + + + button.addActionListener(new ActionListener() { + + public void actionPerformed(ActionEvent e) { + ContractCallDialog payOutDialog = + new ContractCallDialog((Frame)SwingUtilities.getAncestorOfClass(JFrame.class, + contentPane)); + + } + }); + + toolbar.add(button); + } + + + this.contentPane.add(toolbar, BorderLayout.EAST); + } + public static void main(String[] args) { // Start all Swing applications on the EDT. SwingUtilities.invokeLater(new Runnable() { diff --git a/ethereumj-core/src/main/resources/buttons/call.png b/ethereumj-core/src/main/resources/buttons/call.png new file mode 100644 index 0000000000000000000000000000000000000000..769cd9bf1de4a6818699e250f88c1cecc0b9d3ad GIT binary patch literal 1578 zcmV+_2G#kAP)5B>e00R$SBWm~{{Rh2%Lm5|3WP1!Wf?S^Sqjhb;( z{MP^i7e90XR=KXLTO}6EHw+!57?x?lv|k{cq9C zH22cl+85tG+49f;lwj!`xYe32f5Mb-x)E`;8K*4PdQuo&ivhIfv=OGgDhkc^N%PJq zeF7k>=NX3fIa5MU=!Vwq>NpFNtT!DXdH`v&k)T$UEIj*juK=A56&(FJMT)1|aqdxU z#t5`xEOxT~{(y9ylq9x%cEyFuNdUfv3b$z}OlAQ-*^(ZGP9TYZu{qKM7+nhl1Wgp= zoYIYr;dl>RsBr7L!bI86_m*gxL#H5p@C#rtDZscbSp3`&ns&X}92ZalIBQL6D)y zs<&*D1AwAXkqx%@Bw>OJ^PgFap~dea&~^p4t{uV6>vb@Yfyr-f!;pfp2zK7a(VDr) z$=0KuNK9gyQ~aSa%^83(k@@}Yyps!U0mBHOV03AB4s_gU!1-S*p)d*4=6(-vUJ)+U zAI7;OYfvzJAjlC($C2C*P0^hJWLaRHoo#&55$h7d6bm7ig`9$^7&m1J24r{<=xD@= z+A_+Ae9S7X1;@Fud+SVatPy#6nQ*&Zao%LI3Qg0zi#Od!1X${p$Ui<`E8km1GYku| zqC=8(7_J<=I&T-Uy@j~?=Rq`_{0tLkZ^p)&pBL-&j$jI;@)sxa)j1;Cp z*L3gV%}xNKz}nhdyF-vz2l%vH6i-|WCI#^Ov5m+WG!iox?xlMS?Ata2!wZWrV}1?% z9k=oIh6xzzO(hQiDJeWWX(@KOfU0URbi)}y6vFIoTZ?lYpt&9Yk>fsy+<)-fawz^k z@YBO$8Imq^eF@4Skj4fG$vvuF#>e(-`aMc;4XAQy5b<@CWH!#5C zjsV;nF8hdDmbcsqARG#@mX_wOB#b!;_v(OVpv}k7bkk3j5AbG@aF-ha!GcPA`FUyN zavm*h5~aV6!P#zjQeANXT~lxQmSg}|C>WCO+_{z7qc{P=u#1sNaWoJPiIhzAx~915 zh8-e+cXRMi!dWC%Q8c(YE8_Y-0odc(@pqmJ20M2$ro5bJz2)#WlqCfs6&5R@19TGz zPl-p_9_XA zAmv-=D124Exk*dv2a+K6zcN76^p&zKSL(Wvk<@&|996qzv(GoRUQVJ6Qd~n1tS776 z6E`2&6`$ENrGP-HB}tx73S99J@zs(*;~+TBI!(VTDB~M?li%m>f)h29CNZY&lx6l( zY=dDY=14R|O=R_Ia`mAH$$h9Vqf>jPaf&RL3SqHI)%0PB?+SvTFC(j(Zrw)8<-W-5 z*SF#E?nHjI4ftoZ90+^|K==BrD1IpD51f`Xl3! c03OHq2OpgqdzNBOEC2ui07*qoM6N<$f-G?E$N&HU literal 0 HcmV?d00001 diff --git a/ethereumj-core/src/main/resources/buttons/compile.png b/ethereumj-core/src/main/resources/buttons/compile.png new file mode 100644 index 0000000000000000000000000000000000000000..180608546c3cf7c876536d1ac2af3203561d7cfd GIT binary patch literal 2440 zcmV;333v91P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qRNAp5A000R0Nkl8HK?M{91r>2&aX~~)FoHxy4QRqd#kdhS6cuz5Vl?Wg z$zh_7U-TQIs=D|7tM23dKN_DJU4H#P;Jwl+k zd&kD@$dZ0_qRap%wo7qhn*@1rqJ~lSd~X_)dN~O_@)v5W!2&JBO;y7nJzgpKd84rzv4HH#jK6cPck+|1vwCi<4r@QO(C?a5B%B-_tUdKw zjRh`O4@Psf0dDQ%;Oi_1(XqG+}7kv%>JMuB|iheCsS!&G&|t4)-W6R(DHdr8$}om{S6}xLWZl z0V7@BHgc(IX~rM^{6}$DPnR~%my3`ZDZEF|rHX)WFr&wH>FqeZ68J0)J*DCJHP;u& z^#gKzfGlswmwBQs!41*F4BLbPp0~5LdRy5XM;y(z#hn_C1we$q0HK~LKQ5UeD8F@p z`v;zhap$x;&d>^#EY^HZ9dazidSeL+YSu*Tz|mBoC>Y&q{Bd;VNYsTp;9`s;9xil6 zce)3DP4hrU>KOTFGo5eT%n9xKCU-KLGA815i4-lg%%w|JQMF19jXOkma*V@wwaRil zRwTx;VjXNt7vHlsRdJ$tze_?;7BzAWii6Oycr4w;7qnVTB;?uUCk*&Az$GQ zYz%D7WF}R&G3Fj7%$MIroe6`mUjTMGy+%3iSbPfxr2{FZ6wda$39n|+H zur^UcZYWi1gy-pE<k}X>Q z>I@mv!nR=G!zp0@ZBKT`@mM#6I_l#>r5P?z0_Q4>QCDIBJ98C9B~T#Okv1wHl`PTh z-H@y)H#Okzr)NqbRu#-#hMR>zQvt9e47C&_`aNX=%iPV7=wys|$3e*RG{?E<5sXSAmqqMECkBDAD2^)-MVyx>*wS1jT`f z9ASiFe=B5D5_9Rd_h4;|FwpF!H`%dj|I>l+pK*H;a5)b6Vm6+w^uf3Bqfj2@+L0CT z-f9~Iu?zi=H5nb^jivS`6I4cz%tzrwL^v2>SD+2ndYL2H#RSuB_26!z)hiOH1kLra z2=8f5km2DHpgBRY67AF%zM;O*k`;vJi~t;%Gp5H#Q!Rsh{^8&XE1hbe%G90aVXjbr z*@U4e@KJ6DyB?Zi_o8!4P&Zl@0&OY4r8vlHXW(&?8*U|y!_CY^XIfxaVgK(}rXdmN4jTecOEq6Q-Ws2V*<*jG9S%>m$9WQ8XNHGT ze2w#fi?sX=G3X@CJfh}wJ=GUCmQTdhvx*ZGVLj(}xiBW_lp-fmiDze z5yp;@3B$jr9Y3UT5~^HFRj`}6BBl{6_>}(p zas4m>PbNZ%(FEI`-?o8k$emt~niO>IS%8KF4@I|owqz{sE*On&w)A;)7!^|Y+Zv26 zS_xMBZ0Qe2Il)3AdP+VLh)5!wUj;t3`|w*SgKehXt?sBGWj)l~%>9u!8&9v4O7 z!Nv%DID0I80dd_lR_ZiZ_u$oKfif2S3aNg@c>71w%o^<<}eM;7>WTS~YNk$_)G&nFT?i6~7q0Xt4}2)6Wogf{WcjA_E0 z@FkeIW)n83E}0JucJ(ANrJ0yOk7ShCwf#ya>)rkK|TV1@_XE7oN8swg5i=Fmr`vsU{n2QULl z=+H)P2F;zF@V|Q>EOl|N`T^a-!r8Mffq~j~?!o?724FgPyD6lC8D~WL9I%H>( zl$y)ti`?p$O_RIu_bUT1$)Hmye};B2xwiCc<_}e>L&7ChHwrSd!9kmZCHW34j^_4w z3-8E!rq}=`gJ=*Z%a2)7NW#=q={6fQC?QQg?Q@55vze*=>hrlXYqY7y9~R&dm^q`a<0yPcKnMI>f3;+_ylS z$aYbwTLudc!(c6EJr{sP#A)VxZ0NO>4u+fErp$7DoT6F{WlAfvI^vufuf_&&b$U7o z>o$zllF_w;INfR{l^!gl+*D0FL1U%WaLza8+JD3pQ z+x+oH(3B3Xn#k?`YZ#saVFh132S5*ZhRu&;Y6;(hh2vwP)=FL8`O&8cNR+5oPc-w) z5%*ox=%dy7oo!-gcYax%pGIa-DC4f$-W=rcf?<5B+bb}TV;?P1*IUOu$+)U)%&(0y`oK52pL!aBDBXagZTZ4Vl5S`7ivvs(qn zu)NB-+&^i-#bR$|YiQQqEB}_L*+bgURUb=obJd`WdT?yOW?F&T93n{GwJAvPN?JhVk!( zc`<38o-2Opq_Op(sTA2)x)P&y#{~3&_CM99a4fVl>x_3_vVv zq#E?z4YSFAGHW<$-ggJD-@0?YW3b}25-eXIVx;*qrV|+!%P^&IXOVi~q2I0dpP2t7 zhewv-$KYiQ_pnNpSdbJW%~-*WIh$A+WkL51r+Dn8QxpJCj4`TkUR6c~jb^w{ZE;`! zPwm@7eE1>u9nE2_p8WeMgy<9sfE2fN9fL91X3RI;NQjIg>P$LEu1PDjtY@!{jl~|% u1fVikH`(O3IP)zxMpPbCSGiT2K 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 TAB#;b00000NkvXXu0mjfdFo0X literal 0 HcmV?d00001