Compare commits
19 Commits
muwire-0.1
...
muwire-0.1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
34d9165bd5 | ||
![]() |
2e52dd5c49 | ||
![]() |
2a315dd734 | ||
![]() |
6b661b99c5 | ||
![]() |
5dacd60bbb | ||
![]() |
f8f7cfe836 | ||
![]() |
0b4f261bc1 | ||
![]() |
042d67d784 | ||
![]() |
800df88f14 | ||
![]() |
4d1eac50a0 | ||
![]() |
c48df7f14b | ||
![]() |
9d04148001 | ||
![]() |
bb4d522572 | ||
![]() |
8052501e52 | ||
![]() |
66cc6d8ab7 | ||
![]() |
a45e57f5ec | ||
![]() |
7d8ca55d87 | ||
![]() |
de22f3c6b9 | ||
![]() |
3b0eb5678d |
@@ -31,4 +31,4 @@ The first time you run MuWire it will ask you to select a nickname. This nickna
|
|||||||
### Known bugs and limitations
|
### Known bugs and limitations
|
||||||
|
|
||||||
* Many UI features you would expect are not there yet
|
* Many UI features you would expect are not there yet
|
||||||
|
* Sorting the results table sometimes causes the wrong result to be downloaded
|
||||||
|
@@ -34,7 +34,7 @@ class Cli {
|
|||||||
|
|
||||||
Core core
|
Core core
|
||||||
try {
|
try {
|
||||||
core = new Core(props, home, "0.1.6")
|
core = new Core(props, home, "0.1.10")
|
||||||
} catch (Exception bad) {
|
} catch (Exception bad) {
|
||||||
bad.printStackTrace(System.out)
|
bad.printStackTrace(System.out)
|
||||||
println "Failed to initialize core, exiting"
|
println "Failed to initialize core, exiting"
|
||||||
|
@@ -53,7 +53,7 @@ class CliDownloader {
|
|||||||
|
|
||||||
Core core
|
Core core
|
||||||
try {
|
try {
|
||||||
core = new Core(props, home, "0.1.6")
|
core = new Core(props, home, "0.1.10")
|
||||||
} catch (Exception bad) {
|
} catch (Exception bad) {
|
||||||
bad.printStackTrace(System.out)
|
bad.printStackTrace(System.out)
|
||||||
println "Failed to initialize core, exiting"
|
println "Failed to initialize core, exiting"
|
||||||
|
@@ -92,9 +92,9 @@ public class Core {
|
|||||||
if (i2pOptionsFile.exists()) {
|
if (i2pOptionsFile.exists()) {
|
||||||
i2pOptionsFile.withInputStream { i2pOptions.load(it) }
|
i2pOptionsFile.withInputStream { i2pOptions.load(it) }
|
||||||
|
|
||||||
if (!i2pOptions.hasProperty("inbound.nickname"))
|
if (!i2pOptions.containsKey("inbound.nickname"))
|
||||||
i2pOptions["inbound.nickname"] = "MuWire"
|
i2pOptions["inbound.nickname"] = "MuWire"
|
||||||
if (!i2pOptions.hasProperty("outbound.nickname"))
|
if (!i2pOptions.containsKey("outbound.nickname"))
|
||||||
i2pOptions["outbound.nickname"] = "MuWire"
|
i2pOptions["outbound.nickname"] = "MuWire"
|
||||||
} else {
|
} else {
|
||||||
i2pOptions["inbound.nickname"] = "MuWire"
|
i2pOptions["inbound.nickname"] = "MuWire"
|
||||||
@@ -160,7 +160,7 @@ public class Core {
|
|||||||
eventBus.register(SearchEvent.class, fileManager)
|
eventBus.register(SearchEvent.class, fileManager)
|
||||||
|
|
||||||
log.info "initializing persistence service"
|
log.info "initializing persistence service"
|
||||||
persisterService = new PersisterService(new File(home, "files.json"), eventBus, 5000, fileManager)
|
persisterService = new PersisterService(new File(home, "files.json"), eventBus, 15000, fileManager)
|
||||||
|
|
||||||
log.info("initializing host cache")
|
log.info("initializing host cache")
|
||||||
File hostStorage = new File(home, "hosts.json")
|
File hostStorage = new File(home, "hosts.json")
|
||||||
@@ -260,7 +260,7 @@ public class Core {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Core core = new Core(props, home, "0.1.6")
|
Core core = new Core(props, home, "0.1.10")
|
||||||
core.startServices()
|
core.startServices()
|
||||||
|
|
||||||
// ... at the end, sleep or execute script
|
// ... at the end, sleep or execute script
|
||||||
|
@@ -99,6 +99,7 @@ public class DownloadManager {
|
|||||||
}
|
}
|
||||||
def downloader = new Downloader(eventBus, this, me, file, (long)json.length,
|
def downloader = new Downloader(eventBus, this, me, file, (long)json.length,
|
||||||
infoHash, json.pieceSizePow2, connector, destinations, incompletes)
|
infoHash, json.pieceSizePow2, connector, destinations, incompletes)
|
||||||
|
downloaders.add(downloader)
|
||||||
downloader.download()
|
downloader.download()
|
||||||
eventBus.publish(new DownloadStartedEvent(downloader : downloader))
|
eventBus.publish(new DownloadStartedEvent(downloader : downloader))
|
||||||
}
|
}
|
||||||
|
@@ -239,9 +239,12 @@ public class Downloader {
|
|||||||
if (downloaded.isComplete() && !eventFired) {
|
if (downloaded.isComplete() && !eventFired) {
|
||||||
piecesFile.delete()
|
piecesFile.delete()
|
||||||
eventFired = true
|
eventFired = true
|
||||||
eventBus.publish(new FileDownloadedEvent(downloadedFile : new DownloadedFile(file, getInfoHash(), pieceSizePow2, Collections.emptySet())),
|
eventBus.publish(
|
||||||
downloader : Downloader.this)
|
new FileDownloadedEvent(
|
||||||
}
|
downloadedFile : new DownloadedFile(file, getInfoHash(), pieceSizePow2, Collections.emptySet()),
|
||||||
|
downloader : Downloader.this))
|
||||||
|
|
||||||
|
}
|
||||||
endpoint?.close()
|
endpoint?.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,12 +20,12 @@ class FileHasher {
|
|||||||
* @return the size of each piece in power of 2
|
* @return the size of each piece in power of 2
|
||||||
*/
|
*/
|
||||||
static int getPieceSize(long size) {
|
static int getPieceSize(long size) {
|
||||||
if (size <= 0x1 << 27)
|
if (size <= 0x1 << 30)
|
||||||
return 17
|
return 17
|
||||||
|
|
||||||
for (int i = 28; i <= 37; i++) {
|
for (int i = 31; i <= 37; i++) {
|
||||||
if (size <= 0x1L << i) {
|
if (size <= 0x1L << i) {
|
||||||
return i-10
|
return i-13
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -181,6 +181,8 @@ Search results are sent through and HTTP POST method from the responder to the o
|
|||||||
* The "altlocs" list contains list of alternate personas that the responder thinks may also have the file.
|
* The "altlocs" list contains list of alternate personas that the responder thinks may also have the file.
|
||||||
* The "pieceSize" field is the size of the each individual file piece (except possibly the last) in powers of 2
|
* The "pieceSize" field is the size of the each individual file piece (except possibly the last) in powers of 2
|
||||||
|
|
||||||
|
Results version 1 contain the full hashlist, version 2 does not contain that list. See the "infohash-upgrade" document for more information.
|
||||||
|
|
||||||
### "Who do you trust" query - any node to any node
|
### "Who do you trust" query - any node to any node
|
||||||
(See the "web-of-trust" document for more info on this query)
|
(See the "web-of-trust" document for more info on this query)
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
group = com.muwire
|
group = com.muwire
|
||||||
version = 0.1.6
|
version = 0.1.10
|
||||||
groovyVersion = 2.4.15
|
groovyVersion = 2.4.15
|
||||||
slf4jVersion = 1.7.25
|
slf4jVersion = 1.7.25
|
||||||
spockVersion = 1.1-groovy-2.4
|
spockVersion = 1.1-groovy-2.4
|
||||||
|
@@ -66,6 +66,38 @@ class OptionsController {
|
|||||||
settings.write(it)
|
settings.write(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UI Setttings
|
||||||
|
|
||||||
|
UISettings uiSettings = application.context.get("ui-settings")
|
||||||
|
text = view.lnfField.text
|
||||||
|
model.lnf = text
|
||||||
|
uiSettings.lnf = text
|
||||||
|
|
||||||
|
text = view.fontField.text
|
||||||
|
model.font = text
|
||||||
|
uiSettings.font = text
|
||||||
|
|
||||||
|
boolean showMonitor = view.monitorCheckbox.model.isSelected()
|
||||||
|
model.showMonitor = showMonitor
|
||||||
|
uiSettings.showMonitor = showMonitor
|
||||||
|
|
||||||
|
boolean clearCancelledDownloads = view.clearCancelledDownloadsCheckbox.model.isSelected()
|
||||||
|
model.clearCancelledDownloads = clearCancelledDownloads
|
||||||
|
uiSettings.clearCancelledDownloads = clearCancelledDownloads
|
||||||
|
|
||||||
|
boolean clearFinishedDownloads = view.clearFinishedDownloadsCheckbox.model.isSelected()
|
||||||
|
model.clearFinishedDownloads = clearFinishedDownloads
|
||||||
|
uiSettings.clearFinishedDownloads = clearFinishedDownloads
|
||||||
|
|
||||||
|
boolean excludeLocalResult = view.excludeLocalResultCheckbox.model.isSelected()
|
||||||
|
model.excludeLocalResult = excludeLocalResult
|
||||||
|
uiSettings.excludeLocalResult = excludeLocalResult
|
||||||
|
|
||||||
|
File uiSettingsFile = new File(core.home, "gui.properties")
|
||||||
|
uiSettingsFile.withOutputStream {
|
||||||
|
uiSettings.write(it)
|
||||||
|
}
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -69,8 +69,13 @@ class Initialize extends AbstractLifecycleHandler {
|
|||||||
uiSettings = new UISettings(props)
|
uiSettings = new UISettings(props)
|
||||||
log.info "will try default lnfs"
|
log.info "will try default lnfs"
|
||||||
if (isMacOSX()) {
|
if (isMacOSX()) {
|
||||||
uiSettings.lnf = "nimbus"
|
if (SystemVersion.isJava9()) {
|
||||||
lookAndFeel('nimbus') // otherwise the file chooser doesn't open???
|
uiSettings.lnf = "metal"
|
||||||
|
lookAndFeel("metal")
|
||||||
|
} else {
|
||||||
|
uiSettings.lnf = "nimbus"
|
||||||
|
lookAndFeel('nimbus') // otherwise the file chooser doesn't open???
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LookAndFeel chosen = lookAndFeel('system', 'gtk')
|
LookAndFeel chosen = lookAndFeel('system', 'gtk')
|
||||||
uiSettings.lnf = chosen.name
|
uiSettings.lnf = chosen.name
|
||||||
|
@@ -79,11 +79,28 @@ class MainFrameModel {
|
|||||||
|
|
||||||
void mvcGroupInit(Map<String, Object> args) {
|
void mvcGroupInit(Map<String, Object> args) {
|
||||||
|
|
||||||
|
UISettings uiSettings = application.context.get("ui-settings")
|
||||||
|
|
||||||
Timer timer = new Timer("download-pumper", true)
|
Timer timer = new Timer("download-pumper", true)
|
||||||
timer.schedule({
|
timer.schedule({
|
||||||
runInsideUIAsync {
|
runInsideUIAsync {
|
||||||
if (!mvcGroup.alive)
|
if (!mvcGroup.alive)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// remove cancelled or finished downloads
|
||||||
|
def toRemove = []
|
||||||
|
downloads.each {
|
||||||
|
if (uiSettings.clearCancelledDownloads &&
|
||||||
|
it.downloader.getCurrentState() == Downloader.DownloadState.CANCELLED)
|
||||||
|
toRemove << it
|
||||||
|
if (uiSettings.clearFinishedDownloads &&
|
||||||
|
it.downloader.getCurrentState() == Downloader.DownloadState.FINISHED)
|
||||||
|
toRemove << it
|
||||||
|
}
|
||||||
|
toRemove.each {
|
||||||
|
downloads.remove(it)
|
||||||
|
}
|
||||||
|
|
||||||
builder.getVariable("uploads-table")?.model.fireTableDataChanged()
|
builder.getVariable("uploads-table")?.model.fireTableDataChanged()
|
||||||
|
|
||||||
updateTablePreservingSelection("downloads-table")
|
updateTablePreservingSelection("downloads-table")
|
||||||
|
@@ -20,6 +20,14 @@ class OptionsModel {
|
|||||||
@Observable String outboundLength
|
@Observable String outboundLength
|
||||||
@Observable String outboundQuantity
|
@Observable String outboundQuantity
|
||||||
|
|
||||||
|
// gui options
|
||||||
|
@Observable boolean showMonitor
|
||||||
|
@Observable String lnf
|
||||||
|
@Observable String font
|
||||||
|
@Observable boolean clearCancelledDownloads
|
||||||
|
@Observable boolean clearFinishedDownloads
|
||||||
|
@Observable boolean excludeLocalResult
|
||||||
|
|
||||||
void mvcGroupInit(Map<String, String> args) {
|
void mvcGroupInit(Map<String, String> args) {
|
||||||
MuWireSettings settings = application.context.get("muwire-settings")
|
MuWireSettings settings = application.context.get("muwire-settings")
|
||||||
downloadRetryInterval = settings.downloadRetryInterval
|
downloadRetryInterval = settings.downloadRetryInterval
|
||||||
@@ -32,5 +40,13 @@ class OptionsModel {
|
|||||||
inboundQuantity = core.i2pOptions["inbound.quantity"]
|
inboundQuantity = core.i2pOptions["inbound.quantity"]
|
||||||
outboundLength = core.i2pOptions["outbound.length"]
|
outboundLength = core.i2pOptions["outbound.length"]
|
||||||
outboundQuantity = core.i2pOptions["outbound.quantity"]
|
outboundQuantity = core.i2pOptions["outbound.quantity"]
|
||||||
|
|
||||||
|
UISettings uiSettings = application.context.get("ui-settings")
|
||||||
|
showMonitor = uiSettings.showMonitor
|
||||||
|
lnf = uiSettings.lnf
|
||||||
|
font = uiSettings.font
|
||||||
|
clearCancelledDownloads = uiSettings.clearCancelledDownloads
|
||||||
|
clearFinishedDownloads = uiSettings.clearFinishedDownloads
|
||||||
|
excludeLocalResult = uiSettings.excludeLocalResult
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -19,6 +19,7 @@ class SearchTabModel {
|
|||||||
FactoryBuilderSupport builder
|
FactoryBuilderSupport builder
|
||||||
|
|
||||||
Core core
|
Core core
|
||||||
|
UISettings uiSettings
|
||||||
String uuid
|
String uuid
|
||||||
def results = []
|
def results = []
|
||||||
def hashBucket = [:]
|
def hashBucket = [:]
|
||||||
@@ -26,6 +27,7 @@ class SearchTabModel {
|
|||||||
|
|
||||||
void mvcGroupInit(Map<String, String> args) {
|
void mvcGroupInit(Map<String, String> args) {
|
||||||
core = mvcGroup.parentGroup.model.core
|
core = mvcGroup.parentGroup.model.core
|
||||||
|
uiSettings = application.context.get("ui-settings")
|
||||||
mvcGroup.parentGroup.model.results[UUID.fromString(uuid)] = mvcGroup
|
mvcGroup.parentGroup.model.results[UUID.fromString(uuid)] = mvcGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +36,9 @@ class SearchTabModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handleResult(UIResultEvent e) {
|
void handleResult(UIResultEvent e) {
|
||||||
|
if (uiSettings.excludeLocalResult &&
|
||||||
|
e.sender == core.me)
|
||||||
|
return
|
||||||
runInsideUIAsync {
|
runInsideUIAsync {
|
||||||
def bucket = hashBucket.get(e.infohash)
|
def bucket = hashBucket.get(e.infohash)
|
||||||
if (bucket == null) {
|
if (bucket == null) {
|
||||||
|
@@ -41,6 +41,7 @@ class MainFrameView {
|
|||||||
def lastDownloadSortEvent
|
def lastDownloadSortEvent
|
||||||
|
|
||||||
void initUI() {
|
void initUI() {
|
||||||
|
UISettings settings = application.context.get("ui-settings")
|
||||||
builder.with {
|
builder.with {
|
||||||
application(size : [1024,768], id: 'main-frame',
|
application(size : [1024,768], id: 'main-frame',
|
||||||
locationRelativeTo : null,
|
locationRelativeTo : null,
|
||||||
@@ -63,7 +64,8 @@ class MainFrameView {
|
|||||||
gridLayout(rows:1, cols: 2)
|
gridLayout(rows:1, cols: 2)
|
||||||
button(text: "Searches", actionPerformed : showSearchWindow)
|
button(text: "Searches", actionPerformed : showSearchWindow)
|
||||||
button(text: "Uploads", actionPerformed : showUploadsWindow)
|
button(text: "Uploads", actionPerformed : showUploadsWindow)
|
||||||
button(text: "Monitor", actionPerformed : showMonitorWindow)
|
if (settings.showMonitor)
|
||||||
|
button(text: "Monitor", actionPerformed : showMonitorWindow)
|
||||||
button(text: "Trust", actionPerformed : showTrustWindow)
|
button(text: "Trust", actionPerformed : showTrustWindow)
|
||||||
}
|
}
|
||||||
panel(id: "top-panel", constraints: BorderLayout.CENTER) {
|
panel(id: "top-panel", constraints: BorderLayout.CENTER) {
|
||||||
@@ -142,8 +144,7 @@ class MainFrameView {
|
|||||||
table(id : "shared-files-table", autoCreateRowSorter: true) {
|
table(id : "shared-files-table", autoCreateRowSorter: true) {
|
||||||
tableModel(list : model.shared) {
|
tableModel(list : model.shared) {
|
||||||
closureColumn(header : "Name", preferredWidth : 550, type : String, read : {row -> row.file.getAbsolutePath()})
|
closureColumn(header : "Name", preferredWidth : 550, type : String, read : {row -> row.file.getAbsolutePath()})
|
||||||
closureColumn(header : "Size", preferredWidth : 50, type : String,
|
closureColumn(header : "Size", preferredWidth : 50, type : Long, read : {row -> row.file.length() })
|
||||||
read : {row -> DataHelper.formatSize2Decimal(row.file.length(),false) + "B"})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,7 +265,9 @@ class MainFrameView {
|
|||||||
selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
|
selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
|
||||||
selectionModel.addListSelectionListener({
|
selectionModel.addListSelectionListener({
|
||||||
int selectedRow = selectedDownloaderRow()
|
int selectedRow = selectedDownloaderRow()
|
||||||
def downloader = model.downloads[selectedRow].downloader
|
def downloader = model.downloads[selectedRow]?.downloader
|
||||||
|
if (downloader == null)
|
||||||
|
return
|
||||||
switch(downloader.getCurrentState()) {
|
switch(downloader.getCurrentState()) {
|
||||||
case Downloader.DownloadState.CONNECTING :
|
case Downloader.DownloadState.CONNECTING :
|
||||||
case Downloader.DownloadState.DOWNLOADING :
|
case Downloader.DownloadState.DOWNLOADING :
|
||||||
@@ -286,6 +289,10 @@ class MainFrameView {
|
|||||||
downloadsTable.setDefaultRenderer(Integer.class, centerRenderer)
|
downloadsTable.setDefaultRenderer(Integer.class, centerRenderer)
|
||||||
|
|
||||||
downloadsTable.rowSorter.addRowSorterListener({evt -> lastDownloadSortEvent = evt})
|
downloadsTable.rowSorter.addRowSorterListener({evt -> lastDownloadSortEvent = evt})
|
||||||
|
|
||||||
|
// shared files table
|
||||||
|
def sharedFilesTable = builder.getVariable("shared-files-table")
|
||||||
|
sharedFilesTable.columnModel.getColumn(1).setCellRenderer(new SizeRenderer())
|
||||||
}
|
}
|
||||||
|
|
||||||
int selectedDownloaderRow() {
|
int selectedDownloaderRow() {
|
||||||
|
@@ -25,6 +25,8 @@ class OptionsView {
|
|||||||
def d
|
def d
|
||||||
def p
|
def p
|
||||||
def i
|
def i
|
||||||
|
def u
|
||||||
|
|
||||||
def retryField
|
def retryField
|
||||||
def updateField
|
def updateField
|
||||||
def allowUntrustedCheckbox
|
def allowUntrustedCheckbox
|
||||||
@@ -35,6 +37,13 @@ class OptionsView {
|
|||||||
def outboundLengthField
|
def outboundLengthField
|
||||||
def outboundQuantityField
|
def outboundQuantityField
|
||||||
|
|
||||||
|
def lnfField
|
||||||
|
def monitorCheckbox
|
||||||
|
def fontField
|
||||||
|
def clearCancelledDownloadsCheckbox
|
||||||
|
def clearFinishedDownloadsCheckbox
|
||||||
|
def excludeLocalResultCheckbox
|
||||||
|
|
||||||
def buttonsPanel
|
def buttonsPanel
|
||||||
|
|
||||||
def mainFrame
|
def mainFrame
|
||||||
@@ -72,6 +81,22 @@ class OptionsView {
|
|||||||
label(text : "Outbound Quantity", constraints : gbc(gridx:0, gridy:4))
|
label(text : "Outbound Quantity", constraints : gbc(gridx:0, gridy:4))
|
||||||
outboundQuantityField = textField(text : bind {model.outboundQuantity}, columns : 2, constraints : gbc(gridx:1, gridy:4))
|
outboundQuantityField = textField(text : bind {model.outboundQuantity}, columns : 2, constraints : gbc(gridx:1, gridy:4))
|
||||||
}
|
}
|
||||||
|
u = builder.panel {
|
||||||
|
gridBagLayout()
|
||||||
|
label(text : "Changing these settings requires a restart", constraints : gbc(gridx : 0, gridy : 0, gridwidth: 2))
|
||||||
|
label(text : "Look And Feel", constraints : gbc(gridx: 0, gridy:1))
|
||||||
|
lnfField = textField(text : bind {model.lnf}, columns : 4, constraints : gbc(gridx : 1, gridy : 1))
|
||||||
|
label(text : "Font", constraints : gbc(gridx: 0, gridy : 2))
|
||||||
|
fontField = textField(text : bind {model.font}, columns : 4, constraints : gbc(gridx : 1, gridy:2))
|
||||||
|
label(text : "Show Monitor", constraints : gbc(gridx :0, gridy: 3))
|
||||||
|
monitorCheckbox = checkBox(selected : bind {model.showMonitor}, constraints : gbc(gridx : 1, gridy: 3))
|
||||||
|
label(text : "Clear Cancelled Downloads", constraints: gbc(gridx: 0, gridy:4))
|
||||||
|
clearCancelledDownloadsCheckbox = checkBox(selected : bind {model.clearCancelledDownloads}, constraints : gbc(gridx : 1, gridy:4))
|
||||||
|
label(text : "Clear Finished Downloads", constraints: gbc(gridx: 0, gridy:5))
|
||||||
|
clearFinishedDownloadsCheckbox = checkBox(selected : bind {model.clearFinishedDownloads}, constraints : gbc(gridx : 1, gridy:5))
|
||||||
|
label(text : "Exclude Local Files From Results", constraints: gbc(gridx:0, gridy:6))
|
||||||
|
excludeLocalResultCheckbox = checkBox(selected : bind {model.excludeLocalResult}, constraints : gbc(gridx: 1, gridy : 6))
|
||||||
|
}
|
||||||
buttonsPanel = builder.panel {
|
buttonsPanel = builder.panel {
|
||||||
gridBagLayout()
|
gridBagLayout()
|
||||||
button(text : "Save", constraints : gbc(gridx : 1, gridy: 2), saveAction)
|
button(text : "Save", constraints : gbc(gridx : 1, gridy: 2), saveAction)
|
||||||
@@ -81,8 +106,9 @@ class OptionsView {
|
|||||||
|
|
||||||
void mvcGroupInit(Map<String,String> args) {
|
void mvcGroupInit(Map<String,String> args) {
|
||||||
def tabbedPane = new JTabbedPane()
|
def tabbedPane = new JTabbedPane()
|
||||||
tabbedPane.addTab("MuWire Options", p)
|
tabbedPane.addTab("MuWire", p)
|
||||||
tabbedPane.addTab("I2P Options", i)
|
tabbedPane.addTab("I2P", i)
|
||||||
|
tabbedPane.addTab("GUI", u)
|
||||||
|
|
||||||
JPanel panel = new JPanel()
|
JPanel panel = new JPanel()
|
||||||
panel.setLayout(new BorderLayout())
|
panel.setLayout(new BorderLayout())
|
||||||
|
@@ -6,12 +6,17 @@ import griffon.inject.MVCMember
|
|||||||
import griffon.metadata.ArtifactProviderFor
|
import griffon.metadata.ArtifactProviderFor
|
||||||
import net.i2p.data.DataHelper
|
import net.i2p.data.DataHelper
|
||||||
|
|
||||||
|
import javax.swing.JComponent
|
||||||
import javax.swing.JLabel
|
import javax.swing.JLabel
|
||||||
|
import javax.swing.JTable
|
||||||
import javax.swing.ListSelectionModel
|
import javax.swing.ListSelectionModel
|
||||||
import javax.swing.SwingConstants
|
import javax.swing.SwingConstants
|
||||||
import javax.swing.table.DefaultTableCellRenderer
|
import javax.swing.table.DefaultTableCellRenderer
|
||||||
|
|
||||||
|
import com.muwire.core.util.DataUtil
|
||||||
|
|
||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
|
import java.awt.Color
|
||||||
|
|
||||||
import javax.annotation.Nonnull
|
import javax.annotation.Nonnull
|
||||||
|
|
||||||
@@ -35,7 +40,7 @@ class SearchTabView {
|
|||||||
resultsTable = table(id : "results-table", autoCreateRowSorter : true) {
|
resultsTable = table(id : "results-table", autoCreateRowSorter : true) {
|
||||||
tableModel(list: model.results) {
|
tableModel(list: model.results) {
|
||||||
closureColumn(header: "Name", preferredWidth: 350, type: String, read : {row -> row.name.replace('<','_')})
|
closureColumn(header: "Name", preferredWidth: 350, type: String, read : {row -> row.name.replace('<','_')})
|
||||||
closureColumn(header: "Size", preferredWidth: 50, type: String, read : {row -> DataHelper.formatSize2Decimal(row.size, false)+"B"})
|
closureColumn(header: "Size", preferredWidth: 50, type: Long, read : {row -> row.size})
|
||||||
closureColumn(header: "Sources", preferredWidth: 10, type : Integer, read : { row -> model.hashBucket[row.infohash].size()})
|
closureColumn(header: "Sources", preferredWidth: 10, type : Integer, read : { row -> model.hashBucket[row.infohash].size()})
|
||||||
closureColumn(header: "Sender", preferredWidth: 170, type: String, read : {row -> row.sender.getHumanReadableName()})
|
closureColumn(header: "Sender", preferredWidth: 170, type: String, read : {row -> row.sender.getHumanReadableName()})
|
||||||
closureColumn(header: "Trust", preferredWidth: 50, type: String, read : {row ->
|
closureColumn(header: "Trust", preferredWidth: 50, type: String, read : {row ->
|
||||||
@@ -86,6 +91,9 @@ class SearchTabView {
|
|||||||
resultsTable.setDefaultRenderer(Integer.class,centerRenderer)
|
resultsTable.setDefaultRenderer(Integer.class,centerRenderer)
|
||||||
resultsTable.columnModel.getColumn(4).setCellRenderer(centerRenderer)
|
resultsTable.columnModel.getColumn(4).setCellRenderer(centerRenderer)
|
||||||
|
|
||||||
|
resultsTable.columnModel.getColumn(1).setCellRenderer(new SizeRenderer())
|
||||||
|
|
||||||
|
|
||||||
resultsTable.rowSorter.addRowSorterListener({ evt -> lastSortEvent = evt})
|
resultsTable.rowSorter.addRowSorterListener({ evt -> lastSortEvent = evt})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
gui/src/main/groovy/com/muwire/gui/SizeRenderer.groovy
Normal file
29
gui/src/main/groovy/com/muwire/gui/SizeRenderer.groovy
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import javax.swing.JComponent
|
||||||
|
import javax.swing.JLabel
|
||||||
|
import javax.swing.JTable
|
||||||
|
import javax.swing.table.DefaultTableCellRenderer
|
||||||
|
|
||||||
|
import net.i2p.data.DataHelper
|
||||||
|
|
||||||
|
class SizeRenderer extends DefaultTableCellRenderer {
|
||||||
|
SizeRenderer() {
|
||||||
|
setHorizontalAlignment(JLabel.CENTER)
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
JComponent getTableCellRendererComponent(JTable table, Object value,
|
||||||
|
boolean isSelected, boolean hasFocus, int row, int column) {
|
||||||
|
Long l = (Long) value
|
||||||
|
String formatted = DataHelper.formatSize2Decimal(l, false)+"B"
|
||||||
|
setText(formatted)
|
||||||
|
if (isSelected) {
|
||||||
|
setForeground(table.getSelectionForeground())
|
||||||
|
setBackground(table.getSelectionBackground())
|
||||||
|
} else {
|
||||||
|
setForeground(table.getForeground())
|
||||||
|
setBackground(table.getBackground())
|
||||||
|
}
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
@@ -5,19 +5,30 @@ class UISettings {
|
|||||||
String lnf
|
String lnf
|
||||||
boolean showMonitor
|
boolean showMonitor
|
||||||
String font
|
String font
|
||||||
|
boolean clearCancelledDownloads
|
||||||
|
boolean clearFinishedDownloads
|
||||||
|
boolean excludeLocalResult
|
||||||
|
|
||||||
UISettings(Properties props) {
|
UISettings(Properties props) {
|
||||||
lnf = props.getProperty("lnf", "system")
|
lnf = props.getProperty("lnf", "system")
|
||||||
showMonitor = Boolean.parseBoolean(props.getProperty("showMonitor", "true"))
|
showMonitor = Boolean.parseBoolean(props.getProperty("showMonitor", "true"))
|
||||||
font = props.getProperty("font",null)
|
font = props.getProperty("font",null)
|
||||||
|
clearCancelledDownloads = Boolean.parseBoolean(props.getProperty("clearCancelledDownloads","false"))
|
||||||
|
clearFinishedDownloads = Boolean.parseBoolean(props.getProperty("clearFinishedDownloads","false"))
|
||||||
|
excludeLocalResult = Boolean.parseBoolean(props.getProperty("excludeLocalResult","false"))
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(OutputStream out) throws IOException {
|
void write(OutputStream out) throws IOException {
|
||||||
Properties props = new Properties()
|
Properties props = new Properties()
|
||||||
props.setProperty("lnf", lnf)
|
props.setProperty("lnf", lnf)
|
||||||
props.setProperty("showMonitor", showMonitor)
|
props.setProperty("showMonitor", String.valueOf(showMonitor))
|
||||||
|
props.setProperty("clearCancelledDownloads", String.valueOf(clearCancelledDownloads))
|
||||||
|
props.setProperty("clearFinishedDownloads", String.valueOf(clearFinishedDownloads))
|
||||||
|
props.setProperty("excludeLocalResult", String.valueOf(excludeLocalResult))
|
||||||
if (font != null)
|
if (font != null)
|
||||||
props.setProperty("font", font)
|
props.setProperty("font", font)
|
||||||
|
|
||||||
|
|
||||||
props.store(out, "UI Properties")
|
props.store(out, "UI Properties")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user