mirror of https://github.com/zlatinb/muwire
Tree view of the shared files. The count is wrong for some reason
parent
c7284623bc
commit
60ddb85461
Binary file not shown.
|
@ -27,7 +27,7 @@ class AddCommentController {
|
|||
model.selectedFiles.each {
|
||||
it.setComment(comment)
|
||||
}
|
||||
mvcGroup.parentGroup.view.builder.getVariable("shared-files-table").model.fireTableDataChanged()
|
||||
mvcGroup.parentGroup.view.refreshSharedFiles()
|
||||
cancel()
|
||||
}
|
||||
|
||||
|
|
|
@ -143,6 +143,8 @@ class OptionsController {
|
|||
// boolean showSearchHashes = view.showSearchHashesCheckbox.model.isSelected()
|
||||
// model.showSearchHashes = showSearchHashes
|
||||
// uiSettings.showSearchHashes = showSearchHashes
|
||||
|
||||
uiSettings.sharedFilesAsTree = model.sharedFilesAsTree
|
||||
|
||||
File uiSettingsFile = new File(core.home, "gui.properties")
|
||||
uiSettingsFile.withOutputStream {
|
||||
|
@ -168,4 +170,14 @@ class OptionsController {
|
|||
if (rv == JFileChooser.APPROVE_OPTION)
|
||||
model.downloadLocation = chooser.getSelectedFile().getAbsolutePath()
|
||||
}
|
||||
|
||||
@ControllerAction
|
||||
void sharedTree() {
|
||||
model.sharedFilesAsTree = true
|
||||
}
|
||||
|
||||
@ControllerAction
|
||||
void sharedTable() {
|
||||
model.sharedFilesAsTree = false
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.muwire.gui
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.nio.file.Path
|
||||
import java.util.Calendar
|
||||
import java.util.UUID
|
||||
|
||||
|
@ -8,12 +9,16 @@ import javax.annotation.Nonnull
|
|||
import javax.inject.Inject
|
||||
import javax.swing.JOptionPane
|
||||
import javax.swing.JTable
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
import javax.swing.tree.DefaultTreeModel
|
||||
import javax.swing.tree.TreeNode
|
||||
|
||||
import com.muwire.core.Core
|
||||
import com.muwire.core.InfoHash
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.Persona
|
||||
import com.muwire.core.RouterDisconnectedEvent
|
||||
import com.muwire.core.SharedFile
|
||||
import com.muwire.core.connection.ConnectionAttemptStatus
|
||||
import com.muwire.core.connection.ConnectionEvent
|
||||
import com.muwire.core.connection.DisconnectionEvent
|
||||
|
@ -57,6 +62,8 @@ class MainFrameModel {
|
|||
FactoryBuilderSupport builder
|
||||
@MVCMember @Nonnull
|
||||
MainFrameController controller
|
||||
@MVCMember @Nonnull
|
||||
MainFrameView view
|
||||
@Inject @Nonnull GriffonApplication application
|
||||
@Observable boolean coreInitialized = false
|
||||
@Observable boolean routerPresent
|
||||
|
@ -64,7 +71,10 @@ class MainFrameModel {
|
|||
def results = new ConcurrentHashMap<>()
|
||||
def downloads = []
|
||||
def uploads = []
|
||||
def shared = []
|
||||
def shared
|
||||
def sharedTree
|
||||
def treeRoot
|
||||
final Map<SharedFile, TreeNode> fileToNode = new HashMap<>()
|
||||
def watched = []
|
||||
def connectionList = []
|
||||
def searches = new LinkedList()
|
||||
|
@ -122,6 +132,13 @@ class MainFrameModel {
|
|||
void mvcGroupInit(Map<String, Object> args) {
|
||||
|
||||
uiSettings = application.context.get("ui-settings")
|
||||
|
||||
if (!uiSettings.sharedFilesAsTree)
|
||||
shared = []
|
||||
else {
|
||||
treeRoot = new DefaultMutableTreeNode()
|
||||
sharedTree = new DefaultTreeModel(treeRoot)
|
||||
}
|
||||
|
||||
Timer timer = new Timer("download-pumper", true)
|
||||
timer.schedule({
|
||||
|
@ -303,7 +320,6 @@ class MainFrameModel {
|
|||
|
||||
void onFileHashingEvent(FileHashingEvent e) {
|
||||
runInsideUIAsync {
|
||||
loadedFiles = shared.size()
|
||||
hashingFile = e.hashingFile
|
||||
}
|
||||
}
|
||||
|
@ -315,28 +331,53 @@ class MainFrameModel {
|
|||
if (e.error != null)
|
||||
return // TODO do something
|
||||
runInsideUIAsync {
|
||||
shared << e.sharedFile
|
||||
loadedFiles = shared.size()
|
||||
JTable table = builder.getVariable("shared-files-table")
|
||||
table.model.fireTableDataChanged()
|
||||
if (!uiSettings.sharedFilesAsTree) {
|
||||
shared << e.sharedFile
|
||||
loadedFiles = shared.size()
|
||||
JTable table = builder.getVariable("shared-files-table")
|
||||
table.model.fireTableDataChanged()
|
||||
} else {
|
||||
insertIntoTree(e.sharedFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onFileLoadedEvent(FileLoadedEvent e) {
|
||||
runInsideUIAsync {
|
||||
shared << e.loadedFile
|
||||
loadedFiles = shared.size()
|
||||
JTable table = builder.getVariable("shared-files-table")
|
||||
table.model.fireTableDataChanged()
|
||||
if (!uiSettings.sharedFilesAsTree) {
|
||||
shared << e.loadedFile
|
||||
loadedFiles = shared.size()
|
||||
JTable table = builder.getVariable("shared-files-table")
|
||||
table.model.fireTableDataChanged()
|
||||
} else {
|
||||
insertIntoTree(e.loadedFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onFileUnsharedEvent(FileUnsharedEvent e) {
|
||||
runInsideUIAsync {
|
||||
shared.remove(e.unsharedFile)
|
||||
loadedFiles = shared.size()
|
||||
JTable table = builder.getVariable("shared-files-table")
|
||||
table.model.fireTableDataChanged()
|
||||
if (!uiSettings.sharedFilesAsTree) {
|
||||
shared.remove(e.unsharedFile)
|
||||
loadedFiles = shared.size()
|
||||
} else {
|
||||
def dmtn = fileToNode.remove(e.unsharedFile)
|
||||
if (dmtn != null) {
|
||||
loadedFiles = fileToNode.size()
|
||||
while (true) {
|
||||
def parent = dmtn.getParent()
|
||||
parent.remove(dmtn)
|
||||
if (parent == treeRoot)
|
||||
break
|
||||
if (parent.getChildCount() == 0) {
|
||||
dmtn = parent
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
view.refreshSharedFiles()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,11 +517,44 @@ class MainFrameModel {
|
|||
if (!core.muOptions.shareDownloadedFiles)
|
||||
return
|
||||
runInsideUIAsync {
|
||||
shared << e.downloadedFile
|
||||
JTable table = builder.getVariable("shared-files-table")
|
||||
table.model.fireTableDataChanged()
|
||||
if (!uiSettings.sharedFilesAsTree) {
|
||||
shared << e.downloadedFile
|
||||
JTable table = builder.getVariable("shared-files-table")
|
||||
table.model.fireTableDataChanged()
|
||||
} else {
|
||||
insertIntoTree(e.downloadedFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void insertIntoTree(SharedFile file) {
|
||||
Path folder = file.getFile().toPath()
|
||||
folder = folder.subpath(0, folder.getNameCount() - 1)
|
||||
TreeNode node = treeRoot
|
||||
for(Path path : folder) {
|
||||
boolean exists = false
|
||||
def children = node.children()
|
||||
def child = null
|
||||
while(children.hasMoreElements()) {
|
||||
child = children.nextElement()
|
||||
if (child.getUserObject() == path.toString()) {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!exists) {
|
||||
child = new DefaultMutableTreeNode(path.toString())
|
||||
node.add(child)
|
||||
}
|
||||
node = child
|
||||
}
|
||||
|
||||
def dmtn = new DefaultMutableTreeNode(file)
|
||||
fileToNode[file] = dmtn
|
||||
node.add(dmtn)
|
||||
loadedFiles = fileToNode.size()
|
||||
view.refreshSharedFiles()
|
||||
}
|
||||
|
||||
private static class UIConnection {
|
||||
Destination destination
|
||||
|
|
|
@ -31,6 +31,7 @@ class OptionsModel {
|
|||
@Observable boolean clearFinishedDownloads
|
||||
@Observable boolean excludeLocalResult
|
||||
@Observable boolean showSearchHashes
|
||||
@Observable boolean sharedFilesAsTree
|
||||
|
||||
// bw options
|
||||
@Observable String inBw
|
||||
|
@ -67,6 +68,7 @@ class OptionsModel {
|
|||
clearFinishedDownloads = uiSettings.clearFinishedDownloads
|
||||
excludeLocalResult = uiSettings.excludeLocalResult
|
||||
showSearchHashes = uiSettings.showSearchHashes
|
||||
sharedFilesAsTree = uiSettings.sharedFilesAsTree
|
||||
|
||||
if (core.router != null) {
|
||||
inBw = String.valueOf(settings.inBw)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 598 B |
|
@ -16,11 +16,14 @@ import javax.swing.JMenuItem
|
|||
import javax.swing.JPopupMenu
|
||||
import javax.swing.JSplitPane
|
||||
import javax.swing.JTable
|
||||
import javax.swing.JTree
|
||||
import javax.swing.ListSelectionModel
|
||||
import javax.swing.SwingConstants
|
||||
import javax.swing.TransferHandler
|
||||
import javax.swing.border.Border
|
||||
import javax.swing.table.DefaultTableCellRenderer
|
||||
import javax.swing.tree.TreeNode
|
||||
import javax.swing.tree.TreePath
|
||||
|
||||
import com.muwire.core.Constants
|
||||
import com.muwire.core.MuWireSettings
|
||||
|
@ -59,8 +62,10 @@ class MainFrameView {
|
|||
def lastWatchedSortEvent
|
||||
def trustTablesSortEvents = [:]
|
||||
|
||||
UISettings settings
|
||||
|
||||
void initUI() {
|
||||
UISettings settings = application.context.get("ui-settings")
|
||||
settings = application.context.get("ui-settings")
|
||||
builder.with {
|
||||
application(size : [1024,768], id: 'main-frame',
|
||||
locationRelativeTo : null,
|
||||
|
@ -207,12 +212,18 @@ class MainFrameView {
|
|||
panel {
|
||||
borderLayout()
|
||||
scrollPane(constraints : BorderLayout.CENTER) {
|
||||
table(id : "shared-files-table", autoCreateRowSorter: true) {
|
||||
tableModel(list : model.shared) {
|
||||
closureColumn(header : "Name", preferredWidth : 500, type : String, read : {row -> row.getCachedPath()})
|
||||
closureColumn(header : "Size", preferredWidth : 100, type : Long, read : {row -> row.getCachedLength() })
|
||||
closureColumn(header : "Comments", preferredWidth : 100, type : Boolean, read : {it.getComment() != null})
|
||||
if (!settings.sharedFilesAsTree) {
|
||||
table(id : "shared-files-table", autoCreateRowSorter: true) {
|
||||
tableModel(list : model.shared) {
|
||||
closureColumn(header : "Name", preferredWidth : 500, type : String, read : {row -> row.getCachedPath()})
|
||||
closureColumn(header : "Size", preferredWidth : 100, type : Long, read : {row -> row.getCachedLength() })
|
||||
closureColumn(header : "Comments", preferredWidth : 100, type : Boolean, read : {it.getComment() != null})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
def jtree = new JTree(model.sharedTree)
|
||||
jtree.setCellRenderer(new SharedTreeRenderer())
|
||||
tree(id : "shared-files-tree", rootVisible : false, jtree)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +238,7 @@ class MainFrameView {
|
|||
gridLayout(rows : 1, cols : 2)
|
||||
panel {
|
||||
label("Shared:")
|
||||
label(text : bind {model.loadedFiles.toString()})
|
||||
label(text : bind {model.loadedFiles}, id : "shared-files-count")
|
||||
}
|
||||
panel {
|
||||
button(text : "Add Comment", enabled : bind {model.addCommentButtonEnabled}, addCommentAction)
|
||||
|
@ -489,13 +500,7 @@ class MainFrameView {
|
|||
}
|
||||
})
|
||||
|
||||
// shared files table
|
||||
def sharedFilesTable = builder.getVariable("shared-files-table")
|
||||
sharedFilesTable.columnModel.getColumn(1).setCellRenderer(new SizeRenderer())
|
||||
|
||||
sharedFilesTable.rowSorter.addRowSorterListener({evt -> lastSharedSortEvent = evt})
|
||||
sharedFilesTable.rowSorter.setSortsOnUpdates(true)
|
||||
|
||||
// shared files menu
|
||||
JPopupMenu sharedFilesMenu = new JPopupMenu()
|
||||
JMenuItem copyHashToClipboard = new JMenuItem("Copy hash to clipboard")
|
||||
copyHashToClipboard.addActionListener({mvcGroup.view.copyHashToClipboard()})
|
||||
|
@ -506,7 +511,8 @@ class MainFrameView {
|
|||
JMenuItem commentSelectedFiles = new JMenuItem("Comment selected files")
|
||||
commentSelectedFiles.addActionListener({mvcGroup.controller.addComment()})
|
||||
sharedFilesMenu.add(commentSelectedFiles)
|
||||
sharedFilesTable.addMouseListener(new MouseAdapter() {
|
||||
|
||||
def sharedFilesMouseListener = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if (e.isPopupTrigger())
|
||||
|
@ -517,15 +523,36 @@ class MainFrameView {
|
|||
if (e.isPopupTrigger())
|
||||
showPopupMenu(sharedFilesMenu, e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
selectionModel = sharedFilesTable.getSelectionModel()
|
||||
selectionModel.addListSelectionListener({
|
||||
def selectedFiles = selectedSharedFiles()
|
||||
if (selectedFiles == null || selectedFiles.isEmpty())
|
||||
return
|
||||
model.addCommentButtonEnabled = true
|
||||
})
|
||||
// shared files table or tree
|
||||
if (!settings.sharedFilesAsTree) {
|
||||
def sharedFilesTable = builder.getVariable("shared-files-table")
|
||||
sharedFilesTable.columnModel.getColumn(1).setCellRenderer(new SizeRenderer())
|
||||
|
||||
sharedFilesTable.rowSorter.addRowSorterListener({evt -> lastSharedSortEvent = evt})
|
||||
sharedFilesTable.rowSorter.setSortsOnUpdates(true)
|
||||
|
||||
sharedFilesTable.addMouseListener(sharedFilesMouseListener)
|
||||
|
||||
selectionModel = sharedFilesTable.getSelectionModel()
|
||||
selectionModel.addListSelectionListener({
|
||||
def selectedFiles = selectedSharedFiles()
|
||||
if (selectedFiles == null || selectedFiles.isEmpty())
|
||||
return
|
||||
model.addCommentButtonEnabled = true
|
||||
})
|
||||
} else {
|
||||
def sharedFilesTree = builder.getVariable("shared-files-tree")
|
||||
sharedFilesTree.addMouseListener(sharedFilesMouseListener)
|
||||
|
||||
sharedFilesTree.addTreeSelectionListener({
|
||||
def selectedNode = sharedFilesTree.getLastSelectedPathComponent()
|
||||
model.addCommentButtonEnabled = selectedNode != null
|
||||
|
||||
})
|
||||
// TODO: other stuff
|
||||
}
|
||||
|
||||
// searches table
|
||||
def searchesTable = builder.getVariable("searches-table")
|
||||
|
@ -656,20 +683,40 @@ class MainFrameView {
|
|||
}
|
||||
|
||||
def selectedSharedFiles() {
|
||||
def sharedFilesTable = builder.getVariable("shared-files-table")
|
||||
int[] selected = sharedFilesTable.getSelectedRows()
|
||||
if (selected.length == 0)
|
||||
return null
|
||||
List<SharedFile> rv = new ArrayList<>()
|
||||
if (lastSharedSortEvent != null) {
|
||||
for (int i = 0; i < selected.length; i ++) {
|
||||
selected[i] = sharedFilesTable.rowSorter.convertRowIndexToModel(selected[i])
|
||||
if (!settings.sharedFilesAsTree) {
|
||||
def sharedFilesTable = builder.getVariable("shared-files-table")
|
||||
int[] selected = sharedFilesTable.getSelectedRows()
|
||||
if (selected.length == 0)
|
||||
return null
|
||||
List<SharedFile> rv = new ArrayList<>()
|
||||
if (lastSharedSortEvent != null) {
|
||||
for (int i = 0; i < selected.length; i ++) {
|
||||
selected[i] = sharedFilesTable.rowSorter.convertRowIndexToModel(selected[i])
|
||||
}
|
||||
}
|
||||
selected.each {
|
||||
rv.add(model.shared[it])
|
||||
}
|
||||
return rv
|
||||
} else {
|
||||
def sharedFilesTree = builder.getVariable("shared-files-tree")
|
||||
List<SharedFile> rv = new ArrayList<>()
|
||||
for (TreePath path : sharedFilesTree.getSelectionPaths()) {
|
||||
getLeafs(path.getLastPathComponent(), rv)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
selected.each {
|
||||
rv.add(model.shared[it])
|
||||
}
|
||||
|
||||
private static void getLeafs(TreeNode node, List<SharedFile> dest) {
|
||||
if (node.isLeaf()) {
|
||||
dest.add(node.getUserObject())
|
||||
return
|
||||
}
|
||||
def children = node.children()
|
||||
while(children.hasMoreElements()) {
|
||||
getLeafs(children.nextElement(), dest)
|
||||
}
|
||||
rv
|
||||
}
|
||||
|
||||
def copyHashToClipboard() {
|
||||
|
@ -876,4 +923,12 @@ class MainFrameView {
|
|||
selectedRow = table.rowSorter.convertRowIndexToModel(selectedRow)
|
||||
selectedRow
|
||||
}
|
||||
|
||||
public void refreshSharedFiles() {
|
||||
if (settings.sharedFilesAsTree) {
|
||||
model.sharedTree.nodeStructureChanged(model.treeRoot)
|
||||
} else {
|
||||
builder.getVariable("shared-files-table").model.fireTableDataChanged()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -126,6 +126,12 @@ class OptionsView {
|
|||
excludeLocalResultCheckbox = checkBox(selected : bind {model.excludeLocalResult}, constraints : gbc(gridx: 1, gridy : 6))
|
||||
// label(text : "Show Hash Searches In Monitor", constraints: gbc(gridx:0, gridy:7))
|
||||
// showSearchHashesCheckbox = checkBox(selected : bind {model.showSearchHashes}, constraints : gbc(gridx: 1, gridy: 7))
|
||||
label(text : "Show Shared Files as", constraints: gbc(gridx: 0, gridy:8))
|
||||
panel( constraints : gbc(gridx: 1, gridy: 8)) {
|
||||
buttonGroup(id : "viewShared")
|
||||
radioButton(text: "Tree", selected : bind {model.sharedFilesAsTree}, buttonGroup: viewShared, sharedTreeAction)
|
||||
radioButton(text: "Table", selected : bind {!model.sharedFilesAsTree}, buttonGroup: viewShared, sharedTableAction)
|
||||
}
|
||||
}
|
||||
bandwidth = builder.panel {
|
||||
gridBagLayout()
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package com.muwire.gui
|
||||
|
||||
import java.awt.Component
|
||||
|
||||
import javax.swing.ImageIcon
|
||||
import javax.swing.JTree
|
||||
import javax.swing.tree.DefaultTreeCellRenderer
|
||||
|
||||
import com.muwire.core.SharedFile
|
||||
|
||||
import net.i2p.data.DataHelper
|
||||
|
||||
class SharedTreeRenderer extends DefaultTreeCellRenderer {
|
||||
|
||||
private final ImageIcon commentIcon
|
||||
|
||||
SharedTreeRenderer() {
|
||||
commentIcon = new ImageIcon((URL) SharedTreeRenderer.class.getResource("/comment.png"))
|
||||
}
|
||||
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value,
|
||||
boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
|
||||
def userObject = value.getUserObject()
|
||||
def defaultRenderer = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus)
|
||||
if (userObject instanceof String || userObject == null)
|
||||
return defaultRenderer
|
||||
|
||||
|
||||
SharedFile sf = (SharedFile) userObject
|
||||
String name = sf.getFile().getName()
|
||||
long length = sf.getCachedLength()
|
||||
String formatted = DataHelper.formatSize2Decimal(length, false)+"B"
|
||||
|
||||
|
||||
setText("$name ($formatted)")
|
||||
setEnabled(true)
|
||||
if (sf.comment != null) {
|
||||
setIcon(commentIcon)
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ class UISettings {
|
|||
boolean clearFinishedDownloads
|
||||
boolean excludeLocalResult
|
||||
boolean showSearchHashes
|
||||
boolean sharedFilesAsTree
|
||||
|
||||
UISettings(Properties props) {
|
||||
lnf = props.getProperty("lnf", "system")
|
||||
|
@ -18,6 +19,7 @@ class UISettings {
|
|||
clearFinishedDownloads = Boolean.parseBoolean(props.getProperty("clearFinishedDownloads","false"))
|
||||
excludeLocalResult = Boolean.parseBoolean(props.getProperty("excludeLocalResult","true"))
|
||||
showSearchHashes = Boolean.parseBoolean(props.getProperty("showSearchHashes","true"))
|
||||
sharedFilesAsTree = Boolean.parseBoolean(props.getProperty("sharedFilesAsTree","true"))
|
||||
}
|
||||
|
||||
void write(OutputStream out) throws IOException {
|
||||
|
@ -28,6 +30,7 @@ class UISettings {
|
|||
props.setProperty("clearFinishedDownloads", String.valueOf(clearFinishedDownloads))
|
||||
props.setProperty("excludeLocalResult", String.valueOf(excludeLocalResult))
|
||||
props.setProperty("showSearchHashes", String.valueOf(showSearchHashes))
|
||||
props.setProperty("sharedFilesAsTree", String.valueOf(sharedFilesAsTree))
|
||||
if (font != null)
|
||||
props.setProperty("font", font)
|
||||
|
||||
|
|
Loading…
Reference in New Issue