From 5d260de36036f15f8a441899a734dccfb3f16c07 Mon Sep 17 00:00:00 2001
From: Nils Christian Ehmke <nie@informatik.uni-kiel.de>
Date: Mon, 8 Dec 2014 17:09:19 +0100
Subject: [PATCH] Refactoring

---
 .../java/kieker/gui/model/DataSource.java     |  16 +-
 .../AggregatedExecutionEntry.java             |   2 +-
 .../model/{ => domain}/ExecutionEntry.java    |   2 +-
 .../gui/model/{ => domain}/RecordEntry.java   |   2 +-
 .../importer/ImportAnalysisConfiguration.java |   6 +-
 .../importer/filter/RecordSimplificator.java  |   2 +-
 .../importer/filter/TraceAggregator.java      |   4 +-
 .../importer/filter/TraceReconstructor.java   |   2 +-
 .../kieker/gui/view/ClearTreeObserver.java    |  26 --
 .../ExecutionTraceTreeSelectionListener.java  |  61 ----
 .../view/ExplorerTreeSelectionAdapter.java    |  31 --
 src/main/java/kieker/gui/view/MainWindow.java | 286 +++++++++++-------
 .../view/RecordEntryTimestampComparator.java  |  26 --
 .../gui/view/RecordEntryTypeComparator.java   |  25 --
 .../RecordsTableTimestampSortListener.java    |  40 ---
 .../view/util/AbstractDirectedComparator.java |  17 ++
 ...tedExecutionTracesTreeSetDataListener.java |   6 +-
 .../ExecutionTracesTreeSetDataListener.java   |  10 +-
 .../util/RecordEntryTimestampComparator.java  |  18 ++
 .../view/util/RecordEntryTypeComparator.java  |  18 ++
 .../RecordsTableSetDataListener.java          |   6 +-
 .../TableColumnSortListener.java}             |  18 +-
 22 files changed, 285 insertions(+), 339 deletions(-)
 rename src/main/java/kieker/gui/model/{ => domain}/AggregatedExecutionEntry.java (98%)
 rename src/main/java/kieker/gui/model/{ => domain}/ExecutionEntry.java (99%)
 rename src/main/java/kieker/gui/model/{ => domain}/RecordEntry.java (97%)
 delete mode 100644 src/main/java/kieker/gui/view/ClearTreeObserver.java
 delete mode 100644 src/main/java/kieker/gui/view/ExecutionTraceTreeSelectionListener.java
 delete mode 100644 src/main/java/kieker/gui/view/ExplorerTreeSelectionAdapter.java
 delete mode 100644 src/main/java/kieker/gui/view/RecordEntryTimestampComparator.java
 delete mode 100644 src/main/java/kieker/gui/view/RecordEntryTypeComparator.java
 delete mode 100644 src/main/java/kieker/gui/view/RecordsTableTimestampSortListener.java
 create mode 100644 src/main/java/kieker/gui/view/util/AbstractDirectedComparator.java
 rename src/main/java/kieker/gui/view/{ => util}/AggregatedExecutionTracesTreeSetDataListener.java (92%)
 rename src/main/java/kieker/gui/view/{ => util}/ExecutionTracesTreeSetDataListener.java (90%)
 create mode 100644 src/main/java/kieker/gui/view/util/RecordEntryTimestampComparator.java
 create mode 100644 src/main/java/kieker/gui/view/util/RecordEntryTypeComparator.java
 rename src/main/java/kieker/gui/view/{ => util}/RecordsTableSetDataListener.java (86%)
 rename src/main/java/kieker/gui/view/{RecordsTableTypeSortListener.java => util/TableColumnSortListener.java} (68%)

diff --git a/src/main/java/kieker/gui/model/DataSource.java b/src/main/java/kieker/gui/model/DataSource.java
index 514215aa..f752127d 100644
--- a/src/main/java/kieker/gui/model/DataSource.java
+++ b/src/main/java/kieker/gui/model/DataSource.java
@@ -19,7 +19,11 @@ package kieker.gui.model;
 import java.io.File;
 import java.util.Collections;
 import java.util.List;
+import java.util.Observable;
 
+import kieker.gui.model.domain.AggregatedExecutionEntry;
+import kieker.gui.model.domain.ExecutionEntry;
+import kieker.gui.model.domain.RecordEntry;
 import kieker.gui.model.importer.ImportAnalysisConfiguration;
 import teetime.framework.Analysis;
 
@@ -28,12 +32,19 @@ import teetime.framework.Analysis;
  *
  * @author Nils Christian Ehmke
  */
-public final class DataSource {
+public final class DataSource extends Observable {
 
+	private static final DataSource INSTANCE = new DataSource();
 	private List<RecordEntry> records = Collections.emptyList();
 	private List<ExecutionEntry> traces = Collections.emptyList();
 	private List<AggregatedExecutionEntry> aggregatedTraces;
 
+	private DataSource() {}
+
+	public static DataSource getInstance() {
+		return DataSource.INSTANCE;
+	}
+
 	public void loadMonitoringLogFromFS(final String directory) {
 		// Load and analyze the monitoring logs from the given directory
 		final File importDirectory = new File(directory);
@@ -46,6 +57,9 @@ public final class DataSource {
 		this.records = analysisConfiguration.getRecordsList();
 		this.traces = analysisConfiguration.getTracesList();
 		this.aggregatedTraces = analysisConfiguration.getAggregatedTraces();
+
+		this.setChanged();
+		this.notifyObservers();
 	}
 
 	public List<RecordEntry> getRecords() {
diff --git a/src/main/java/kieker/gui/model/AggregatedExecutionEntry.java b/src/main/java/kieker/gui/model/domain/AggregatedExecutionEntry.java
similarity index 98%
rename from src/main/java/kieker/gui/model/AggregatedExecutionEntry.java
rename to src/main/java/kieker/gui/model/domain/AggregatedExecutionEntry.java
index 9fcf9db2..8c2534ce 100644
--- a/src/main/java/kieker/gui/model/AggregatedExecutionEntry.java
+++ b/src/main/java/kieker/gui/model/domain/AggregatedExecutionEntry.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  ***************************************************************************/
 
-package kieker.gui.model;
+package kieker.gui.model.domain;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/main/java/kieker/gui/model/ExecutionEntry.java b/src/main/java/kieker/gui/model/domain/ExecutionEntry.java
similarity index 99%
rename from src/main/java/kieker/gui/model/ExecutionEntry.java
rename to src/main/java/kieker/gui/model/domain/ExecutionEntry.java
index 598e7d68..e3fb7e1e 100644
--- a/src/main/java/kieker/gui/model/ExecutionEntry.java
+++ b/src/main/java/kieker/gui/model/domain/ExecutionEntry.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  ***************************************************************************/
 
-package kieker.gui.model;
+package kieker.gui.model.domain;
 
 import java.util.ArrayList;
 import java.util.Iterator;
diff --git a/src/main/java/kieker/gui/model/RecordEntry.java b/src/main/java/kieker/gui/model/domain/RecordEntry.java
similarity index 97%
rename from src/main/java/kieker/gui/model/RecordEntry.java
rename to src/main/java/kieker/gui/model/domain/RecordEntry.java
index a4914d32..987f8997 100644
--- a/src/main/java/kieker/gui/model/RecordEntry.java
+++ b/src/main/java/kieker/gui/model/domain/RecordEntry.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  ***************************************************************************/
 
-package kieker.gui.model;
+package kieker.gui.model.domain;
 
 /**
  * A simplified representation of a monitoring record.
diff --git a/src/main/java/kieker/gui/model/importer/ImportAnalysisConfiguration.java b/src/main/java/kieker/gui/model/importer/ImportAnalysisConfiguration.java
index cf73b0e7..ec13cd44 100644
--- a/src/main/java/kieker/gui/model/importer/ImportAnalysisConfiguration.java
+++ b/src/main/java/kieker/gui/model/importer/ImportAnalysisConfiguration.java
@@ -22,9 +22,9 @@ import java.util.Vector;
 
 import kieker.common.record.IMonitoringRecord;
 import kieker.common.record.flow.IFlowRecord;
-import kieker.gui.model.AggregatedExecutionEntry;
-import kieker.gui.model.ExecutionEntry;
-import kieker.gui.model.RecordEntry;
+import kieker.gui.model.domain.AggregatedExecutionEntry;
+import kieker.gui.model.domain.ExecutionEntry;
+import kieker.gui.model.domain.RecordEntry;
 import kieker.gui.model.importer.filter.Cloner;
 import kieker.gui.model.importer.filter.RecordSimplificator;
 import kieker.gui.model.importer.filter.TraceAggregator;
diff --git a/src/main/java/kieker/gui/model/importer/filter/RecordSimplificator.java b/src/main/java/kieker/gui/model/importer/filter/RecordSimplificator.java
index 28ad9c64..0ee3602c 100644
--- a/src/main/java/kieker/gui/model/importer/filter/RecordSimplificator.java
+++ b/src/main/java/kieker/gui/model/importer/filter/RecordSimplificator.java
@@ -17,7 +17,7 @@
 package kieker.gui.model.importer.filter;
 
 import kieker.common.record.IMonitoringRecord;
-import kieker.gui.model.RecordEntry;
+import kieker.gui.model.domain.RecordEntry;
 import teetime.framework.AbstractConsumerStage;
 import teetime.framework.OutputPort;
 
diff --git a/src/main/java/kieker/gui/model/importer/filter/TraceAggregator.java b/src/main/java/kieker/gui/model/importer/filter/TraceAggregator.java
index 97dab84b..609422c6 100644
--- a/src/main/java/kieker/gui/model/importer/filter/TraceAggregator.java
+++ b/src/main/java/kieker/gui/model/importer/filter/TraceAggregator.java
@@ -19,8 +19,8 @@ package kieker.gui.model.importer.filter;
 import java.util.HashMap;
 import java.util.Map;
 
-import kieker.gui.model.AggregatedExecutionEntry;
-import kieker.gui.model.ExecutionEntry;
+import kieker.gui.model.domain.AggregatedExecutionEntry;
+import kieker.gui.model.domain.ExecutionEntry;
 import teetime.framework.AbstractConsumerStage;
 import teetime.framework.OutputPort;
 
diff --git a/src/main/java/kieker/gui/model/importer/filter/TraceReconstructor.java b/src/main/java/kieker/gui/model/importer/filter/TraceReconstructor.java
index 42454d88..c7058aaf 100644
--- a/src/main/java/kieker/gui/model/importer/filter/TraceReconstructor.java
+++ b/src/main/java/kieker/gui/model/importer/filter/TraceReconstructor.java
@@ -27,7 +27,7 @@ import kieker.common.record.flow.trace.operation.AbstractOperationEvent;
 import kieker.common.record.flow.trace.operation.AfterOperationEvent;
 import kieker.common.record.flow.trace.operation.AfterOperationFailedEvent;
 import kieker.common.record.flow.trace.operation.BeforeOperationEvent;
-import kieker.gui.model.ExecutionEntry;
+import kieker.gui.model.domain.ExecutionEntry;
 import teetime.framework.AbstractConsumerStage;
 import teetime.framework.OutputPort;
 
diff --git a/src/main/java/kieker/gui/view/ClearTreeObserver.java b/src/main/java/kieker/gui/view/ClearTreeObserver.java
deleted file mode 100644
index f446fd55..00000000
--- a/src/main/java/kieker/gui/view/ClearTreeObserver.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package kieker.gui.view;
-
-import java.util.Observable;
-import java.util.Observer;
-
-import org.eclipse.swt.widgets.Tree;
-
-/**
- * An observer clearing an instance of {@link Tree}.
- *
- * @author Nils Christian Ehmke
- */
-public final class ClearTreeObserver implements Observer {
-
-	private final Tree tree;
-
-	public ClearTreeObserver(final Tree tree) {
-		this.tree = tree;
-	}
-
-	@Override
-	public void update(final Observable observable, final Object obj) {
-		this.tree.clearAll(true);
-	}
-
-}
diff --git a/src/main/java/kieker/gui/view/ExecutionTraceTreeSelectionListener.java b/src/main/java/kieker/gui/view/ExecutionTraceTreeSelectionListener.java
deleted file mode 100644
index 170ec8d7..00000000
--- a/src/main/java/kieker/gui/view/ExecutionTraceTreeSelectionListener.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package kieker.gui.view;
-
-import kieker.gui.model.ExecutionEntry;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Display;
-
-class ExecutionTraceTreeSelectionListener implements SelectionListener {
-
-	/**
-	 * 
-	 */
-	private final MainWindow mainWindow;
-
-	/**
-	 * @param mainWindow
-	 */
-	ExecutionTraceTreeSelectionListener(MainWindow mainWindow) {
-		this.mainWindow = mainWindow;
-	}
-
-	@Override
-	public void widgetSelected(final SelectionEvent e) {
-		final Object data = e.item.getData();
-		if (data instanceof ExecutionEntry) {
-			this.mainWindow.lblNa_1.setText(Long.toString(((ExecutionEntry) data).getTraceID()));
-			this.mainWindow.lblNa_3.setText(Long.toString(((ExecutionEntry) data).getDuration()));
-
-			this.mainWindow.lblNa_4.setText(((ExecutionEntry) data).getContainer());
-			this.mainWindow.lblNa_5.setText(((ExecutionEntry) data).getComponent());
-			this.mainWindow.lblNa_6.setText(((ExecutionEntry) data).getOperation());
-			this.mainWindow.lblNa_7.setText(Integer.toString(((ExecutionEntry) data).getStackDepth()));
-
-			if (((ExecutionEntry) data).isFailed()) {
-				this.mainWindow.lblNa_2.setText("Yes (" + ((ExecutionEntry) data).getFailedCause() + ")");
-				this.mainWindow.lblNa_2.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
-				this.mainWindow.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
-			} else {
-				this.mainWindow.lblNa_2.setText("No");
-				this.mainWindow.lblNa_2.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
-				this.mainWindow.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
-			}
-
-			this.mainWindow.lblNa_1.pack();
-			this.mainWindow.lblNa_2.pack();
-			this.mainWindow.lblNa_3.pack();
-			this.mainWindow.lblNa_4.pack();
-			this.mainWindow.lblNa_5.pack();
-			this.mainWindow.lblNa_6.pack();
-			this.mainWindow.lblNa_7.pack();
-		}
-	}
-
-	@Override
-	public void widgetDefaultSelected(final SelectionEvent e) {
-
-	}
-
-}
\ No newline at end of file
diff --git a/src/main/java/kieker/gui/view/ExplorerTreeSelectionAdapter.java b/src/main/java/kieker/gui/view/ExplorerTreeSelectionAdapter.java
deleted file mode 100644
index 0f2a8e12..00000000
--- a/src/main/java/kieker/gui/view/ExplorerTreeSelectionAdapter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package kieker.gui.view;
-
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.widgets.Widget;
-
-public final class ExplorerTreeSelectionAdapter extends SelectionAdapter {
-
-	private final MainWindow mainWindow;
-
-	public ExplorerTreeSelectionAdapter(final MainWindow mainWindow) {
-		this.mainWindow = mainWindow;
-	}
-
-	@Override
-	public void widgetSelected(final SelectionEvent e) {
-		final Widget selectedWidget = e.item;
-
-		if (this.mainWindow.recordsTreeItem == selectedWidget) {
-			this.mainWindow.showRecords();
-		} else if (this.mainWindow.executionTracesTreeItem == selectedWidget) {
-			this.mainWindow.showExecutionTraces();
-		} else if (this.mainWindow.trtmAggregatedExecutionTraces == selectedWidget) {
-			this.mainWindow.showAggregatedExecutionTraces();
-		} else {
-			this.mainWindow.setVisibleMainComponent(null);
-			this.mainWindow.lblNa.setText("");
-		}
-	}
-
-}
diff --git a/src/main/java/kieker/gui/view/MainWindow.java b/src/main/java/kieker/gui/view/MainWindow.java
index 987baa90..c21dd4f7 100644
--- a/src/main/java/kieker/gui/view/MainWindow.java
+++ b/src/main/java/kieker/gui/view/MainWindow.java
@@ -17,12 +17,20 @@
 package kieker.gui.view;
 
 import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
 
-import kieker.gui.model.AggregatedExecutionEntry;
 import kieker.gui.model.DataSource;
-import kieker.gui.model.ExecutionEntry;
 import kieker.gui.model.Properties;
-import kieker.gui.model.RecordEntry;
+import kieker.gui.model.domain.AggregatedExecutionEntry;
+import kieker.gui.model.domain.ExecutionEntry;
+import kieker.gui.model.domain.RecordEntry;
+import kieker.gui.view.util.AggregatedExecutionTracesTreeSetDataListener;
+import kieker.gui.view.util.ExecutionTracesTreeSetDataListener;
+import kieker.gui.view.util.RecordEntryTimestampComparator;
+import kieker.gui.view.util.RecordEntryTypeComparator;
+import kieker.gui.view.util.RecordsTableSetDataListener;
+import kieker.gui.view.util.TableColumnSortListener;
 
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.viewers.TreeViewer;
@@ -46,6 +54,7 @@ import org.eclipse.swt.widgets.TableColumn;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeColumn;
 import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.swt.widgets.Widget;
 import org.eclipse.wb.swt.SWTResourceManager;
 
 /**
@@ -53,7 +62,7 @@ import org.eclipse.wb.swt.SWTResourceManager;
  *
  * @author Nils Christian Ehmke
  */
-public class MainWindow {
+public final class MainWindow {
 
 	protected Shell shell;
 	private Composite mainComposite;
@@ -75,7 +84,7 @@ public class MainWindow {
 	private Menu helpMenu;
 	private MenuItem aboutMenuItem;
 	private Tree explorerTree;
-	private Tree executionTracesTree;
+	private Tree tracesTree;
 	private TreeColumn tracesTreeContainerColumn;
 	private TreeColumn treeColumn_8;
 	private TreeColumn treeColumn_10;
@@ -89,7 +98,6 @@ public class MainWindow {
 	private MenuItem mntmLongOperationParameters;
 	private TableColumn recordsTableTypeColumn;
 	private SashForm explorerForm;
-	final DataSource model = new DataSource();
 	private TreeColumn trclmnPercent;
 	Label lblNa;
 	private SashForm executionTracesForm;
@@ -109,7 +117,7 @@ public class MainWindow {
 	private Label lblStackDepth;
 	Label lblNa_7;
 	private SashForm sashForm;
-	private Tree tree_1;
+	private Tree aggregatedTracesTree;
 	private TreeColumn treeColumn;
 	private TreeColumn treeColumn_1;
 	private TreeColumn treeColumn_2;
@@ -135,7 +143,8 @@ public class MainWindow {
 	public void open() {
 		final Display display = Display.getDefault();
 		this.createContents();
-		this.model.loadMonitoringLogFromFS("testdata");
+		this.addLogic();
+		DataSource.getInstance().loadMonitoringLogFromFS("testdata");
 		this.shell.open();
 		this.shell.layout();
 		while (!this.shell.isDisposed()) {
@@ -175,7 +184,6 @@ public class MainWindow {
 		this.executionTracesTreeItem.setExpanded(true);
 		this.explorerTreeItem.setExpanded(true);
 
-		this.explorerTree.addSelectionListener(new ExplorerTreeSelectionAdapter(this));
 		this.explorerForm.setWeights(new int[] { 3 });
 
 		this.mainComposite = new Composite(this.outerForm, SWT.NONE);
@@ -185,52 +193,45 @@ public class MainWindow {
 		this.recordsTableViewer = new TableViewer(this.mainComposite, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
 		this.recordsTable = this.recordsTableViewer.getTable();
 		this.recordsTable.setHeaderVisible(true);
-		this.recordsTable.addListener(SWT.SetData, new RecordsTableSetDataListener());
 
 		this.recordsTableTimestampColumn = new TableColumn(this.recordsTable, SWT.NONE);
 		this.recordsTableTimestampColumn.setWidth(100);
 		this.recordsTableTimestampColumn.setText("Timestamp");
-		this.recordsTableTimestampColumn.addListener(SWT.Selection, new RecordsTableTimestampSortListener());
 
 		this.recordsTableTypeColumn = new TableColumn(this.recordsTable, SWT.NONE);
 		this.recordsTableTypeColumn.setWidth(100);
 		this.recordsTableTypeColumn.setText("Type");
-		this.recordsTableTypeColumn.addListener(SWT.Selection, new RecordsTableTypeSortListener());
 
 		this.recordsTableRecordColumn = new TableColumn(this.recordsTable, SWT.NONE);
 		this.recordsTableRecordColumn.setWidth(100);
 		this.recordsTableRecordColumn.setText("Record");
-		this.recordsTableRecordColumn.addListener(SWT.Selection, new RecordsTableTimestampSortListener());
 
 		this.executionTracesForm = new SashForm(this.mainComposite, SWT.VERTICAL);
 
-		this.executionTracesTree = new Tree(this.executionTracesForm, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
-		this.executionTracesTree.setHeaderVisible(true);
-		this.executionTracesTree.addListener(SWT.SetData, new ExecutionTracesTreeSetDataListener());
-		this.executionTracesTree.addSelectionListener(new ExecutionTraceTreeSelectionListener(this));
-		Properties.getInstance().addObserver(new ClearTreeObserver(this.executionTracesTree));
+		this.tracesTree = new Tree(this.executionTracesForm, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
+		this.tracesTree.setHeaderVisible(true);
 
-		this.tracesTreeContainerColumn = new TreeColumn(this.executionTracesTree, SWT.NONE);
+		this.tracesTreeContainerColumn = new TreeColumn(this.tracesTree, SWT.NONE);
 		this.tracesTreeContainerColumn.setWidth(100);
 		this.tracesTreeContainerColumn.setText("Execution Container");
 
-		this.treeColumn_8 = new TreeColumn(this.executionTracesTree, SWT.NONE);
+		this.treeColumn_8 = new TreeColumn(this.tracesTree, SWT.NONE);
 		this.treeColumn_8.setWidth(100);
 		this.treeColumn_8.setText("Component");
 
-		this.treeColumn_10 = new TreeColumn(this.executionTracesTree, SWT.NONE);
+		this.treeColumn_10 = new TreeColumn(this.tracesTree, SWT.NONE);
 		this.treeColumn_10.setWidth(100);
 		this.treeColumn_10.setText("Operation");
 
-		this.treeColumn_11 = new TreeColumn(this.executionTracesTree, SWT.NONE);
+		this.treeColumn_11 = new TreeColumn(this.tracesTree, SWT.NONE);
 		this.treeColumn_11.setWidth(100);
 		this.treeColumn_11.setText("Duration");
 
-		this.trclmnPercent = new TreeColumn(this.executionTracesTree, SWT.NONE);
+		this.trclmnPercent = new TreeColumn(this.tracesTree, SWT.NONE);
 		this.trclmnPercent.setWidth(100);
 		this.trclmnPercent.setText("Percent");
 
-		this.treeColumn_16 = new TreeColumn(this.executionTracesTree, SWT.NONE);
+		this.treeColumn_16 = new TreeColumn(this.tracesTree, SWT.NONE);
 		this.treeColumn_16.setWidth(100);
 		this.treeColumn_16.setText("Trace ID");
 
@@ -298,24 +299,22 @@ public class MainWindow {
 
 		this.sashForm = new SashForm(this.mainComposite, SWT.VERTICAL);
 
-		this.tree_1 = new Tree(this.sashForm, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
-		this.tree_1.setHeaderVisible(true);
-		this.tree_1.addListener(SWT.SetData, new AggregatedExecutionTracesTreeSetDataListener());
-		Properties.getInstance().addObserver(new ClearTreeObserver(this.tree_1));
+		this.aggregatedTracesTree = new Tree(this.sashForm, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
+		this.aggregatedTracesTree.setHeaderVisible(true);
 
-		this.treeColumn = new TreeColumn(this.tree_1, SWT.NONE);
+		this.treeColumn = new TreeColumn(this.aggregatedTracesTree, SWT.NONE);
 		this.treeColumn.setWidth(100);
 		this.treeColumn.setText("Execution Container");
 
-		this.treeColumn_1 = new TreeColumn(this.tree_1, SWT.NONE);
+		this.treeColumn_1 = new TreeColumn(this.aggregatedTracesTree, SWT.NONE);
 		this.treeColumn_1.setWidth(100);
 		this.treeColumn_1.setText("Component");
 
-		this.treeColumn_2 = new TreeColumn(this.tree_1, SWT.NONE);
+		this.treeColumn_2 = new TreeColumn(this.aggregatedTracesTree, SWT.NONE);
 		this.treeColumn_2.setWidth(100);
 		this.treeColumn_2.setText("Operation");
 
-		this.trclmnCalls = new TreeColumn(this.tree_1, SWT.NONE);
+		this.trclmnCalls = new TreeColumn(this.aggregatedTracesTree, SWT.NONE);
 		this.trclmnCalls.setWidth(100);
 		this.trclmnCalls.setText("# Calls");
 
@@ -377,12 +376,6 @@ public class MainWindow {
 		this.fileMenuItem.setMenu(this.fileMenu);
 
 		this.openMonitoringLogMenuItem = new MenuItem(this.fileMenu, SWT.NONE);
-		this.openMonitoringLogMenuItem.addSelectionListener(new SelectionAdapter() {
-			@Override
-			public void widgetSelected(final SelectionEvent e) {
-				MainWindow.this.showOpenMonitoringLogDialog();
-			}
-		});
 		this.openMonitoringLogMenuItem.setText("Open Monitoring Log");
 
 		new MenuItem(this.fileMenu, SWT.SEPARATOR);
@@ -398,137 +391,226 @@ public class MainWindow {
 
 		this.mntmShortOperationParameters = new MenuItem(this.menu, SWT.RADIO);
 		this.mntmShortOperationParameters.setSelection(true);
+		this.mntmShortOperationParameters.setText("Short Operation Parameters");
+
+		this.mntmLongOperationParameters = new MenuItem(this.menu, SWT.RADIO);
+		this.mntmLongOperationParameters.setText("Long Operation Parameters");
+
+		new MenuItem(this.menu, SWT.SEPARATOR);
+
+		this.mntmShortComponentNames = new MenuItem(this.menu, SWT.RADIO);
+		this.mntmShortComponentNames.setText("Short Component Names");
+
+		this.mntmLongComponentNames = new MenuItem(this.menu, SWT.RADIO);
+		this.mntmLongComponentNames.setSelection(true);
+		this.mntmLongComponentNames.setText("Long Component Names");
+
+		this.helpMenuItem = new MenuItem(this.menuBar, SWT.CASCADE);
+		this.helpMenuItem.setText("Help");
+
+		this.helpMenu = new Menu(this.helpMenuItem);
+		this.helpMenuItem.setMenu(this.helpMenu);
+
+		this.aboutMenuItem = new MenuItem(this.helpMenu, SWT.NONE);
+		this.aboutMenuItem.setText("About...");
+
+		this.lblNa = new Label(this.shell, SWT.NONE);
+		this.lblNa.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
+	}
+
+	private void addLogic() {
+		DataSource.getInstance().addObserver(new Observer() {
+
+			@Override
+			public void update(final Observable o, final Object arg) {
+				MainWindow.this.reloadFromModel();
+			}
+
+		});
+
+		this.openMonitoringLogMenuItem.addSelectionListener(new SelectionAdapter() {
+
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				MainWindow.this.showOpenMonitoringLogDialog();
+			}
+
+		});
+
 		this.mntmShortOperationParameters.addSelectionListener(new SelectionAdapter() {
+
 			@Override
 			public void widgetSelected(final SelectionEvent e) {
 				Properties.getInstance().setShortOperationParameters(true);
 			}
+
 		});
-		this.mntmShortOperationParameters.setText("Short Operation Parameters");
 
-		this.mntmLongOperationParameters = new MenuItem(this.menu, SWT.RADIO);
 		this.mntmLongOperationParameters.addSelectionListener(new SelectionAdapter() {
+
 			@Override
 			public void widgetSelected(final SelectionEvent e) {
 				Properties.getInstance().setShortOperationParameters(false);
 			}
-		});
-		this.mntmLongOperationParameters.setText("Long Operation Parameters");
 
-		new MenuItem(this.menu, SWT.SEPARATOR);
+		});
 
-		this.mntmShortComponentNames = new MenuItem(this.menu, SWT.RADIO);
 		this.mntmShortComponentNames.addSelectionListener(new SelectionAdapter() {
+
 			@Override
 			public void widgetSelected(final SelectionEvent e) {
 				Properties.getInstance().setShortComponentNames(true);
 			}
+
 		});
-		this.mntmShortComponentNames.setText("Short Component Names");
 
-		this.mntmLongComponentNames = new MenuItem(this.menu, SWT.RADIO);
 		this.mntmLongComponentNames.addSelectionListener(new SelectionAdapter() {
+
 			@Override
 			public void widgetSelected(final SelectionEvent e) {
 				Properties.getInstance().setShortComponentNames(false);
 			}
+
 		});
-		this.mntmLongComponentNames.setSelection(true);
-		this.mntmLongComponentNames.setText("Long Component Names");
 
-		this.helpMenuItem = new MenuItem(this.menuBar, SWT.CASCADE);
-		this.helpMenuItem.setText("Help");
+		Properties.getInstance().addObserver(new Observer() {
 
-		this.helpMenu = new Menu(this.helpMenuItem);
-		this.helpMenuItem.setMenu(this.helpMenu);
+			@Override
+			public void update(final Observable o, final Object arg) {
+				MainWindow.this.aggregatedTracesTree.clearAll(true);
+				MainWindow.this.tracesTree.clearAll(true);
+			}
 
-		this.aboutMenuItem = new MenuItem(this.helpMenu, SWT.NONE);
-		this.aboutMenuItem.setText("About...");
+		});
 
-		this.lblNa = new Label(this.shell, SWT.NONE);
-		this.lblNa.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
-	}
+		this.recordsTable.addListener(SWT.SetData, new RecordsTableSetDataListener());
+		this.aggregatedTracesTree.addListener(SWT.SetData, new AggregatedExecutionTracesTreeSetDataListener());
+		this.tracesTree.addListener(SWT.SetData, new ExecutionTracesTreeSetDataListener());
 
-	protected void showSystemModel() {
-		// Show the tree
+		this.recordsTableTimestampColumn.addListener(SWT.Selection, new TableColumnSortListener<RecordEntry>(new RecordEntryTimestampComparator()));
+		this.recordsTableTypeColumn.addListener(SWT.Selection, new TableColumnSortListener<RecordEntry>(new RecordEntryTypeComparator()));
+		this.recordsTableRecordColumn.addListener(SWT.Selection, new TableColumnSortListener<RecordEntry>(new RecordEntryTimestampComparator()));
+
+		this.explorerTree.addSelectionListener(new SelectionAdapter() {
+
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				final Widget selectedWidget = e.item;
+				MainWindow.this.handleExplorerSelection(selectedWidget);
+			}
+		});
+
+		this.tracesTree.addSelectionListener(new SelectionAdapter() {
+
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				final Object data = e.item.getData();
+				if (data instanceof ExecutionEntry) {
+					MainWindow.this.handleTracesSelection((ExecutionEntry) data);
+				}
+			}
 
+		});
 	}
 
-	protected void showAggregatedExecutionTraces() {
+	private void showAggregatedExecutionTraces() {
 		// Show the tree
 		this.setVisibleMainComponent(this.sashForm);
 
-		// Reload the data from the model...
-		final List<AggregatedExecutionEntry> traces = this.model.getAggregatedTrace();
-
-		// ...and write it into the tree
-		this.tree_1.setItemCount(traces.size());
-		this.tree_1.setData(traces);
-		this.lblNa.setText(Integer.toString(traces.size()) + " Aggregated Traces");
-		this.lblNa.pack();
-
 		// Resize the columns
-		for (final TreeColumn column : this.tree_1.getColumns()) {
+		for (final TreeColumn column : this.aggregatedTracesTree.getColumns()) {
 			column.pack();
 		}
 	}
 
-	protected void showAggregatedExecutionTracesByContainer() {
-
-	}
-
-	protected void showAggregatedExecutionTracesByComponent() {
-
-	}
-
-	protected void showExecutionTraces() {
+	private void showExecutionTraces() {
 		// Show the tree
 		this.setVisibleMainComponent(this.executionTracesForm);
 
-		// Reload the data from the model...
-		final List<ExecutionEntry> traces = this.model.getTraces();
-
-		// ...and write it into the tree
-		this.executionTracesTree.setItemCount(traces.size());
-		this.executionTracesTree.setData(traces);
-		this.lblNa.setText(Integer.toString(traces.size()) + " Traces");
-		this.lblNa.pack();
-
 		// Resize the columns
-		for (final TreeColumn column : this.executionTracesTree.getColumns()) {
+		for (final TreeColumn column : this.tracesTree.getColumns()) {
 			column.pack();
 		}
 	}
 
-	protected void showRecords() {
+	private void showRecords() {
 		// Show the table
 		this.setVisibleMainComponent(this.recordsTable);
 
-		// Reload the data from the model...
-		final List<RecordEntry> records = this.model.getRecords();
-
-		// ...and write it into the table
-		this.recordsTable.setItemCount(records.size());
-		this.recordsTable.setData(records);
-		this.lblNa.setText(Integer.toString(records.size()) + " Records");
-		this.lblNa.pack();
-
 		// Resize the columns
 		for (final TableColumn column : this.recordsTable.getColumns()) {
 			column.pack();
 		}
 	}
 
-	protected void showOpenMonitoringLogDialog() {
+	private void handleExplorerSelection(final Widget selectedWidget) {
+		if (MainWindow.this.recordsTreeItem == selectedWidget) {
+			MainWindow.this.showRecords();
+		} else if (MainWindow.this.executionTracesTreeItem == selectedWidget) {
+			MainWindow.this.showExecutionTraces();
+		} else if (MainWindow.this.trtmAggregatedExecutionTraces == selectedWidget) {
+			MainWindow.this.showAggregatedExecutionTraces();
+		} else {
+			MainWindow.this.setVisibleMainComponent(null);
+			MainWindow.this.lblNa.setText("");
+		}
+	}
+
+	private void handleTracesSelection(final ExecutionEntry data) {
+		this.lblNa_1.setText(Long.toString(data.getTraceID()));
+		this.lblNa_3.setText(Long.toString(data.getDuration()));
+
+		this.lblNa_4.setText(data.getContainer());
+		this.lblNa_5.setText(data.getComponent());
+		this.lblNa_6.setText(data.getOperation());
+		this.lblNa_7.setText(Integer.toString(data.getStackDepth()));
+
+		if (data.isFailed()) {
+			this.lblNa_2.setText("Yes (" + data.getFailedCause() + ")");
+			this.lblNa_2.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+		} else {
+			this.lblNa_2.setText("No");
+			this.lblNa_2.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+		}
+
+		this.lblNa_1.pack();
+		this.lblNa_2.pack();
+		this.lblNa_3.pack();
+		this.lblNa_4.pack();
+		this.lblNa_5.pack();
+		this.lblNa_6.pack();
+		this.lblNa_7.pack();
+	}
+
+	private void reloadFromModel() {
+		// Reload the data from the model...
+		final List<RecordEntry> records = DataSource.getInstance().getRecords();
+		final List<ExecutionEntry> traces = DataSource.getInstance().getTraces();
+		final List<AggregatedExecutionEntry> aggregatedTraces = DataSource.getInstance().getAggregatedTrace();
+
+		// ...and write it into the corresponding widgets
+		MainWindow.this.recordsTable.setItemCount(records.size());
+		MainWindow.this.recordsTable.setData(records);
+
+		MainWindow.this.tracesTree.setItemCount(traces.size());
+		MainWindow.this.tracesTree.setData(traces);
+
+		MainWindow.this.aggregatedTracesTree.setItemCount(aggregatedTraces.size());
+		MainWindow.this.aggregatedTracesTree.setData(aggregatedTraces);
+	}
+
+	private void showOpenMonitoringLogDialog() {
 		final DirectoryDialog dialog = new DirectoryDialog(this.shell);
 		final String selectedDirectory = dialog.open();
 
 		if (null != selectedDirectory) {
-			this.model.loadMonitoringLogFromFS(selectedDirectory);
+			DataSource.getInstance().loadMonitoringLogFromFS(selectedDirectory);
 		}
 	}
 
-	void setVisibleMainComponent(final Control component) {
+	private void setVisibleMainComponent(final Control component) {
 		final StackLayout layout = (StackLayout) this.mainComposite.getLayout();
 		layout.topControl = component;
 
diff --git a/src/main/java/kieker/gui/view/RecordEntryTimestampComparator.java b/src/main/java/kieker/gui/view/RecordEntryTimestampComparator.java
deleted file mode 100644
index 45927152..00000000
--- a/src/main/java/kieker/gui/view/RecordEntryTimestampComparator.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package kieker.gui.view;
-
-import java.util.Comparator;
-
-import kieker.gui.model.RecordEntry;
-
-import org.eclipse.swt.SWT;
-
-class RecordEntryTimestampComparator implements Comparator<RecordEntry> {
-
-	private final int direction;
-
-	public RecordEntryTimestampComparator(final int direction) {
-		this.direction = direction;
-	}
-
-	@Override
-	public int compare(final RecordEntry o1, final RecordEntry o2) {
-		int result = Long.compare(o1.getTimestamp(), o2.getTimestamp());
-		if (this.direction == SWT.UP) {
-			result = -result;
-		}
-		return result;
-	}
-
-}
\ No newline at end of file
diff --git a/src/main/java/kieker/gui/view/RecordEntryTypeComparator.java b/src/main/java/kieker/gui/view/RecordEntryTypeComparator.java
deleted file mode 100644
index 28b80f21..00000000
--- a/src/main/java/kieker/gui/view/RecordEntryTypeComparator.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package kieker.gui.view;
-
-import java.util.Comparator;
-
-import kieker.gui.model.RecordEntry;
-
-import org.eclipse.swt.SWT;
-
-class RecordEntryTypeComparator implements Comparator<RecordEntry> {
-
-	private final int direction;
-
-	public RecordEntryTypeComparator(final int direction) {
-		this.direction = direction;
-	}
-
-	@Override
-	public int compare(final RecordEntry o1, final RecordEntry o2) {
-		int result = o1.getType().compareTo(o2.getType());
-		if (this.direction == SWT.UP) {
-			result = -result;
-		}
-		return result;
-	}
-}
diff --git a/src/main/java/kieker/gui/view/RecordsTableTimestampSortListener.java b/src/main/java/kieker/gui/view/RecordsTableTimestampSortListener.java
deleted file mode 100644
index c5d9d414..00000000
--- a/src/main/java/kieker/gui/view/RecordsTableTimestampSortListener.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package kieker.gui.view;
-
-import java.util.Collections;
-import java.util.List;
-
-import kieker.gui.model.RecordEntry;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-
-class RecordsTableTimestampSortListener implements Listener {
-
-	@Override
-	public void handleEvent(final Event event) {
-		// Get the necessary information from the event
-		final TableColumn currentColumn = (TableColumn) event.widget;
-		final Table table = currentColumn.getParent();
-		final TableColumn sortColumn = table.getSortColumn();
-
-		// Determine new sort column and direction
-		int direction = table.getSortDirection();
-		if (sortColumn == currentColumn) {
-			direction = ((direction == SWT.UP) ? SWT.DOWN : SWT.UP);
-		} else {
-			table.setSortColumn(currentColumn);
-			direction = SWT.UP;
-		}
-
-		// Sort the data
-		final List<RecordEntry> records = (List<RecordEntry>) table.getData();
-		Collections.sort(records, new RecordEntryTimestampComparator(direction));
-
-		// Update the data displayed in the table
-		table.setSortDirection(direction);
-		table.clearAll();
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/kieker/gui/view/util/AbstractDirectedComparator.java b/src/main/java/kieker/gui/view/util/AbstractDirectedComparator.java
new file mode 100644
index 00000000..52a28e64
--- /dev/null
+++ b/src/main/java/kieker/gui/view/util/AbstractDirectedComparator.java
@@ -0,0 +1,17 @@
+package kieker.gui.view.util;
+
+import java.util.Comparator;
+
+public abstract class AbstractDirectedComparator<T> implements Comparator<T> {
+
+	private int direction;
+
+	public int getDirection() {
+		return this.direction;
+	}
+
+	public void setDirection(final int direction) {
+		this.direction = direction;
+	}
+
+}
diff --git a/src/main/java/kieker/gui/view/AggregatedExecutionTracesTreeSetDataListener.java b/src/main/java/kieker/gui/view/util/AggregatedExecutionTracesTreeSetDataListener.java
similarity index 92%
rename from src/main/java/kieker/gui/view/AggregatedExecutionTracesTreeSetDataListener.java
rename to src/main/java/kieker/gui/view/util/AggregatedExecutionTracesTreeSetDataListener.java
index e1a354cb..8bc0982c 100644
--- a/src/main/java/kieker/gui/view/AggregatedExecutionTracesTreeSetDataListener.java
+++ b/src/main/java/kieker/gui/view/util/AggregatedExecutionTracesTreeSetDataListener.java
@@ -1,9 +1,9 @@
-package kieker.gui.view;
+package kieker.gui.view.util;
 
 import java.util.List;
 
-import kieker.gui.model.AggregatedExecutionEntry;
 import kieker.gui.model.Properties;
+import kieker.gui.model.domain.AggregatedExecutionEntry;
 
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
@@ -13,7 +13,7 @@ import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeItem;
 
-class AggregatedExecutionTracesTreeSetDataListener implements Listener {
+public class AggregatedExecutionTracesTreeSetDataListener implements Listener {
 
 	@Override
 	public void handleEvent(final Event event) {
diff --git a/src/main/java/kieker/gui/view/ExecutionTracesTreeSetDataListener.java b/src/main/java/kieker/gui/view/util/ExecutionTracesTreeSetDataListener.java
similarity index 90%
rename from src/main/java/kieker/gui/view/ExecutionTracesTreeSetDataListener.java
rename to src/main/java/kieker/gui/view/util/ExecutionTracesTreeSetDataListener.java
index ca8bf61b..51c04188 100644
--- a/src/main/java/kieker/gui/view/ExecutionTracesTreeSetDataListener.java
+++ b/src/main/java/kieker/gui/view/util/ExecutionTracesTreeSetDataListener.java
@@ -1,9 +1,9 @@
-package kieker.gui.view;
+package kieker.gui.view.util;
 
 import java.util.List;
 
-import kieker.gui.model.ExecutionEntry;
 import kieker.gui.model.Properties;
+import kieker.gui.model.domain.ExecutionEntry;
 
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
@@ -13,7 +13,7 @@ import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeItem;
 
-class ExecutionTracesTreeSetDataListener implements Listener {
+public class ExecutionTracesTreeSetDataListener implements Listener {
 
 	@Override
 	public void handleEvent(final Event event) {
@@ -48,7 +48,7 @@ class ExecutionTracesTreeSetDataListener implements Listener {
 			operationString = operationString.substring(lastPointPos + 1);
 		}
 		item.setText(new String[] { executionEntry.getContainer(), componentName, operationString, Long.toString(executionEntry.getDuration()),
-				String.format("%.1f%%", executionEntry.getPercent()), traceID });
+			String.format("%.1f%%", executionEntry.getPercent()), traceID });
 
 		if (executionEntry.isFailed()) {
 			final Color colorRed = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
@@ -58,4 +58,4 @@ class ExecutionTracesTreeSetDataListener implements Listener {
 		item.setData(executionEntry);
 		item.setItemCount(executionEntry.getChildren().size());
 	}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/kieker/gui/view/util/RecordEntryTimestampComparator.java b/src/main/java/kieker/gui/view/util/RecordEntryTimestampComparator.java
new file mode 100644
index 00000000..2b03ff11
--- /dev/null
+++ b/src/main/java/kieker/gui/view/util/RecordEntryTimestampComparator.java
@@ -0,0 +1,18 @@
+package kieker.gui.view.util;
+
+import kieker.gui.model.domain.RecordEntry;
+
+import org.eclipse.swt.SWT;
+
+public class RecordEntryTimestampComparator extends AbstractDirectedComparator<RecordEntry> {
+
+	@Override
+	public int compare(final RecordEntry o1, final RecordEntry o2) {
+		int result = Long.compare(o1.getTimestamp(), o2.getTimestamp());
+		if (this.getDirection() == SWT.UP) {
+			result = -result;
+		}
+		return result;
+	}
+
+}
diff --git a/src/main/java/kieker/gui/view/util/RecordEntryTypeComparator.java b/src/main/java/kieker/gui/view/util/RecordEntryTypeComparator.java
new file mode 100644
index 00000000..611a46f8
--- /dev/null
+++ b/src/main/java/kieker/gui/view/util/RecordEntryTypeComparator.java
@@ -0,0 +1,18 @@
+package kieker.gui.view.util;
+
+import kieker.gui.model.domain.RecordEntry;
+
+import org.eclipse.swt.SWT;
+
+public class RecordEntryTypeComparator extends AbstractDirectedComparator<RecordEntry> {
+
+	@Override
+	public int compare(final RecordEntry o1, final RecordEntry o2) {
+		int result = o1.getType().compareTo(o2.getType());
+		if (this.getDirection() == SWT.UP) {
+			result = -result;
+		}
+		return result;
+	}
+
+}
diff --git a/src/main/java/kieker/gui/view/RecordsTableSetDataListener.java b/src/main/java/kieker/gui/view/util/RecordsTableSetDataListener.java
similarity index 86%
rename from src/main/java/kieker/gui/view/RecordsTableSetDataListener.java
rename to src/main/java/kieker/gui/view/util/RecordsTableSetDataListener.java
index 2bd108ba..797d90b4 100644
--- a/src/main/java/kieker/gui/view/RecordsTableSetDataListener.java
+++ b/src/main/java/kieker/gui/view/util/RecordsTableSetDataListener.java
@@ -1,15 +1,15 @@
-package kieker.gui.view;
+package kieker.gui.view.util;
 
 import java.util.List;
 
-import kieker.gui.model.RecordEntry;
+import kieker.gui.model.domain.RecordEntry;
 
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableItem;
 
-class RecordsTableSetDataListener implements Listener {
+public class RecordsTableSetDataListener implements Listener {
 
 	@Override
 	public void handleEvent(final Event event) {
diff --git a/src/main/java/kieker/gui/view/RecordsTableTypeSortListener.java b/src/main/java/kieker/gui/view/util/TableColumnSortListener.java
similarity index 68%
rename from src/main/java/kieker/gui/view/RecordsTableTypeSortListener.java
rename to src/main/java/kieker/gui/view/util/TableColumnSortListener.java
index 5f0135cd..11dca925 100644
--- a/src/main/java/kieker/gui/view/RecordsTableTypeSortListener.java
+++ b/src/main/java/kieker/gui/view/util/TableColumnSortListener.java
@@ -1,17 +1,21 @@
-package kieker.gui.view;
+package kieker.gui.view.util;
 
 import java.util.Collections;
 import java.util.List;
 
-import kieker.gui.model.RecordEntry;
-
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
 
-class RecordsTableTypeSortListener implements Listener {
+public final class TableColumnSortListener<T> implements Listener {
+
+	private final AbstractDirectedComparator<T> comparator;
+
+	public TableColumnSortListener(final AbstractDirectedComparator<T> comparator) {
+		this.comparator = comparator;
+	}
 
 	@Override
 	public void handleEvent(final Event event) {
@@ -30,11 +34,13 @@ class RecordsTableTypeSortListener implements Listener {
 		}
 
 		// Sort the data
-		final List<RecordEntry> records = (List<RecordEntry>) table.getData();
-		Collections.sort(records, new RecordEntryTypeComparator(direction));
+		this.comparator.setDirection(direction);
+		final List<T> entries = (List<T>) table.getData();
+		Collections.sort(entries, this.comparator);
 
 		// Update the data displayed in the table
 		table.setSortDirection(direction);
 		table.clearAll();
 	}
+
 }
-- 
GitLab