From 08652d7d5a915d80974a81f973a776e301c3ca03 Mon Sep 17 00:00:00 2001 From: Zlatin Balevsky Date: Sun, 10 Oct 2021 01:52:04 +0100 Subject: [PATCH] working downloads and popup menu --- .../com/muwire/gui/SearchTabController.groovy | 39 ++-- .../views/com/muwire/gui/BrowseView.groovy | 19 +- .../views/com/muwire/gui/SearchTabView.groovy | 170 ++++++++++++------ .../groovy/com/muwire/gui/ResultTree.groovy | 15 ++ 4 files changed, 146 insertions(+), 97 deletions(-) diff --git a/gui/griffon-app/controllers/com/muwire/gui/SearchTabController.groovy b/gui/griffon-app/controllers/com/muwire/gui/SearchTabController.groovy index 461be940..f1c616a8 100644 --- a/gui/griffon-app/controllers/com/muwire/gui/SearchTabController.groovy +++ b/gui/griffon-app/controllers/com/muwire/gui/SearchTabController.groovy @@ -28,43 +28,30 @@ class SearchTabController { Core core - private def selectedResults() { - if (model.groupedByFile) { - return [view.getSelectedResult()] - } else { - int[] rows = view.resultsTable.getSelectedRows() - if (rows.length == 0) - return null - def sortEvt = view.lastSortEvent - if (sortEvt != null) { - for (int i = 0; i < rows.length; i++) { - rows[i] = view.resultsTable.rowSorter.convertRowIndexToModel(rows[i]) - } - } - List results = new ArrayList<>() - rows.each { results.add(model.results[it]) } - return results - } - } - @ControllerAction void download() { - def results = selectedResults() - if (results == null) + def results = view.selectedResults() + if (results == null || results.isEmpty()) return results.removeAll { !mvcGroup.parentGroup.model.canDownload(it.infohash) } - results.each { result -> - def file = new File(application.context.get("muwire-settings").downloadLocation, result.name) + File downloadsFolder = application.context.get("muwire-settings").downloadLocation + List targets = view.decorateResults(results) + + targets.each { target -> + File file = new File(downloadsFolder, target.target.toString()) + File parent = null + if (target.parent != null) + parent = new File(downloadsFolder, target.parent.toString()) - def resultsBucket = model.hashBucket[result.infohash] - def sources = model.sourcesBucket[result.infohash] + def resultsBucket = model.hashBucket[target.resultEvent.infohash] + def sources = model.sourcesBucket[target.resultEvent.infohash] core.eventBus.publish(new UIDownloadEvent(result : resultsBucket, sources: sources, - target : file, sequential : view.sequentialDownload())) + target : file, toShare: parent, sequential : view.sequentialDownload())) } mvcGroup.parentGroup.view.showDownloadsWindow.call() } diff --git a/gui/griffon-app/views/com/muwire/gui/BrowseView.groovy b/gui/griffon-app/views/com/muwire/gui/BrowseView.groovy index ea2cbb2e..254b2188 100644 --- a/gui/griffon-app/views/com/muwire/gui/BrowseView.groovy +++ b/gui/griffon-app/views/com/muwire/gui/BrowseView.groovy @@ -78,8 +78,7 @@ class BrowseView { borderLayout() scrollPane(constraints: BorderLayout.CENTER) { resultsTree = new ResultTree(model.resultsTreeModel) - tree(id: "results-tree", rowHeight: rowHeight, rootVisible: false, expandsSelectedPaths: true, - largeModel: true, resultsTree) + tree(id: "results-tree", rowHeight: rowHeight, resultsTree) } } } @@ -123,7 +122,6 @@ class BrowseView { } // results tree - JTree resultsTree = builder.getVariable("results-tree") resultsTree.addTreeExpansionListener(treeExpansions) resultsTree.addMouseListener(mouseListener) resultsTree.addTreeSelectionListener({ @@ -137,14 +135,11 @@ class BrowseView { } model.downloadActionEnabled = true - if (selected.length == 1) { - def userObject = selected[0].getLastPathComponent().getUserObject() - if (userObject instanceof UIResultEvent) { - UIResultEvent result = (UIResultEvent) userObject - model.viewCommentActionEnabled = result.comment != null - model.viewCollectionsActionEnabled = !result.collections.isEmpty() - model.viewCertificatesActionEnabled = result.certificates > 0 - } + UIResultEvent result = resultsTree.singleResultSelected() + if (result != null) { + model.viewCommentActionEnabled = result.comment != null + model.viewCollectionsActionEnabled = !result.collections.isEmpty() + model.viewCertificatesActionEnabled = result.certificates > 0 } }) @@ -340,7 +335,7 @@ class BrowseView { List rv = new ArrayList<>() for (Integer i : rows) rv << model.results[i] - rv + return rv } } diff --git a/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy b/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy index b358075f..7bb3c5cb 100644 --- a/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy +++ b/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy @@ -3,6 +3,7 @@ package com.muwire.gui import griffon.core.artifact.GriffonView import javax.swing.JPanel +import javax.swing.tree.TreePath import static com.muwire.gui.Translator.trans import griffon.core.mvc.MVCGroup @@ -43,6 +44,8 @@ class SearchTabView { FactoryBuilderSupport builder @MVCMember @Nonnull SearchTabModel model + @MVCMember @Nonnull + SearchTabController controller UISettings settings @@ -54,7 +57,6 @@ class SearchTabView { def resultsTable, resultsTable2 private JPanel resultsPanel private ResultTree resultTree - def treeExpansions = new TreeExpansions() def lastSortEvent def lastResults2SortEvent, lastSenders2SortEvent @@ -64,12 +66,7 @@ class SearchTabView { void initUI() { int rowHeight = application.context.get("row-height") - builder.with { - def resultsTable, resultsTable2 - def sendersTable, sendersTable2 - def sequentialDownloadCheckbox, sequentialDownloadCheckbox2 - JPanel resultsPanel - def pane = panel { + pane = builder.panel { borderLayout() panel (id : "results-panel", constraints : BorderLayout.CENTER) { cardLayout() @@ -135,8 +132,7 @@ class SearchTabView { borderLayout() scrollPane(constraints: BorderLayout.CENTER) { resultTree = new ResultTree(model.treeModel) - tree(id: "results-tree", rowHeight: rowHeight, rootVisible: false, - expandsSelectedPaths: true, largeModel: true, resultTree) + tree(id: "results-tree", rowHeight: rowHeight, resultTree) } } } @@ -290,38 +286,28 @@ class SearchTabView { } } - this.pane = pane - this.pane.putClientProperty("mvc-group", mvcGroup) - this.pane.putClientProperty("results-table",resultsTable) + this.pane.putClientProperty("mvc-group", mvcGroup) + this.pane.putClientProperty("results-table",resultsTable) - this.resultsTable = resultsTable - this.sendersTable = sendersTable - this.resultsTable2 = resultsTable2 - this.sendersTable2 = sendersTable2 - this.sequentialDownloadCheckbox = sequentialDownloadCheckbox - this.sequentialDownloadCheckbox2 = sequentialDownloadCheckbox2 - this.resultsPanel = resultsPanel - - def selectionModel = resultsTable.getSelectionModel() - selectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) - selectionModel.addListSelectionListener( { - int[] rows = resultsTable.getSelectedRows() - if (rows.length == 0) { - model.downloadActionEnabled = false - return + def selectionModel = resultsTable.getSelectionModel() + selectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) + selectionModel.addListSelectionListener( { + int[] rows = resultsTable.getSelectedRows() + if (rows.length == 0) { + model.downloadActionEnabled = false + return + } + if (lastSortEvent != null) { + for (int i = 0; i < rows.length; i ++) { + rows[i] = resultsTable.rowSorter.convertRowIndexToModel(rows[i]) } - if (lastSortEvent != null) { - for (int i = 0; i < rows.length; i ++) { - rows[i] = resultsTable.rowSorter.convertRowIndexToModel(rows[i]) - } - } - boolean downloadActionEnabled = true - rows.each { - downloadActionEnabled &= mvcGroup.parentGroup.model.canDownload(model.results[it].infohash) - } - model.downloadActionEnabled = downloadActionEnabled - }) - } + } + boolean downloadActionEnabled = true + rows.each { + downloadActionEnabled &= mvcGroup.parentGroup.model.canDownload(model.results[it].infohash) + } + model.downloadActionEnabled = downloadActionEnabled + }) } void mvcGroupInit(Map args) { @@ -353,7 +339,7 @@ class SearchTabView { copyFullIDItem.addActionListener({mvcGroup.controller.copyFullID()}) popupMenu.add(copyFullIDItem) - def mouseListener = new MouseAdapter() { + def sendersMouseListener = new MouseAdapter() { public void mousePressed(MouseEvent e) { if (e.isPopupTrigger() || e.button == MouseEvent.BUTTON3) popupMenu.show(e.getComponent(), e.getX(), e.getY()) @@ -364,7 +350,43 @@ class SearchTabView { } } + // results table + tree mouse listener when grouped by sender + def resultsMouseListener = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.button == MouseEvent.BUTTON3) + showPopupMenu(e) + else if (e.button == MouseEvent.BUTTON1 && e.clickCount == 2) + controller.download() + } + @Override + public void mouseReleased(MouseEvent e) { + if (e.button == MouseEvent.BUTTON3) + showPopupMenu(e) + } + } + // results tree + resultTree.addMouseListener(resultsMouseListener) + resultTree.addTreeSelectionListener { + model.downloadActionEnabled = false + model.viewCommentActionEnabled = false + model.viewCollectionsActionEnabled = false + model.viewCertificatesActionEnabled = false + TreePath [] selected = resultTree.selectionModel.getSelectionPaths() + if (selected == null || selected.length == 0) + return + + model.downloadActionEnabled = true + UIResultEvent result = resultTree.singleResultSelected() + if (result != null) { + model.viewCommentActionEnabled = result.comment != null + model.viewCollectionsActionEnabled = !result.collections.isEmpty() + model.viewCertificatesActionEnabled = result.certificates > 0 + } + } + + // results table1 def centerRenderer = new DefaultTableCellRenderer() centerRenderer.setHorizontalAlignment(JLabel.CENTER) resultsTable.setDefaultRenderer(Integer.class,centerRenderer) @@ -376,20 +398,7 @@ class SearchTabView { resultsTable.rowSorter.setSortsOnUpdates(true) - resultsTable.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.button == MouseEvent.BUTTON3) - showPopupMenu(e) - else if (e.button == MouseEvent.BUTTON1 && e.clickCount == 2) - mvcGroup.controller.download() - } - @Override - public void mouseReleased(MouseEvent e) { - if (e.button == MouseEvent.BUTTON3) - showPopupMenu(e) - } - }) + resultsTable.addMouseListener(resultsMouseListener) resultsTable.getSelectionModel().addListSelectionListener({ def result = getSelectedResult() @@ -407,7 +416,7 @@ class SearchTabView { }) // senders table - sendersTable.addMouseListener(mouseListener) + sendersTable.addMouseListener(sendersMouseListener) sendersTable.setDefaultRenderer(Integer.class, centerRenderer) sendersTable.rowSorter.addRowSorterListener({evt -> lastSendersSortEvent = evt}) sendersTable.rowSorter.setSortsOnUpdates(true) @@ -441,6 +450,7 @@ class SearchTabView { for(UIResultEvent event : model.sendersBucket[sender]) model.treeModel.addToTree(event) model.treeModel.nodeStructureChanged(model.root) + TreeUtil.expand(resultTree) } }) @@ -485,7 +495,7 @@ class SearchTabView { // TODO: add download right-click action // senders table 2 - sendersTable2.addMouseListener(mouseListener) + sendersTable2.addMouseListener(sendersMouseListener) sendersTable2.setDefaultRenderer(Integer.class, centerRenderer) sendersTable2.rowSorter.addRowSorterListener({ evt -> lastSenders2SortEvent = evt}) sendersTable2.rowSorter.setSortsOnUpdates(true) @@ -519,9 +529,10 @@ class SearchTabView { if (settings.groupByFile) { showFileGrouping.call() - showTree.call() - } else + } else { showSenderGrouping.call() + showTree.call() + } } def closeTab = { @@ -541,7 +552,13 @@ class SearchTabView { menu.add(download) showMenu = true } - if (resultsTable.getSelectedRows().length == 1) { + + boolean singleSelected + if (model.treeVisible) + singleSelected = resultTree.singleResultSelected() != null + else + singleSelected = resultsTable.getSelectedRows().length == 1 + if (singleSelected) { JMenuItem copyHashToClipboard = new JMenuItem(trans("COPY_HASH_TO_CLIPBOARD")) copyHashToClipboard.addActionListener({mvcGroup.view.copyHashToClipboard()}) menu.add(copyHashToClipboard) @@ -605,6 +622,41 @@ class SearchTabView { return model.results[selected] } } + + List selectedResults() { + if (model.groupedByFile) { + return [getSelectedResult()] + } else { + List results = new ArrayList<>() + if (model.treeVisible) { + for (TreePath path : resultTree.getSelectionPaths()) + TreeUtil.getLeafs(path.getLastPathComponent(), results) + } else { + int[] rows = view.resultsTable.getSelectedRows() + if (rows.length == 0) + return null + def sortEvt = view.lastSortEvent + if (sortEvt != null) { + for (int i = 0; i < rows.length; i++) { + rows[i] = view.resultsTable.rowSorter.convertRowIndexToModel(rows[i]) + } + } + rows.each { results.add(model.results[it]) } + } + return results + } + } + + List decorateResults(List results) { + List rv = new ArrayList<>() + if (model.groupedByFile || !model.treeVisible) { + // flat + for(UIResultEvent event : results) + rv << new ResultAndTargets(event, new File(event.name), null) + } else + rv.addAll(resultTree.decorateResults(results)) + rv + } def copyHashToClipboard() { def result = getSelectedResult() diff --git a/gui/src/main/groovy/com/muwire/gui/ResultTree.groovy b/gui/src/main/groovy/com/muwire/gui/ResultTree.groovy index decdc0a8..fe3f90c4 100644 --- a/gui/src/main/groovy/com/muwire/gui/ResultTree.groovy +++ b/gui/src/main/groovy/com/muwire/gui/ResultTree.groovy @@ -11,6 +11,9 @@ class ResultTree extends JTree{ ResultTree(TreeModel model) { super(model) setCellRenderer(new ResultTreeRenderer()) + setRootVisible(false) + setLargeModel(true) + setExpandsSelectedPaths(true) } List decorateResults(List results) { @@ -47,5 +50,17 @@ class ResultTree extends JTree{ rv } + /** + * @return if and only if a single result is selected, return it. Null otherwise. + */ + UIResultEvent singleResultSelected() { + TreePath[] selected = getSelectionPaths() + if (selected == null || selected.length == 0) + return null + def obj = selected[0].getLastPathComponent().getUserObject() + if (obj instanceof UIResultEvent) + return obj + return null + } }