mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-04-03 06:25:44 +02:00
WIP: fix #30 with limit to 10000 Messages with dequeList
This commit is contained in:
@@ -23,6 +23,7 @@ import kst4contest.locatorUtils.DirectionUtils;
|
||||
import kst4contest.logic.PriorityCalculator;
|
||||
import kst4contest.model.*;
|
||||
import kst4contest.test.MockKstServer;
|
||||
import kst4contest.utils.BoundedDequeObservableList;
|
||||
import kst4contest.utils.PlayAudioUtils;
|
||||
import kst4contest.view.Kst4ContestApplication;
|
||||
|
||||
@@ -1007,7 +1008,8 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
// ******All abstract types below here are used by the messageprocessor!
|
||||
// ***************
|
||||
|
||||
private ObservableList<ChatMessage> lst_globalChatMessageList = FXCollections.observableArrayList(); //All chatmessages will be put in there, later create filtered message lists
|
||||
private static final int MAX_CHAT_MESSAGES = 10000;
|
||||
private final BoundedDequeObservableList<ChatMessage> lst_globalChatMessageList = new BoundedDequeObservableList<>(MAX_CHAT_MESSAGES); //All chatmessages will be put in there, later create filtered message lists
|
||||
// private ObservableList<ChatMessage> lst_toAllMessageList = FXCollections.observableArrayList(); // directed to all
|
||||
// (beacon)
|
||||
private FilteredList<ChatMessage> lst_toAllMessageList = new FilteredList<>(lst_globalChatMessageList); // directed to all
|
||||
@@ -1152,13 +1154,14 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
this.lst_selectedCallSignInfofilteredMessageList = lst_selectedCallSignInfofilteredMessageList;
|
||||
}
|
||||
|
||||
public void addChatMessage(ChatMessage message) {
|
||||
lst_globalChatMessageList.addFirst(message);
|
||||
}
|
||||
|
||||
public ObservableList<ChatMessage> getLst_globalChatMessageList() {
|
||||
return lst_globalChatMessageList;
|
||||
}
|
||||
|
||||
public void setLst_globalChatMessageList(ObservableList<ChatMessage> lst_globalChatMessageList) {
|
||||
this.lst_globalChatMessageList = lst_globalChatMessageList;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
|
||||
@@ -772,7 +772,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
dummy.setCallSign("ALL");
|
||||
newMessageArrived.setReceiver(dummy);
|
||||
|
||||
this.client.getLst_globalChatMessageList().add(0, newMessageArrived); // sdtout to all message-List
|
||||
this.client.addChatMessage(newMessageArrived); // sdtout to all message-List
|
||||
|
||||
} else {
|
||||
//message is directed to another chatmember, process as such!
|
||||
@@ -817,7 +817,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
if (newMessageArrived.getReceiver().getCallSign()
|
||||
.equals(this.client.getChatPreferences().getStn_loginCallSign())) {
|
||||
|
||||
this.client.getLst_globalChatMessageList().add(0, newMessageArrived);
|
||||
this.client.addChatMessage(newMessageArrived);
|
||||
|
||||
if (this.client.getChatPreferences().isNotify_playSimpleSounds()) {
|
||||
this.client.getPlayAudioUtils().playNoiseLauncher('P');
|
||||
@@ -960,7 +960,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
String originalMessage = newMessageArrived.getMessageText();
|
||||
newMessageArrived
|
||||
.setMessageText("(>" + newMessageArrived.getReceiver().getCallSign() + ")" + originalMessage);
|
||||
this.client.getLst_globalChatMessageList().add(0,newMessageArrived);
|
||||
this.client.addChatMessage(newMessageArrived);
|
||||
|
||||
// if you sent the message to another station, it will be sorted in to
|
||||
// the "to me message list" with modified messagetext, added rxers callsign
|
||||
@@ -1024,7 +1024,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
newMessageArrived.getSender().setInAngleAndRange(false);
|
||||
}
|
||||
|
||||
this.client.getLst_globalChatMessageList().add(0, newMessageArrived);
|
||||
this.client.addChatMessage(newMessageArrived);
|
||||
// System.out.println("MSGBS bgfx: tx call = " + newMessageArrived.getSender().getCallSign() + " / rx call = " + newMessageArrived.getReceiver().getCallSign());
|
||||
}
|
||||
} catch (NullPointerException referenceDeletedByUserLeftChatDuringMessageprocessing) {
|
||||
@@ -1364,7 +1364,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
dummy.setCallSign("ALL");
|
||||
newMessageArrived.setReceiver(dummy);
|
||||
|
||||
this.client.getLst_globalChatMessageList().add(0, newMessageArrived); // sdtout to all message-List
|
||||
this.client.addChatMessage(newMessageArrived); // sdtout to all message-List
|
||||
|
||||
} else {
|
||||
//message is directed to another chatmember, process as such!
|
||||
@@ -1408,7 +1408,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
if (newMessageArrived.getReceiver().getCallSign()
|
||||
.equals(this.client.getChatPreferences().getStn_loginCallSign())) {
|
||||
|
||||
this.client.getLst_globalChatMessageList().add(0, newMessageArrived);
|
||||
this.client.addChatMessage(newMessageArrived);
|
||||
|
||||
System.out.println("Historic message directed to me: " + newMessageArrived.getReceiver().getCallSign() + ".");
|
||||
|
||||
@@ -1421,7 +1421,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
String originalMessage = newMessageArrived.getMessageText();
|
||||
newMessageArrived
|
||||
.setMessageText("(>" + newMessageArrived.getReceiver().getCallSign() + ")" + originalMessage);
|
||||
this.client.getLst_globalChatMessageList().add(0,newMessageArrived);
|
||||
this.client.addChatMessage(newMessageArrived);
|
||||
|
||||
// if you sent the message to another station, it will be sorted in to
|
||||
// the "to me message list" with modified messagetext, added rxers callsign
|
||||
@@ -1441,7 +1441,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
newMessageArrived.getSender().setInAngleAndRange(false);
|
||||
}
|
||||
|
||||
this.client.getLst_globalChatMessageList().add(0, newMessageArrived);
|
||||
this.client.addChatMessage(newMessageArrived);
|
||||
// System.out.println("MSGBS bgfx: tx call = " + newMessageArrived.getSender().getCallSign() + " / rx call = " + newMessageArrived.getReceiver().getCallSign());
|
||||
}
|
||||
} catch (NullPointerException referenceDeletedByUserLeftChatDuringMessageprocessing) {
|
||||
@@ -1514,7 +1514,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
client.getLst_globalChatMessageList().add(pwErrorMsg);
|
||||
client.addChatMessage(pwErrorMsg);
|
||||
// client.getLst_toMeMessageList().add(pwErrorMsg);
|
||||
// client.getLst_toAllMessageList().add(pwErrorMsg);
|
||||
}
|
||||
|
||||
168
src/main/java/kst4contest/utils/BoundedDequeObservableList.java
Normal file
168
src/main/java/kst4contest/utils/BoundedDequeObservableList.java
Normal file
@@ -0,0 +1,168 @@
|
||||
package kst4contest.utils;
|
||||
|
||||
import javafx.collections.ObservableListBase;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A bounded ObservableList backed by a circular buffer (ring buffer).
|
||||
* <p>
|
||||
* Provides O(1) {@link #addFirst} and {@link #addLast} as well as O(1)
|
||||
* random access via {@link #get}. When the list reaches {@code maxCapacity},
|
||||
* adding a new element at the front automatically evicts the oldest element
|
||||
* at the back — and vice versa.
|
||||
* <p>
|
||||
* This is a drop-in replacement for {@code FXCollections.observableArrayList()}
|
||||
* wherever elements are prepended frequently, e.g. chat message lists.
|
||||
*/
|
||||
public class BoundedDequeObservableList<E> extends ObservableListBase<E> {
|
||||
|
||||
private final int maxCapacity;
|
||||
private final Object[] elements;
|
||||
private int head = 0;
|
||||
private int size = 0;
|
||||
|
||||
public BoundedDequeObservableList(int maxCapacity) {
|
||||
if (maxCapacity <= 0) throw new IllegalArgumentException("maxCapacity must be > 0");
|
||||
this.maxCapacity = maxCapacity;
|
||||
this.elements = new Object[maxCapacity];
|
||||
}
|
||||
|
||||
// ── read access ──────────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public E get(int index) {
|
||||
checkIndex(index);
|
||||
return (E) elements[physicalIndex(index)];
|
||||
}
|
||||
|
||||
// ── O(1) deque operations ─────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Inserts {@code element} at index 0 (newest-first order).
|
||||
* If the list is already at capacity the oldest element (last index) is
|
||||
* removed first — both changes are reported as a single compound change.
|
||||
*/
|
||||
public void addFirst(E element) {
|
||||
beginChange();
|
||||
if (size == maxCapacity) {
|
||||
// evict last element
|
||||
int lastPhysical = physicalIndex(size - 1);
|
||||
@SuppressWarnings("unchecked")
|
||||
E evicted = (E) elements[lastPhysical];
|
||||
elements[lastPhysical] = null;
|
||||
size--;
|
||||
nextRemove(size, evicted); // index after decrement == old last index
|
||||
}
|
||||
head = (head - 1 + maxCapacity) % maxCapacity;
|
||||
elements[head] = element;
|
||||
size++;
|
||||
nextAdd(0, 1);
|
||||
endChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends {@code element} at the last index (oldest-first order).
|
||||
* If the list is already at capacity the newest element (index 0) is
|
||||
* removed first.
|
||||
*/
|
||||
public void addLast(E element) {
|
||||
beginChange();
|
||||
if (size == maxCapacity) {
|
||||
// evict first element
|
||||
@SuppressWarnings("unchecked")
|
||||
E evicted = (E) elements[head];
|
||||
elements[head] = null;
|
||||
head = (head + 1) % maxCapacity;
|
||||
size--;
|
||||
nextRemove(0, evicted);
|
||||
}
|
||||
elements[physicalIndex(size)] = element;
|
||||
size++;
|
||||
nextAdd(size - 1, size);
|
||||
endChange();
|
||||
}
|
||||
|
||||
// ── standard List mutation (O(n) — use addFirst/addLast for hot path) ─────
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
if (index == 0) {
|
||||
addFirst(element);
|
||||
return;
|
||||
}
|
||||
if (index == size) {
|
||||
addLast(element);
|
||||
return;
|
||||
}
|
||||
checkIndexForAdd(index);
|
||||
beginChange();
|
||||
if (size == maxCapacity) {
|
||||
int lastPhysical = physicalIndex(size - 1);
|
||||
@SuppressWarnings("unchecked")
|
||||
E evicted = (E) elements[lastPhysical];
|
||||
elements[lastPhysical] = null;
|
||||
size--;
|
||||
nextRemove(size, evicted);
|
||||
}
|
||||
// shift elements [index .. size-1] one position towards the end
|
||||
for (int i = size; i > index; i--) {
|
||||
elements[physicalIndex(i)] = elements[physicalIndex(i - 1)];
|
||||
}
|
||||
elements[physicalIndex(index)] = element;
|
||||
size++;
|
||||
nextAdd(index, index + 1);
|
||||
endChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
checkIndex(index);
|
||||
beginChange();
|
||||
@SuppressWarnings("unchecked")
|
||||
E removed = (E) elements[physicalIndex(index)];
|
||||
// shift elements [index+1 .. size-1] one position towards the front
|
||||
for (int i = index; i < size - 1; i++) {
|
||||
elements[physicalIndex(i)] = elements[physicalIndex(i + 1)];
|
||||
}
|
||||
elements[physicalIndex(size - 1)] = null;
|
||||
size--;
|
||||
nextRemove(index, removed);
|
||||
endChange();
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
checkIndex(index);
|
||||
beginChange();
|
||||
@SuppressWarnings("unchecked")
|
||||
E old = (E) elements[physicalIndex(index)];
|
||||
elements[physicalIndex(index)] = element;
|
||||
nextSet(index, old);
|
||||
endChange();
|
||||
return old;
|
||||
}
|
||||
|
||||
// ── helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
private int physicalIndex(int virtualIndex) {
|
||||
return (head + virtualIndex) % maxCapacity;
|
||||
}
|
||||
|
||||
private void checkIndex(int index) {
|
||||
if (index < 0 || index >= size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
|
||||
}
|
||||
|
||||
private void checkIndexForAdd(int index) {
|
||||
if (index < 0 || index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user