Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/org/openlcb/cdi/swing/CdiPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -2447,7 +2447,7 @@ void updateColor() {
if (eventTableEntryHolder.getEntry().getEvent().equals(id)) {
return;
}
releaseListener();
eraseListener();
}
if (id == null || id.equals(nullEvent)) {
// Ignore event if it is the null event.
Expand All @@ -2465,8 +2465,14 @@ private void releaseListener() {
eventTableEntryHolder.release();
eventTableEntryHolder = null;
}
}

private void eraseListener() {
if (eventTableEntryHolder == null) return;
eventTableEntryHolder.getList().removePropertyChangeListener(eventListUpdateListener);
eventTableEntryHolder.erase();
eventTableEntryHolder = null;
}
}


// represent a slider with an optional text view
Expand Down
83 changes: 75 additions & 8 deletions src/org/openlcb/implementations/EventTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,33 @@
*/

@ThreadSafe
public class EventTable {
public class EventTable extends DefaultPropertyListenerSupport {
private final HashMap<Long, EventInfo> entries = new HashMap<>();

/// This property change notification is produced when the list of descriptions registered
/// for a given event ID has changed (due to addition, removal or description change).
public final static String UPDATED_EVENT_LIST = "UPDATED_EVENT_LIST";

/// This property change notification is produced in addition to UPDATED_EVENT_LIST
/// when a given eventID is removed.
public final static String DESCRIPTION_ADDED = "DESCRIPTION_ADDED";

/// This property change notification is produced in addition to UPDATED_EVENT_LIST
/// when a given eventID holder is removed, e.g. when closing a CDI window.
public final static String DESCRIPTION_REMOVED = "DESCRIPTION_REMOVED";

/// This property change notification is produced in addition to UPDATED_EVENT_LIST
/// when a given eventID description has been erased, e.g. the event ID description is permanently changed
public final static String DESCRIPTION_ERASED = "DESCRIPTION_ERASED";

/// This property change notification is produced in addition to UPDATED_EVENT_LIST
/// when a given eventID is removed.
public final static String DESCRIPTION_UPDATED = "DESCRIPTION_UPDATED";

/// This property change notification is produced when a new EventID-description
/// pair is added via the addEvent method
public final static String EVENT_ENTRY_ADDED = "EVENT_ENTRY_ADDED";

/**
* Looks up a given event ID and tells what we know about it.
*
Expand Down Expand Up @@ -59,7 +79,19 @@ EventInfo getEventInfo(EventID event) {
* keep this and call the release method before going out of scope.
*/
public EventTableEntryHolder addEvent(EventID event, String description) {
return getEventInfo(event).add(description);
synchronized (entries) {
EventTableEntryHolder holder = getEventInfo(event).add(description);
notifyUpdated(holder); // notify _after_ the entry is added
return holder;
}
}


/**
* Helper function used by the modifying functions.
*/
void notifyUpdated(EventTableEntryHolder holder) {
firePropertyChange(EVENT_ENTRY_ADDED, null, holder);
}

/**
Expand Down Expand Up @@ -230,13 +262,15 @@ public EventTableEntryHolder add(String description) {
synchronized (entries) {
entries.add(newEntry);
}
notifyUpdated();
notifyEventUpdated(DESCRIPTION_ADDED);
return h;
}

/**
* Removes the entry represented by a given holder object. This method is not public,
* please use Holder.release() as the client API.
* Removes the entry represented by a given holder object.
* To be used e.g, when a CDI window is closed to drop the connection to the
* event description, without implying that the description has been erased.
* This method is not public, please use Holder.release() as the client API.
*
* @param h the holder object.
*/
Expand All @@ -249,14 +283,37 @@ void remove(EventTableEntryHolder h) {
}
}
}
notifyUpdated();
notifyEventUpdated(DESCRIPTION_REMOVED);
}

/**
* Removes the entry represented by a given holder object.
* To be used e.g, when an event ID in an input field has changed, implying
* that the associated description is no longer relevant for the event ID.
* This method is not public, please use Holder.release() as the client API.
*
* @param h the holder object.
*/
void erase(EventTableEntryHolder h) {
synchronized (entries) {
for (int i = 0; i < entries.size(); ++i) {
if (entries.get(i).h == h) {
entries.remove(i);
--i;
}
}
}
notifyEventUpdated(DESCRIPTION_ERASED);
}

/**
* Helper function used by the modifying functions.
*/
void notifyUpdated() {
void notifyEventUpdated(String reason) {
// fired first for every notification
firePropertyChange(UPDATED_EVENT_LIST, null, this);
// then fire the specific reason
firePropertyChange(reason, null, this);
}

/**
Expand Down Expand Up @@ -320,7 +377,7 @@ public void updateDescription(String newDescription) {
if (description.equals(newDescription)) return;
description = newDescription;
}
h.event.notifyUpdated();
h.event.notifyEventUpdated(DESCRIPTION_UPDATED);
}
}

Expand All @@ -340,11 +397,21 @@ public class EventTableEntryHolder {

/**
* Removes the pointed entry from the event table.
* This is used for transitent removals, e.g. closing a CDI window.
*/
public void release() {
event.remove(this);
}

/**
* Removes the pointed entry from the event table.
* This is used for permenent removal of a description,
* e.g. while editing an EventID field
*/
public void erase() {
event.erase(this);
}

/**
* @return the pointed event table entry.
*/
Expand Down
27 changes: 17 additions & 10 deletions test/org/openlcb/implementations/EventTableTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,29 @@ public void testAddRemove() {
}

class FakeListener implements PropertyChangeListener {
EventTable.EventInfo newValue = null;
int calls = 0;
String expectedCall;
@Override
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
Assert.assertEquals(EventTable.UPDATED_EVENT_LIST, propertyChangeEvent.getPropertyName());
if (! propertyChangeEvent.getPropertyName().equals(expectedCall) &&
! propertyChangeEvent.getPropertyName().equals(EventTable.UPDATED_EVENT_LIST))
Assert.fail(propertyChangeEvent.getPropertyName()+" unexpected");


Assert.assertNull(propertyChangeEvent.getOldValue());

Assert.assertNull("duplicate listener call", newValue);
newValue = (EventTable.EventInfo) propertyChangeEvent.getNewValue();
Assert.assertNotNull(newValue);

calls = calls+1;
}

public void reset() { newValue = null; }
public void reset() { calls = 0; }

public void verifyCall(EventTable.EventInfo expected) {
Assert.assertNotNull("Expected call, but did not happen.", newValue);
Assert.assertTrue("Incorrect newValue passed to property listener", newValue == expected);
Assert.assertEquals("Expected call, but did not happen.", 2, calls);
reset();
}

public void verifyNoInteraction() {
Assert.assertNull("Expected no call, got one.", newValue);
Assert.assertTrue("Expected no call, got one.", calls == 0);
}
}

Expand All @@ -94,18 +96,23 @@ public void testNotify() {

elist.addPropertyChangeListener(l);
l.verifyNoInteraction();

l.expectedCall = EventTable.DESCRIPTION_ADDED;
EventTable.EventTableEntryHolder h1 = elist.add("teste3");
l.verifyCall(elist);

elist.add("teste3alt");
l.verifyCall(elist);

l.expectedCall = EventTable.DESCRIPTION_REMOVED;
h1.release();
l.verifyCall(elist);

l.expectedCall = EventTable.DESCRIPTION_ADDED;
h1 = elist.add("testf3");
l.verifyCall(elist);

l.expectedCall = EventTable.DESCRIPTION_UPDATED;
h1.getEntry().updateDescription("testf3bar");
l.verifyCall(elist);
}
Expand Down
Loading