muwire/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy

1056 lines
36 KiB
Groovy

package com.muwire.gui
import com.muwire.core.files.DirectoryUnsharedEvent
import com.muwire.core.files.directories.WatchedDirectory
import com.muwire.core.messenger.UIFolderCreateEvent
import com.muwire.core.messenger.UIFolderDeleteEvent
import javax.swing.JTextField
import java.util.regex.Pattern
import static com.muwire.gui.Translator.trans
import griffon.core.GriffonApplication
import griffon.core.artifact.GriffonController
import griffon.core.controller.ControllerAction
import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor
import net.i2p.crypto.DSAEngine
import net.i2p.data.Base64
import net.i2p.data.Signature
import java.awt.Desktop
import java.awt.Toolkit
import java.awt.datatransfer.StringSelection
import java.awt.event.ActionEvent
import java.nio.charset.StandardCharsets
import javax.annotation.Nonnull
import javax.inject.Inject
import javax.swing.JOptionPane
import javax.swing.JTable
import com.muwire.core.Constants
import com.muwire.core.Core
import com.muwire.core.InfoHash
import com.muwire.core.Persona
import com.muwire.core.SharedFile
import com.muwire.core.SplitPattern
import com.muwire.core.collections.FileCollection
import com.muwire.core.collections.UICollectionDeletedEvent
import com.muwire.core.download.Downloader
import com.muwire.core.download.UIDownloadCancelledEvent
import com.muwire.core.download.UIDownloadPausedEvent
import com.muwire.core.download.UIDownloadResumedEvent
import com.muwire.core.filecert.UICreateCertificateEvent
import com.muwire.core.filefeeds.Feed
import com.muwire.core.filefeeds.FeedItem
import com.muwire.core.filefeeds.UIDownloadFeedItemEvent
import com.muwire.core.filefeeds.UIFeedConfigurationEvent
import com.muwire.core.filefeeds.UIFeedDeletedEvent
import com.muwire.core.filefeeds.UIFeedUpdateEvent
import com.muwire.core.filefeeds.UIFilePublishedEvent
import com.muwire.core.filefeeds.UIFileUnpublishedEvent
import com.muwire.core.files.FileUnsharedEvent
import com.muwire.core.search.QueryEvent
import com.muwire.core.search.SearchEvent
import com.muwire.core.trust.RemoteTrustList
import com.muwire.core.trust.TrustEvent
import com.muwire.core.trust.TrustLevel
import com.muwire.core.trust.TrustService.TrustEntry
import com.muwire.core.trust.TrustSubscriptionEvent
import com.muwire.core.upload.HashListUploader
import com.muwire.core.upload.Uploader
import com.muwire.core.util.DataUtil
@ArtifactProviderFor(GriffonController)
class MainFrameController {
@Inject @Nonnull GriffonApplication application
@MVCMember @Nonnull
FactoryBuilderSupport builder
@MVCMember @Nonnull
MainFrameModel model
@MVCMember @Nonnull
MainFrameView view
private volatile Core core
@ControllerAction
void search(ActionEvent evt) {
if (evt?.getActionCommand() == null)
return
def cardsPanel = builder.getVariable("cards-panel")
cardsPanel.getLayout().show(cardsPanel, "search window")
def searchField = builder.getVariable("search-field")
def search = searchField.getSelectedItem()
searchField.model.addElement(search)
performSearch(search, null)
}
void repeatSearch(String terms, Integer tab, Boolean regex) {
if (regex)
terms = "/$terms/"
performSearch(terms, tab)
}
private void performSearch(String search, Integer tab) {
model.sessionRestored = true
search = search.trim()
if (search.length() == 0)
return
if (search.length() > 128) {
try {
Persona p = new Persona(new ByteArrayInputStream(Base64.decode(search)))
String groupId = p.getHumanReadableName() + "-browse"
def params = [:]
params['host'] = p
params['core'] = model.core
mvcGroup.createMVCGroup("browse",groupId,params)
return
} catch (Exception notPersona) {
search = search.substring(0,128)
}
}
boolean hashSearch = false
byte [] root = null
if (search.length() == 44 && search.indexOf(" ") < 0) {
try {
root = Base64.decode(search)
hashSearch = true
} catch (Exception e) {
// not a hash search
}
}
boolean regexSearch = false
if (search.length() > 1 && search.startsWith("/") && search.endsWith("/")) {
search = search.substring(1, search.length() - 1)
try {
Pattern.compile(search)
regexSearch = true
} catch (Exception e) {
// not a regex search
JOptionPane.showMessageDialog(null, trans("NOT_A_REGEX", search),
trans("NOT_A_REGEX_TITLE"), JOptionPane.WARNING_MESSAGE);
return
}
}
def uuid = UUID.randomUUID()
Map<String, Object> params = new HashMap<>()
params["search-terms"] = search
params["uuid"] = uuid.toString()
params["core"] = core
params["settings"] = view.settings
params["tab"] = tab
params["regex"] = regexSearch
def group = mvcGroup.createMVCGroup("SearchTab", uuid.toString(), params)
model.results[uuid.toString()] = group
def searchEvent
byte [] payload
if (hashSearch) {
searchEvent = new SearchEvent(searchHash : root, uuid : uuid, oobInfohash: true,
compressedResults : true, persona : core.me, collections : core.muOptions.searchCollections)
payload = root
} else {
String [] terms
if (regexSearch) {
terms = new String[] {search}
payload = search.getBytes(StandardCharsets.UTF_8)
} else {
terms = SplitPattern.termify(search)
payload = String.join(" ", terms).getBytes(StandardCharsets.UTF_8)
}
searchEvent = new SearchEvent(searchTerms : terms, uuid : uuid, oobInfohash: true,
searchComments : core.muOptions.searchComments, compressedResults : true, persona : core.me,
collections : core.muOptions.searchCollections, searchPaths: core.muOptions.searchPaths, regex: regexSearch)
}
boolean firstHop = core.muOptions.allowUntrusted || core.muOptions.searchExtraHop
Signature sig = DSAEngine.getInstance().sign(payload, core.spk)
long timestamp = System.currentTimeMillis()
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : firstHop, local: true,
replyTo: core.me.destination, receivedOn: core.me.destination,
originator : core.me, sig : sig.data, queryTime : timestamp, sig2 : DataUtil.signUUID(uuid, timestamp, core.spk)))
}
void search(String infoHash, String tabTitle) {
def cardsPanel = builder.getVariable("cards-panel")
cardsPanel.getLayout().show(cardsPanel, "search window")
def uuid = UUID.randomUUID()
Map<String, Object> params = new HashMap<>()
params["search-terms"] = tabTitle
params["uuid"] = uuid.toString()
params["core"] = core
params["settings"] = view.settings
def group = mvcGroup.createMVCGroup("SearchTab", uuid.toString(), params)
model.results[uuid.toString()] = group
byte [] infoHashBytes = Base64.decode(infoHash)
Signature sig = DSAEngine.getInstance().sign(infoHashBytes, core.spk)
long timestamp = System.currentTimeMillis()
byte [] sig2 = DataUtil.signUUID(uuid, timestamp, core.spk)
def searchEvent = new SearchEvent(searchHash : Base64.decode(infoHash), uuid:uuid,
oobInfohash: true, persona : core.me)
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : true, local: true,
replyTo: core.me.destination, receivedOn: core.me.destination,
originator : core.me, sig : sig.data, queryTime : timestamp, sig2 : sig2))
}
private List<Downloader> selectedDownloads() {
int [] rows = view.selectedDownloaderRows()
if (rows.length == 0)
return Collections.emptyList()
List<Downloader> rv = []
for (int row : rows)
rv << model.downloads[row].downloader
rv
}
@ControllerAction
void trustPersonaFromSearch() {
int selected = builder.getVariable("searches-table").getSelectedRow()
if (selected < 0)
return
String reason = JOptionPane.showInputDialog(trans("ENTER_REASON_OPTIONAL"))
Persona p = model.searches[selected].originator
core.eventBus.publish( new TrustEvent(persona : p, level : TrustLevel.TRUSTED, reason : reason) )
}
@ControllerAction
void distrustPersonaFromSearch() {
int selected = builder.getVariable("searches-table").getSelectedRow()
if (selected < 0)
return
String reason = JOptionPane.showInputDialog(trans("ENTER_REASON_OPTIONAL"))
Persona p = model.searches[selected].originator
core.eventBus.publish( new TrustEvent(persona : p, level : TrustLevel.DISTRUSTED, reason : reason) )
}
@ControllerAction
void copyDownloadHash() {
List<Downloader> downloaders = selectedDownloads()
if (downloaders.size() != 1)
return
def download = downloaders.first()
CopyPasteSupport.copyToClipboard(Base64.encode(download.getInfoHash().getRoot()))
}
@ControllerAction
void cancel() {
for (Downloader downloader : selectedDownloads()) {
downloader.cancel()
model.downloadInfoHashes.remove(downloader.getInfoHash())
core.eventBus.publish(new UIDownloadCancelledEvent(downloader: downloader))
}
}
@ControllerAction
void resume() {
for (Downloader downloader : selectedDownloads()) {
downloader.resume()
core.eventBus.publish(new UIDownloadResumedEvent())
}
}
@ControllerAction
void pause() {
for (Downloader downloader : selectedDownloads()) {
downloader.pause()
core.eventBus.publish(new UIDownloadPausedEvent())
}
}
@ControllerAction
void preview() {
def downloads = selectedDownloads()
if (downloads.size() != 1)
return
def downloader = downloads.get(0)
def params = [:]
params['downloader'] = downloader
mvcGroup.createMVCGroup("download-preview", params)
}
@ControllerAction
void open() {
List<SharedFile> selected = view.selectedSharedFiles()
if (selected == null || selected.size() != 1)
return
if (!view.selectedFolders().isEmpty())
return
SharedFile sf = selected[0]
Desktop.getDesktop().open(sf.file)
}
@ControllerAction
void clear() {
model.downloads.removeAll {
def state = it.downloader.getCurrentState()
state == Downloader.DownloadState.CANCELLED ||
state == Downloader.DownloadState.FINISHED ||
state == Downloader.DownloadState.HOPELESS
}
model.clearButtonEnabled = false
}
@ControllerAction
void openContainingFolderFromDownload() {
def downloads = selectedDownloads()
if (downloads.size() != 1)
return
def downloader = downloads.get(0)
try {
Desktop.getDesktop().open(downloader.file.getParentFile())
} catch (Exception ignored) {}
}
@ControllerAction
void addContact() {
def params = [:]
params.core = core
mvcGroup.createMVCGroup("add-contact", params).destroy()
}
@ControllerAction
void removeContact() {
markTrust(TrustLevel.NEUTRAL)
}
private void markTrust(TrustLevel level) {
int row = view.getSelectedContactsTableRow()
if (row < 0)
return
String reason = null
if (level != TrustLevel.NEUTRAL)
reason = JOptionPane.showInputDialog(trans("ENTER_REASON_OPTIONAL"))
builder.getVariable("contacts-table").model.fireTableDataChanged()
core.eventBus.publish(new TrustEvent(persona : model.contacts[row].persona, level : level, reason : reason))
}
@ControllerAction
void markTrusted() {
markTrust(TrustLevel.TRUSTED)
model.markTrustedButtonEnabled = false
}
@ControllerAction
void markDistrusted() {
markTrust(TrustLevel.DISTRUSTED)
model.subscribeButtonEnabled = false
model.markDistrustedButtonEnabled = false
}
@ControllerAction
void subscribe() {
int row = view.getSelectedContactsTableRow()
if (row < 0)
return
Persona p = model.contacts[row].persona
core.muOptions.trustSubscriptions.add(p)
saveMuWireSettings()
core.eventBus.publish(new TrustSubscriptionEvent(persona : p, subscribe : true))
model.subscribeButtonEnabled = false
model.markDistrustedButtonEnabled = false
model.removeContactButtonEnabled = false
}
@ControllerAction
void subscribeToFeed() {
String address = JOptionPane.showInputDialog(trans("COPY_PASTE_FEED_ID"))
if (address == null)
return
Persona p
try {
p = new Persona(new ByteArrayInputStream(Base64.decode(address)))
} catch (Exception bad) {
JOptionPane.showMessageDialog(null, trans("ADD_CONTACT_INVALID_ID_TITLE"), trans("ADD_CONTACT_INVALID_ID_TITLE"), JOptionPane.ERROR_MESSAGE)
return
}
Feed feed = new Feed(p)
feed.setAutoDownload(core.muOptions.defaultFeedAutoDownload)
feed.setSequential(core.muOptions.defaultFeedSequential)
feed.setItemsToKeep(core.muOptions.defaultFeedItemsToKeep)
feed.setUpdateInterval(core.muOptions.defaultFeedUpdateInterval)
core.eventBus.publish(new UIFeedConfigurationEvent(feed : feed, newFeed: true))
Thread.sleep(10)
view.refreshFeeds()
}
@ControllerAction
void showMyFeed() {
def params = [:]
params['core'] = model.core
mvcGroup.createMVCGroup("my-feed", params).destroy()
}
@ControllerAction
void review() {
RemoteTrustList list = getSelectedTrustList()
if (list == null)
return
Map<String,Object> env = new HashMap<>()
env["trustList"] = list
env["trustService"] = core.trustService
env["eventBus"] = core.eventBus
mvcGroup.createMVCGroup("trust-list", env)
}
@ControllerAction
void update() {
RemoteTrustList list = getSelectedTrustList()
if (list == null)
return
core.eventBus.publish(new TrustSubscriptionEvent(persona : list.persona, subscribe : true))
}
@ControllerAction
void unsubscribe() {
RemoteTrustList list = getSelectedTrustList()
if (list == null)
return
core.muOptions.trustSubscriptions.remove(list.persona)
saveMuWireSettings()
model.subscriptions.remove(list)
JTable table = builder.getVariable("subscription-table")
table.model.fireTableDataChanged()
core.eventBus.publish(new TrustSubscriptionEvent(persona : list.persona, subscribe : false))
}
private RemoteTrustList getSelectedTrustList() {
int row = view.getSelectedContactSubscriptionTableRow()
if (row < 0)
return null
model.subscriptions[row]
}
@ControllerAction
void browseFromTrusted() {
int row = view.getSelectedContactsTableRow()
if (row < 0)
return
Persona p = model.contacts[row].persona
String groupId = UUID.randomUUID().toString()
def params = [:]
params['host'] = p
params['core'] = model.core
mvcGroup.createMVCGroup("browse",groupId,params)
view.showSearchWindow.call()
}
@ControllerAction
void browseCollectionsFromTrusted() {
int row = view.getSelectedContactsTableRow()
if (row < 0)
return
Persona p = model.contacts[row].persona
UUID uuid = UUID.randomUUID()
def params = [:]
params.fileName = p.getHumanReadableName()
params.eventBus = core.eventBus
params.everything = true
params.uuid = uuid
params.host = p
mvcGroup.createMVCGroup("collection-tab", uuid.toString(), params)
view.showSearchWindow.call()
}
@ControllerAction
void browseFromUpload(Uploader u) {
Persona p = u.getDownloaderPersona()
String groupId = UUID.randomUUID().toString()
def params = [:]
params['host'] = p
params['core'] = model.core
mvcGroup.createMVCGroup("browse",groupId,params)
view.showSearchWindow.call()
}
@ControllerAction
void browseCollectionsFromUpload(Uploader u) {
Persona p = u.getDownloaderPersona()
UUID uuid = UUID.randomUUID()
def params = [:]
params.fileName = p.getHumanReadableName()
params.eventBus = core.eventBus
params.host = p
params.uuid = uuid
params.everything = true
mvcGroup.createMVCGroup("collection-tab", uuid.toString(), params)
view.showSearchWindow.call()
}
@ControllerAction
void subscribeFromUpload(Uploader u) {
Persona p = u.getDownloaderPersona()
Feed feed = new Feed(p)
feed.setAutoDownload(core.muOptions.defaultFeedAutoDownload)
feed.setSequential(core.muOptions.defaultFeedSequential)
feed.setItemsToKeep(core.muOptions.defaultFeedItemsToKeep)
feed.setUpdateInterval(core.muOptions.defaultFeedUpdateInterval)
core.eventBus.publish(new UIFeedConfigurationEvent(feed : feed, newFeed : true))
view.showFeedsWindow.call()
}
@ControllerAction
void chatFromUpload(Uploader u) {
Persona p = u.getDownloaderPersona()
startChat(p)
view.showChatWindow.call()
}
void unshareSelectedFile() {
def sfs = view.selectedSharedFiles()
Set<File> folders = view.selectedFolders()
if (sfs == null && folders.isEmpty())
return
if (sfs == null)
sfs = Collections.emptyList()
List<SharedFile> toUnshare = new ArrayList<>()
sfs.each { SharedFile sf ->
if (view.settings.collectionWarning) {
Set<InfoHash> collectionsInfoHashes = core.collectionManager.collectionsForFile(sf.rootInfoHash)
if (!collectionsInfoHashes.isEmpty()) {
String[] affected = collectionsInfoHashes.collect({core.collectionManager.getByInfoHash(it)}).collect{it.name}.toArray(new String[0])
boolean [] answer = new boolean[1]
def props = [:]
props.collections = affected
props.answer = answer
props.fileName = sf.file.getName()
props.settings = view.settings
props.home = core.home
def mvc = mvcGroup.createMVCGroup("collection-warning", props)
mvc.destroy()
if (!answer[0]) {
File f = sf.getFile()
while(true) {
File parent = f.getParentFile()
if (parent == null)
break
folders.remove(parent)
f = parent
}
return
}
}
}
toUnshare.add(sf)
}
if (!folders.isEmpty())
core.eventBus.publish(new DirectoryUnsharedEvent(directories: folders.toArray(new File[0]), deleted: false))
if (!toUnshare.isEmpty())
core.eventBus.publish(new FileUnsharedEvent(unsharedFiles : toUnshare.toArray(new SharedFile[0])))
}
@ControllerAction
void addComment() {
def selectedFiles = view.selectedSharedFiles()
if (selectedFiles == null || selectedFiles.isEmpty())
return
Map<String, Object> params = new HashMap<>()
params['selectedFiles'] = selectedFiles
params['core'] = core
mvcGroup.createMVCGroup("add-comment", "Add Comment", params).destroy()
}
@ControllerAction
void clearUploads() {
model.uploads.removeAll { it.finished }
}
@ControllerAction
void showInLibrary(Uploader uploader) {
SharedFile sf = null
if (uploader instanceof HashListUploader) {
InfoHash infoHash = uploader.infoHash
SharedFile[] sfs = core.fileManager.rootToFiles.get(infoHash)
if (sfs != null && sfs.length > 0)
sf = sfs[0]
} else {
File f = uploader.file
sf = core.fileManager.fileToSharedFile.get(f)
}
if (sf == null)
return // can happen if user un-shared
view.focusOnSharedFile(sf)
}
@ControllerAction
void restoreSession() {
model.sessionRestored = true
view.settings.openTabs.each {
performSearch(it, null)
}
}
@ControllerAction
void issueCertificate() {
if (view.settings.certificateWarning) {
def params = [:]
params['settings'] = view.settings
params['home'] = core.home
mvcGroup.createMVCGroup("certificate-warning", params).destroy()
} else {
int count = 0
view.selectedSharedFiles().each {
count++
core.eventBus.publish(new UICreateCertificateEvent(sharedFile : it))
}
if (count > 1)
JOptionPane.showMessageDialog(null, trans("CERTIFICATES_ISSUED"))
else if (count == 1)
JOptionPane.showMessageDialog(null, trans("CERTIFICATE_ISSUED"))
}
}
@ControllerAction
void showFileDetails() {
def selected = view.selectedSharedFiles()
if (selected == null || selected.size() != 1) {
JOptionPane.showMessageDialog(null, trans("PLEASE_SELECT_ONE_FILE_DETAILS"))
return
}
def params = [:]
params['sf'] = selected[0]
params['core'] = core
mvcGroup.createMVCGroup("shared-file", params)
}
@ControllerAction
void configureFolder() {
Set<File> selectedFolders = view.selectedFolders()
if (selectedFolders.size() != 1)
return
def file = selectedFolders.first()
def wdm = model.core.getWatchedDirectoryManager()
if (!wdm.isWatched(file))
return
WatchedDirectory wd = wdm.getDirectory(file)
def props = [:]
props.core = model.core
props.directory = wd
mvcGroup.createMVCGroup("watched-directory", props).destroy()
}
@ControllerAction
void openContainingFolder() {
def selected = view.selectedSharedFiles()
if (selected == null || selected.size() != 1 || !view.selectedFolders().isEmpty()) {
JOptionPane.showMessageDialog(null, trans("PLEASE_SELECT_ONE_FILE_FOLDER"))
return
}
try {
Desktop.getDesktop().open(selected[0].file.getParentFile())
} catch (Exception ignored) {}
}
@ControllerAction
void filterLibrary() {
JTextField field = builder.getVariable("library-filter-textfield")
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.filterLibrary()
}
@ControllerAction
void clearLibraryFilter() {
model.clearFilterActionEnabled = false
model.filter = null
model.filterLibrary()
}
@ControllerAction
void startChatServer() {
model.core.chatServer.start()
model.chatServerRunning = true
if (!mvcGroup.getChildrenGroups().containsKey("local-chat-server")) {
def params = [:]
params['core'] = model.core
params['host'] = model.core.me
params['chatNotificator'] = view.chatNotificator
mvcGroup.createMVCGroup("chat-server","local-chat-server", params)
}
}
@ControllerAction
void stopChatServer() {
model.core.chatServer.stop()
model.chatServerRunning = false
}
@ControllerAction
void connectChatServer() {
String address = JOptionPane.showInputDialog(trans("COPY_PASTE_SERVER_ADDRESS"))
if (address == null)
return
Persona p
try {
p = new Persona(new ByteArrayInputStream(Base64.decode(address)))
} catch (Exception bad) {
JOptionPane.showMessageDialog(null, trans("INVALID_SERVER_ADDRESS"), trans("INVALID_SERVER_ADDRESS"), JOptionPane.ERROR_MESSAGE)
return
}
startChat(p)
}
@ControllerAction
void copyShort() {
copy(model.core.me.getHumanReadableName())
}
@ControllerAction
void copyFull() {
copy(model.core.me.toBase64())
}
private void copy(String s) {
StringSelection selection = new StringSelection(s)
def clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
clipboard.setContents(selection, null)
}
@ControllerAction
void publish() {
def selectedFiles = view.selectedSharedFiles()
if (selectedFiles == null || selectedFiles.isEmpty())
return
def params = [:]
params.core = model.core
params.requested = selectedFiles
mvcGroup.createMVCGroup("publish-preview",params).destroy()
view.refreshSharedFiles()
}
@ControllerAction
void updateFileFeed() {
Feed feed = view.selectedFeed()
if (feed == null)
return
model.core.eventBus.publish(new UIFeedUpdateEvent(host: feed.getPublisher()))
}
@ControllerAction
void unsubscribeFileFeed() {
Feed feed = view.selectedFeed()
if (feed == null)
return
model.core.eventBus.publish(new UIFeedDeletedEvent(host : feed.getPublisher()))
runInsideUIAsync {
model.feeds.remove(feed)
model.feedItems.clear()
view.refreshFeeds()
}
}
@ControllerAction
void configureFileFeed() {
Feed feed = view.selectedFeed()
if (feed == null)
return
def params = [:]
params['core'] = core
params['feed'] = feed
mvcGroup.createMVCGroup("feed-configuration", params)
}
@ControllerAction
void downloadFeedItem() {
List<FeedItem> items = view.selectedFeedItems()
if (items == null || items.isEmpty())
return
Feed f = model.core.getFeedManager().getFeed(items.get(0).getPublisher())
items.each {
if (!model.canDownload(it.getInfoHash()))
return
File target = new File(application.context.get("muwire-settings").downloadLocation, it.getName())
model.core.eventBus.publish(new UIDownloadFeedItemEvent(item : it, target : target, sequential : f.isSequential()))
}
view.showDownloadsWindow.call()
}
@ControllerAction
void viewFeedItemComment() {
List<FeedItem> items = view.selectedFeedItems()
if (items == null || items.size() != 1)
return
FeedItem item = items.get(0)
String groupId = Base64.encode(item.getInfoHash().getRoot())
Map<String, Object> params = new HashMap<>()
params['text'] = DataUtil.readi18nString(Base64.decode(item.getComment()))
params['name'] = item.getName()
mvcGroup.createMVCGroup("show-comment", groupId, params).destroy()
}
@ControllerAction
void viewFeedItemCertificates() {
List<FeedItem> items = view.selectedFeedItems()
if (items == null || items.size() != 1)
return
FeedItem item = items.get(0)
def params = [:]
params['core'] = core
params['host'] = item.getPublisher()
params['infoHash'] = item.getInfoHash()
params['name'] = item.getName()
mvcGroup.createMVCGroup("fetch-certificates", params)
}
@ControllerAction
void collection() {
def files = view.selectedSharedFiles()
if (files != null && files.size() > Constants.COLLECTION_MAX_ITEMS) {
JOptionPane.showMessageDialog(null, trans("CREATE_COLLECTION_MAX_FILES", Constants.COLLECTION_MAX_ITEMS, files.size()),
trans("CREATE_COLLECTION_MAX_FILES_TITLE"), JOptionPane.WARNING_MESSAGE)
return
}
if (files == null)
files = new ArrayList<>()
def params = [:]
params['files'] = files
params['spk'] = model.core.spk
params['me'] = model.core.me
params['eventBus'] = model.core.eventBus
mvcGroup.createMVCGroup("collection-wizard", UUID.randomUUID().toString(), params)
}
@ControllerAction
void viewCollectionComment() {
int row = view.selectedCollectionRow()
if (row < 0)
return
FileCollection collection = model.localCollections.get(row)
def params = [:]
params['text'] = collection.comment
mvcGroup.createMVCGroup("show-comment", params).destroy()
}
@ControllerAction
void copyCollectionHash() {
int row = view.selectedCollectionRow()
if (row < 0)
return
FileCollection collection = model.localCollections.get(row)
String b64 = Base64.encode(collection.getInfoHash().getRoot())
StringSelection selection = new StringSelection(b64)
def clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
clipboard.setContents(selection, null)
}
@ControllerAction
void deleteCollection() {
int row = view.selectedCollectionRow()
if (row < 0)
return
FileCollection collection = model.localCollections.get(row)
UICollectionDeletedEvent e = new UICollectionDeletedEvent(collection : collection)
model.core.eventBus.publish(e)
model.localCollections.remove(row)
view.collectionsTable.model.fireTableDataChanged()
model.collectionFiles.clear()
view.collectionFilesTable.model.fireTableDataChanged()
}
@ControllerAction
void viewItemComment() {
int row = view.selectedItemRow()
if (row < 0)
return
SharedFile sf = model.collectionFiles.get(row)
def params = [:]
params['text'] = DataUtil.readi18nString(Base64.decode(sf.getComment()))
mvcGroup.createMVCGroup("show-comment", params).destroy()
}
@ControllerAction
void showCollectionTool() {
int row = view.selectedCollectionRow()
if (row < 0)
return
FileCollection collection = model.localCollections.get(row)
def params = [:]
params['collection'] = collection
mvcGroup.createMVCGroup("collections-tool", params)
}
@ControllerAction
void messageComposeFromUpload(Uploader u) {
Persona p = u.getDownloaderPersona()
def params = [:]
params.recipients = new HashSet<>(Collections.singletonList(p))
params.core = core
mvcGroup.createMVCGroup("new-message", UUID.randomUUID().toString(), params)
}
@ControllerAction
void messageFromTrusted() {
int row = view.getSelectedContactsTableRow()
if (row < 0)
return
TrustEntry te = model.contacts[row]
def params = [:]
params.recipients = new HashSet<>(Collections.singletonList(te.persona))
params.core = core
mvcGroup.createMVCGroup("new-message", UUID.randomUUID().toString(), params)
}
@ControllerAction
void copyIdFromUploads(Uploader u) {
CopyPasteSupport.copyToClipboard(u.getDownloaderPersona().toBase64())
}
@ControllerAction
void copyIdFromTrusted() {
int row = view.getSelectedContactsTableRow()
if (row < 0)
return
TrustEntry te = model.contacts.get(row)
CopyPasteSupport.copyToClipboard(te.persona.toBase64())
}
@ControllerAction
void copyIdFromFeed() {
Feed feed = view.selectedFeed()
if (feed == null)
return
CopyPasteSupport.copyToClipboard(feed.getPublisher().toBase64())
}
@ControllerAction
void createMessageFolder() {
String name = null
while(name == null) {
name = JOptionPane.showInputDialog(trans("FOLDER_ENTER_NAME"))
if (name == null)
return
name = name.trim()
if (name.length() == 0) {
JOptionPane.showMessageDialog(null, trans("FOLDER_NAME_EMPTY"),
trans("FOLDER_NAME_EMPTY"), JOptionPane.WARNING_MESSAGE)
name = null
continue
}
if (model.messageFoldersMap.containsKey(name)) {
JOptionPane.showMessageDialog(null, trans("FOLDER_ALREADY_EXISTS"),
trans("FOLDER_ALREADY_EXISTS"), JOptionPane.WARNING_MESSAGE)
name = null
continue
}
}
def params = [:]
params['core'] = core
params['outgoing'] = false
params['name'] = name
def group = application.mvcGroupManager.createMVCGroup('message-folder', 'folder-$name', params)
view.addUserMessageFolder(group)
UIFolderCreateEvent event = new UIFolderCreateEvent(name: name)
core.eventBus.publish(event)
}
@ControllerAction
void deleteMessageFolder() {
def group = model.messageFoldersMap.get(model.folderIdx)
if (group == null)
return
if (!group.model.messages.isEmpty()) {
int result = JOptionPane.showConfirmDialog(null, trans("FOLDER_CONFIRM_DELETE"),
trans("FOLDER_CONFIRM_DELETE_TITLE"), JOptionPane.YES_NO_OPTION)
if (result != JOptionPane.YES_OPTION)
return
}
view.deleteUserMessageFolder(model.folderIdx)
UIFolderDeleteEvent event = new UIFolderDeleteEvent(name: model.folderIdx)
core.eventBus.publish(event)
}
void startChat(Persona p) {
if (!mvcGroup.getChildrenGroups().containsKey(p.getHumanReadableName())) {
def params = [:]
params['core'] = model.core
params['host'] = p
params['chatNotificator'] = view.chatNotificator
mvcGroup.createMVCGroup("chat-server", p.getHumanReadableName(), params)
} else
mvcGroup.getChildrenGroups().get(p.getHumanReadableName()).model.connect()
}
@ControllerAction
void chatFavorites() {
if (application.getMvcGroupManager().findGroup("chat-favorites") != null)
return
def params = [:]
params.chatFavorites = view.chatFavorites
mvcGroup.createMVCGroup("chat-favorites", params)
}
void saveMuWireSettings() {
core.saveMuSettings()
}
void mvcGroupInit(Map<String, String> args) {
application.addPropertyChangeListener("core", {e->
core = e.getNewValue()
})
}
}