Compare commits

..

6 Commits

Author SHA1 Message Date
Zlatin Balevsky
4bb27b84de release 0.0.3 for fixed first hop and tabbed search ui 2019-06-01 11:11:22 +01:00
Zlatin Balevsky
d5b8c0c694 fix parsing of first hop 2019-06-01 11:03:27 +01:00
Zlatin Balevsky
1e314b3cca serialize firstHop 2019-06-01 10:44:24 +01:00
Zlatin Balevsky
6f02e3e9c0 hook up buttons to tabbed results 2019-06-01 10:04:10 +01:00
Zlatin Balevsky
9f5f21376a one tab per search 2019-06-01 09:29:03 +01:00
Zlatin Balevsky
d2231b8e38 attach uuid to search results 2019-06-01 07:20:39 +01:00
15 changed files with 214 additions and 28 deletions

View File

@@ -120,6 +120,7 @@ abstract class Connection implements Closeable {
query.type = "Search"
query.version = 1
query.uuid = e.searchEvent.getUuid()
query.firstHop = e.firstHop
// TODO: first hop figure out
query.keywords = e.searchEvent.getSearchTerms()
query.replyTo = e.getReceivedOn().toBase64()
@@ -164,7 +165,7 @@ abstract class Connection implements Closeable {
QueryEvent event = new QueryEvent ( searchEvent : searchEvent,
replyTo : replyTo,
receivedOn : endpoint.destination,
firstHop : Boolean.parseBoolean(search.firstHop) )
firstHop : search.firstHop )
eventBus.publish(event)
}

View File

@@ -204,7 +204,7 @@ class ConnectionAcceptor {
byte [] payload = new byte[jsonSize]
dis.readFully(payload)
def json = slurper.parse(payload)
eventBus.publish(ResultsParser.parse(sender, json))
eventBus.publish(ResultsParser.parse(sender, resultsUUID, json))
}
} catch (IOException | UnexpectedResultsException | InvalidSearchResultException bad) {
log.log(Level.WARNING, "failed to process POST", bad)

View File

@@ -9,7 +9,7 @@ import com.muwire.core.util.DataUtil
import net.i2p.data.Base64
class ResultsParser {
public static UIResultEvent parse(Persona p, def json) throws InvalidSearchResultException {
public static UIResultEvent parse(Persona p, UUID uuid, def json) throws InvalidSearchResultException {
if (json.type != "Result")
throw new InvalidSearchResultException("not a result json")
if (json.version != 1)
@@ -46,7 +46,8 @@ class ResultsParser {
name : name,
size : size,
infohash : parsedIH,
pieceSize : pieceSize)
pieceSize : pieceSize,
uuid : uuid)
} catch (Exception e) {
throw new InvalidSearchResultException("parsing search result failed",e)
}

View File

@@ -55,7 +55,8 @@ class ResultsSender {
name : it.getFile().getName(),
size : length,
infohash : it.getInfoHash(),
pieceSize : FileHasher.getPieceSize(length)
pieceSize : FileHasher.getPieceSize(length),
uuid : uuid
)
eventBus.publish(uiResultEvent)
}

View File

@@ -6,6 +6,7 @@ import com.muwire.core.Persona
class UIResultEvent extends Event {
Persona sender
UUID uuid
String name
long size
InfoHash infohash

View File

@@ -1,5 +1,5 @@
group = com.muwire
version = 0.0.2
version = 0.0.3
groovyVersion = 2.4.15
slf4jVersion = 1.7.25
spockVersion = 1.1-groovy-2.4

View File

@@ -16,4 +16,9 @@ mvcGroups {
view = 'com.muwire.gui.MainFrameView'
controller = 'com.muwire.gui.MainFrameController'
}
'SearchTab' {
model = 'com.muwire.gui.SearchTabModel'
view = 'com.muwire.gui.SearchTabView'
controller = 'com.muwire.gui.SearchTabController'
}
}

View File

@@ -3,6 +3,8 @@ package com.muwire.gui
import griffon.core.GriffonApplication
import griffon.core.artifact.GriffonController
import griffon.core.controller.ControllerAction
import griffon.core.mvc.MVCGroup
import griffon.core.mvc.MVCGroupConfiguration
import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor
import javax.annotation.Nonnull
@@ -30,20 +32,32 @@ class MainFrameController {
@ControllerAction
void search() {
def search = builder.getVariable("search-field").text
def searchEvent = new SearchEvent(searchTerms : [search], uuid : UUID.randomUUID())
def uuid = UUID.randomUUID()
Map<String, Object> params = new HashMap<>()
params["search-terms"] = search
params["uuid"] = uuid.toString()
def group = mvcGroup.createMVCGroup("SearchTab", uuid.toString(), params)
model.results[uuid.toString()] = group
def searchEvent = new SearchEvent(searchTerms : [search], uuid : uuid)
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : true,
replyTo: core.me.destination, receivedOn: core.me.destination))
}
private def selectedResult() {
def resultsTable = builder.getVariable("results-table")
int row = resultsTable.getSelectedRow()
model.results[row]
def selected = builder.getVariable("result-tabs").getSelectedComponent()
def group = selected.getClientProperty("mvc-group")
def table = selected.getClientProperty("results-table")
int row = table.getSelectedRow()
group.model.results[row]
}
@ControllerAction
void download() {
def result = selectedResult()
if (result == null)
return // TODO disable button
def file = new File(application.context.get("muwire-settings").downloadLocation, result.name)
core.eventBus.publish(new UIDownloadEvent(result : result, target : file))
}
@@ -51,12 +65,16 @@ class MainFrameController {
@ControllerAction
void trust() {
def result = selectedResult()
if (result == null)
return // TODO disable button
core.eventBus.publish( new TrustEvent(destination : result.sender.destination, level : TrustLevel.TRUSTED))
}
@ControllerAction
void distrust() {
def result = selectedResult()
if (result == null)
return // TODO disable button
core.eventBus.publish( new TrustEvent(destination : result.sender.destination, level : TrustLevel.DISTRUSTED))
}

View File

@@ -0,0 +1,11 @@
package com.muwire.gui
import griffon.core.artifact.GriffonController
import griffon.core.controller.ControllerAction
import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor
import javax.annotation.Nonnull
@ArtifactProviderFor(GriffonController)
class SearchTabController {
}

View File

@@ -1,5 +1,7 @@
package com.muwire.gui
import java.util.concurrent.ConcurrentHashMap
import javax.annotation.Nonnull
import javax.inject.Inject
import javax.swing.JTable
@@ -21,6 +23,7 @@ import com.muwire.core.upload.UploadFinishedEvent
import griffon.core.GriffonApplication
import griffon.core.artifact.GriffonModel
import griffon.core.mvc.MVCGroup
import griffon.inject.MVCMember
import griffon.transform.FXObservable
import griffon.transform.Observable
@@ -33,7 +36,7 @@ class MainFrameModel {
@Inject @Nonnull GriffonApplication application
@Observable boolean coreInitialized = false
@Observable def results = []
def results = new ConcurrentHashMap<>()
@Observable def downloads = []
@Observable def uploads = []
@Observable def shared = []
@@ -69,11 +72,8 @@ class MainFrameModel {
}
void onUIResultEvent(UIResultEvent e) {
runInsideUIAsync {
results << e
JTable table = builder.getVariable("results-table")
table.model.fireTableDataChanged()
}
MVCGroup resultsGroup = results.get(e.uuid)
resultsGroup?.model.handleResult(e)
}
void onDownloadStartedEvent(DownloadStartedEvent e) {

View File

@@ -0,0 +1,42 @@
package com.muwire.gui
import javax.annotation.Nonnull
import javax.inject.Inject
import javax.swing.JTable
import com.muwire.core.Core
import com.muwire.core.search.UIResultEvent
import griffon.core.artifact.GriffonModel
import griffon.core.mvc.MVCGroup
import griffon.inject.MVCMember
import griffon.transform.Observable
import griffon.metadata.ArtifactProviderFor
@ArtifactProviderFor(GriffonModel)
class SearchTabModel {
@MVCMember @Nonnull
FactoryBuilderSupport builder
Core core
String uuid
def results = []
void mvcGroupInit(Map<String, String> args) {
core = mvcGroup.parentGroup.model.core
mvcGroup.parentGroup.model.results[UUID.fromString(uuid)] = mvcGroup
}
void mvcGroupDestroy() {
mvcGroup.parentGroup.model.results.remove(uuid)
}
void handleResult(UIResultEvent e) {
runInsideUIAsync {
results << e
JTable table = builder.getVariable("results-table")
table.model.fireTableDataChanged()
}
}
}

View File

@@ -67,18 +67,7 @@ class MainFrameView {
continuousLayout : true, constraints : BorderLayout.CENTER) {
panel (constraints : JSplitPane.TOP) {
borderLayout()
scrollPane (constraints : BorderLayout.CENTER){
table(id : "results-table") {
tableModel(list: model.results) {
closureColumn(header: "Name", type: String, read : {row -> row.name})
closureColumn(header: "Size", preferredWidth: 150, type: Long, read : {row -> row.size})
closureColumn(header: "Sender", type: String, read : {row -> row.sender.getHumanReadableName()})
closureColumn(header: "Trust", type: String, read : {row ->
model.core.trustService.getLevel(row.sender.destination)
})
}
}
}
tabbedPane(id : "result-tabs", constraints: BorderLayout.CENTER)
panel(constraints : BorderLayout.SOUTH) {
button(text : "Download", downloadAction)
button(text : "Trust", trustAction)

View File

@@ -0,0 +1,71 @@
package com.muwire.gui
import griffon.core.artifact.GriffonView
import griffon.core.mvc.MVCGroup
import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor
import javax.swing.SwingConstants
import java.awt.BorderLayout
import javax.annotation.Nonnull
@ArtifactProviderFor(GriffonView)
class SearchTabView {
@MVCMember @Nonnull
FactoryBuilderSupport builder
@MVCMember @Nonnull
SearchTabModel model
def pane
def parent
def searchTerms
void initUI() {
builder.with {
def resultsTable
def pane = scrollPane {
resultsTable = table(id : "results-table") {
tableModel(list: model.results) {
closureColumn(header: "Name", type: String, read : {row -> row.name})
closureColumn(header: "Size", preferredWidth: 150, type: Long, read : {row -> row.size})
closureColumn(header: "Sender", type: String, read : {row -> row.sender.getHumanReadableName()})
closureColumn(header: "Trust", type: String, read : {row ->
model.core.trustService.getLevel(row.sender.destination)
})
}
}
}
this.pane = pane
this.pane.putClientProperty("mvc-group", mvcGroup)
this.pane.putClientProperty("results-table",resultsTable)
}
}
void mvcGroupInit(Map<String, String> args) {
searchTerms = args["search-terms"]
parent = mvcGroup.parentGroup.view.builder.getVariable("result-tabs")
parent.addTab(searchTerms, pane)
int index = parent.indexOfTab(searchTerms)
def tabPanel
builder.with {
tabPanel = panel {
borderLayout()
panel {
label(text : searchTerms, constraints : BorderLayout.CENTER)
}
button(text : "x", preferredSize : [17,17], constraints : BorderLayout.EAST, // TODO: in osx is probably WEST
actionPerformed : closeTab )
}
}
parent.setTabComponentAt(index, tabPanel)
}
def closeTab = {
int index = parent.indexOfTab(searchTerms)
parent.removeTabAt(index)
mvcGroup.destroy()
}
}

View File

@@ -0,0 +1,25 @@
package com.muwire.gui
import griffon.core.test.GriffonFestRule
import org.fest.swing.fixture.FrameFixture
import org.junit.Rule
import org.junit.Test
import static org.junit.Assert.fail
class SearchTabIntegrationTest {
static {
System.setProperty('griffon.swing.edt.violations.check', 'true')
System.setProperty('griffon.swing.edt.hang.monitor', 'true')
}
@Rule
public final GriffonFestRule fest = new GriffonFestRule()
private FrameFixture window
@Test
void smokeTest() {
fail('Not implemented yet!')
}
}

View File

@@ -0,0 +1,21 @@
package com.muwire.gui
import griffon.core.test.GriffonUnitRule
import griffon.core.test.TestFor
import org.junit.Rule
import org.junit.Test
import static org.junit.Assert.fail
@TestFor(SearchTabController)
class SearchTabControllerTest {
private SearchTabController controller
@Rule
public final GriffonUnitRule griffon = new GriffonUnitRule()
@Test
void smokeTest() {
fail('Not yet implemented!')
}
}