Add Ability to Delete Messages Locally (#70)
Merge branch 'develop' into f/delete-messages Additionally added system commands to copy, delete or save attachments of selected messages Reviewed-on: https://git.kske.dev/zdm/envoy/pulls/70 Reviewed-by: kske <kai@kske.dev> Reviewed-by: DieGurke <maxi@kske.dev>
This commit is contained in:
		@@ -74,7 +74,7 @@ public class Chat implements Serializable {
 | 
			
		||||
	public boolean equals(Object obj) {
 | 
			
		||||
		if (this == obj) return true;
 | 
			
		||||
		if (!(obj instanceof Chat)) return false;
 | 
			
		||||
		final Chat other = (Chat) obj;
 | 
			
		||||
		final var other = (Chat) obj;
 | 
			
		||||
		return Objects.equals(recipient, other.recipient);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -89,7 +89,7 @@ public class Chat implements Serializable {
 | 
			
		||||
	 */
 | 
			
		||||
	public void read(WriteProxy writeProxy) {
 | 
			
		||||
		for (int i = messages.size() - 1; i >= 0; --i) {
 | 
			
		||||
			final Message m = messages.get(i);
 | 
			
		||||
			final var m = messages.get(i);
 | 
			
		||||
			if (m.getSenderID() == recipient.getID()) if (m.getStatus() == MessageStatus.READ) break;
 | 
			
		||||
			else {
 | 
			
		||||
				m.setStatus(MessageStatus.READ);
 | 
			
		||||
@@ -121,6 +121,15 @@ public class Chat implements Serializable {
 | 
			
		||||
		messages.add(0, message);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Removes the message with the given ID.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param messageID the ID of the message to remove
 | 
			
		||||
	 * @return whether the message has been found and removed
 | 
			
		||||
	 * @since Envoy Client v0.3-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public boolean remove(long messageID) { return messages.removeIf(m -> m.getID() == messageID); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Increments the amount of unread messages.
 | 
			
		||||
	 *
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ import java.time.Instant;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.logging.*;
 | 
			
		||||
 | 
			
		||||
import javafx.application.Platform;
 | 
			
		||||
import javafx.collections.*;
 | 
			
		||||
 | 
			
		||||
import envoy.client.event.*;
 | 
			
		||||
@@ -273,6 +274,24 @@ public final class LocalDB implements EventListener {
 | 
			
		||||
		cacheMap.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Deletes the message with the given ID, if present.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param message the event that was
 | 
			
		||||
	 * @since Envoy Client v0.3-beta
 | 
			
		||||
	 */
 | 
			
		||||
	@Event
 | 
			
		||||
	private void onMessageDeletion(MessageDeletion message) {
 | 
			
		||||
		Platform.runLater(() -> {
 | 
			
		||||
 | 
			
		||||
			// We suppose that messages have unique IDs, hence the search can be stopped
 | 
			
		||||
			// once a message was removed
 | 
			
		||||
			final var messageID = message.get();
 | 
			
		||||
			for (final var chat : chats)
 | 
			
		||||
				if (chat.remove(messageID)) break;
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return a {@code Map<String, User>} of all users stored locally with their
 | 
			
		||||
	 *         user names as keys
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								client/src/main/java/envoy/client/event/MessageDeletion.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								client/src/main/java/envoy/client/event/MessageDeletion.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
package envoy.client.event;
 | 
			
		||||
 | 
			
		||||
import envoy.event.Event;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Conveys the deletion of a message.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Leon Hofmeister
 | 
			
		||||
 * @since Envoy Common v0.3-beta
 | 
			
		||||
 */
 | 
			
		||||
public class MessageDeletion extends Event<Long> {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param messageID the ID of the deleted message
 | 
			
		||||
	 * @since Envoy Common v0.3-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public MessageDeletion(long messageID) { super(messageID); }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,6 @@
 | 
			
		||||
package envoy.client.ui.control;
 | 
			
		||||
 | 
			
		||||
import java.awt.Toolkit;
 | 
			
		||||
import java.awt.datatransfer.StringSelection;
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.time.ZoneId;
 | 
			
		||||
import java.time.format.DateTimeFormatter;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
@@ -12,11 +10,10 @@ import javafx.geometry.*;
 | 
			
		||||
import javafx.scene.control.*;
 | 
			
		||||
import javafx.scene.image.*;
 | 
			
		||||
import javafx.scene.layout.*;
 | 
			
		||||
import javafx.stage.FileChooser;
 | 
			
		||||
 | 
			
		||||
import envoy.client.data.*;
 | 
			
		||||
import envoy.client.ui.*;
 | 
			
		||||
import envoy.client.util.IconUtil;
 | 
			
		||||
import envoy.client.net.Client;
 | 
			
		||||
import envoy.client.util.*;
 | 
			
		||||
import envoy.data.*;
 | 
			
		||||
import envoy.data.Message.MessageStatus;
 | 
			
		||||
import envoy.util.EnvoyLog;
 | 
			
		||||
@@ -32,13 +29,13 @@ public final class MessageControl extends Label {
 | 
			
		||||
 | 
			
		||||
	private final boolean ownMessage;
 | 
			
		||||
 | 
			
		||||
	private final LocalDB		localDB			= Context.getInstance().getLocalDB();
 | 
			
		||||
	private final SceneContext	sceneContext	= Context.getInstance().getSceneContext();
 | 
			
		||||
	private final LocalDB	localDB	= context.getLocalDB();
 | 
			
		||||
	private final Client	client	= context.getClient();
 | 
			
		||||
 | 
			
		||||
	private static final Context					context			= Context.getInstance();
 | 
			
		||||
	private static final DateTimeFormatter			dateFormat		= DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
 | 
			
		||||
		.withZone(ZoneId.systemDefault());
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -47,6 +44,8 @@ public final class MessageControl extends Label {
 | 
			
		||||
	 * @since Envoy Client v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public MessageControl(Message message) {
 | 
			
		||||
		ownMessage = message.getSenderID() == localDB.getUser().getID();
 | 
			
		||||
 | 
			
		||||
		// Creating the underlying VBox and the dateLabel
 | 
			
		||||
		final var hbox = new HBox();
 | 
			
		||||
		if (message.getSenderID() != localDB.getUser().getID() && message instanceof GroupMessage) {
 | 
			
		||||
@@ -67,18 +66,42 @@ public final class MessageControl extends Label {
 | 
			
		||||
		final var vbox = new VBox(hbox);
 | 
			
		||||
 | 
			
		||||
		// Creating the actions for the MenuItems
 | 
			
		||||
		final var	contextMenu		= new ContextMenu();
 | 
			
		||||
		final var	copyMenuItem	= new MenuItem("Copy");
 | 
			
		||||
		final var	deleteMenuItem	= new MenuItem("Delete");
 | 
			
		||||
		final var	forwardMenuItem	= new MenuItem("Forward");
 | 
			
		||||
		final var	quoteMenuItem	= new MenuItem("Quote");
 | 
			
		||||
		final var	infoMenuItem	= new MenuItem("Info");
 | 
			
		||||
		copyMenuItem.setOnAction(e -> copyMessage(message));
 | 
			
		||||
		deleteMenuItem.setOnAction(e -> deleteMessage(message));
 | 
			
		||||
		forwardMenuItem.setOnAction(e -> forwardMessage(message));
 | 
			
		||||
		quoteMenuItem.setOnAction(e -> quoteMessage(message));
 | 
			
		||||
		final var	contextMenu	= new ContextMenu();
 | 
			
		||||
		final var	items		= contextMenu.getItems();
 | 
			
		||||
 | 
			
		||||
		// Copy message action
 | 
			
		||||
		if (!message.getText().isEmpty()) {
 | 
			
		||||
			final var copyMenuItem = new MenuItem("Copy Text");
 | 
			
		||||
			copyMenuItem.setOnAction(e -> MessageUtil.copyMessageText(message));
 | 
			
		||||
			items.add(copyMenuItem);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Delete message - if own message - action
 | 
			
		||||
		if (ownMessage && client.isOnline()) {
 | 
			
		||||
			final var deleteMenuItem = new MenuItem("Delete locally");
 | 
			
		||||
			deleteMenuItem.setOnAction(e -> MessageUtil.deleteMessage(message));
 | 
			
		||||
			items.add(deleteMenuItem);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// As long as these types of messages are not implemented and no caches are
 | 
			
		||||
		// defined for them, we only want them to appear when being online
 | 
			
		||||
		if (client.isOnline()) {
 | 
			
		||||
 | 
			
		||||
			// Forward menu item
 | 
			
		||||
			final var forwardMenuItem = new MenuItem("Forward");
 | 
			
		||||
			forwardMenuItem.setOnAction(e -> MessageUtil.forwardMessage(message));
 | 
			
		||||
			items.add(forwardMenuItem);
 | 
			
		||||
 | 
			
		||||
			// Quote menu item
 | 
			
		||||
			final var quoteMenuItem = new MenuItem("Quote");
 | 
			
		||||
			quoteMenuItem.setOnAction(e -> MessageUtil.quoteMessage(message));
 | 
			
		||||
			items.add(quoteMenuItem);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Info actions
 | 
			
		||||
		final var infoMenuItem = new MenuItem("Info");
 | 
			
		||||
		infoMenuItem.setOnAction(e -> loadMessageInfoScene(message));
 | 
			
		||||
		contextMenu.getItems().addAll(copyMenuItem, deleteMenuItem, forwardMenuItem, quoteMenuItem, infoMenuItem);
 | 
			
		||||
		items.add(infoMenuItem);
 | 
			
		||||
 | 
			
		||||
		// Handling message attachment display
 | 
			
		||||
		// TODO: Add missing attachment types
 | 
			
		||||
@@ -97,8 +120,8 @@ public final class MessageControl extends Label {
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
			final var saveAttachment = new MenuItem("Save attachment");
 | 
			
		||||
			saveAttachment.setOnAction(e -> saveAttachment(message));
 | 
			
		||||
			contextMenu.getItems().add(saveAttachment);
 | 
			
		||||
			saveAttachment.setOnAction(e -> MessageUtil.saveAttachment(message));
 | 
			
		||||
			items.add(saveAttachment);
 | 
			
		||||
		}
 | 
			
		||||
		// Creating the textLabel
 | 
			
		||||
		final var textLabel = new Label(message.getText());
 | 
			
		||||
@@ -116,12 +139,8 @@ public final class MessageControl extends Label {
 | 
			
		||||
			hBoxBottom.getChildren().add(statusIcon);
 | 
			
		||||
			hBoxBottom.setAlignment(Pos.BOTTOM_RIGHT);
 | 
			
		||||
			getStyleClass().add("own-message");
 | 
			
		||||
			ownMessage = true;
 | 
			
		||||
			hbox.setAlignment(Pos.CENTER_RIGHT);
 | 
			
		||||
		} else {
 | 
			
		||||
			getStyleClass().add("received-message");
 | 
			
		||||
			ownMessage = false;
 | 
			
		||||
		}
 | 
			
		||||
		} else getStyleClass().add("received-message");
 | 
			
		||||
		vbox.getChildren().add(hBoxBottom);
 | 
			
		||||
		// Adjusting height and weight of the cell to the corresponding ListView
 | 
			
		||||
		paddingProperty().setValue(new Insets(5, 20, 5, 20));
 | 
			
		||||
@@ -129,41 +148,8 @@ public final class MessageControl extends Label {
 | 
			
		||||
		setGraphic(vbox);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Context Menu actions
 | 
			
		||||
 | 
			
		||||
	private void copyMessage(Message message) {
 | 
			
		||||
		Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(message.getText()), null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void deleteMessage(Message message) { 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 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
 | 
			
		||||
	 *         sent by this user of Envoy
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,7 @@ public class TextInputContextMenu extends ContextMenu {
 | 
			
		||||
		copyMI.disableProperty().bind(control.selectedTextProperty().isEmpty());
 | 
			
		||||
		deleteMI.disableProperty().bind(control.selectedTextProperty().isEmpty());
 | 
			
		||||
		clearMI.disableProperty().bind(control.textProperty().isEmpty());
 | 
			
		||||
		selectAllMI.disableProperty().bind(control.textProperty().isEmpty());
 | 
			
		||||
		setOnShowing(e -> pasteMI.setDisable(!Clipboard.getSystemClipboard().hasString()));
 | 
			
		||||
 | 
			
		||||
		selectAllMI.getProperties().put("refreshMenu", Boolean.TRUE);
 | 
			
		||||
 
 | 
			
		||||
@@ -223,8 +223,8 @@ public final class ChatScene implements EventListener, Restorable {
 | 
			
		||||
		// The sender of the message is the recipient of the chat
 | 
			
		||||
		// Exceptions: this user is the sender (sync) or group message (group is
 | 
			
		||||
		// recipient)
 | 
			
		||||
		final boolean	ownMessage	= message.getSenderID() == localDB.getUser().getID();
 | 
			
		||||
		final var		recipientID	= message instanceof GroupMessage || ownMessage ? message.getRecipientID() : message.getSenderID();
 | 
			
		||||
		final var	ownMessage	= message.getSenderID() == localDB.getUser().getID();
 | 
			
		||||
		final var	recipientID	= message instanceof GroupMessage || ownMessage ? message.getRecipientID() : message.getSenderID();
 | 
			
		||||
 | 
			
		||||
		localDB.getChat(recipientID).ifPresent(chat -> {
 | 
			
		||||
			chat.insert(message);
 | 
			
		||||
@@ -336,6 +336,24 @@ public final class ChatScene implements EventListener, Restorable {
 | 
			
		||||
			.setNumberOfArguments(0)
 | 
			
		||||
			.setDescription("Opens the settings screen")
 | 
			
		||||
			.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
 | 
			
		||||
@@ -387,7 +405,7 @@ public final class ChatScene implements EventListener, Restorable {
 | 
			
		||||
		if (currentChat != null) {
 | 
			
		||||
			topBarContactLabel.setText(currentChat.getRecipient().getName());
 | 
			
		||||
			if (currentChat.getRecipient() instanceof User) {
 | 
			
		||||
				final String status = ((User) currentChat.getRecipient()).getStatus().toString();
 | 
			
		||||
				final var status = ((User) currentChat.getRecipient()).getStatus().toString();
 | 
			
		||||
				topBarStatusLabel.setText(status);
 | 
			
		||||
				topBarStatusLabel.getStyleClass().add(status.toLowerCase());
 | 
			
		||||
				recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
 | 
			
		||||
@@ -395,7 +413,7 @@ public final class ChatScene implements EventListener, Restorable {
 | 
			
		||||
				topBarStatusLabel.setText(currentChat.getRecipient().getContacts().size() + " members");
 | 
			
		||||
				recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
 | 
			
		||||
			}
 | 
			
		||||
			final Rectangle clip = new Rectangle();
 | 
			
		||||
			final var clip = new Rectangle();
 | 
			
		||||
			clip.setWidth(43);
 | 
			
		||||
			clip.setHeight(43);
 | 
			
		||||
			clip.setArcHeight(43);
 | 
			
		||||
@@ -753,6 +771,13 @@ public final class ChatScene implements EventListener, Restorable {
 | 
			
		||||
		pendingAttachment = messageAttachment;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Clears the current message selection.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since Envoy Client v0.3-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void clearMessageSelection() { messageList.getSelectionModel().clearSelection(); }
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void searchContacts() {
 | 
			
		||||
		chats.setPredicate(contactSearch.getText().isBlank() ? c -> true
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										105
									
								
								client/src/main/java/envoy/client/util/MessageUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								client/src/main/java/envoy/client/util/MessageUtil.java
									
									
									
									
									
										Normal 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.client.event.MessageDeletion;
 | 
			
		||||
import envoy.client.ui.controller.ChatScene;
 | 
			
		||||
import envoy.data.Message;
 | 
			
		||||
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());
 | 
			
		||||
		final var	controller				= Context.getInstance().getSceneContext().getController();
 | 
			
		||||
		if (controller instanceof ChatScene) ((ChatScene) controller).clearMessageSelection();
 | 
			
		||||
 | 
			
		||||
		// Removing the message locally
 | 
			
		||||
		EventBus.getInstance().dispatch(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); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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 IllegalArgumentException("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 (var 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);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user