From b28587a275711562d2b437bc0915f0040a90f2de Mon Sep 17 00:00:00 2001 From: Zlatin Balevsky Date: Fri, 11 Oct 2019 18:42:02 +0100 Subject: [PATCH] wip on file comments --- .../muwire/core/files/PersisterService.groovy | 3 + .../muwire/core/search/ResultsParser.groovy | 5 ++ .../muwire/core/search/ResultsSender.groovy | 3 + .../muwire/core/search/UIResultEvent.groovy | 1 + .../main/java/com/muwire/core/SharedFile.java | 10 +++ gui/griffon-app/conf/Config.groovy | 10 +++ .../muwire/gui/AddCommentController.groovy | 39 +++++++++++ .../com/muwire/gui/MainFrameController.groovy | 11 +++ .../muwire/gui/ShowCommentController.groovy | 19 ++++++ .../com/muwire/gui/AddCommentModel.groovy | 12 ++++ .../com/muwire/gui/MainFrameModel.groovy | 1 + .../com/muwire/gui/ShowCommentModel.groovy | 12 ++++ .../com/muwire/gui/AddCommentView.groovy | 68 +++++++++++++++++++ .../views/com/muwire/gui/MainFrameView.groovy | 22 +++++- .../views/com/muwire/gui/SearchTabView.groovy | 29 ++++++++ .../com/muwire/gui/ShowCommentView.groovy | 63 +++++++++++++++++ 16 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 gui/griffon-app/controllers/com/muwire/gui/AddCommentController.groovy create mode 100644 gui/griffon-app/controllers/com/muwire/gui/ShowCommentController.groovy create mode 100644 gui/griffon-app/models/com/muwire/gui/AddCommentModel.groovy create mode 100644 gui/griffon-app/models/com/muwire/gui/ShowCommentModel.groovy create mode 100644 gui/griffon-app/views/com/muwire/gui/AddCommentView.groovy create mode 100644 gui/griffon-app/views/com/muwire/gui/ShowCommentView.groovy diff --git a/core/src/main/groovy/com/muwire/core/files/PersisterService.groovy b/core/src/main/groovy/com/muwire/core/files/PersisterService.groovy index 2a947930..720eb96b 100644 --- a/core/src/main/groovy/com/muwire/core/files/PersisterService.groovy +++ b/core/src/main/groovy/com/muwire/core/files/PersisterService.groovy @@ -115,11 +115,13 @@ class PersisterService extends Service { List sources = (List)json.sources Set sourceSet = sources.stream().map({d -> new Destination(d.toString())}).collect Collectors.toSet() DownloadedFile df = new DownloadedFile(file, ih, pieceSize, sourceSet) + df.setComment(json.comment) return new FileLoadedEvent(loadedFile : df) } SharedFile sf = new SharedFile(file, ih, pieceSize) + sf.setComment(json.comment) return new FileLoadedEvent(loadedFile: sf) } @@ -148,6 +150,7 @@ class PersisterService extends Service { json.infoHash = sf.getB64EncodedHashRoot() json.pieceSize = sf.getPieceSize() json.hashList = sf.getB64EncodedHashList() + json.comment = sf.getComment() if (sf instanceof DownloadedFile) { json.sources = sf.sources.stream().map( {d -> d.toBase64()}).collect(Collectors.toList()) diff --git a/core/src/main/groovy/com/muwire/core/search/ResultsParser.groovy b/core/src/main/groovy/com/muwire/core/search/ResultsParser.groovy index 5be464e2..60315c8e 100644 --- a/core/src/main/groovy/com/muwire/core/search/ResultsParser.groovy +++ b/core/src/main/groovy/com/muwire/core/search/ResultsParser.groovy @@ -90,6 +90,10 @@ class ResultsParser { Set sources = Collections.emptySet() if (json.sources != null) sources = json.sources.stream().map({new Destination(it)}).collect(Collectors.toSet()) + + String comment = null + if (json.comment != null) + comment = DataUtil.readi18nString(Base64.decode(json.comment)) return new UIResultEvent( sender : p, name : name, @@ -97,6 +101,7 @@ class ResultsParser { infohash : new InfoHash(infoHash), pieceSize : pieceSize, sources : sources, + comment : comment, uuid: uuid) } catch (Exception e) { throw new InvalidSearchResultException("parsing search result failed",e) diff --git a/core/src/main/groovy/com/muwire/core/search/ResultsSender.groovy b/core/src/main/groovy/com/muwire/core/search/ResultsSender.groovy index 70b9d188..6a655701 100644 --- a/core/src/main/groovy/com/muwire/core/search/ResultsSender.groovy +++ b/core/src/main/groovy/com/muwire/core/search/ResultsSender.groovy @@ -121,6 +121,9 @@ class ResultsSender { if (it instanceof DownloadedFile) obj.sources = it.sources.stream().map({dest -> dest.toBase64()}).collect(Collectors.toSet()) + + if (it.getComment() != null) + obj.comment = it.getComment() def json = jsonOutput.toJson(obj) os.writeShort((short)json.length()) diff --git a/core/src/main/groovy/com/muwire/core/search/UIResultEvent.groovy b/core/src/main/groovy/com/muwire/core/search/UIResultEvent.groovy index ef9a792e..6acff265 100644 --- a/core/src/main/groovy/com/muwire/core/search/UIResultEvent.groovy +++ b/core/src/main/groovy/com/muwire/core/search/UIResultEvent.groovy @@ -14,6 +14,7 @@ class UIResultEvent extends Event { long size InfoHash infohash int pieceSize + String comment @Override public String toString() { diff --git a/core/src/main/java/com/muwire/core/SharedFile.java b/core/src/main/java/com/muwire/core/SharedFile.java index 22006f80..1860b91e 100644 --- a/core/src/main/java/com/muwire/core/SharedFile.java +++ b/core/src/main/java/com/muwire/core/SharedFile.java @@ -21,6 +21,8 @@ public class SharedFile { private final String b64EncodedFileName; private final String b64EncodedHashRoot; private final List b64EncodedHashList; + + private volatile String comment; public SharedFile(File file, InfoHash infoHash, int pieceSize) throws IOException { this.file = file; @@ -80,6 +82,14 @@ public class SharedFile { public long getCachedLength() { return cachedLength; } + + public void setComment(String comment) { + this.comment = comment; + } + + public String getComment() { + return comment; + } @Override public int hashCode() { diff --git a/gui/griffon-app/conf/Config.groovy b/gui/griffon-app/conf/Config.groovy index 79f10922..7333f769 100644 --- a/gui/griffon-app/conf/Config.groovy +++ b/gui/griffon-app/conf/Config.groovy @@ -46,4 +46,14 @@ mvcGroups { view = 'com.muwire.gui.ContentPanelView' controller = 'com.muwire.gui.ContentPanelController' } + 'show-comment' { + model = 'com.muwire.gui.ShowConmmentModel' + view = 'com.muwire.gui.ShowCommentView' + controller = 'com.muwire.gui.ShowCommentController' + } + 'add-comment' { + model = 'com.muwire.gui.AddCommentModel' + view = 'com.muwire.gui.AddCommentView' + controller = 'com.muwire.gui.AddCommentController' + } } diff --git a/gui/griffon-app/controllers/com/muwire/gui/AddCommentController.groovy b/gui/griffon-app/controllers/com/muwire/gui/AddCommentController.groovy new file mode 100644 index 00000000..3f5050be --- /dev/null +++ b/gui/griffon-app/controllers/com/muwire/gui/AddCommentController.groovy @@ -0,0 +1,39 @@ +package com.muwire.gui + +import griffon.core.artifact.GriffonController +import griffon.core.controller.ControllerAction +import griffon.inject.MVCMember +import griffon.metadata.ArtifactProviderFor +import net.i2p.data.Base64 + +import javax.annotation.Nonnull + +import com.muwire.core.util.DataUtil + +@ArtifactProviderFor(GriffonController) +class AddCommentController { + @MVCMember @Nonnull + AddCommentModel model + @MVCMember @Nonnull + AddCommentView view + + @ControllerAction + void save() { + String comment = view.textarea.getText() + if (comment.trim().length() == 0) + comment = null + else + comment = Base64.encode(DataUtil.encodei18nString(comment)) + model.selectedFiles.each { + it.setComment(comment) + } + mvcGroup.parentGroup.view.builder.getVariable("shared-files-table").model.fireTableDataChanged() + cancel() + } + + @ControllerAction + void cancel() { + view.dialog.setVisible(false) + mvcGroup.destroy() + } +} \ No newline at end of file diff --git a/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy b/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy index a5ee34f0..d87c635f 100644 --- a/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy +++ b/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy @@ -277,6 +277,17 @@ class MainFrameController { core.eventBus.publish(new FileUnsharedEvent(unsharedFile : it)) } } + + @ControllerAction + void addComment() { + def selectedFiles = view.selectedSharedFiles() + if (selectedFiles == null || selectedFiles.isEmpty()) + return + + Map params = new HashMap<>() + params['selectedFiles'] = selectedFiles + mvcGroup.createMVCGroup("add-comment", "Add Comment", params) + } void stopWatchingDirectory() { String directory = mvcGroup.view.getSelectedWatchedDirectory() diff --git a/gui/griffon-app/controllers/com/muwire/gui/ShowCommentController.groovy b/gui/griffon-app/controllers/com/muwire/gui/ShowCommentController.groovy new file mode 100644 index 00000000..eee43320 --- /dev/null +++ b/gui/griffon-app/controllers/com/muwire/gui/ShowCommentController.groovy @@ -0,0 +1,19 @@ +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 ShowCommentController { + @MVCMember @Nonnull + ShowCommentView view + + @ControllerAction + void dismiss() { + view.dialog.setVisible(false) + mvcGroup.destroy() + } +} \ No newline at end of file diff --git a/gui/griffon-app/models/com/muwire/gui/AddCommentModel.groovy b/gui/griffon-app/models/com/muwire/gui/AddCommentModel.groovy new file mode 100644 index 00000000..286247ca --- /dev/null +++ b/gui/griffon-app/models/com/muwire/gui/AddCommentModel.groovy @@ -0,0 +1,12 @@ +package com.muwire.gui + +import com.muwire.core.SharedFile + +import griffon.core.artifact.GriffonModel +import griffon.transform.Observable +import griffon.metadata.ArtifactProviderFor + +@ArtifactProviderFor(GriffonModel) +class AddCommentModel { + List selectedFiles +} \ No newline at end of file diff --git a/gui/griffon-app/models/com/muwire/gui/MainFrameModel.groovy b/gui/griffon-app/models/com/muwire/gui/MainFrameModel.groovy index b431cecd..0cac1ccd 100644 --- a/gui/griffon-app/models/com/muwire/gui/MainFrameModel.groovy +++ b/gui/griffon-app/models/com/muwire/gui/MainFrameModel.groovy @@ -81,6 +81,7 @@ class MainFrameModel { @Observable boolean pauseButtonEnabled @Observable boolean clearButtonEnabled @Observable String resumeButtonText + @Observable boolean addCommentButtonEnabled @Observable boolean subscribeButtonEnabled @Observable boolean markNeutralFromTrustedButtonEnabled @Observable boolean markDistrustedButtonEnabled diff --git a/gui/griffon-app/models/com/muwire/gui/ShowCommentModel.groovy b/gui/griffon-app/models/com/muwire/gui/ShowCommentModel.groovy new file mode 100644 index 00000000..08b597f1 --- /dev/null +++ b/gui/griffon-app/models/com/muwire/gui/ShowCommentModel.groovy @@ -0,0 +1,12 @@ +package com.muwire.gui + +import com.muwire.core.search.UIResultEvent + +import griffon.core.artifact.GriffonModel +import griffon.transform.Observable +import griffon.metadata.ArtifactProviderFor + +@ArtifactProviderFor(GriffonModel) +class ShowCommentModel { + UIResultEvent result +} \ No newline at end of file diff --git a/gui/griffon-app/views/com/muwire/gui/AddCommentView.groovy b/gui/griffon-app/views/com/muwire/gui/AddCommentView.groovy new file mode 100644 index 00000000..31058c97 --- /dev/null +++ b/gui/griffon-app/views/com/muwire/gui/AddCommentView.groovy @@ -0,0 +1,68 @@ +package com.muwire.gui + +import griffon.core.artifact.GriffonView +import griffon.inject.MVCMember +import griffon.metadata.ArtifactProviderFor +import net.i2p.data.Base64 + +import javax.swing.JDialog +import javax.swing.SwingConstants + +import com.muwire.core.util.DataUtil + +import java.awt.BorderLayout +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent + +import javax.annotation.Nonnull + +@ArtifactProviderFor(GriffonView) +class AddCommentView { + @MVCMember @Nonnull + FactoryBuilderSupport builder + @MVCMember @Nonnull + AddCommentModel model + + def mainFrame + def dialog + def p + def textarea + + void initUI() { + mainFrame = application.windowManager.findWindow("main-frame") + String title = "Add comment to multiple files" + String comment = "" + if (model.selectedFiles.size() == 1) { + title = "Add comments to " + model.selectedFiles[0].getFile().getName() + if (model.selectedFiles[0].comment != null) + comment = DataUtil.readi18nString(Base64.decode(model.selectedFiles[0].comment)) + } + dialog = new JDialog(mainFrame, title, true) + + p = builder.panel { + borderLayout() + panel (constraints : BorderLayout.CENTER) { + scrollPane { + textarea = textArea(text : comment, rows : 20, columns : 100, editable : true) + } + } + panel (constraints : BorderLayout.SOUTH) { + button(text : "Save", saveAction) + button(text : "Cancel", cancelAction) + } + } + } + + void mvcGroupInit(Map args) { + dialog.getContentPane().add(p) + dialog.pack() + dialog.setLocationRelativeTo(mainFrame) + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE) + dialog.addWindowListener( new WindowAdapter() { + public void windowClosed(WindowEvent e) { + mvcGroup.destroy() + } + }) + dialog.show() + } +} \ No newline at end of file diff --git a/gui/griffon-app/views/com/muwire/gui/MainFrameView.groovy b/gui/griffon-app/views/com/muwire/gui/MainFrameView.groovy index 16e93f31..79b5a10f 100644 --- a/gui/griffon-app/views/com/muwire/gui/MainFrameView.groovy +++ b/gui/griffon-app/views/com/muwire/gui/MainFrameView.groovy @@ -209,6 +209,7 @@ class MainFrameView { 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}) } } } @@ -221,8 +222,14 @@ class MainFrameView { button(text : "Share files", actionPerformed : shareFiles) } panel { - label("Shared:") - label(text : bind {model.loadedFiles.toString()}) + gridLayout(rows : 1, cols : 2) + panel { + label("Shared:") + label(text : bind {model.loadedFiles.toString()}) + } + panel { + button(text : "Add Comment", enabled : bind {model.addCommentButtonEnabled}, addCommentAction) + } } } } @@ -475,6 +482,9 @@ class MainFrameView { JMenuItem unshareSelectedFiles = new JMenuItem("Unshare selected files") unshareSelectedFiles.addActionListener({mvcGroup.controller.unshareSelectedFile()}) sharedFilesMenu.add(unshareSelectedFiles) + JMenuItem commentSelectedFiles = new JMenuItem("Comment selected files") + commentSelectedFiles.addActionListener({mvcGroup.controller.addComment()}) + sharedFilesMenu.add(commentSelectedFiles) sharedFilesTable.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { @@ -487,6 +497,14 @@ class MainFrameView { showPopupMenu(sharedFilesMenu, e) } }) + + selectionModel = sharedFilesTable.getSelectionModel() + selectionModel.addListSelectionListener({ + def selectedFiles = selectedSharedFiles() + if (selectedFiles == null || selectedFiles.isEmpty()) + return + model.addCommentButtonEnabled = true + }) // searches table def searchesTable = builder.getVariable("searches-table") diff --git a/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy b/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy index 91bd26c3..3b686bd2 100644 --- a/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy +++ b/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy @@ -18,6 +18,7 @@ import javax.swing.SwingConstants import javax.swing.table.DefaultTableCellRenderer import com.muwire.core.Persona +import com.muwire.core.search.UIResultEvent import com.muwire.core.util.DataUtil import java.awt.BorderLayout @@ -83,6 +84,7 @@ class SearchTabView { closureColumn(header: "Size", preferredWidth: 20, type: Long, read : {row -> row.size}) closureColumn(header: "Direct Sources", preferredWidth: 50, type : Integer, read : { row -> model.hashBucket[row.infohash].size()}) closureColumn(header: "Possible Sources", preferredWidth : 50, type : Integer, read : {row -> model.sourcesBucket[row.infohash].size()}) + closureColumn(header: "Comments", preferredWidth: 20, type: Boolean, read : {row -> row.comment != null}) } } } @@ -225,6 +227,16 @@ class SearchTabView { copyHashToClipboard.addActionListener({mvcGroup.view.copyHashToClipboard()}) menu.add(copyHashToClipboard) showMenu = true + + // show comment if any + int selectedRow = resultsTable.getSelectedRow() + if (lastSortEvent != null) + selectedRow = resultsTable.rowSorter.convertRowIndexToModel(selectedRow) + if (model.results[selectedRow].comment != null) { + JMenuItem showComment = new JMenuItem("Show Comment") + showComment.addActionListener({mvcGroup.view.showComment()}) + menu.add(showComment) + } } if (showMenu) menu.show(e.getComponent(), e.getX(), e.getY()) @@ -243,6 +255,23 @@ class SearchTabView { clipboard.setContents(selection, null) } + def showComment() { + int selectedRow = resultsTable.getSelectedRow() + if (selectedRow < 0) + return + if (lastSortEvent != null) + selectedRow = resultsTable.rowSorter.convertRowIndexToModel(selectedRow) + UIResultEvent event = model.results[selectedRow] + if (event.comment == null) + return + + String groupId = Base64.encode(event.infohash.getRoot()) + Map params = new HashMap<>() + params['result'] = event + + mvcGroup.createMVCGroup("show-comment", groupId, params) + } + int selectedSenderRow() { int row = sendersTable.getSelectedRow() if (row < 0) diff --git a/gui/griffon-app/views/com/muwire/gui/ShowCommentView.groovy b/gui/griffon-app/views/com/muwire/gui/ShowCommentView.groovy new file mode 100644 index 00000000..b211d112 --- /dev/null +++ b/gui/griffon-app/views/com/muwire/gui/ShowCommentView.groovy @@ -0,0 +1,63 @@ +package com.muwire.gui + +import griffon.core.artifact.GriffonView +import griffon.inject.MVCMember +import griffon.metadata.ArtifactProviderFor +import net.i2p.data.Base64 + +import javax.swing.JDialog +import javax.swing.SwingConstants + +import com.muwire.core.util.DataUtil + +import java.awt.BorderLayout +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent + +import javax.annotation.Nonnull + +@ArtifactProviderFor(GriffonView) +class ShowCommentView { + @MVCMember @Nonnull + FactoryBuilderSupport builder + @MVCMember @Nonnull + ShowCommentModel model + + def mainFrame + def dialog + def p + + void initUI() { + mainFrame = application.windowManager.findWindow("main-frame") + dialog = new JDialog(mainFrame, model.result.name, true) + dialog.setResizable(true) + + + String comment = DataUtil.readi18nString(Base64.decode(model.result.comment)) + + p = builder.panel { + borderLayout() + panel (constraints : BorderLayout.CENTER) { + scrollPane { + textArea(text : comment, rows : 20, columns : 100, editable : false) + } + } + panel (constraints : BorderLayout.SOUTH) { + button(text : "Dismiss", dismissAction) + } + } + } + + void mvcGroupInit(Map args) { + dialog.getContentPane().add(p) + dialog.pack() + dialog.setLocationRelativeTo(mainFrame) + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE) + dialog.addWindowListener( new WindowAdapter() { + public void windowClosed(WindowEvent e) { + mvcGroup.destroy() + } + }) + dialog.show() + } +} \ No newline at end of file