Added CLI options to copy, delete or save attachm. of selected messages

This commit is contained in:
Leon Hofmeister 2020-09-29 00:28:06 +02:00
parent 43981c9272
commit 0be5d0e12a
Signed by: delvh
GPG Key ID: 3DECE05F6D9A647C
3 changed files with 138 additions and 68 deletions

View File

@ -1,8 +1,6 @@
package envoy.client.ui.control; package envoy.client.ui.control;
import java.awt.Toolkit; import java.io.ByteArrayInputStream;
import java.awt.datatransfer.StringSelection;
import java.io.*;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Map; import java.util.Map;
@ -12,19 +10,14 @@ import javafx.geometry.*;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.*; import javafx.scene.image.*;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import javafx.stage.FileChooser;
import envoy.client.data.*; import envoy.client.data.*;
import envoy.client.net.Client; import envoy.client.net.Client;
import envoy.client.ui.SceneContext; import envoy.client.util.*;
import envoy.client.util.IconUtil;
import envoy.data.*; import envoy.data.*;
import envoy.data.Message.MessageStatus; import envoy.data.Message.MessageStatus;
import envoy.event.MessageDeletion;
import envoy.util.EnvoyLog; import envoy.util.EnvoyLog;
import dev.kske.eventbus.EventBus;
/** /**
* This class transforms a single {@link Message} into a UI component. * This class transforms a single {@link Message} into a UI component.
* *
@ -36,15 +29,13 @@ public final class MessageControl extends Label {
private final boolean ownMessage; private final boolean ownMessage;
private final LocalDB localDB = context.getLocalDB(); private final LocalDB localDB = context.getLocalDB();
private final SceneContext sceneContext = context.getSceneContext(); private final Client client = context.getClient();
private final Client client = context.getClient();
private static final Context context = Context.getInstance(); private static final Context context = Context.getInstance();
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss") private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
.withZone(ZoneId.systemDefault()); .withZone(ZoneId.systemDefault());
private static final Map<MessageStatus, Image> statusImages = IconUtil.loadByEnum(MessageStatus.class, 16); private static final Map<MessageStatus, Image> statusImages = IconUtil.loadByEnum(MessageStatus.class, 16);
private static final Settings settings = Settings.getInstance();
private static final Logger logger = EnvoyLog.getLogger(MessageControl.class); private static final Logger logger = EnvoyLog.getLogger(MessageControl.class);
/** /**
@ -79,14 +70,16 @@ public final class MessageControl extends Label {
final var items = contextMenu.getItems(); final var items = contextMenu.getItems();
// Copy message action // Copy message action
final var copyMenuItem = new MenuItem("Copy Text"); if (!message.getText().isEmpty()) {
copyMenuItem.setOnAction(e -> copyMessageText(message.getText())); final var copyMenuItem = new MenuItem("Copy Text");
items.add(copyMenuItem); copyMenuItem.setOnAction(e -> MessageUtil.copyMessageText(message));
items.add(copyMenuItem);
}
// Delete message - if own message - action // Delete message - if own message - action
if (ownMessage && client.isOnline()) { if (ownMessage && client.isOnline()) {
final var deleteMenuItem = new MenuItem("Delete"); final var deleteMenuItem = new MenuItem("Delete");
deleteMenuItem.setOnAction(e -> deleteMessage(message)); deleteMenuItem.setOnAction(e -> MessageUtil.deleteMessage(message));
items.add(deleteMenuItem); items.add(deleteMenuItem);
} }
@ -96,12 +89,12 @@ public final class MessageControl extends Label {
// Forward menu item // Forward menu item
final var forwardMenuItem = new MenuItem("Forward"); final var forwardMenuItem = new MenuItem("Forward");
forwardMenuItem.setOnAction(e -> forwardMessage(message)); forwardMenuItem.setOnAction(e -> MessageUtil.forwardMessage(message));
items.add(forwardMenuItem); items.add(forwardMenuItem);
// Quote menu item // Quote menu item
final var quoteMenuItem = new MenuItem("Quote"); final var quoteMenuItem = new MenuItem("Quote");
quoteMenuItem.setOnAction(e -> quoteMessage(message)); quoteMenuItem.setOnAction(e -> MessageUtil.quoteMessage(message));
items.add(quoteMenuItem); items.add(quoteMenuItem);
} }
@ -127,7 +120,7 @@ public final class MessageControl extends Label {
break; break;
} }
final var saveAttachment = new MenuItem("Save attachment"); final var saveAttachment = new MenuItem("Save attachment");
saveAttachment.setOnAction(e -> saveAttachment(message)); saveAttachment.setOnAction(e -> MessageUtil.saveAttachment(message));
items.add(saveAttachment); items.add(saveAttachment);
} }
// Creating the textLabel // Creating the textLabel
@ -155,52 +148,8 @@ public final class MessageControl extends Label {
setGraphic(vbox); setGraphic(vbox);
} }
// Context Menu actions
private void copyMessageText(String text) {
logger.log(Level.FINEST, "A copy of message text \"" + text + "\" was requested");
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null);
}
private void deleteMessage(Message message) {
final var messageDeletionEvent = new MessageDeletion(message.getID());
messageDeletionEvent.setOwnEvent();
// Removing the message locally
EventBus.getInstance().dispatch(messageDeletionEvent);
// Removing the message on the server and this chat's recipients
Context.getInstance().getClient().send(messageDeletionEvent);
logger.log(Level.FINEST, "message deletion was requested for " + message);
}
private void forwardMessage(Message message) { logger.log(Level.FINEST, "message forwarding was requested for " + message); }
private void quoteMessage(Message message) { logger.log(Level.FINEST, "message quotation was requested for " + message); }
private void loadMessageInfoScene(Message message) { logger.log(Level.FINEST, "message info scene was requested for " + message); } private void loadMessageInfoScene(Message message) { logger.log(Level.FINEST, "message info scene was requested for " + message); }
private void saveAttachment(Message message) {
File file;
final var fileName = message.getAttachment().getName();
final var downloadLocation = settings.getDownloadLocation();
// Show save file dialog, if the user did not opt-out
if (!settings.isDownloadSavedWithoutAsking()) {
final var fileChooser = new FileChooser();
fileChooser.setInitialFileName(fileName);
fileChooser.setInitialDirectory(downloadLocation);
file = fileChooser.showSaveDialog(sceneContext.getStage());
} else file = new File(downloadLocation, fileName);
// A file was selected
if (file != null) try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(message.getAttachment().getData());
logger.log(Level.FINE, "Attachment of message was saved at " + file.getAbsolutePath());
} catch (final IOException e) {
logger.log(Level.WARNING, "Could not save attachment of " + message + ": ", e);
}
}
/** /**
* @return whether the message stored by this {@code MessageControl} has been * @return whether the message stored by this {@code MessageControl} has been
* sent by this user of Envoy * sent by this user of Envoy

View File

@ -312,9 +312,7 @@ public final class ChatScene implements EventListener, Restorable {
private void onMessageDeletion(MessageDeletion message) { private void onMessageDeletion(MessageDeletion message) {
// Clearing the selection if the own user was the sender of this event // Clearing the selection if the own user was the sender of this event
if (message.isOwnEvent()) Platform.runLater(() -> { if (message.isOwnEvent()) Platform.runLater(() -> { messageList.getSelectionModel().clearSelection(); });
messageList.getSelectionModel().clearSelection();
});
} }
/** /**
@ -345,6 +343,24 @@ public final class ChatScene implements EventListener, Restorable {
.setNumberOfArguments(0) .setNumberOfArguments(0)
.setDescription("Opens the settings screen") .setDescription("Opens the settings screen")
.build("settings"); .build("settings");
// Copy text of selection initialization
builder.setAction(text -> {
final var selectedMessage = messageList.getSelectionModel().getSelectedItem();
if (selectedMessage != null) MessageUtil.copyMessageText(selectedMessage);
}).setNumberOfArguments(0).setDescription("Copies the text of the currently selected message").build("cp-s");
// Delete selection initialization
builder.setAction(text -> {
final var selectedMessage = messageList.getSelectionModel().getSelectedItem();
if (selectedMessage != null) MessageUtil.deleteMessage(selectedMessage);
}).setNumberOfArguments(0).setDescription("Deletes the currently selected message").build("del-s");
// Save attachment of selection initialization
builder.setAction(text -> {
final var selectedMessage = messageList.getSelectionModel().getSelectedItem();
if (selectedMessage != null && selectedMessage.hasAttachment()) MessageUtil.saveAttachment(selectedMessage);
}).setNumberOfArguments(0).setDescription("Copies the text of the currently selected message").build("save-a-s");
} }
@Override @Override

View File

@ -0,0 +1,105 @@
package envoy.client.util;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.io.*;
import java.util.logging.*;
import javafx.stage.FileChooser;
import envoy.client.data.*;
import envoy.data.Message;
import envoy.event.MessageDeletion;
import envoy.util.EnvoyLog;
import dev.kske.eventbus.EventBus;
/**
* Contains methods that are commonly used for {@link Message}s.
*
* @author Leon Hofmeister
* @since Envoy Client v0.3-beta
*/
public class MessageUtil {
private MessageUtil() {}
private static Logger logger = EnvoyLog.getLogger(MessageUtil.class);
/**
* Copies the text of the given message to the System Clipboard.
*
* @param message the message whose text to copy
* @since Envoy Client v0.3-beta
*/
public static void copyMessageText(Message message) {
logger.log(Level.FINEST, "A copy of message text \"" + message.getText() + "\" was requested");
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(message.getText()), null);
}
/**
* Deletes the given message.
*
* @param message the message to delete
* @since Envoy Client v0.3-beta
*/
public static void deleteMessage(Message message) {
final var messageDeletionEvent = new MessageDeletion(message.getID());
messageDeletionEvent.setOwnEvent();
// Removing the message locally
EventBus.getInstance().dispatch(messageDeletionEvent);
// Removing the message on the server and this chat's recipients
Context.getInstance().getClient().send(messageDeletionEvent);
logger.log(Level.FINEST, "message deletion was requested for " + message);
}
/**
* Forwards the given message.
* Currently not implemented.
*
* @param message the message to forward
* @since Envoy Client v0.3-beta
*/
public static void forwardMessage(Message message) { logger.log(Level.FINEST, "message forwarding was requested for " + message); }
/**selected
* Quotes the given message.
* Currently not implemented.
*
* @param message the message to quote
* @since Envoy Client v0.3-beta
*/
public static void quoteMessage(Message message) { logger.log(Level.FINEST, "message quotation was requested for " + message); }
/**
* Saves the attachment of a message, if present.
*
* @param message the message whose attachment to save
* @throws IllegalStateException if no attachment is present in the message
* @since Envoy Client v0.3-beta
*/
public static void saveAttachment(Message message) {
if (!message.hasAttachment()) throw new IllegalStateException("Cannot save a non-existing attachment");
File file;
final var fileName = message.getAttachment().getName();
final var downloadLocation = Settings.getInstance().getDownloadLocation();
// Show save file dialog, if the user did not opt-out
if (!Settings.getInstance().isDownloadSavedWithoutAsking()) {
final var fileChooser = new FileChooser();
fileChooser.setInitialFileName(fileName);
fileChooser.setInitialDirectory(downloadLocation);
file = fileChooser.showSaveDialog(Context.getInstance().getSceneContext().getStage());
} else file = new File(downloadLocation, fileName);
// A file was selected
if (file != null) try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(message.getAttachment().getData());
logger.log(Level.FINE, "Attachment of message was saved at " + file.getAbsolutePath());
} catch (final IOException e) {
logger.log(Level.WARNING, "Could not save attachment of " + message + ": ", e);
}
}
}