From 9194e92da9332f6e2f4fa7ea4c1300d2c309c831 Mon Sep 17 00:00:00 2001
From: Nils Christian Ehmke <nie@informatik.uni-kiel.de>
Date: Fri, 12 Dec 2014 10:48:52 +0100
Subject: [PATCH] Refactoring for a better MVC pattern

---
 src/main/java/kieker/gui/Main.java            |  12 +
 .../AggregatedTracesSubViewController.java    |  39 ++
 .../gui/controller/MainViewController.java    |  87 ++++
 .../controller/RecordsSubViewController.java  |  20 +
 .../controller/TracesSubViewController.java   |  39 ++
 .../model/AggregatedTracesSubViewModel.java   |  22 +
 .../model/{DataSource.java => DataModel.java} |  40 +-
 .../java/kieker/gui/model/MainViewModel.java  |  24 +
 .../java/kieker/gui/model/Properties.java     |  60 ---
 .../kieker/gui/model/PropertiesModel.java     |  32 ++
 .../kieker/gui/model/TracesSubViewModel.java  |  22 +
 .../domain/AggregatedExecutionEntry.java      |  21 +-
 .../gui/model/domain/ExecutionEntry.java      |  23 +-
 .../view/AggregatedTraceDetailComposite.java  | 138 -----
 .../gui/view/AggregatedTracesSubView.java     | 303 +++++++++++
 src/main/java/kieker/gui/view/MainView.java   | 250 +++++++++
 src/main/java/kieker/gui/view/MainWindow.java | 485 ------------------
 .../java/kieker/gui/view/RecordsSubView.java  | 121 +++++
 .../kieker/gui/view/TraceDetailComposite.java | 120 -----
 .../java/kieker/gui/view/TracesSubView.java   | 293 +++++++++++
 ...tedExecutionTracesTreeSetDataListener.java |  60 ---
 .../ExecutionTracesTreeSetDataListener.java   |  61 ---
 .../util/RecordsTableSetDataListener.java     |  32 --
 .../view/util/TableColumnSortListener.java    |   8 +-
 .../gui/view/util/TreeColumnSortListener.java |   8 +-
 25 files changed, 1313 insertions(+), 1007 deletions(-)
 create mode 100644 src/main/java/kieker/gui/Main.java
 create mode 100644 src/main/java/kieker/gui/controller/AggregatedTracesSubViewController.java
 create mode 100644 src/main/java/kieker/gui/controller/MainViewController.java
 create mode 100644 src/main/java/kieker/gui/controller/RecordsSubViewController.java
 create mode 100644 src/main/java/kieker/gui/controller/TracesSubViewController.java
 create mode 100644 src/main/java/kieker/gui/model/AggregatedTracesSubViewModel.java
 rename src/main/java/kieker/gui/model/{DataSource.java => DataModel.java} (52%)
 create mode 100644 src/main/java/kieker/gui/model/MainViewModel.java
 delete mode 100644 src/main/java/kieker/gui/model/Properties.java
 create mode 100644 src/main/java/kieker/gui/model/PropertiesModel.java
 create mode 100644 src/main/java/kieker/gui/model/TracesSubViewModel.java
 delete mode 100644 src/main/java/kieker/gui/view/AggregatedTraceDetailComposite.java
 create mode 100644 src/main/java/kieker/gui/view/AggregatedTracesSubView.java
 create mode 100644 src/main/java/kieker/gui/view/MainView.java
 delete mode 100644 src/main/java/kieker/gui/view/MainWindow.java
 create mode 100644 src/main/java/kieker/gui/view/RecordsSubView.java
 delete mode 100644 src/main/java/kieker/gui/view/TraceDetailComposite.java
 create mode 100644 src/main/java/kieker/gui/view/TracesSubView.java
 delete mode 100644 src/main/java/kieker/gui/view/util/AggregatedExecutionTracesTreeSetDataListener.java
 delete mode 100644 src/main/java/kieker/gui/view/util/ExecutionTracesTreeSetDataListener.java
 delete mode 100644 src/main/java/kieker/gui/view/util/RecordsTableSetDataListener.java

diff --git a/src/main/java/kieker/gui/Main.java b/src/main/java/kieker/gui/Main.java
new file mode 100644
index 00000000..c276f226
--- /dev/null
+++ b/src/main/java/kieker/gui/Main.java
@@ -0,0 +1,12 @@
+package kieker.gui;
+
+import kieker.gui.controller.MainViewController;
+
+public class Main {
+
+	public static void main(final String[] args) {
+		final MainViewController controller = new MainViewController();
+		controller.showView();
+	}
+
+}
diff --git a/src/main/java/kieker/gui/controller/AggregatedTracesSubViewController.java b/src/main/java/kieker/gui/controller/AggregatedTracesSubViewController.java
new file mode 100644
index 00000000..488b797b
--- /dev/null
+++ b/src/main/java/kieker/gui/controller/AggregatedTracesSubViewController.java
@@ -0,0 +1,39 @@
+package kieker.gui.controller;
+
+import kieker.gui.model.AggregatedTracesSubViewModel;
+import kieker.gui.model.DataModel;
+import kieker.gui.model.PropertiesModel;
+import kieker.gui.model.domain.AggregatedExecutionEntry;
+import kieker.gui.view.AggregatedTracesSubView;
+
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+
+public class AggregatedTracesSubViewController implements SelectionListener {
+
+	private final DataModel model;
+	private final AggregatedTracesSubView view;
+	private final AggregatedTracesSubViewModel aggregatedTracesSubViewModel;
+
+	public AggregatedTracesSubViewController(final DataModel model, final PropertiesModel propertiesModel) {
+		this.model = model;
+		this.aggregatedTracesSubViewModel = new AggregatedTracesSubViewModel();
+
+		this.view = new AggregatedTracesSubView(this.model, this.aggregatedTracesSubViewModel, propertiesModel, this);
+	}
+
+	public AggregatedTracesSubView getView() {
+		return this.view;
+	}
+
+	@Override
+	public void widgetSelected(final SelectionEvent e) {
+		if (e.item.getData() instanceof AggregatedExecutionEntry) {
+			this.aggregatedTracesSubViewModel.setCurrentActiveTrace((AggregatedExecutionEntry) e.item.getData());
+		}
+	}
+
+	@Override
+	public void widgetDefaultSelected(final SelectionEvent e) {}
+
+}
diff --git a/src/main/java/kieker/gui/controller/MainViewController.java b/src/main/java/kieker/gui/controller/MainViewController.java
new file mode 100644
index 00000000..2ce82ddc
--- /dev/null
+++ b/src/main/java/kieker/gui/controller/MainViewController.java
@@ -0,0 +1,87 @@
+package kieker.gui.controller;
+
+import kieker.gui.model.DataModel;
+import kieker.gui.model.MainViewModel;
+import kieker.gui.model.MainViewModel.SubView;
+import kieker.gui.model.PropertiesModel;
+import kieker.gui.view.AggregatedTracesSubView;
+import kieker.gui.view.MainView;
+import kieker.gui.view.RecordsSubView;
+import kieker.gui.view.TracesSubView;
+
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+
+public class MainViewController implements SelectionListener {
+
+	private final DataModel dataModel;
+	private final MainViewModel mainViewModel;
+	private final PropertiesModel propertiesModel;
+	private final MainView view;
+
+	public MainViewController() {
+		this.dataModel = new DataModel();
+		this.mainViewModel = new MainViewModel();
+		this.propertiesModel = new PropertiesModel();
+
+		final RecordsSubViewController subView1Controller = new RecordsSubViewController(this.dataModel);
+		final TracesSubViewController subView2Controller = new TracesSubViewController(this.dataModel, this.propertiesModel);
+		final AggregatedTracesSubViewController subView3Controller = new AggregatedTracesSubViewController(this.dataModel, this.propertiesModel);
+
+		final RecordsSubView subView1 = subView1Controller.getView();
+		final TracesSubView subView2 = subView2Controller.getView();
+		final AggregatedTracesSubView subView3 = subView3Controller.getView();
+
+		this.view = new MainView(this.dataModel, this.mainViewModel, this, subView1, subView2, subView3);
+	}
+
+	public void showView() {
+		this.view.show();
+	}
+
+	@Override
+	public void widgetSelected(final SelectionEvent e) {
+		if (e.item == this.view.getTrtmExplorer()) {
+			this.mainViewModel.setCurrentActiveSubView(SubView.NONE);
+		}
+		if (e.item == this.view.getTrtmRecords()) {
+			this.mainViewModel.setCurrentActiveSubView(SubView.RECORDS_SUB_VIEW);
+		}
+		if (e.item == this.view.getTrtmTraces()) {
+			this.mainViewModel.setCurrentActiveSubView(SubView.TRACES_SUB_VIEW);
+		}
+		if (e.item == this.view.getTrtmAggregatedTraces()) {
+			this.mainViewModel.setCurrentActiveSubView(SubView.AGGREGATED_TRACES_SUB_VIEW);
+		}
+
+		if (e.widget == this.view.getMntmOpenMonitoringLog()) {
+			final String selectedDirectory = this.view.getDialog().open();
+
+			if (null != selectedDirectory) {
+				this.dataModel.loadMonitoringLogFromFS(selectedDirectory);
+			}
+		}
+		if (e.widget == this.view.getMntmExit()) {
+			this.view.close();
+		}
+
+		if (e.widget == this.view.getMntmShortOperationNames()) {
+			this.propertiesModel.setShortOperationNames(true);
+		}
+		if (e.widget == this.view.getMntmLongOperationNames()) {
+			this.propertiesModel.setShortOperationNames(false);
+		}
+		if (e.widget == this.view.getMntmShortComponentNames()) {
+			this.propertiesModel.setShortComponentNames(true);
+		}
+		if (e.widget == this.view.getMntmLongComponentNames()) {
+			this.propertiesModel.setShortComponentNames(false);
+		}
+	}
+
+	@Override
+	public void widgetDefaultSelected(final SelectionEvent e) {
+
+	}
+
+}
diff --git a/src/main/java/kieker/gui/controller/RecordsSubViewController.java b/src/main/java/kieker/gui/controller/RecordsSubViewController.java
new file mode 100644
index 00000000..661f1735
--- /dev/null
+++ b/src/main/java/kieker/gui/controller/RecordsSubViewController.java
@@ -0,0 +1,20 @@
+package kieker.gui.controller;
+
+import kieker.gui.model.DataModel;
+import kieker.gui.view.RecordsSubView;
+
+public class RecordsSubViewController {
+
+	private final DataModel model;
+	private final RecordsSubView view;
+
+	public RecordsSubViewController(final DataModel model) {
+		this.model = model;
+		this.view = new RecordsSubView(this.model, this);
+	}
+
+	public RecordsSubView getView() {
+		return this.view;
+	}
+
+}
diff --git a/src/main/java/kieker/gui/controller/TracesSubViewController.java b/src/main/java/kieker/gui/controller/TracesSubViewController.java
new file mode 100644
index 00000000..0c4134d6
--- /dev/null
+++ b/src/main/java/kieker/gui/controller/TracesSubViewController.java
@@ -0,0 +1,39 @@
+package kieker.gui.controller;
+
+import kieker.gui.model.DataModel;
+import kieker.gui.model.PropertiesModel;
+import kieker.gui.model.TracesSubViewModel;
+import kieker.gui.model.domain.ExecutionEntry;
+import kieker.gui.view.TracesSubView;
+
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+
+public class TracesSubViewController implements SelectionListener {
+
+	private final TracesSubViewModel tracesSubViewModel;
+	private final DataModel model;
+	private final TracesSubView view;
+
+	public TracesSubViewController(final DataModel model, final PropertiesModel propertiesModel) {
+		this.model = model;
+
+		this.tracesSubViewModel = new TracesSubViewModel();
+		this.view = new TracesSubView(this.model, this.tracesSubViewModel, propertiesModel, this);
+	}
+
+	public TracesSubView getView() {
+		return this.view;
+	}
+
+	@Override
+	public void widgetSelected(final SelectionEvent e) {
+		if (e.item.getData() instanceof ExecutionEntry) {
+			this.tracesSubViewModel.setCurrentActiveTrace((ExecutionEntry) e.item.getData());
+		}
+	}
+
+	@Override
+	public void widgetDefaultSelected(final SelectionEvent e) {}
+
+}
diff --git a/src/main/java/kieker/gui/model/AggregatedTracesSubViewModel.java b/src/main/java/kieker/gui/model/AggregatedTracesSubViewModel.java
new file mode 100644
index 00000000..88bc468e
--- /dev/null
+++ b/src/main/java/kieker/gui/model/AggregatedTracesSubViewModel.java
@@ -0,0 +1,22 @@
+package kieker.gui.model;
+
+import java.util.Observable;
+
+import kieker.gui.model.domain.AggregatedExecutionEntry;
+
+public final class AggregatedTracesSubViewModel extends Observable {
+
+	private AggregatedExecutionEntry currentActiveTrace;
+
+	public AggregatedExecutionEntry getCurrentActiveTrace() {
+		return this.currentActiveTrace;
+	}
+
+	public void setCurrentActiveTrace(final AggregatedExecutionEntry currentActiveTrace) {
+		this.currentActiveTrace = currentActiveTrace;
+
+		this.setChanged();
+		this.notifyObservers();
+	}
+
+}
diff --git a/src/main/java/kieker/gui/model/DataSource.java b/src/main/java/kieker/gui/model/DataModel.java
similarity index 52%
rename from src/main/java/kieker/gui/model/DataSource.java
rename to src/main/java/kieker/gui/model/DataModel.java
index f752127d..d62de2cd 100644
--- a/src/main/java/kieker/gui/model/DataSource.java
+++ b/src/main/java/kieker/gui/model/DataModel.java
@@ -1,22 +1,7 @@
-/***************************************************************************
- * Copyright 2014 Kieker Project (http://kieker-monitoring.net)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- ***************************************************************************/
-
 package kieker.gui.model;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Observable;
@@ -29,21 +14,16 @@ import teetime.framework.Analysis;
 
 /**
  * A container for data used within this application.
- *
+ * 
  * @author Nils Christian Ehmke
  */
-public final class DataSource extends Observable {
+public final class DataModel 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 DataModel() {}
 
 	public void loadMonitoringLogFromFS(final String directory) {
 		// Load and analyze the monitoring logs from the given directory
@@ -62,16 +42,16 @@ public final class DataSource extends Observable {
 		this.notifyObservers();
 	}
 
-	public List<RecordEntry> getRecords() {
-		return this.records;
+	public List<RecordEntry> getRecordsCopy() {
+		return new ArrayList<>(this.records);
 	}
 
-	public List<ExecutionEntry> getTraces() {
-		return this.traces;
+	public List<ExecutionEntry> getTracesCopy() {
+		return new ArrayList<>(this.traces);
 	}
 
-	public List<AggregatedExecutionEntry> getAggregatedTrace() {
-		return this.aggregatedTraces;
+	public List<AggregatedExecutionEntry> getAggregatedTracesCopy() {
+		return new ArrayList<>(this.aggregatedTraces);
 	}
 
 }
diff --git a/src/main/java/kieker/gui/model/MainViewModel.java b/src/main/java/kieker/gui/model/MainViewModel.java
new file mode 100644
index 00000000..372364c8
--- /dev/null
+++ b/src/main/java/kieker/gui/model/MainViewModel.java
@@ -0,0 +1,24 @@
+package kieker.gui.model;
+
+import java.util.Observable;
+
+public final class MainViewModel extends Observable {
+
+	private SubView currentActiveSubView = SubView.NONE;
+
+	public SubView getCurrentActiveSubView() {
+		return this.currentActiveSubView;
+	}
+
+	public void setCurrentActiveSubView(final SubView currentActiveSubView) {
+		this.currentActiveSubView = currentActiveSubView;
+
+		this.setChanged();
+		this.notifyObservers();
+	}
+
+	public enum SubView {
+		RECORDS_SUB_VIEW, TRACES_SUB_VIEW, AGGREGATED_TRACES_SUB_VIEW, NONE
+	}
+
+}
diff --git a/src/main/java/kieker/gui/model/Properties.java b/src/main/java/kieker/gui/model/Properties.java
deleted file mode 100644
index b52fb21c..00000000
--- a/src/main/java/kieker/gui/model/Properties.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/***************************************************************************
- * Copyright 2014 Kieker Project (http://kieker-monitoring.net)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- ***************************************************************************/
-
-package kieker.gui.model;
-
-import java.util.Observable;
-
-/**
- * An observable singleton container for properties used within this application.
- *
- * @author Nils Christian Ehmke
- */
-public final class Properties extends Observable {
-
-	private static final Properties INSTANCE = new Properties();
-	private boolean shortComponentNames = false;
-	private boolean shortOperationParameters = true;
-
-	private Properties() {}
-
-	public static Properties getInstance() {
-		return Properties.INSTANCE;
-	}
-
-	public boolean isShortComponentNames() {
-		return this.shortComponentNames;
-	}
-
-	public void setShortComponentNames(final boolean shortComponentNames) {
-		this.shortComponentNames = shortComponentNames;
-
-		this.setChanged();
-		this.notifyObservers();
-	}
-
-	public boolean isShortOperationParameters() {
-		return this.shortOperationParameters;
-	}
-
-	public void setShortOperationParameters(final boolean shortOperationParameters) {
-		this.shortOperationParameters = shortOperationParameters;
-
-		this.setChanged();
-		this.notifyObservers();
-	}
-
-}
diff --git a/src/main/java/kieker/gui/model/PropertiesModel.java b/src/main/java/kieker/gui/model/PropertiesModel.java
new file mode 100644
index 00000000..b3d1a3ec
--- /dev/null
+++ b/src/main/java/kieker/gui/model/PropertiesModel.java
@@ -0,0 +1,32 @@
+package kieker.gui.model;
+
+import java.util.Observable;
+
+public final class PropertiesModel extends Observable {
+
+	private boolean shortComponentNames = false;
+	private boolean shortOperationNames = true;
+
+	public boolean isShortComponentNames() {
+		return this.shortComponentNames;
+	}
+
+	public void setShortComponentNames(final boolean shortComponentNames) {
+		this.shortComponentNames = shortComponentNames;
+
+		this.setChanged();
+		this.notifyObservers();
+	}
+
+	public boolean isShortOperationNames() {
+		return this.shortOperationNames;
+	}
+
+	public void setShortOperationNames(final boolean shortOperationNames) {
+		this.shortOperationNames = shortOperationNames;
+
+		this.setChanged();
+		this.notifyObservers();
+	}
+
+}
diff --git a/src/main/java/kieker/gui/model/TracesSubViewModel.java b/src/main/java/kieker/gui/model/TracesSubViewModel.java
new file mode 100644
index 00000000..d0de2ec6
--- /dev/null
+++ b/src/main/java/kieker/gui/model/TracesSubViewModel.java
@@ -0,0 +1,22 @@
+package kieker.gui.model;
+
+import java.util.Observable;
+
+import kieker.gui.model.domain.ExecutionEntry;
+
+public final class TracesSubViewModel extends Observable {
+
+	private ExecutionEntry currentActiveTrace;
+
+	public ExecutionEntry getCurrentActiveTrace() {
+		return this.currentActiveTrace;
+	}
+
+	public void setCurrentActiveTrace(final ExecutionEntry currentActiveTrace) {
+		this.currentActiveTrace = currentActiveTrace;
+
+		this.setChanged();
+		this.notifyObservers();
+	}
+
+}
diff --git a/src/main/java/kieker/gui/model/domain/AggregatedExecutionEntry.java b/src/main/java/kieker/gui/model/domain/AggregatedExecutionEntry.java
index 7197b267..b48d7564 100644
--- a/src/main/java/kieker/gui/model/domain/AggregatedExecutionEntry.java
+++ b/src/main/java/kieker/gui/model/domain/AggregatedExecutionEntry.java
@@ -44,16 +44,25 @@ public final class AggregatedExecutionEntry {
 		}
 	}
 
-	public int getStackDepth() {
-		int stackDepth = this.children.isEmpty() ? 0 : 1;
+	public int getTraceDepth() {
+		int traceDepth = this.children.isEmpty() ? 0 : 1;
 
-		int maxChildrenStackDepth = 0;
+		int maxChildrenTraceDepth = 0;
 		for (final AggregatedExecutionEntry child : this.children) {
-			maxChildrenStackDepth = Math.max(maxChildrenStackDepth, child.getStackDepth());
+			maxChildrenTraceDepth = Math.max(maxChildrenTraceDepth, child.getTraceDepth());
 		}
-		stackDepth += maxChildrenStackDepth;
+		traceDepth += maxChildrenTraceDepth;
 
-		return stackDepth;
+		return traceDepth;
+	}
+
+	public int getTraceSize() {
+		int traceSize = 1;
+
+		for (final AggregatedExecutionEntry child : this.children) {
+			traceSize += child.getTraceSize();
+		}
+		return traceSize;
 	}
 
 	public List<AggregatedExecutionEntry> getChildren() {
diff --git a/src/main/java/kieker/gui/model/domain/ExecutionEntry.java b/src/main/java/kieker/gui/model/domain/ExecutionEntry.java
index f854928e..04b42985 100644
--- a/src/main/java/kieker/gui/model/domain/ExecutionEntry.java
+++ b/src/main/java/kieker/gui/model/domain/ExecutionEntry.java
@@ -22,7 +22,7 @@ import java.util.List;
 
 /**
  * A simplified representation of an execution within a trace. As an instance of this class can contain other instances, it can be used to represent a trace tree.
- *
+ * 
  * @author Nils Christian Ehmke
  */
 public final class ExecutionEntry {
@@ -45,16 +45,25 @@ public final class ExecutionEntry {
 		this.operation = operation;
 	}
 
-	public int getStackDepth() {
-		int stackDepth = this.children.isEmpty() ? 0 : 1;
+	public int getTraceDepth() {
+		int traceDepth = this.children.isEmpty() ? 0 : 1;
 
-		int maxChildrenStackDepth = 0;
+		int maxChildrenTraceDepth = 0;
 		for (final ExecutionEntry child : this.children) {
-			maxChildrenStackDepth = Math.max(maxChildrenStackDepth, child.getStackDepth());
+			maxChildrenTraceDepth = Math.max(maxChildrenTraceDepth, child.getTraceDepth());
 		}
-		stackDepth += maxChildrenStackDepth;
+		traceDepth += maxChildrenTraceDepth;
+
+		return traceDepth;
+	}
 
-		return stackDepth;
+	public int getTraceSize() {
+		int traceSize = 1;
+
+		for (final ExecutionEntry child : this.children) {
+			traceSize += child.getTraceSize();
+		}
+		return traceSize;
 	}
 
 	public long getTraceID() {
diff --git a/src/main/java/kieker/gui/view/AggregatedTraceDetailComposite.java b/src/main/java/kieker/gui/view/AggregatedTraceDetailComposite.java
deleted file mode 100644
index 82733f46..00000000
--- a/src/main/java/kieker/gui/view/AggregatedTraceDetailComposite.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package kieker.gui.view;
-
-import kieker.gui.model.domain.AggregatedExecutionEntry;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.wb.swt.SWTResourceManager;
-
-public final class AggregatedTraceDetailComposite extends Composite {
-
-	private final Label lblExecutionContainerDisplay;
-	private final Label lblComponentDisplay;
-	private final Label lblOperationDisplay;
-	private final Label lblFailed;
-	private final Label lblFailedDisplay;
-	private final Label lblCalledDisplay;
-	private final Label lblStackDepthDisplay;
-	private final Label lblMinimalDurationDisplay;
-	private final Label lblMaximalDurationDisplay;
-	private final Label lblAverageDuration;
-	private final Label lblAverageDurationDisplay;
-
-	public AggregatedTraceDetailComposite(final Composite parent, final int style) {
-		super(parent, style);
-		this.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.setLayout(new GridLayout(2, false));
-
-		final Label lblExecutionContainer = new Label(this, SWT.NONE);
-		lblExecutionContainer.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblExecutionContainer.setText("Execution Container:");
-
-		this.lblExecutionContainerDisplay = new Label(this, SWT.NONE);
-		this.lblExecutionContainerDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblExecutionContainerDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblExecutionContainerDisplay.setText("N/A");
-
-		final Label lblComponent = new Label(this, SWT.NONE);
-		lblComponent.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblComponent.setText("Component:");
-
-		this.lblComponentDisplay = new Label(this, SWT.NONE);
-		this.lblComponentDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblComponentDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblComponentDisplay.setText("N/A");
-
-		final Label lblOperation = new Label(this, SWT.NONE);
-		lblOperation.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblOperation.setText("Operation:");
-
-		this.lblOperationDisplay = new Label(this, SWT.NONE);
-		this.lblOperationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblOperationDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblOperationDisplay.setText("N/A");
-
-		final Label lblStackDepth = new Label(this, SWT.NONE);
-		lblStackDepth.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblStackDepth.setText("Stack Depth:");
-
-		this.lblStackDepthDisplay = new Label(this, SWT.NONE);
-		this.lblStackDepthDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblStackDepthDisplay.setText("N/A");
-
-		this.lblFailed = new Label(this, SWT.NONE);
-		this.lblFailed.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblFailed.setText("Failed:");
-
-		this.lblFailedDisplay = new Label(this, SWT.NONE);
-		this.lblFailedDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblFailedDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblFailedDisplay.setText("N/A");
-
-		final Label lblCalled = new Label(this, SWT.NONE);
-		lblCalled.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblCalled.setText("# Calls:");
-
-		this.lblCalledDisplay = new Label(this, SWT.NONE);
-		this.lblCalledDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblCalledDisplay.setText("N/A");
-
-		final Label lblMinimalDuration = new Label(this, SWT.NONE);
-		lblMinimalDuration.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblMinimalDuration.setText("Minimal Duration:");
-
-		this.lblMinimalDurationDisplay = new Label(this, SWT.NONE);
-		this.lblMinimalDurationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblMinimalDurationDisplay.setText("N/A");
-
-		this.lblAverageDuration = new Label(this, SWT.NONE);
-		this.lblAverageDuration.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblAverageDuration.setText("Average Duration:");
-
-		this.lblAverageDurationDisplay = new Label(this, SWT.NONE);
-		this.lblAverageDurationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblAverageDurationDisplay.setText("N/A");
-
-		final Label lblMaximalDuration = new Label(this, SWT.NONE);
-		lblMaximalDuration.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblMaximalDuration.setText("Maximal Duration:");
-
-		this.lblMaximalDurationDisplay = new Label(this, SWT.NONE);
-		this.lblMaximalDurationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblMaximalDurationDisplay.setText("N/A");
-	}
-
-	public void setTraceToDisplay(final AggregatedExecutionEntry trace) {
-		this.lblExecutionContainerDisplay.setText(trace.getContainer());
-		this.lblComponentDisplay.setText(trace.getComponent());
-		this.lblOperationDisplay.setText(trace.getOperation());
-		this.lblStackDepthDisplay.setText(Integer.toString(trace.getStackDepth()));
-		this.lblCalledDisplay.setText(Integer.toString(trace.getCalls()));
-
-		this.lblMinimalDurationDisplay.setText(Long.toString(trace.getMinDuration()));
-		this.lblMaximalDurationDisplay.setText(Long.toString(trace.getMaxDuration()));
-		this.lblAverageDurationDisplay.setText(Long.toString(trace.getAvgDuration()));
-
-		if (trace.isFailed()) {
-			this.lblFailedDisplay.setText("Yes (" + trace.getFailedCause() + ")");
-			this.lblFailedDisplay.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
-			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
-		} else {
-			this.lblFailedDisplay.setText("No");
-			this.lblFailedDisplay.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
-			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
-		}
-
-		super.layout();
-	}
-
-	@Override
-	protected void checkSubclass() {
-		// Disable the check that prevents subclassing of SWT components
-	}
-
-}
diff --git a/src/main/java/kieker/gui/view/AggregatedTracesSubView.java b/src/main/java/kieker/gui/view/AggregatedTracesSubView.java
new file mode 100644
index 00000000..50109419
--- /dev/null
+++ b/src/main/java/kieker/gui/view/AggregatedTracesSubView.java
@@ -0,0 +1,303 @@
+package kieker.gui.view;
+
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+
+import kieker.gui.controller.AggregatedTracesSubViewController;
+import kieker.gui.model.AggregatedTracesSubViewModel;
+import kieker.gui.model.DataModel;
+import kieker.gui.model.PropertiesModel;
+import kieker.gui.model.domain.AggregatedExecutionEntry;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.wb.swt.SWTResourceManager;
+
+public class AggregatedTracesSubView implements Observer {
+
+	private final AggregatedTracesSubViewModel aggregatedTracesSubViewModel;
+	private final AggregatedTracesSubViewController controller;
+	private final DataModel model;
+	private Composite composite;
+	private Tree tree;
+	private Composite detailComposite;
+	private Label lblComponentDisplay;
+	private Label lblOperationDisplay;
+	private Label lblNumberOfCallsDisplay;
+	private Label lblMinimalDurationDisplay;
+	private Label lblAverageDurationDisplay;
+	private Label lblMaximalDurationDisplay;
+	private Label lblFailedDisplay;
+	private Label lblTraceDepthDisplay;
+	private Label lblTraceSizeDisplay;
+	private Label lblExecutionContainerDisplay;
+	private Label lblFailed;
+	private final PropertiesModel propertiesModel;
+
+	public AggregatedTracesSubView(final DataModel model, final AggregatedTracesSubViewModel aggregatedTracesSubViewModel,
+			final PropertiesModel propertiesModel, final AggregatedTracesSubViewController controller) {
+		this.controller = controller;
+		this.model = model;
+		this.propertiesModel = propertiesModel;
+		this.aggregatedTracesSubViewModel = aggregatedTracesSubViewModel;
+
+		model.addObserver(this);
+		aggregatedTracesSubViewModel.addObserver(this);
+		propertiesModel.addObserver(this);
+	}
+
+	/**
+	 * @wbp.parser.entryPoint
+	 */
+	public void createComposite(final Composite parent) {
+		if (this.composite != null) {
+			this.composite.dispose();
+		}
+
+		this.composite = new Composite(parent, SWT.NONE);
+		this.composite.setLayout(new FillLayout(SWT.HORIZONTAL));
+
+		final SashForm sashForm = new SashForm(this.composite, SWT.VERTICAL);
+
+		this.tree = new Tree(sashForm, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
+		this.tree.setHeaderVisible(true);
+
+		final TreeColumn trclmnExecutionContainer = new TreeColumn(this.tree, SWT.NONE);
+		trclmnExecutionContainer.setWidth(100);
+		trclmnExecutionContainer.setText("Execution Container");
+
+		final TreeColumn trclmnComponent = new TreeColumn(this.tree, SWT.NONE);
+		trclmnComponent.setWidth(100);
+		trclmnComponent.setText("Component");
+
+		final TreeColumn trclmnOperation = new TreeColumn(this.tree, SWT.NONE);
+		trclmnOperation.setWidth(100);
+		trclmnOperation.setText("Operation");
+
+		final TreeColumn trclmnCalls = new TreeColumn(this.tree, SWT.NONE);
+		trclmnCalls.setWidth(100);
+		trclmnCalls.setText("Number of Calls");
+
+		final TreeColumn trclmnMinimalDuration = new TreeColumn(this.tree, SWT.NONE);
+		trclmnMinimalDuration.setWidth(100);
+		trclmnMinimalDuration.setText("Minimal Duration");
+
+		final TreeColumn trclmnAverageDuration = new TreeColumn(this.tree, SWT.NONE);
+		trclmnAverageDuration.setWidth(100);
+		trclmnAverageDuration.setText("Average Duration");
+
+		final TreeColumn trclmnMaximalDuration = new TreeColumn(this.tree, SWT.NONE);
+		trclmnMaximalDuration.setWidth(100);
+		trclmnMaximalDuration.setText("Maximal Duration");
+
+		this.detailComposite = new Composite(sashForm, SWT.BORDER);
+		this.detailComposite.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.detailComposite.setLayout(new GridLayout(2, false));
+
+		final Label lblExecutionContainer = new Label(this.detailComposite, SWT.NONE);
+		lblExecutionContainer.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblExecutionContainer.setText("Execution Container:");
+
+		this.lblExecutionContainerDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblExecutionContainerDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblExecutionContainerDisplay.setText("N/A");
+
+		final Label lblComponent = new Label(this.detailComposite, SWT.NONE);
+		lblComponent.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblComponent.setText("Component:");
+
+		this.lblComponentDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblComponentDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblComponentDisplay.setText("N/A");
+
+		final Label lblOperation = new Label(this.detailComposite, SWT.NONE);
+		lblOperation.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblOperation.setText("Operation:");
+
+		this.lblOperationDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblOperationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblOperationDisplay.setText("N/A");
+
+		final Label lblNumberOfCalls = new Label(this.detailComposite, SWT.NONE);
+		lblNumberOfCalls.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblNumberOfCalls.setText("Number of Calls:");
+
+		this.lblNumberOfCallsDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblNumberOfCallsDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblNumberOfCallsDisplay.setText("N/A");
+
+		final Label lblMinimalDuration = new Label(this.detailComposite, SWT.NONE);
+		lblMinimalDuration.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblMinimalDuration.setText("Minimal Duration:");
+
+		this.lblMinimalDurationDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblMinimalDurationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblMinimalDurationDisplay.setText("N/A");
+
+		final Label lblAverageDuration = new Label(this.detailComposite, SWT.NONE);
+		lblAverageDuration.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblAverageDuration.setText("Average Duration:");
+
+		this.lblAverageDurationDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblAverageDurationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblAverageDurationDisplay.setText("N/A");
+
+		final Label lblMaximalDuration = new Label(this.detailComposite, SWT.NONE);
+		lblMaximalDuration.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblMaximalDuration.setText("Maximal Duration:");
+
+		this.lblMaximalDurationDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblMaximalDurationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblMaximalDurationDisplay.setText("N/A");
+
+		this.lblFailed = new Label(this.detailComposite, SWT.NONE);
+		this.lblFailed.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblFailed.setText("Failed:");
+
+		this.lblFailedDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblFailedDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblFailedDisplay.setText("N/A");
+
+		final Label lblTraceDepth = new Label(this.detailComposite, SWT.NONE);
+		lblTraceDepth.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblTraceDepth.setText("Trace Depth:");
+
+		this.lblTraceDepthDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblTraceDepthDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblTraceDepthDisplay.setText("N/A");
+
+		final Label lblTraceSize = new Label(this.detailComposite, SWT.NONE);
+		lblTraceSize.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblTraceSize.setText("Trace Size:");
+
+		this.lblTraceSizeDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblTraceSizeDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblTraceSizeDisplay.setText("N/A");
+		sashForm.setWeights(new int[] { 2, 1 });
+
+		this.tree.addSelectionListener(this.controller);
+		this.tree.addListener(SWT.SetData, new DataProvider());
+	}
+
+	public Composite getComposite() {
+		return this.composite;
+	}
+
+	@Override
+	public void update(final Observable observable, final Object obj) {
+		if (observable == this.model) {
+			this.updateTree();
+		}
+		if (observable == this.aggregatedTracesSubViewModel) {
+			this.updateDetailComposite();
+		}
+		if (observable == this.propertiesModel) {
+			this.clearTree();
+		}
+	}
+
+	private void updateTree() {
+		final List<AggregatedExecutionEntry> records = this.model.getAggregatedTracesCopy();
+
+		this.tree.setData(records);
+		this.tree.setItemCount(records.size());
+
+		this.clearTree();
+	}
+
+	private void clearTree() {
+		this.tree.clearAll(true);
+
+		for (final TreeColumn column : this.tree.getColumns()) {
+			column.pack();
+		}
+	}
+
+	private void updateDetailComposite() {
+		final AggregatedExecutionEntry trace = this.aggregatedTracesSubViewModel.getCurrentActiveTrace();
+
+		this.lblMinimalDurationDisplay.setText(Long.toString(trace.getMinDuration()));
+		this.lblMaximalDurationDisplay.setText(Long.toString(trace.getMaxDuration()));
+		this.lblAverageDurationDisplay.setText(Long.toString(trace.getAvgDuration()));
+
+		this.lblExecutionContainerDisplay.setText(trace.getContainer());
+		this.lblComponentDisplay.setText(trace.getComponent());
+		this.lblOperationDisplay.setText(trace.getOperation());
+		this.lblTraceDepthDisplay.setText(Integer.toString(trace.getTraceDepth()));
+		this.lblTraceSizeDisplay.setText(Integer.toString(trace.getTraceSize()));
+		this.lblNumberOfCallsDisplay.setText(Integer.toString(trace.getCalls()));
+
+		if (trace.isFailed()) {
+			this.lblFailedDisplay.setText("Yes (" + trace.getFailedCause() + ")");
+			this.lblFailedDisplay.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+		} else {
+			this.lblFailedDisplay.setText("No");
+			this.lblFailedDisplay.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+		}
+
+		this.detailComposite.layout();
+	}
+
+	private class DataProvider implements Listener {
+
+		@Override
+		@SuppressWarnings("unchecked")
+		public void handleEvent(final Event event) {
+			// Get the necessary information from the event
+			final Tree tree = (Tree) event.widget;
+			final TreeItem item = (TreeItem) event.item;
+			final int tableIndex = event.index;
+			final TreeItem parent = item.getParentItem();
+
+			// Decide whether the current item is a root or not
+			final AggregatedExecutionEntry executionEntry;
+			if (parent == null) {
+				executionEntry = ((List<AggregatedExecutionEntry>) tree.getData()).get(tableIndex);
+			} else {
+				executionEntry = ((AggregatedExecutionEntry) parent.getData()).getChildren().get(tableIndex);
+			}
+
+			String componentName = executionEntry.getComponent();
+			if (AggregatedTracesSubView.this.propertiesModel.isShortComponentNames()) {
+				final int lastPointPos = componentName.lastIndexOf('.');
+				componentName = componentName.substring(lastPointPos + 1);
+			}
+			String operationString = executionEntry.getOperation();
+			if (AggregatedTracesSubView.this.propertiesModel.isShortOperationNames()) {
+				operationString = operationString.replaceAll("\\(..*\\)", "(...)");
+
+				final int lastPointPos = operationString.lastIndexOf('.', operationString.length() - 5);
+				operationString = operationString.substring(lastPointPos + 1);
+			}
+			if (parent != null) {
+				item.setText(new String[] { executionEntry.getContainer(), componentName, operationString, "" });
+			} else {
+				item.setText(new String[] { executionEntry.getContainer(), componentName, operationString, Integer.toString(executionEntry.getCalls()) });
+			}
+
+			if (executionEntry.isFailed()) {
+				final Color colorRed = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
+				item.setForeground(colorRed);
+			}
+
+			item.setData(executionEntry);
+			item.setItemCount(executionEntry.getChildren().size());
+		}
+
+	}
+
+}
diff --git a/src/main/java/kieker/gui/view/MainView.java b/src/main/java/kieker/gui/view/MainView.java
new file mode 100644
index 00000000..2efbea43
--- /dev/null
+++ b/src/main/java/kieker/gui/view/MainView.java
@@ -0,0 +1,250 @@
+package kieker.gui.view;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import kieker.gui.controller.MainViewController;
+import kieker.gui.model.DataModel;
+import kieker.gui.model.MainViewModel;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+public class MainView implements Observer {
+
+	private final DataModel dataModel;
+	private final MainViewModel mainViewModel;
+	private final RecordsSubView recordsSubView;
+	private final TracesSubView tracesSubView;
+	private final AggregatedTracesSubView aggregatedTracesSubView;
+	private final MainViewController controller;
+
+	private Shell shell;
+	private Composite subViewComposite;
+	private StackLayout subViewLayout;
+	private Tree tree;
+	private TreeItem trtmExplorer;
+	private TreeItem trtmRecords;
+	private TreeItem trtmTraces;
+	private TreeItem trtmAggregatedTraces;
+	private MenuItem mntmExit;
+	private MenuItem mntmShortOperationNames;
+	private MenuItem mntmLongOperationNames;
+	private MenuItem mntmShortComponentNames;
+	private MenuItem mntmLongComponentNames;
+	private MenuItem mntmOpenMonitoringLog;
+	private DirectoryDialog dialog;
+
+	public MainView(final DataModel dataModel, final MainViewModel mainViewModel, final MainViewController controller, final RecordsSubView recordsSubView,
+			final TracesSubView tracesSubView, final AggregatedTracesSubView aggregatedTracesSubView) {
+		this.dataModel = dataModel;
+		this.mainViewModel = mainViewModel;
+
+		this.recordsSubView = recordsSubView;
+		this.tracesSubView = tracesSubView;
+		this.aggregatedTracesSubView = aggregatedTracesSubView;
+
+		this.controller = controller;
+	}
+
+	public void show() {
+		final Display display = Display.getDefault();
+
+		this.createContents();
+		this.addLogic();
+		this.shell.open();
+		this.shell.layout();
+
+		while (!this.shell.isDisposed()) {
+			if (!display.readAndDispatch()) {
+				display.sleep();
+			}
+		}
+	}
+
+	public void close() {
+		this.shell.close();
+	}
+
+	public TreeItem getTrtmExplorer() {
+		return this.trtmExplorer;
+	}
+
+	public TreeItem getTrtmRecords() {
+		return this.trtmRecords;
+	}
+
+	public TreeItem getTrtmTraces() {
+		return this.trtmTraces;
+	}
+
+	public TreeItem getTrtmAggregatedTraces() {
+		return this.trtmAggregatedTraces;
+	}
+
+	public MenuItem getMntmExit() {
+		return this.mntmExit;
+	}
+
+	public MenuItem getMntmShortOperationNames() {
+		return this.mntmShortOperationNames;
+	}
+
+	public MenuItem getMntmLongOperationNames() {
+		return this.mntmLongOperationNames;
+	}
+
+	public MenuItem getMntmShortComponentNames() {
+		return this.mntmShortComponentNames;
+	}
+
+	public MenuItem getMntmLongComponentNames() {
+		return this.mntmLongComponentNames;
+	}
+
+	public MenuItem getMntmOpenMonitoringLog() {
+		return this.mntmOpenMonitoringLog;
+	}
+
+	public DirectoryDialog getDialog() {
+		return this.dialog;
+	}
+
+	/**
+	 * @wbp.parser.entryPoint
+	 */
+	protected void createContents() {
+		this.shell = new Shell();
+		this.shell.setImage(null);
+		this.shell.setMaximized(true);
+		this.shell.setText("Kieker's GUI");
+		this.shell.setLayout(new FillLayout(SWT.HORIZONTAL));
+
+		this.dialog = new DirectoryDialog(this.shell);
+
+		final SashForm sashForm = new SashForm(this.shell, SWT.NONE);
+
+		this.tree = new Tree(sashForm, SWT.BORDER);
+
+		this.trtmExplorer = new TreeItem(this.tree, SWT.NONE);
+		this.trtmExplorer.setText("Explorer");
+
+		this.trtmRecords = new TreeItem(this.trtmExplorer, SWT.NONE);
+		this.trtmRecords.setText("Records");
+
+		this.trtmTraces = new TreeItem(this.trtmExplorer, SWT.NONE);
+		this.trtmTraces.setText("Traces");
+
+		this.trtmAggregatedTraces = new TreeItem(this.trtmTraces, SWT.NONE);
+		this.trtmAggregatedTraces.setText("Aggregated Traces");
+		this.trtmTraces.setExpanded(true);
+		this.trtmExplorer.setExpanded(true);
+
+		this.subViewLayout = new StackLayout();
+		this.subViewComposite = new Composite(sashForm, SWT.NONE);
+		this.subViewComposite.setLayout(this.subViewLayout);
+		sashForm.setWeights(new int[] { 1, 4 });
+
+		this.recordsSubView.createComposite(this.subViewComposite);
+		this.tracesSubView.createComposite(this.subViewComposite);
+		this.aggregatedTracesSubView.createComposite(this.subViewComposite);
+
+		final Menu menu = new Menu(this.shell, SWT.BAR);
+		this.shell.setMenuBar(menu);
+
+		final MenuItem mntmFile = new MenuItem(menu, SWT.CASCADE);
+		mntmFile.setText("File");
+
+		final Menu menu_1 = new Menu(mntmFile);
+		mntmFile.setMenu(menu_1);
+
+		this.mntmOpenMonitoringLog = new MenuItem(menu_1, SWT.NONE);
+		this.mntmOpenMonitoringLog.setText("Open Monitoring Log");
+
+		new MenuItem(menu_1, SWT.SEPARATOR);
+
+		this.mntmExit = new MenuItem(menu_1, SWT.NONE);
+		this.mntmExit.setText("Exit");
+
+		final MenuItem mntmView = new MenuItem(menu, SWT.CASCADE);
+		mntmView.setText("View");
+
+		final Menu menu_2 = new Menu(mntmView);
+		mntmView.setMenu(menu_2);
+
+		this.mntmShortOperationNames = new MenuItem(menu_2, SWT.RADIO);
+		this.mntmShortOperationNames.setSelection(true);
+		this.mntmShortOperationNames.setText("Short Operation Names");
+
+		this.mntmLongOperationNames = new MenuItem(menu_2, SWT.RADIO);
+		this.mntmLongOperationNames.setText("Long Operation Names");
+
+		new MenuItem(menu_2, SWT.SEPARATOR);
+
+		this.mntmShortComponentNames = new MenuItem(menu_2, SWT.RADIO);
+		this.mntmShortComponentNames.setText("Short Component Names");
+
+		this.mntmLongComponentNames = new MenuItem(menu_2, SWT.RADIO);
+		this.mntmLongComponentNames.setSelection(true);
+		this.mntmLongComponentNames.setText("Long Component Names");
+	}
+
+	private void addLogic() {
+		this.dataModel.addObserver(this);
+		this.mainViewModel.addObserver(this);
+
+		this.tree.addSelectionListener(this.controller);
+
+		this.mntmExit.addSelectionListener(this.controller);
+		this.mntmOpenMonitoringLog.addSelectionListener(this.controller);
+
+		this.mntmShortOperationNames.addSelectionListener(this.controller);
+		this.mntmLongOperationNames.addSelectionListener(this.controller);
+		this.mntmShortComponentNames.addSelectionListener(this.controller);
+		this.mntmLongOperationNames.addSelectionListener(this.controller);
+	}
+
+	@Override
+	public void update(final Observable observable, final Object obj) {
+		if (observable == this.dataModel) {
+
+		}
+		if (observable == this.mainViewModel) {
+			this.handleChangedSubView();
+		}
+	}
+
+	private void handleChangedSubView() {
+		final Composite subViewToShow;
+		switch (this.mainViewModel.getCurrentActiveSubView()) {
+		case NONE:
+			subViewToShow = null;
+			break;
+		case RECORDS_SUB_VIEW:
+			subViewToShow = this.recordsSubView.getComposite();
+			break;
+		case TRACES_SUB_VIEW:
+			subViewToShow = this.tracesSubView.getComposite();
+			break;
+		case AGGREGATED_TRACES_SUB_VIEW:
+			subViewToShow = this.aggregatedTracesSubView.getComposite();
+			break;
+		default:
+			subViewToShow = null;
+			break;
+		}
+
+		this.subViewLayout.topControl = subViewToShow;
+		this.subViewComposite.layout();
+	}
+}
diff --git a/src/main/java/kieker/gui/view/MainWindow.java b/src/main/java/kieker/gui/view/MainWindow.java
deleted file mode 100644
index 11374674..00000000
--- a/src/main/java/kieker/gui/view/MainWindow.java
+++ /dev/null
@@ -1,485 +0,0 @@
-/***************************************************************************
- * Copyright 2014 Kieker Project (http://kieker-monitoring.net)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- ***************************************************************************/
-
-package kieker.gui.view;
-
-import java.util.List;
-import java.util.Observable;
-import java.util.Observer;
-
-import kieker.gui.model.DataSource;
-import kieker.gui.model.Properties;
-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.ExecutionEntryComponentComparator;
-import kieker.gui.view.util.ExecutionEntryDurationComparator;
-import kieker.gui.view.util.ExecutionEntryOperationComparator;
-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 kieker.gui.view.util.TreeColumnSortListener;
-
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.custom.StackLayout;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.DirectoryDialog;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Table;
-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;
-
-/**
- * The main window of this application. This file should probably be maintained with the Eclipse GUI builder.
- *
- * @author Nils Christian Ehmke
- */
-public final class MainWindow {
-
-	protected Shell shell;
-	private Composite mainComposite;
-	Table recordsTable;
-	private SashForm outerForm;
-	private TreeViewer explorerTreeViewer;
-	private TreeItem explorerTreeItem;
-	TreeItem recordsTreeItem;
-	TreeItem executionTracesTreeItem;
-	private TableViewer recordsTableViewer;
-	private TableColumn recordsTableTimestampColumn;
-	private TableColumn recordsTableRecordColumn;
-	private Menu menuBar;
-	private MenuItem fileMenuItem;
-	private Menu fileMenu;
-	private MenuItem openMonitoringLogMenuItem;
-	private MenuItem exitMenuItem;
-	private MenuItem helpMenuItem;
-	private Menu helpMenu;
-	private MenuItem aboutMenuItem;
-	private Tree explorerTree;
-	private Tree tracesTree;
-	private TreeColumn tracesTreeContainerColumn;
-	private TreeColumn treeColumn_8;
-	private TreeColumn treeColumn_10;
-	private TreeColumn treeColumn_11;
-	private TreeColumn treeColumn_16;
-	private MenuItem mntmView_1;
-	private Menu menu;
-	private MenuItem mntmShortComponentNames;
-	private MenuItem mntmLongComponentNames;
-	private MenuItem mntmShortOperationParameters;
-	private MenuItem mntmLongOperationParameters;
-	private TableColumn recordsTableTypeColumn;
-	private SashForm explorerForm;
-	private TreeColumn trclmnPercent;
-	Label lblNa;
-	private SashForm executionTracesForm;
-	private TraceDetailComposite traceDetailComposite;
-	private SashForm sashForm;
-	private Tree aggregatedTracesTree;
-	private TreeColumn treeColumn;
-	private TreeColumn treeColumn_1;
-	private TreeColumn treeColumn_2;
-	private TreeColumn trclmnCalls;
-	private AggregatedTraceDetailComposite aggregatedTraceDetailComposite;
-	TreeItem trtmAggregatedExecutionTraces;
-
-	public static void main(final String[] args) {
-		final MainWindow window = new MainWindow();
-		window.open();
-	}
-
-	public void open() {
-		final Display display = Display.getDefault();
-		this.createContents();
-		this.addLogic();
-		this.shell.open();
-		this.shell.layout();
-		while (!this.shell.isDisposed()) {
-			if (!display.readAndDispatch()) {
-				display.sleep();
-			}
-		}
-	}
-
-	protected void createContents() {
-		this.shell = new Shell();
-		this.shell.setImage(null);
-		this.shell.setMaximized(true);
-		this.shell.setText("Kieker's GUI");
-		this.shell.setLayout(new GridLayout(1, false));
-
-		this.outerForm = new SashForm(this.shell, SWT.NONE);
-		this.outerForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
-
-		this.explorerForm = new SashForm(this.outerForm, SWT.VERTICAL);
-
-		this.explorerTreeViewer = new TreeViewer(this.explorerForm, SWT.BORDER);
-		this.explorerTree = this.explorerTreeViewer.getTree();
-
-		this.explorerTreeItem = new TreeItem(this.explorerTree, SWT.NONE);
-		this.explorerTreeItem.setText("Explorer");
-
-		this.recordsTreeItem = new TreeItem(this.explorerTreeItem, SWT.NONE);
-		this.recordsTreeItem.setText("Records");
-
-		this.executionTracesTreeItem = new TreeItem(this.explorerTreeItem, SWT.NONE);
-		this.executionTracesTreeItem.setText("Execution Traces");
-
-		this.trtmAggregatedExecutionTraces = new TreeItem(this.executionTracesTreeItem, SWT.NONE);
-		this.trtmAggregatedExecutionTraces.setText("Aggregated Execution Traces");
-
-		this.executionTracesTreeItem.setExpanded(true);
-		this.explorerTreeItem.setExpanded(true);
-
-		this.explorerForm.setWeights(new int[] { 3 });
-
-		this.mainComposite = new Composite(this.outerForm, SWT.NONE);
-		this.mainComposite.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.mainComposite.setLayout(new StackLayout());
-
-		this.recordsTableViewer = new TableViewer(this.mainComposite, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
-		this.recordsTable = this.recordsTableViewer.getTable();
-		this.recordsTable.setHeaderVisible(true);
-
-		this.recordsTableTimestampColumn = new TableColumn(this.recordsTable, SWT.NONE);
-		this.recordsTableTimestampColumn.setWidth(100);
-		this.recordsTableTimestampColumn.setText("Timestamp");
-
-		this.recordsTableTypeColumn = new TableColumn(this.recordsTable, SWT.NONE);
-		this.recordsTableTypeColumn.setWidth(100);
-		this.recordsTableTypeColumn.setText("Type");
-
-		this.recordsTableRecordColumn = new TableColumn(this.recordsTable, SWT.NONE);
-		this.recordsTableRecordColumn.setWidth(100);
-		this.recordsTableRecordColumn.setText("Record");
-
-		this.executionTracesForm = new SashForm(this.mainComposite, SWT.VERTICAL);
-
-		this.tracesTree = new Tree(this.executionTracesForm, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
-		this.tracesTree.setHeaderVisible(true);
-
-		this.tracesTreeContainerColumn = new TreeColumn(this.tracesTree, SWT.NONE);
-		this.tracesTreeContainerColumn.setWidth(100);
-		this.tracesTreeContainerColumn.setText("Execution Container");
-
-		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.tracesTree, SWT.NONE);
-		this.treeColumn_10.setWidth(100);
-		this.treeColumn_10.setText("Operation");
-
-		this.treeColumn_11 = new TreeColumn(this.tracesTree, SWT.NONE);
-		this.treeColumn_11.setWidth(100);
-		this.treeColumn_11.setText("Duration");
-
-		this.trclmnPercent = new TreeColumn(this.tracesTree, SWT.NONE);
-		this.trclmnPercent.setWidth(100);
-		this.trclmnPercent.setText("Percent");
-
-		this.treeColumn_16 = new TreeColumn(this.tracesTree, SWT.NONE);
-		this.treeColumn_16.setWidth(100);
-		this.treeColumn_16.setText("Trace ID");
-
-		this.traceDetailComposite = new TraceDetailComposite(this.executionTracesForm, SWT.BORDER);
-		this.executionTracesForm.setWeights(new int[] { 2, 1 });
-
-		this.sashForm = new SashForm(this.mainComposite, SWT.VERTICAL);
-
-		this.aggregatedTracesTree = new Tree(this.sashForm, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
-		this.aggregatedTracesTree.setHeaderVisible(true);
-
-		this.treeColumn = new TreeColumn(this.aggregatedTracesTree, SWT.NONE);
-		this.treeColumn.setWidth(100);
-		this.treeColumn.setText("Execution Container");
-
-		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.aggregatedTracesTree, SWT.NONE);
-		this.treeColumn_2.setWidth(100);
-		this.treeColumn_2.setText("Operation");
-
-		this.trclmnCalls = new TreeColumn(this.aggregatedTracesTree, SWT.NONE);
-		this.trclmnCalls.setWidth(100);
-		this.trclmnCalls.setText("# Calls");
-
-		this.aggregatedTraceDetailComposite = new AggregatedTraceDetailComposite(this.sashForm, SWT.BORDER);
-		this.sashForm.setWeights(new int[] { 2, 1 });
-
-		this.outerForm.setWeights(new int[] { 2, 4 });
-
-		this.menuBar = new Menu(this.shell, SWT.BAR);
-		this.shell.setMenuBar(this.menuBar);
-
-		this.fileMenuItem = new MenuItem(this.menuBar, SWT.CASCADE);
-		this.fileMenuItem.setText("File");
-
-		this.fileMenu = new Menu(this.fileMenuItem);
-		this.fileMenuItem.setMenu(this.fileMenu);
-
-		this.openMonitoringLogMenuItem = new MenuItem(this.fileMenu, SWT.NONE);
-		this.openMonitoringLogMenuItem.setText("Open Monitoring Log");
-
-		new MenuItem(this.fileMenu, SWT.SEPARATOR);
-
-		this.exitMenuItem = new MenuItem(this.fileMenu, SWT.NONE);
-		this.exitMenuItem.setText("Exit");
-
-		this.mntmView_1 = new MenuItem(this.menuBar, SWT.CASCADE);
-		this.mntmView_1.setText("View");
-
-		this.menu = new Menu(this.mntmView_1);
-		this.mntmView_1.setMenu(this.menu);
-
-		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.mntmLongOperationParameters.addSelectionListener(new SelectionAdapter() {
-
-			@Override
-			public void widgetSelected(final SelectionEvent e) {
-				Properties.getInstance().setShortOperationParameters(false);
-			}
-
-		});
-
-		this.mntmShortComponentNames.addSelectionListener(new SelectionAdapter() {
-
-			@Override
-			public void widgetSelected(final SelectionEvent e) {
-				Properties.getInstance().setShortComponentNames(true);
-			}
-
-		});
-
-		this.mntmLongComponentNames.addSelectionListener(new SelectionAdapter() {
-
-			@Override
-			public void widgetSelected(final SelectionEvent e) {
-				Properties.getInstance().setShortComponentNames(false);
-			}
-
-		});
-
-		Properties.getInstance().addObserver(new Observer() {
-
-			@Override
-			public void update(final Observable o, final Object arg) {
-				MainWindow.this.aggregatedTracesTree.clearAll(true);
-				MainWindow.this.tracesTree.clearAll(true);
-			}
-
-		});
-
-		this.recordsTable.addListener(SWT.SetData, new RecordsTableSetDataListener());
-		this.aggregatedTracesTree.addListener(SWT.SetData, new AggregatedExecutionTracesTreeSetDataListener());
-		this.tracesTree.addListener(SWT.SetData, new ExecutionTracesTreeSetDataListener());
-
-		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.treeColumn_10.addListener(SWT.Selection, new TreeColumnSortListener<ExecutionEntry>(new ExecutionEntryOperationComparator()));
-		this.treeColumn_11.addListener(SWT.Selection, new TreeColumnSortListener<ExecutionEntry>(new ExecutionEntryDurationComparator()));
-		this.treeColumn_8.addListener(SWT.Selection, new TreeColumnSortListener<ExecutionEntry>(new ExecutionEntryComponentComparator()));
-
-		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.traceDetailComposite.setTraceToDisplay((ExecutionEntry) data);
-				}
-			}
-
-		});
-
-		this.aggregatedTracesTree.addSelectionListener(new SelectionAdapter() {
-
-			@Override
-			public void widgetSelected(final SelectionEvent e) {
-				final Object data = e.item.getData();
-				if (data instanceof AggregatedExecutionEntry) {
-					MainWindow.this.aggregatedTraceDetailComposite.setTraceToDisplay((AggregatedExecutionEntry) data);
-				}
-			}
-
-		});
-	}
-
-	private void showAggregatedExecutionTraces() {
-		// Show the tree
-		this.setVisibleMainComponent(this.sashForm);
-
-		// Resize the columns
-		for (final TreeColumn column : this.aggregatedTracesTree.getColumns()) {
-			column.pack();
-		}
-	}
-
-	private void showExecutionTraces() {
-		// Show the tree
-		this.setVisibleMainComponent(this.executionTracesForm);
-
-		// Resize the columns
-		for (final TreeColumn column : this.tracesTree.getColumns()) {
-			column.pack();
-		}
-	}
-
-	private void showRecords() {
-		// Show the table
-		this.setVisibleMainComponent(this.recordsTable);
-
-		// Resize the columns
-		for (final TableColumn column : this.recordsTable.getColumns()) {
-			column.pack();
-		}
-	}
-
-	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 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) {
-			DataSource.getInstance().loadMonitoringLogFromFS(selectedDirectory);
-		}
-	}
-
-	private void setVisibleMainComponent(final Control component) {
-		final StackLayout layout = (StackLayout) this.mainComposite.getLayout();
-		layout.topControl = component;
-
-		this.mainComposite.layout();
-	}
-
-}
diff --git a/src/main/java/kieker/gui/view/RecordsSubView.java b/src/main/java/kieker/gui/view/RecordsSubView.java
new file mode 100644
index 00000000..9749046d
--- /dev/null
+++ b/src/main/java/kieker/gui/view/RecordsSubView.java
@@ -0,0 +1,121 @@
+package kieker.gui.view;
+
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+
+import kieker.gui.controller.RecordsSubViewController;
+import kieker.gui.model.DataModel;
+import kieker.gui.model.domain.RecordEntry;
+import kieker.gui.view.util.RecordEntryTimestampComparator;
+import kieker.gui.view.util.RecordEntryTypeComparator;
+import kieker.gui.view.util.TableColumnSortListener;
+
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+
+public final class RecordsSubView implements Observer {
+
+	private final DataModel model;
+	private Composite composite;
+	private Table table;
+
+	public RecordsSubView(final DataModel model, final RecordsSubViewController controller) {
+		this.model = model;
+
+		model.addObserver(this);
+	}
+
+	/**
+	 * @wbp.parser.entryPoint
+	 */
+	public void createComposite(final Composite parent) {
+		if (this.composite != null) {
+			this.composite.dispose();
+		}
+
+		this.composite = new Composite(parent, SWT.NONE);
+		this.composite.setLayout(new FillLayout(SWT.HORIZONTAL));
+
+		final TableViewer tableViewer = new TableViewer(this.composite, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
+		this.table = tableViewer.getTable();
+		this.table.setHeaderVisible(true);
+		this.table.setLinesVisible(true);
+
+		final TableColumn tblclmnTimestamp = new TableColumn(this.table, SWT.NONE);
+		tblclmnTimestamp.setWidth(100);
+		tblclmnTimestamp.setText("Timestamp");
+
+		final TableColumn tblclmnRecordType = new TableColumn(this.table, SWT.NONE);
+		tblclmnRecordType.setWidth(100);
+		tblclmnRecordType.setText("Record Type");
+
+		final TableColumn tblclmnRecordContent = new TableColumn(this.table, SWT.NONE);
+		tblclmnRecordContent.setWidth(100);
+		tblclmnRecordContent.setText("Record Content");
+
+		this.table.addListener(SWT.SetData, new DataProvider());
+
+		tblclmnTimestamp.addSelectionListener(new TableColumnSortListener<>(new RecordEntryTimestampComparator()));
+		tblclmnRecordType.addSelectionListener(new TableColumnSortListener<>(new RecordEntryTypeComparator()));
+		tblclmnRecordContent.addSelectionListener(new TableColumnSortListener<>(new RecordEntryTimestampComparator()));
+	}
+
+	public Table getTable() {
+		return this.table;
+	}
+
+	public Composite getComposite() {
+		return this.composite;
+	}
+
+	@Override
+	public void update(final Observable observable, final Object obj) {
+		if (observable == this.model) {
+			this.updateTable();
+		}
+	}
+
+	private void updateTable() {
+		final List<RecordEntry> records = this.model.getRecordsCopy();
+
+		this.table.setData(records);
+		this.table.setItemCount(records.size());
+		this.table.clearAll();
+
+		for (final TableColumn column : this.table.getColumns()) {
+			column.pack();
+		}
+	}
+
+	private static class DataProvider implements Listener {
+
+		@Override
+		@SuppressWarnings("unchecked")
+		public void handleEvent(final Event event) {
+			// Get the necessary information from the event
+			final Table table = (Table) event.widget;
+			final TableItem item = (TableItem) event.item;
+			final int tableIndex = event.index;
+
+			// Get the data for the current row
+			final List<RecordEntry> records = (List<RecordEntry>) table.getData();
+			final RecordEntry record = records.get(tableIndex);
+
+			// Get the data to display
+			final String timestampStr = Long.toString(record.getTimestamp());
+			final String type = record.getType();
+			final String recordStr = record.getRepresentation();
+			item.setText(new String[] { timestampStr, type, recordStr });
+		}
+
+	}
+
+}
diff --git a/src/main/java/kieker/gui/view/TraceDetailComposite.java b/src/main/java/kieker/gui/view/TraceDetailComposite.java
deleted file mode 100644
index 33dc54e4..00000000
--- a/src/main/java/kieker/gui/view/TraceDetailComposite.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package kieker.gui.view;
-
-import kieker.gui.model.domain.ExecutionEntry;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.wb.swt.SWTResourceManager;
-
-public final class TraceDetailComposite extends Composite {
-
-	private final Label lblExecutionContainerDisplay;
-	private final Label lblComponentDisplay;
-	private final Label lblOperationDisplay;
-	private final Label lblTraceIdDisplay;
-	private final Label lblDurationDisplay;
-	private final Label lblStackDepthDisplay;
-	private final Label lblFailed;
-	private final Label lblFailedDisplay;
-
-	public TraceDetailComposite(final Composite parent, final int style) {
-		super(parent, style);
-		this.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.setLayout(new GridLayout(2, false));
-
-		final Label lblExecutionContainer = new Label(this, SWT.NONE);
-		lblExecutionContainer.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblExecutionContainer.setText("Execution Container:");
-
-		this.lblExecutionContainerDisplay = new Label(this, SWT.NONE);
-		this.lblExecutionContainerDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblExecutionContainerDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblExecutionContainerDisplay.setText("N/A");
-
-		final Label lblComponent = new Label(this, SWT.NONE);
-		lblComponent.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblComponent.setText("Component:");
-
-		this.lblComponentDisplay = new Label(this, SWT.NONE);
-		this.lblComponentDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblComponentDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblComponentDisplay.setText("N/A");
-
-		final Label lblOperation = new Label(this, SWT.NONE);
-		lblOperation.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblOperation.setText("Operation:");
-
-		this.lblOperationDisplay = new Label(this, SWT.NONE);
-		this.lblOperationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblOperationDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblOperationDisplay.setText("N/A");
-
-		final Label lblTraceId = new Label(this, SWT.NONE);
-		lblTraceId.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblTraceId.setText("Trace ID:");
-
-		this.lblTraceIdDisplay = new Label(this, SWT.NONE);
-		this.lblTraceIdDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblTraceIdDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblTraceIdDisplay.setText("N/A");
-
-		final Label lblDuration = new Label(this, SWT.NONE);
-		lblDuration.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblDuration.setText("Duration:");
-
-		this.lblDurationDisplay = new Label(this, SWT.NONE);
-		this.lblDurationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblDurationDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblDurationDisplay.setText("N/A");
-
-		final Label lblStackDepth = new Label(this, SWT.NONE);
-		lblStackDepth.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		lblStackDepth.setText("Stack Depth:");
-
-		this.lblStackDepthDisplay = new Label(this, SWT.NONE);
-		this.lblStackDepthDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblStackDepthDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblStackDepthDisplay.setText("N/A");
-
-		this.lblFailed = new Label(this, SWT.NONE);
-		this.lblFailed.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblFailed.setText("Failed:");
-
-		this.lblFailedDisplay = new Label(this, SWT.NONE);
-		this.lblFailedDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
-		this.lblFailedDisplay.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-		this.lblFailedDisplay.setText("N/A");
-	}
-
-	public void setTraceToDisplay(final ExecutionEntry trace) {
-		this.lblTraceIdDisplay.setText(Long.toString(trace.getTraceID()));
-		this.lblDurationDisplay.setText(Long.toString(trace.getDuration()));
-
-		this.lblExecutionContainerDisplay.setText(trace.getContainer());
-		this.lblComponentDisplay.setText(trace.getComponent());
-		this.lblOperationDisplay.setText(trace.getOperation());
-		this.lblStackDepthDisplay.setText(Integer.toString(trace.getStackDepth()));
-
-		if (trace.isFailed()) {
-			this.lblFailedDisplay.setText("Yes (" + trace.getFailedCause() + ")");
-			this.lblFailedDisplay.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
-			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
-		} else {
-			this.lblFailedDisplay.setText("No");
-			this.lblFailedDisplay.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
-			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
-		}
-
-		super.layout();
-	}
-
-	@Override
-	protected void checkSubclass() {
-		// Disable the check that prevents subclassing of SWT components
-	}
-
-}
diff --git a/src/main/java/kieker/gui/view/TracesSubView.java b/src/main/java/kieker/gui/view/TracesSubView.java
new file mode 100644
index 00000000..f6a54950
--- /dev/null
+++ b/src/main/java/kieker/gui/view/TracesSubView.java
@@ -0,0 +1,293 @@
+package kieker.gui.view;
+
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+
+import kieker.gui.controller.TracesSubViewController;
+import kieker.gui.model.DataModel;
+import kieker.gui.model.PropertiesModel;
+import kieker.gui.model.TracesSubViewModel;
+import kieker.gui.model.domain.ExecutionEntry;
+import kieker.gui.view.util.ExecutionEntryComponentComparator;
+import kieker.gui.view.util.ExecutionEntryDurationComparator;
+import kieker.gui.view.util.ExecutionEntryOperationComparator;
+import kieker.gui.view.util.TreeColumnSortListener;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.wb.swt.SWTResourceManager;
+
+public class TracesSubView implements Observer {
+
+	private final DataModel model;
+	private final TracesSubViewModel tracesSubViewModel;
+	private final TracesSubViewController controller;
+	private Composite composite;
+	private Tree tree;
+	private Composite detailComposite;
+	private Label lblTraceIdDisplay;
+	private Label lblDurationDisplay;
+	private Label lblFailedDisplay;
+	private Label lblTraceDepthDisplay;
+	private Label lblTraceSizeDisplay;
+	private Label lblOperationDisplay;
+	private Label lblComponentDisplay;
+	private Label lblExecutionContainerDisplay;
+	private Label lblFailed;
+	private final PropertiesModel propertiesModel;
+
+	public TracesSubView(final DataModel model, final TracesSubViewModel tracesSubViewModel, final PropertiesModel propertiesModel, final TracesSubViewController controller) {
+		this.model = model;
+		this.propertiesModel = propertiesModel;
+		this.tracesSubViewModel = tracesSubViewModel;
+		this.controller = controller;
+
+		model.addObserver(this);
+		tracesSubViewModel.addObserver(this);
+		propertiesModel.addObserver(this);
+	}
+
+	/**
+	 * @wbp.parser.entryPoint
+	 */
+	public void createComposite(final Composite parent) {
+		if (this.composite != null) {
+			this.composite.dispose();
+		}
+
+		this.composite = new Composite(parent, SWT.NONE);
+		this.composite.setLayout(new FillLayout(SWT.HORIZONTAL));
+
+		final SashForm sashForm = new SashForm(this.composite, SWT.VERTICAL);
+
+		this.tree = new Tree(sashForm, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
+		this.tree.setHeaderVisible(true);
+
+		final TreeColumn trclmnExecutionContainer = new TreeColumn(this.tree, SWT.NONE);
+		trclmnExecutionContainer.setWidth(100);
+		trclmnExecutionContainer.setText("Execution Container");
+
+		final TreeColumn trclmnComponent = new TreeColumn(this.tree, SWT.NONE);
+		trclmnComponent.setWidth(100);
+		trclmnComponent.setText("Component");
+
+		final TreeColumn trclmnOperation = new TreeColumn(this.tree, SWT.NONE);
+		trclmnOperation.setWidth(100);
+		trclmnOperation.setText("Operation");
+
+		final TreeColumn trclmnDuration = new TreeColumn(this.tree, SWT.NONE);
+		trclmnDuration.setWidth(100);
+		trclmnDuration.setText("Duration");
+
+		final TreeColumn trclmnPercent = new TreeColumn(this.tree, SWT.NONE);
+		trclmnPercent.setWidth(100);
+		trclmnPercent.setText("Percent");
+
+		final TreeColumn trclmnTraceId = new TreeColumn(this.tree, SWT.NONE);
+		trclmnTraceId.setWidth(100);
+		trclmnTraceId.setText("Trace ID");
+
+		this.detailComposite = new Composite(sashForm, SWT.BORDER);
+		this.detailComposite.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.detailComposite.setLayout(new GridLayout(2, false));
+
+		final Label lblExecutionContainer = new Label(this.detailComposite, SWT.NONE);
+		lblExecutionContainer.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblExecutionContainer.setText("Execution Container:");
+
+		this.lblExecutionContainerDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblExecutionContainerDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblExecutionContainerDisplay.setText("N/A");
+
+		final Label lblComponent = new Label(this.detailComposite, SWT.NONE);
+		lblComponent.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblComponent.setText("Component:");
+
+		this.lblComponentDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblComponentDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblComponentDisplay.setText("N/A");
+
+		final Label lblOperation = new Label(this.detailComposite, SWT.NONE);
+		lblOperation.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblOperation.setText("Operation:");
+
+		this.lblOperationDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblOperationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblOperationDisplay.setText("N/A");
+
+		final Label lblDuration = new Label(this.detailComposite, SWT.NONE);
+		lblDuration.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblDuration.setText("Duration:");
+
+		this.lblDurationDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblDurationDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblDurationDisplay.setText("N/A");
+
+		final Label lblTraceId = new Label(this.detailComposite, SWT.NONE);
+		lblTraceId.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblTraceId.setBounds(0, 0, 55, 15);
+		lblTraceId.setText("Trace ID:");
+
+		this.lblTraceIdDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblTraceIdDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblTraceIdDisplay.setText("N/A");
+
+		this.lblFailed = new Label(this.detailComposite, SWT.NONE);
+		this.lblFailed.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblFailed.setText("Failed:");
+
+		this.lblFailedDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblFailedDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblFailedDisplay.setText("N/A");
+
+		final Label lblTraceDepth = new Label(this.detailComposite, SWT.NONE);
+		lblTraceDepth.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblTraceDepth.setText("Trace Depth:");
+
+		this.lblTraceDepthDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblTraceDepthDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblTraceDepthDisplay.setText("N/A");
+
+		final Label lblTraceSize = new Label(this.detailComposite, SWT.NONE);
+		lblTraceSize.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		lblTraceSize.setText("Trace Size:");
+
+		this.lblTraceSizeDisplay = new Label(this.detailComposite, SWT.NONE);
+		this.lblTraceSizeDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
+		this.lblTraceSizeDisplay.setText("N/A");
+
+		sashForm.setWeights(new int[] { 2, 1 });
+
+		this.tree.addSelectionListener(this.controller);
+		this.tree.addListener(SWT.SetData, new DataProvider());
+
+		trclmnComponent.addSelectionListener(new TreeColumnSortListener<>(new ExecutionEntryComponentComparator()));
+		trclmnOperation.addSelectionListener(new TreeColumnSortListener<>(new ExecutionEntryOperationComparator()));
+		trclmnDuration.addSelectionListener(new TreeColumnSortListener<>(new ExecutionEntryDurationComparator()));
+	}
+
+	public Tree getTree() {
+		return this.tree;
+	}
+
+	public Composite getComposite() {
+		return this.composite;
+	}
+
+	@Override
+	public void update(final Observable observable, final Object obj) {
+		if (observable == this.model) {
+			this.updateTree();
+		}
+		if (observable == this.tracesSubViewModel) {
+			this.updateDetailComposite();
+		}
+		if (observable == this.propertiesModel) {
+			this.clearTree();
+		}
+	}
+
+	private void updateTree() {
+		final List<ExecutionEntry> records = this.model.getTracesCopy();
+
+		this.tree.setData(records);
+		this.tree.setItemCount(records.size());
+
+		this.clearTree();
+	}
+
+	private void clearTree() {
+		this.tree.clearAll(true);
+
+		for (final TreeColumn column : this.tree.getColumns()) {
+			column.pack();
+		}
+	}
+
+	private void updateDetailComposite() {
+		final ExecutionEntry trace = this.tracesSubViewModel.getCurrentActiveTrace();
+
+		this.lblTraceIdDisplay.setText(Long.toString(trace.getTraceID()));
+		this.lblDurationDisplay.setText(Long.toString(trace.getDuration()));
+
+		this.lblExecutionContainerDisplay.setText(trace.getContainer());
+		this.lblComponentDisplay.setText(trace.getComponent());
+		this.lblOperationDisplay.setText(trace.getOperation());
+		this.lblTraceDepthDisplay.setText(Integer.toString(trace.getTraceDepth()));
+		this.lblTraceSizeDisplay.setText(Integer.toString(trace.getTraceSize()));
+
+		if (trace.isFailed()) {
+			this.lblFailedDisplay.setText("Yes (" + trace.getFailedCause() + ")");
+			this.lblFailedDisplay.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+		} else {
+			this.lblFailedDisplay.setText("No");
+			this.lblFailedDisplay.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+			this.lblFailed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+		}
+
+		this.detailComposite.layout();
+	}
+
+	private class DataProvider implements Listener {
+
+		@Override
+		@SuppressWarnings("unchecked")
+		public void handleEvent(final Event event) {
+			// Get the necessary information from the event
+			final Tree tree = (Tree) event.widget;
+			final TreeItem item = (TreeItem) event.item;
+			final int tableIndex = event.index;
+			final TreeItem parent = item.getParentItem();
+
+			// Decide whether the current item is a root or not
+			final ExecutionEntry executionEntry;
+			final String traceID;
+
+			if (parent == null) {
+				executionEntry = ((List<ExecutionEntry>) tree.getData()).get(tableIndex);
+				traceID = Long.toString(executionEntry.getTraceID());
+			} else {
+				executionEntry = ((ExecutionEntry) parent.getData()).getChildren().get(tableIndex);
+				traceID = "";
+			}
+
+			String componentName = executionEntry.getComponent();
+			if (TracesSubView.this.propertiesModel.isShortComponentNames()) {
+				final int lastPointPos = componentName.lastIndexOf('.');
+				componentName = componentName.substring(lastPointPos + 1);
+			}
+			String operationString = executionEntry.getOperation();
+			if (TracesSubView.this.propertiesModel.isShortOperationNames()) {
+				operationString = operationString.replaceAll("\\(..*\\)", "(...)");
+
+				final int lastPointPos = operationString.lastIndexOf('.', operationString.length() - 5);
+				operationString = operationString.substring(lastPointPos + 1);
+			}
+			item.setText(new String[] { executionEntry.getContainer(), componentName, operationString, Long.toString(executionEntry.getDuration()),
+					String.format("%.1f%%", executionEntry.getPercent()), traceID });
+
+			if (executionEntry.isFailed()) {
+				final Color colorRed = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
+				item.setForeground(colorRed);
+			}
+
+			item.setData(executionEntry);
+			item.setItemCount(executionEntry.getChildren().size());
+		}
+
+	}
+
+}
diff --git a/src/main/java/kieker/gui/view/util/AggregatedExecutionTracesTreeSetDataListener.java b/src/main/java/kieker/gui/view/util/AggregatedExecutionTracesTreeSetDataListener.java
deleted file mode 100644
index 8bc0982c..00000000
--- a/src/main/java/kieker/gui/view/util/AggregatedExecutionTracesTreeSetDataListener.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package kieker.gui.view.util;
-
-import java.util.List;
-
-import kieker.gui.model.Properties;
-import kieker.gui.model.domain.AggregatedExecutionEntry;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeItem;
-
-public class AggregatedExecutionTracesTreeSetDataListener implements Listener {
-
-	@Override
-	public void handleEvent(final Event event) {
-		// Get the necessary information from the event
-		final Tree tree = (Tree) event.widget;
-		final TreeItem item = (TreeItem) event.item;
-		final int tableIndex = event.index;
-		final TreeItem parent = item.getParentItem();
-
-		// Decide whether the current item is a root or not
-		final AggregatedExecutionEntry executionEntry;
-		if (parent == null) {
-			executionEntry = ((List<AggregatedExecutionEntry>) tree.getData()).get(tableIndex);
-		} else {
-			executionEntry = ((AggregatedExecutionEntry) parent.getData()).getChildren().get(tableIndex);
-		}
-
-		String componentName = executionEntry.getComponent();
-		if (Properties.getInstance().isShortComponentNames()) {
-			final int lastPointPos = componentName.lastIndexOf('.');
-			componentName = componentName.substring(lastPointPos + 1);
-		}
-		String operationString = executionEntry.getOperation();
-		if (Properties.getInstance().isShortOperationParameters()) {
-			operationString = operationString.replaceAll("\\(..*\\)", "(...)");
-
-			final int lastPointPos = operationString.lastIndexOf('.', operationString.length() - 5);
-			operationString = operationString.substring(lastPointPos + 1);
-		}
-		if (parent != null) {
-			item.setText(new String[] { executionEntry.getContainer(), componentName, operationString, "" });
-		} else {
-			item.setText(new String[] { executionEntry.getContainer(), componentName, operationString, Integer.toString(executionEntry.getCalls()) });
-		}
-
-		if (executionEntry.isFailed()) {
-			final Color colorRed = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
-			item.setForeground(colorRed);
-		}
-
-		item.setData(executionEntry);
-		item.setItemCount(executionEntry.getChildren().size());
-	}
-}
diff --git a/src/main/java/kieker/gui/view/util/ExecutionTracesTreeSetDataListener.java b/src/main/java/kieker/gui/view/util/ExecutionTracesTreeSetDataListener.java
deleted file mode 100644
index 51c04188..00000000
--- a/src/main/java/kieker/gui/view/util/ExecutionTracesTreeSetDataListener.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package kieker.gui.view.util;
-
-import java.util.List;
-
-import kieker.gui.model.Properties;
-import kieker.gui.model.domain.ExecutionEntry;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeItem;
-
-public class ExecutionTracesTreeSetDataListener implements Listener {
-
-	@Override
-	public void handleEvent(final Event event) {
-		// Get the necessary information from the event
-		final Tree tree = (Tree) event.widget;
-		final TreeItem item = (TreeItem) event.item;
-		final int tableIndex = event.index;
-		final TreeItem parent = item.getParentItem();
-
-		// Decide whether the current item is a root or not
-		final ExecutionEntry executionEntry;
-		final String traceID;
-
-		if (parent == null) {
-			executionEntry = ((List<ExecutionEntry>) tree.getData()).get(tableIndex);
-			traceID = Long.toString(executionEntry.getTraceID());
-		} else {
-			executionEntry = ((ExecutionEntry) parent.getData()).getChildren().get(tableIndex);
-			traceID = "";
-		}
-
-		String componentName = executionEntry.getComponent();
-		if (Properties.getInstance().isShortComponentNames()) {
-			final int lastPointPos = componentName.lastIndexOf('.');
-			componentName = componentName.substring(lastPointPos + 1);
-		}
-		String operationString = executionEntry.getOperation();
-		if (Properties.getInstance().isShortOperationParameters()) {
-			operationString = operationString.replaceAll("\\(..*\\)", "(...)");
-
-			final int lastPointPos = operationString.lastIndexOf('.', operationString.length() - 5);
-			operationString = operationString.substring(lastPointPos + 1);
-		}
-		item.setText(new String[] { executionEntry.getContainer(), componentName, operationString, Long.toString(executionEntry.getDuration()),
-			String.format("%.1f%%", executionEntry.getPercent()), traceID });
-
-		if (executionEntry.isFailed()) {
-			final Color colorRed = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
-			item.setForeground(colorRed);
-		}
-
-		item.setData(executionEntry);
-		item.setItemCount(executionEntry.getChildren().size());
-	}
-}
diff --git a/src/main/java/kieker/gui/view/util/RecordsTableSetDataListener.java b/src/main/java/kieker/gui/view/util/RecordsTableSetDataListener.java
deleted file mode 100644
index 797d90b4..00000000
--- a/src/main/java/kieker/gui/view/util/RecordsTableSetDataListener.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package kieker.gui.view.util;
-
-import java.util.List;
-
-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;
-
-public class RecordsTableSetDataListener implements Listener {
-
-	@Override
-	public void handleEvent(final Event event) {
-		// Get the necessary information from the event
-		final Table table = (Table) event.widget;
-		final TableItem item = (TableItem) event.item;
-		final int tableIndex = event.index;
-
-		// Get the data for the current row
-		final List<RecordEntry> records = (List<RecordEntry>) table.getData();
-		final RecordEntry record = records.get(tableIndex);
-
-		// Get the data to display
-		final String timestampStr = Long.toString(record.getTimestamp());
-		final String type = record.getType();
-		final String recordStr = record.getRepresentation();
-		item.setText(new String[] { timestampStr, type, recordStr });
-	}
-
-}
diff --git a/src/main/java/kieker/gui/view/util/TableColumnSortListener.java b/src/main/java/kieker/gui/view/util/TableColumnSortListener.java
index 11dca925..67fba7d5 100644
--- a/src/main/java/kieker/gui/view/util/TableColumnSortListener.java
+++ b/src/main/java/kieker/gui/view/util/TableColumnSortListener.java
@@ -4,12 +4,12 @@ import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
 
-public final class TableColumnSortListener<T> implements Listener {
+public final class TableColumnSortListener<T> extends SelectionAdapter {
 
 	private final AbstractDirectedComparator<T> comparator;
 
@@ -18,7 +18,7 @@ public final class TableColumnSortListener<T> implements Listener {
 	}
 
 	@Override
-	public void handleEvent(final Event event) {
+	public void widgetSelected(final SelectionEvent event) {
 		// Get the necessary information from the event
 		final TableColumn currentColumn = (TableColumn) event.widget;
 		final Table table = currentColumn.getParent();
diff --git a/src/main/java/kieker/gui/view/util/TreeColumnSortListener.java b/src/main/java/kieker/gui/view/util/TreeColumnSortListener.java
index 65794711..882c4952 100644
--- a/src/main/java/kieker/gui/view/util/TreeColumnSortListener.java
+++ b/src/main/java/kieker/gui/view/util/TreeColumnSortListener.java
@@ -4,12 +4,12 @@ import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeColumn;
 
-public final class TreeColumnSortListener<T> implements Listener {
+public final class TreeColumnSortListener<T> extends SelectionAdapter {
 
 	private final AbstractDirectedComparator<T> comparator;
 
@@ -18,7 +18,7 @@ public final class TreeColumnSortListener<T> implements Listener {
 	}
 
 	@Override
-	public void handleEvent(final Event event) {
+	public void widgetSelected(final SelectionEvent event) {
 		// Get the necessary information from the event
 		final TreeColumn currentColumn = (TreeColumn) event.widget;
 		final Tree tree = currentColumn.getParent();
-- 
GitLab