diff --git a/gui/griffon-app/lifecycle/Ready.groovy b/gui/griffon-app/lifecycle/Ready.groovy index 30c35adc..4de541b7 100644 --- a/gui/griffon-app/lifecycle/Ready.groovy +++ b/gui/griffon-app/lifecycle/Ready.groovy @@ -73,30 +73,14 @@ class Ready extends AbstractLifecycleHandler { JOptionPane.showMessageDialog(parent, "MuWire will now exit") System.exit(0) } - -// props.incompleteLocation = new File(home, "incompletes") -// props.embeddedRouter = Boolean.parseBoolean(System.getProperties().getProperty("embeddedRouter")) -// props.updateType = System.getProperty("updateType","jar") -// props.setNickname(selectNickname()) -// -// -// def portableDownloads = System.getProperty("portable.downloads") -// if (portableDownloads != null) { -// props.downloadLocation = new File(portableDownloads) -// } else { -// def chooser = new JFileChooser() -// chooser.setFileHidingEnabled(false) -// chooser.setDialogTitle("Select a directory where downloads will be saved") -// chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY) -// int rv = chooser.showOpenDialog(null) -// if (rv != JFileChooser.APPROVE_OPTION) { -// JOptionPane.showMessageDialog(null, "MuWire will now exit") -// System.exit(0) -// } -// props.downloadLocation = chooser.getSelectedFile() -// } - + File i2pPropsFile = new File(home, "i2p.properties") + i2pPropsFile.withPrintWriter { i2pProps.store(it, "") } + + props.embeddedRouter = embeddedRouterAvailable + props.updateType = System.getProperty("updateType","jar") + + propsFile.withPrintWriter("UTF-8", { props.write(it) }) diff --git a/gui/griffon-app/models/com/muwire/gui/wizard/WizardModel.groovy b/gui/griffon-app/models/com/muwire/gui/wizard/WizardModel.groovy index 5110ea10..1eb65c42 100644 --- a/gui/griffon-app/models/com/muwire/gui/wizard/WizardModel.groovy +++ b/gui/griffon-app/models/com/muwire/gui/wizard/WizardModel.groovy @@ -16,9 +16,7 @@ class WizardModel { Properties i2pProps def finished - final List steps = [new NicknameStep(), - new DirectoriesStep(), - new LastStep(embeddedRouterAvailable)] + final List steps = [] int currentStep @Observable boolean finishButtonEnabled @@ -26,6 +24,15 @@ class WizardModel { @Observable boolean nextButtonEnabled void mvcGroupInit(Map args) { + + steps << new NicknameStep() + steps << new DirectoriesStep() + if (embeddedRouterAvailable) + steps << new EmbeddedRouterStep() + else + steps << new ExternalRouterStep() + steps << new LastStep(embeddedRouterAvailable) + currentStep = 0 previousButtonEnabled = false nextButtonEnabled = steps.size() > (currentStep + 1) diff --git a/gui/src/main/groovy/com/muwire/gui/wizard/DirectoriesStep.groovy b/gui/src/main/groovy/com/muwire/gui/wizard/DirectoriesStep.groovy index 6c56ec9b..fdbfd66b 100644 --- a/gui/src/main/groovy/com/muwire/gui/wizard/DirectoriesStep.groovy +++ b/gui/src/main/groovy/com/muwire/gui/wizard/DirectoriesStep.groovy @@ -1,5 +1,7 @@ package com.muwire.gui.wizard +import java.awt.GridBagConstraints + import javax.swing.JFileChooser import com.muwire.core.MuWireSettings @@ -22,15 +24,19 @@ class DirectoriesStep extends WizardStep { builder.panel(constraints : getConstraint()) { gridBagLayout() - label(text : "Select directories for saving downloaded and incomplete files. They will be created if they do not already exist", - constraints : gbc(gridx: 0, gridy: 0, gridwidth : 2)) + label(text : "Select directories for saving downloaded and incomplete files.", + constraints : gbc(gridx: 0, gridy: 0, gridwidth : 2, insets: [10,0,0,0])) + label(text : "They will be created if they do not already exist.", + constraints : gbc(gridx:0, gridy: 1, gridwidth: 2, insets: [0,0,10,0])) - label(text : "Directory for saving downloaded files", constraints : gbc(gridx:0, gridy: 1)) - downloadLocationField = textField(text : defaultDownloadLocation.getAbsolutePath(), constraints : gbc(gridx : 0, gridy : 2)) - downloadLocationButton = button(text : "Choose", constraints : gbc(gridx: 1, gridy: 2), actionPerformed : showDownloadChooser) - label(text : "Directory for storing incomplete files", constraints : gbc(gridx:0, gridy: 3)) - incompleteLocationField = textField(text : defaultIncompleteLocation.getAbsolutePath(), constraints : gbc(gridx:0, gridy:4)) - incompleteLocationButton = button(text : "Choose", constraints : gbc(gridx: 1, gridy: 4), actionPerformed : showIncompleteChooser) + label(text : "Directory for saving downloaded files", constraints : gbc(gridx:0, gridy: 2)) + downloadLocationField = textField(text : defaultDownloadLocation.getAbsolutePath(), + constraints : gbc(gridx : 0, gridy : 3, fill : GridBagConstraints.HORIZONTAL, weightx: 100)) + downloadLocationButton = button(text : "Choose", constraints : gbc(gridx: 1, gridy: 3), actionPerformed : showDownloadChooser) + label(text : "Directory for storing incomplete files", constraints : gbc(gridx:0, gridy: 4)) + incompleteLocationField = textField(text : defaultIncompleteLocation.getAbsolutePath(), + constraints : gbc(gridx:0, gridy:5, fill : GridBagConstraints.HORIZONTAL, weightx: 100)) + incompleteLocationButton = button(text : "Choose", constraints : gbc(gridx: 1, gridy: 5), actionPerformed : showIncompleteChooser) } } diff --git a/gui/src/main/groovy/com/muwire/gui/wizard/EmbeddedRouterStep.groovy b/gui/src/main/groovy/com/muwire/gui/wizard/EmbeddedRouterStep.groovy new file mode 100644 index 00000000..a3e4ffef --- /dev/null +++ b/gui/src/main/groovy/com/muwire/gui/wizard/EmbeddedRouterStep.groovy @@ -0,0 +1,82 @@ +package com.muwire.gui.wizard + +import java.awt.GridBagConstraints + +import javax.swing.border.TitledBorder + +import com.muwire.core.MuWireSettings + +class EmbeddedRouterStep extends WizardStep { + + + def udpPortField + def tcpPortField + + def inBwField + def outBwField + + public EmbeddedRouterStep() { + super("router") + } + + @Override + protected void buildUI(FactoryBuilderSupport builder) { + Random r = new Random() + int port = 9151 + r.nextInt(1 + 30777 - 9151) // this range matches what the i2p router would choose + builder.panel(constraints : getConstraint()) { + gridBagLayout() + panel(border : titledBorder(title : "Port Settings", border : etchedBorder(), titlePosition : TitledBorder.TOP, + constraints : gbc(gridx: 0, gridy : 0, fill : GridBagConstraints.HORIZONTAL, weightx: 100))) { + gridBagLayout() + label(text : "TCP port", constraints : gbc(gridx :0, gridy: 0, anchor : GridBagConstraints.LINE_START, weightx : 100)) + tcpPortField = textField(text : String.valueOf(port), columns : 4, constraints : gbc(gridx:1, gridy:0, anchor : GridBagConstraints.LINE_END)) + label(text : "UDP port", constraints : gbc(gridx :0, gridy: 1, anchor : GridBagConstraints.LINE_START, weightx : 100)) + udpPortField = textField(text : String.valueOf(port), columns : 4, constraints : gbc(gridx:1, gridy:1, anchor : GridBagConstraints.LINE_END)) + } + panel( border : titledBorder(title : "Bandwidth Settings", border : etchedBorder(), titlePosition : TitledBorder.TOP), + constraints : gbc(gridx : 0, gridy : 1, fill : GridBagConstraints.HORIZONTAL, weightx : 100)) { + gridBagLayout() + label(text : "Inbound bandwidth (KB)", constraints : gbc(gridx: 0, gridy : 0, anchor : GridBagConstraints.LINE_START, weightx : 100)) + inBwField = textField(text : "512", columns : 3, constraints : gbc(gridx : 1, gridy : 0, anchor : GridBagConstraints.LINE_END)) + label(text : "Outbound bandwidth (KB)", constraints : gbc(gridx: 0, gridy : 1, anchor : GridBagConstraints.LINE_START, weightx : 100)) + outBwField = textField(text : "256", columns : 3, constraints : gbc(gridx : 1, gridy : 1, anchor : GridBagConstraints.LINE_END)) + } + panel (constraints : gbc(gridx: 0, gridy : 2, weighty: 100)) + } + } + + @Override + protected List validate() { + def rv = [] + try { + int udpPort = Integer.parseInt(udpPortField.text) + int tcpPort = Integer.parseInt(tcpPortField.text) + if (udpPort <= 0 || udpPort > 0xFFFF) + rv << "Invalid UDP Port" + if (tcpPort <= 0 || tcpPort > 0xFFFF) + rv << "Invalid TCP Port" + } catch (NumberFormatException e) { + rv << "Invalid port" + } + try { + int outBw = Integer.parseInt(outBwField.text) + int inBw = Integer.parseInt(inBwField.text) + if (outBw <= 0) + rv << "Out bandwidth cannot be negative" + if (inBw <= 0) + rv << "In bandwidth cannot be ngative" + } catch (NumberFormatException e) { + rv << "Invalid bandwidth" + } + + rv + } + + @Override + protected void apply(MuWireSettings muSettings, Properties i2pSettings) { + i2pSettings['i2np.ntcp.port'] = tcpPortField.text + i2pSettings['i2np.udp.port'] = udpPortField.text + muSettings.outBw = Integer.parseInt(outBwField.text) + muSettings.inBw = Integer.parseInt(inBwField.text) + } +} diff --git a/gui/src/main/groovy/com/muwire/gui/wizard/ExternalRouterStep.groovy b/gui/src/main/groovy/com/muwire/gui/wizard/ExternalRouterStep.groovy new file mode 100644 index 00000000..a6232306 --- /dev/null +++ b/gui/src/main/groovy/com/muwire/gui/wizard/ExternalRouterStep.groovy @@ -0,0 +1,59 @@ +package com.muwire.gui.wizard + +import java.awt.GridBagConstraints + +import javax.swing.border.TitledBorder + +import com.muwire.core.MuWireSettings + +class ExternalRouterStep extends WizardStep { + + def addressField + def portField + + public ExternalRouterStep() { + super("router") + } + + @Override + protected void buildUI(FactoryBuilderSupport builder) { + builder.panel(constraints : getConstraint()) { + gridBagLayout() + panel(border : titledBorder(title : "External Router I2CP Settings", border : etchedBorder(), titlePosition : TitledBorder.TOP, + constraints : gbc(gridx: 0, gridy : 0, fill : GridBagConstraints.HORIZONTAL, weightx: 100))) { + gridBagLayout() + + label(text : "Host", constraints : gbc(gridx: 0, gridy : 0, anchor : GridBagConstraints.LINE_START, weightx : 100)) + addressField = textField(text : "127.0.0.1", constraints : gbc(gridx:1, gridy:0, anchor: GridBagConstraints.LINE_END)) + + label(text : "Port", constraints : gbc(gridx: 0, gridy : 1, anchor : GridBagConstraints.LINE_START, weightx : 100)) + portField = textField(text : "7654", constraints : gbc(gridx:1, gridy:1, anchor: GridBagConstraints.LINE_END)) + } + panel(constraints : gbc(gridx:0, gridy:1, weighty: 100)) + } + } + + @Override + protected List validate() { + def rv = [] + try { + InetAddress.getAllByName(addressField.text) + } catch (UnknownHostException iox) { + rv << "Not a valid InetAddress" + } + try { + int port = Integer.parseInt(portField.text) + if (port <= 0 && port > 0xFFFF) + rv << "Not a valid port" + } catch (NumberFormatException e) { + rv << "Not a valid port" + } + rv + } + + @Override + protected void apply(MuWireSettings muSettings, Properties i2pSettings) { + i2pSettings['i2cp.tcp.host'] = addressField.text + i2pSettings['i2cp.tcp.port'] = portField.text + } +} diff --git a/gui/src/main/groovy/com/muwire/gui/wizard/LastStep.groovy b/gui/src/main/groovy/com/muwire/gui/wizard/LastStep.groovy index 11ac1b1c..a706136a 100644 --- a/gui/src/main/groovy/com/muwire/gui/wizard/LastStep.groovy +++ b/gui/src/main/groovy/com/muwire/gui/wizard/LastStep.groovy @@ -14,9 +14,10 @@ class LastStep extends WizardStep { @Override protected void buildUI(FactoryBuilderSupport builder) { builder.panel(constraints: getConstraint()) { - label("The wizard is complete. Press \"Finish\" to launch MuWire.") + gridBagLayout() + label(text: "The wizard is complete. Press \"Finish\" to launch MuWire.", constraints : gbc(gridx: 0, gridy: 0)) if (embeddedRouterAvailable) - label("MuWire will launch an embedded I2P router. This can take a few minutes.") + label(text : "MuWire will launch an embedded I2P router. This can take a few minutes.", constraints: gbc(gridx:0, gridy:1)) } } diff --git a/gui/src/main/groovy/com/muwire/gui/wizard/NicknameStep.groovy b/gui/src/main/groovy/com/muwire/gui/wizard/NicknameStep.groovy index a2ae904a..1bccfbaf 100644 --- a/gui/src/main/groovy/com/muwire/gui/wizard/NicknameStep.groovy +++ b/gui/src/main/groovy/com/muwire/gui/wizard/NicknameStep.groovy @@ -22,13 +22,19 @@ class NicknameStep extends WizardStep { @Override protected List validate() { - if (!DataUtil.isValidName(nickField.text)) + String nickname = nickField.text + if (nickname == null) + return ['Please select a nickname'] + nickname = nickname.trim() + if (nickname.length() == 0) + return ['Nickname cannot be blank'] + if (!DataUtil.isValidName(nickname)) return ["Nickname cannot contain any of ${Constants.INVALID_NICKNAME_CHARS} and must be no longer than ${Constants.MAX_NICKNAME_LENGTH} characters. Choose another."] null } @Override protected void apply(MuWireSettings muSettings, Properties i2pSettings) { - muSettings.nickname = nickField.text + muSettings.nickname = nickField.text.trim() } }