add filtering in browse host view

auto-update
Zlatin Balevsky 2021-09-07 10:45:29 +01:00
parent 0b2fd2017a
commit a0ce1655ce
No known key found for this signature in database
GPG Key ID: A72832072D525E41
3 changed files with 142 additions and 23 deletions

View File

@ -1,5 +1,6 @@
package com.muwire.gui package com.muwire.gui
import com.muwire.core.SplitPattern
import griffon.core.artifact.GriffonController import griffon.core.artifact.GriffonController
import griffon.core.controller.ControllerAction import griffon.core.controller.ControllerAction
import griffon.inject.MVCMember import griffon.inject.MVCMember
@ -9,7 +10,6 @@ import net.i2p.data.Base64
import javax.annotation.Nonnull import javax.annotation.Nonnull
import com.muwire.core.Core import com.muwire.core.Core
import com.muwire.core.EventBus
import com.muwire.core.download.UIDownloadEvent import com.muwire.core.download.UIDownloadEvent
import com.muwire.core.search.BrowseStatus import com.muwire.core.search.BrowseStatus
import com.muwire.core.search.BrowseStatusEvent import com.muwire.core.search.BrowseStatusEvent
@ -17,8 +17,12 @@ import com.muwire.core.search.UIBrowseEvent
import com.muwire.core.search.UIResultBatchEvent import com.muwire.core.search.UIResultBatchEvent
import com.muwire.core.search.UIResultEvent import com.muwire.core.search.UIResultEvent
import javax.swing.JTextField
@ArtifactProviderFor(GriffonController) @ArtifactProviderFor(GriffonController)
class BrowseController { class BrowseController {
@MVCMember @Nonnull
FactoryBuilderSupport builder
@MVCMember @Nonnull @MVCMember @Nonnull
BrowseModel model BrowseModel model
@MVCMember @Nonnull @MVCMember @Nonnull
@ -44,6 +48,8 @@ class BrowseController {
return return
runInsideUIAsync { runInsideUIAsync {
model.status = e.status model.status = e.status
model.filterEnabled = (e.status == BrowseStatus.FINISHED || e.status == BrowseStatus.FAILED) &&
model.resultCount > 0
if (e.status == BrowseStatus.FETCHING) if (e.status == BrowseStatus.FETCHING)
model.totalResults = e.totalResults model.totalResults = e.totalResults
} }
@ -54,25 +60,37 @@ class BrowseController {
if (e.uuid != model.uuid) if (e.uuid != model.uuid)
return return
model.chatActionEnabled = e.results[0].chat model.chatActionEnabled = e.results[0].chat
model.results.addAll(e.results.toList()) List<UIResultEvent> results = e.results.toList()
model.results.addAll(results)
synchronized (model.allResults) {
model.allResults.addAll(results)
}
model.resultCount = model.results.size() model.resultCount = model.results.size()
int [] selectedRows = view.resultsTable.getSelectedRows() view.refreshResults()
if (view.lastSortEvent != null) {
for (int i = 0; i < selectedRows.length; i ++)
selectedRows[i] = view.resultsTable.rowSorter.convertRowIndexToModel(selectedRows[i])
}
view.resultsTable.model.fireTableDataChanged()
if (view.lastSortEvent != null) {
for (int i = 0; i < selectedRows.length; i ++)
selectedRows[i] = view.resultsTable.rowSorter.convertRowIndexToView(selectedRows[i])
}
for (int row : selectedRows)
view.resultsTable.selectionModel.addSelectionInterval(row, row)
} }
} }
@ControllerAction
void filter() {
JTextField field = builder.getVariable("filter-field")
String filter = field.getText()
if (filter == null)
return
filter = filter.strip().replaceAll(SplitPattern.SPLIT_PATTERN," ").toLowerCase()
String [] split = filter.split(" ")
def hs = new HashSet()
split.each {if (it.length() > 0) hs << it}
model.filter = hs.toArray(new String[0])
model.filterResults()
}
@ControllerAction
void clearFilter() {
model.filter = null
model.filterResults()
}
@ControllerAction @ControllerAction
void download() { void download() {
def selectedResults = view.selectedResults() def selectedResults = view.selectedResults()

View File

@ -1,15 +1,22 @@
package com.muwire.gui package com.muwire.gui
import com.muwire.core.Persona import com.muwire.core.Persona
import com.muwire.core.search.UIResultEvent
import griffon.core.artifact.GriffonModel import griffon.core.artifact.GriffonModel
import griffon.inject.MVCMember
import griffon.transform.Observable import griffon.transform.Observable
import griffon.metadata.ArtifactProviderFor import griffon.metadata.ArtifactProviderFor
import com.muwire.core.search.BrowseStatus import com.muwire.core.search.BrowseStatus
import javax.annotation.Nonnull
import javax.swing.SwingWorker
@ArtifactProviderFor(GriffonModel) @ArtifactProviderFor(GriffonModel)
class BrowseModel { class BrowseModel {
@MVCMember @Nonnull
BrowseView view
Persona host Persona host
@Observable BrowseStatus status @Observable BrowseStatus status
@Observable boolean downloadActionEnabled @Observable boolean downloadActionEnabled
@ -19,7 +26,71 @@ class BrowseModel {
@Observable boolean chatActionEnabled @Observable boolean chatActionEnabled
@Observable int totalResults @Observable int totalResults
@Observable int resultCount @Observable int resultCount
@Observable boolean filterEnabled
volatile UUID uuid volatile UUID uuid
def results = [] def results = []
List<UIResultEvent> allResults = []
volatile String[] filter
volatile Filterer filterer
private boolean filter(UIResultEvent result) {
if (filter == null)
return true
String name = result.getName().toLowerCase()
boolean contains = true
for (String keyword : filter) {
contains &= name.contains(keyword)
}
contains
}
void filterResults() {
results.clear()
filterer?.cancel()
if (filter != null) {
filterer = new Filterer()
filterer.execute()
} else {
synchronized (allResults) {
results.addAll(allResults)
}
view.refreshResults()
}
}
private class Filterer extends SwingWorker<List<UIResultEvent>, UIResultEvent> {
private volatile boolean cancelled;
void cancel() {
cancelled = true
}
@Override
protected List<UIResultEvent> doInBackground() throws Exception {
synchronized (allResults) {
for (UIResultEvent result : allResults) {
if (cancelled)
break
if (filter(result))
publish(result)
}
}
}
@Override
protected void process(List<UIResultEvent> chunks) {
if (cancelled)
return
results.addAll(chunks)
}
@Override
protected void done() {
if (cancelled)
return
view.refreshResults()
}
}
} }

View File

@ -1,6 +1,10 @@
package com.muwire.gui package com.muwire.gui
import com.muwire.core.search.BrowseStatus
import griffon.core.artifact.GriffonView import griffon.core.artifact.GriffonView
import javax.swing.JTextField
import static com.muwire.gui.Translator.trans import static com.muwire.gui.Translator.trans
import griffon.inject.MVCMember import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor import griffon.metadata.ArtifactProviderFor
@ -63,13 +67,25 @@ class BrowseView {
} }
} }
panel (constraints : BorderLayout.SOUTH) { panel (constraints : BorderLayout.SOUTH) {
button(text : trans("DOWNLOAD"), enabled : bind {model.downloadActionEnabled}, downloadAction) gridLayout(rows: 1, cols: 3)
button(text : trans("VIEW_COMMENT"), enabled : bind{model.viewCommentActionEnabled}, viewCommentAction) panel(border: etchedBorder()) {
button(text : trans("VIEW_CERTIFICATES"), enabled : bind{model.viewCertificatesActionEnabled}, viewCertificatesAction) button(text: trans("DOWNLOAD"), enabled: bind { model.downloadActionEnabled }, downloadAction)
button(text : trans("VIEW_COLLECTIONS"), enabled : bind{model.viewCollectionsActionEnabled}, viewCollectionsAction) label(text: trans("DOWNLOAD_SEQUENTIALLY"), enabled: bind {model.downloadActionEnabled})
button(text : trans("CHAT"), enabled : bind {model.chatActionEnabled}, chatAction) sequentialDownloadCheckbox = checkBox(enabled: bind {model.downloadActionEnabled})
label(text : trans("DOWNLOAD_SEQUENTIALLY")) }
sequentialDownloadCheckbox = checkBox() panel(border: etchedBorder()) {
button(text: trans("VIEW_COMMENT"), enabled: bind { model.viewCommentActionEnabled }, viewCommentAction)
button(text: trans("VIEW_CERTIFICATES"), enabled: bind { model.viewCertificatesActionEnabled }, viewCertificatesAction)
button(text: trans("VIEW_COLLECTIONS"), enabled: bind { model.viewCollectionsActionEnabled }, viewCollectionsAction)
button(text: trans("CHAT"), enabled: bind { model.chatActionEnabled }, chatAction)
}
panel(border: etchedBorder()) {
def textField = new JTextField(15)
textField.addActionListener({ controller.filter() })
widget(id: "filter-field", enabled: bind { model.filterEnabled }, textField)
button(text: trans("FILTER"), enabled: bind { model.filterEnabled }, filterAction)
button(text: trans("CLEAR"), enabled: bind { model.filterEnabled }, clearFilterAction)
}
} }
} }
@ -217,6 +233,20 @@ class BrowseView {
parent.setTabComponentAt(index, tabPanel) parent.setTabComponentAt(index, tabPanel)
} }
void refreshResults() {
int [] selectedRows = resultsTable.getSelectedRows()
if (lastSortEvent != null) {
for (int i = 0; i < selectedRows.length; i ++)
selectedRows[i] = resultsTable.rowSorter.convertRowIndexToModel(selectedRows[i])
}
resultsTable.model.fireTableDataChanged()
if (lastSortEvent != null) {
for (int i = 0; i < selectedRows.length; i ++)
selectedRows[i] = resultsTable.rowSorter.convertRowIndexToView(selectedRows[i])
}
for (int row : selectedRows)
resultsTable.selectionModel.addSelectionInterval(row, row)
}
def selectedResults() { def selectedResults() {
int [] rows = resultsTable.getSelectedRows() int [] rows = resultsTable.getSelectedRows()