better search box
This commit is contained in:
@@ -78,10 +78,10 @@ class MuWireSettings {
|
|||||||
totalUploadSlots = Integer.valueOf(props.getProperty("totalUploadSlots","-1"))
|
totalUploadSlots = Integer.valueOf(props.getProperty("totalUploadSlots","-1"))
|
||||||
uploadSlotsPerUser = Integer.valueOf(props.getProperty("uploadSlotsPerUser","-1"))
|
uploadSlotsPerUser = Integer.valueOf(props.getProperty("uploadSlotsPerUser","-1"))
|
||||||
|
|
||||||
watchedDirectories = readEncodedSet(props, "watchedDirectories")
|
watchedDirectories = DataUtil.readEncodedSet(props, "watchedDirectories")
|
||||||
watchedKeywords = readEncodedSet(props, "watchedKeywords")
|
watchedKeywords = DataUtil.readEncodedSet(props, "watchedKeywords")
|
||||||
watchedRegexes = readEncodedSet(props, "watchedRegexes")
|
watchedRegexes = DataUtil.readEncodedSet(props, "watchedRegexes")
|
||||||
negativeFileTree = readEncodedSet(props, "negativeFileTree")
|
negativeFileTree = DataUtil.readEncodedSet(props, "negativeFileTree")
|
||||||
|
|
||||||
trustSubscriptions = new HashSet<>()
|
trustSubscriptions = new HashSet<>()
|
||||||
if (props.containsKey("trustSubscriptions")) {
|
if (props.containsKey("trustSubscriptions")) {
|
||||||
@@ -125,10 +125,10 @@ class MuWireSettings {
|
|||||||
props.setProperty("totalUploadSlots", String.valueOf(totalUploadSlots))
|
props.setProperty("totalUploadSlots", String.valueOf(totalUploadSlots))
|
||||||
props.setProperty("uploadSlotsPerUser", String.valueOf(uploadSlotsPerUser))
|
props.setProperty("uploadSlotsPerUser", String.valueOf(uploadSlotsPerUser))
|
||||||
|
|
||||||
writeEncodedSet(watchedDirectories, "watchedDirectories", props)
|
DataUtil.writeEncodedSet(watchedDirectories, "watchedDirectories", props)
|
||||||
writeEncodedSet(watchedKeywords, "watchedKeywords", props)
|
DataUtil.writeEncodedSet(watchedKeywords, "watchedKeywords", props)
|
||||||
writeEncodedSet(watchedRegexes, "watchedRegexes", props)
|
DataUtil.writeEncodedSet(watchedRegexes, "watchedRegexes", props)
|
||||||
writeEncodedSet(negativeFileTree, "negativeFileTree", props)
|
DataUtil.writeEncodedSet(negativeFileTree, "negativeFileTree", props)
|
||||||
|
|
||||||
if (!trustSubscriptions.isEmpty()) {
|
if (!trustSubscriptions.isEmpty()) {
|
||||||
String encoded = trustSubscriptions.stream().
|
String encoded = trustSubscriptions.stream().
|
||||||
@@ -140,24 +140,6 @@ class MuWireSettings {
|
|||||||
props.store(out, "This file is UTF-8")
|
props.store(out, "This file is UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> readEncodedSet(Properties props, String property) {
|
|
||||||
Set<String> rv = new ConcurrentHashSet<>()
|
|
||||||
if (props.containsKey(property)) {
|
|
||||||
String[] encoded = props.getProperty(property).split(",")
|
|
||||||
encoded.each { rv << DataUtil.readi18nString(Base64.decode(it)) }
|
|
||||||
}
|
|
||||||
rv
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void writeEncodedSet(Set<String> set, String property, Properties props) {
|
|
||||||
if (set.isEmpty())
|
|
||||||
return
|
|
||||||
String encoded = set.stream().
|
|
||||||
map({Base64.encode(DataUtil.encodei18nString(it))}).
|
|
||||||
collect(Collectors.joining(","))
|
|
||||||
props.setProperty(property, encoded)
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isLeaf() {
|
boolean isLeaf() {
|
||||||
isLeaf
|
isLeaf
|
||||||
}
|
}
|
||||||
|
@@ -11,10 +11,14 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.muwire.core.Constants;
|
import com.muwire.core.Constants;
|
||||||
|
|
||||||
import net.i2p.data.Base64;
|
import net.i2p.data.Base64;
|
||||||
|
import net.i2p.util.ConcurrentHashSet;
|
||||||
|
|
||||||
public class DataUtil {
|
public class DataUtil {
|
||||||
|
|
||||||
@@ -165,4 +169,22 @@ public class DataUtil {
|
|||||||
} catch(Exception ex) { }
|
} catch(Exception ex) { }
|
||||||
cb = null;
|
cb = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<String> readEncodedSet(Properties props, String property) {
|
||||||
|
Set<String> rv = new ConcurrentHashSet<>();
|
||||||
|
if (props.containsKey(property)) {
|
||||||
|
String [] encoded = props.getProperty(property).split(",");
|
||||||
|
for(String s : encoded)
|
||||||
|
rv.add(readi18nString(Base64.decode(s)));
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeEncodedSet(Set<String> set, String property, Properties props) {
|
||||||
|
if (set.isEmpty())
|
||||||
|
return;
|
||||||
|
String encoded = set.stream().map(s -> Base64.encode(encodei18nString(s)))
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
|
props.setProperty(property, encoded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@ import net.i2p.crypto.DSAEngine
|
|||||||
import net.i2p.data.Base64
|
import net.i2p.data.Base64
|
||||||
import net.i2p.data.Signature
|
import net.i2p.data.Signature
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
import javax.annotation.Nonnull
|
import javax.annotation.Nonnull
|
||||||
@@ -51,11 +52,16 @@ class MainFrameController {
|
|||||||
private volatile Core core
|
private volatile Core core
|
||||||
|
|
||||||
@ControllerAction
|
@ControllerAction
|
||||||
void search() {
|
void search(ActionEvent evt) {
|
||||||
|
if (evt.getActionCommand() == null)
|
||||||
|
return
|
||||||
def cardsPanel = builder.getVariable("cards-panel")
|
def cardsPanel = builder.getVariable("cards-panel")
|
||||||
cardsPanel.getLayout().show(cardsPanel, "search window")
|
cardsPanel.getLayout().show(cardsPanel, "search window")
|
||||||
|
|
||||||
def search = builder.getVariable("search-field").text
|
def searchField = builder.getVariable("search-field")
|
||||||
|
def search = searchField.getSelectedItem()
|
||||||
|
searchField.model.addElement(search)
|
||||||
|
|
||||||
search = search.trim()
|
search = search.trim()
|
||||||
if (search.length() == 0)
|
if (search.length() == 0)
|
||||||
return
|
return
|
||||||
|
@@ -11,6 +11,7 @@ import net.i2p.data.DataHelper
|
|||||||
import javax.swing.BorderFactory
|
import javax.swing.BorderFactory
|
||||||
import javax.swing.Box
|
import javax.swing.Box
|
||||||
import javax.swing.BoxLayout
|
import javax.swing.BoxLayout
|
||||||
|
import javax.swing.JComboBox
|
||||||
import javax.swing.JFileChooser
|
import javax.swing.JFileChooser
|
||||||
import javax.swing.JFrame
|
import javax.swing.JFrame
|
||||||
import javax.swing.JLabel
|
import javax.swing.JLabel
|
||||||
@@ -24,6 +25,8 @@ import javax.swing.SwingConstants
|
|||||||
import javax.swing.SwingUtilities
|
import javax.swing.SwingUtilities
|
||||||
import javax.swing.TransferHandler
|
import javax.swing.TransferHandler
|
||||||
import javax.swing.border.Border
|
import javax.swing.border.Border
|
||||||
|
import javax.swing.event.DocumentEvent
|
||||||
|
import javax.swing.event.DocumentListener
|
||||||
import javax.swing.event.TreeExpansionEvent
|
import javax.swing.event.TreeExpansionEvent
|
||||||
import javax.swing.event.TreeExpansionListener
|
import javax.swing.event.TreeExpansionListener
|
||||||
import javax.swing.table.DefaultTableCellRenderer
|
import javax.swing.table.DefaultTableCellRenderer
|
||||||
@@ -135,7 +138,11 @@ class MainFrameView {
|
|||||||
panel(constraints: BorderLayout.CENTER) {
|
panel(constraints: BorderLayout.CENTER) {
|
||||||
borderLayout()
|
borderLayout()
|
||||||
label(" Enter search here:", constraints: BorderLayout.WEST) // TODO: fix this
|
label(" Enter search here:", constraints: BorderLayout.WEST) // TODO: fix this
|
||||||
textField(id: "search-field", constraints: BorderLayout.CENTER, action : searchAction)
|
|
||||||
|
def searchFieldModel = new SearchFieldModel(settings, new File(application.context.get("muwire-home")))
|
||||||
|
JComboBox myComboBox = new SearchField(searchFieldModel)
|
||||||
|
myComboBox.setAction(searchAction)
|
||||||
|
widget(id: "search-field", constraints: BorderLayout.CENTER, myComboBox)
|
||||||
|
|
||||||
}
|
}
|
||||||
panel( constraints: BorderLayout.EAST) {
|
panel( constraints: BorderLayout.EAST) {
|
||||||
@@ -484,6 +491,10 @@ class MainFrameView {
|
|||||||
}
|
}
|
||||||
}})
|
}})
|
||||||
|
|
||||||
|
// search field
|
||||||
|
def searchField = builder.getVariable("search-field")
|
||||||
|
|
||||||
|
// downloads table
|
||||||
def downloadsTable = builder.getVariable("downloads-table")
|
def downloadsTable = builder.getVariable("downloads-table")
|
||||||
def selectionModel = downloadsTable.getSelectionModel()
|
def selectionModel = downloadsTable.getSelectionModel()
|
||||||
selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
|
selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
|
||||||
|
14
gui/src/main/groovy/com/muwire/gui/SearchField.groovy
Normal file
14
gui/src/main/groovy/com/muwire/gui/SearchField.groovy
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import java.awt.event.KeyEvent
|
||||||
|
|
||||||
|
import javax.swing.JComboBox
|
||||||
|
|
||||||
|
class SearchField extends JComboBox {
|
||||||
|
SearchField(SearchFieldModel model) {
|
||||||
|
super()
|
||||||
|
setEditable(true)
|
||||||
|
setModel(model)
|
||||||
|
setEditor(new SearchFieldEditor(model, this))
|
||||||
|
}
|
||||||
|
}
|
47
gui/src/main/groovy/com/muwire/gui/SearchFieldEditor.groovy
Normal file
47
gui/src/main/groovy/com/muwire/gui/SearchFieldEditor.groovy
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import javax.swing.JTextField
|
||||||
|
import javax.swing.SwingUtilities
|
||||||
|
import javax.swing.event.DocumentEvent
|
||||||
|
import javax.swing.event.DocumentListener
|
||||||
|
import javax.swing.plaf.basic.BasicComboBoxEditor
|
||||||
|
|
||||||
|
class SearchFieldEditor extends BasicComboBoxEditor {
|
||||||
|
|
||||||
|
private final SearchFieldModel model
|
||||||
|
private final SearchField field
|
||||||
|
|
||||||
|
SearchFieldEditor(SearchFieldModel model, SearchField field) {
|
||||||
|
super()
|
||||||
|
this.model = model
|
||||||
|
this.field = field
|
||||||
|
def action = field.getAction()
|
||||||
|
field.setAction(null)
|
||||||
|
editor.setAction(action)
|
||||||
|
editor.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
SwingUtilities.invokeLater({
|
||||||
|
field.hidePopup()
|
||||||
|
if (model.onKeyStroke(editor.text))
|
||||||
|
field.showPopup()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
SwingUtilities.invokeLater({
|
||||||
|
field.hidePopup()
|
||||||
|
if (model.onKeyStroke(editor.text))
|
||||||
|
field.showPopup()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
96
gui/src/main/groovy/com/muwire/gui/SearchFieldModel.groovy
Normal file
96
gui/src/main/groovy/com/muwire/gui/SearchFieldModel.groovy
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import javax.swing.AbstractListModel
|
||||||
|
import javax.swing.MutableComboBoxModel
|
||||||
|
|
||||||
|
class SearchFieldModel extends AbstractListModel implements MutableComboBoxModel {
|
||||||
|
private final UISettings uiSettings
|
||||||
|
private final File settingsFile
|
||||||
|
private final List<String> objects = new ArrayList<>()
|
||||||
|
private String selectedObject
|
||||||
|
|
||||||
|
SearchFieldModel(UISettings uiSettings, File home) {
|
||||||
|
super()
|
||||||
|
this.uiSettings = uiSettings
|
||||||
|
this.settingsFile = new File(home, "gui.properties")
|
||||||
|
uiSettings.searchHistory.each { objects.add(it) }
|
||||||
|
fireIntervalAdded(this, 0, objects.size() - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addElement(Object string) {
|
||||||
|
if (!uiSettings.searchHistory.add(string))
|
||||||
|
return
|
||||||
|
settingsFile.withOutputStream { uiSettings.write(it) }
|
||||||
|
objects.add(string);
|
||||||
|
fireIntervalAdded(this,objects.size()-1, objects.size()-1);
|
||||||
|
if ( objects.size() == 1 && selectedObject == null && string != null ) {
|
||||||
|
setSelectedItem( string );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean onKeyStroke(String selected) {
|
||||||
|
selectedObject = selected
|
||||||
|
if (selected == null || selected.length() == 0) {
|
||||||
|
objects.clear()
|
||||||
|
uiSettings.searchHistory.each { objects.add(it) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
objects.clear()
|
||||||
|
|
||||||
|
Set<String> matching = new HashSet<>(uiSettings.searchHistory)
|
||||||
|
matching.retainAll { it.contains(selected) }
|
||||||
|
|
||||||
|
matching.each {
|
||||||
|
objects.add(it)
|
||||||
|
}
|
||||||
|
Collections.sort(objects)
|
||||||
|
if (!objects.isEmpty()) {
|
||||||
|
fireIntervalAdded(this, 0, objects.size() - 1)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSelectedItem(Object anObject) {
|
||||||
|
if ((selectedObject != null && !selectedObject.equals( anObject )) ||
|
||||||
|
selectedObject == null && anObject != null) {
|
||||||
|
selectedObject = anObject;
|
||||||
|
fireContentsChanged(this, -1, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getSelectedItem() {
|
||||||
|
selectedObject
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
objects.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getElementAt(int index) {
|
||||||
|
if ( index >= 0 && index < objects.size() )
|
||||||
|
return objects.get(index);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeElement(Object obj) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertElementAt(Object item, int index) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeElementAt(int index) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,7 @@
|
|||||||
package com.muwire.gui
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import com.muwire.core.util.DataUtil
|
||||||
|
|
||||||
class UISettings {
|
class UISettings {
|
||||||
|
|
||||||
String lnf
|
String lnf
|
||||||
@@ -14,6 +16,7 @@ class UISettings {
|
|||||||
boolean closeWarning
|
boolean closeWarning
|
||||||
boolean exitOnClose
|
boolean exitOnClose
|
||||||
boolean clearUploads
|
boolean clearUploads
|
||||||
|
Set<String> searchHistory
|
||||||
|
|
||||||
UISettings(Properties props) {
|
UISettings(Properties props) {
|
||||||
lnf = props.getProperty("lnf", "system")
|
lnf = props.getProperty("lnf", "system")
|
||||||
@@ -28,6 +31,8 @@ class UISettings {
|
|||||||
closeWarning = Boolean.parseBoolean(props.getProperty("closeWarning","true"))
|
closeWarning = Boolean.parseBoolean(props.getProperty("closeWarning","true"))
|
||||||
exitOnClose = Boolean.parseBoolean(props.getProperty("exitOnClose","false"))
|
exitOnClose = Boolean.parseBoolean(props.getProperty("exitOnClose","false"))
|
||||||
clearUploads = Boolean.parseBoolean(props.getProperty("clearUploads","false"))
|
clearUploads = Boolean.parseBoolean(props.getProperty("clearUploads","false"))
|
||||||
|
|
||||||
|
searchHistory = DataUtil.readEncodedSet(props, "searchHistory")
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(OutputStream out) throws IOException {
|
void write(OutputStream out) throws IOException {
|
||||||
@@ -46,6 +51,7 @@ class UISettings {
|
|||||||
if (font != null)
|
if (font != null)
|
||||||
props.setProperty("font", font)
|
props.setProperty("font", font)
|
||||||
|
|
||||||
|
DataUtil.writeEncodedSet(searchHistory, "searchHistory", props)
|
||||||
|
|
||||||
props.store(out, "UI Properties")
|
props.store(out, "UI Properties")
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user