diff --git a/CHANGES.md b/CHANGES.md
index 019683ae795a4300879fa132d77e68bb1044608a..15b73b06746dda54774d5368b2759ca50409b9fa 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -3,6 +3,10 @@
 - changing the coordinate reference system to one that is obviously not suited for the data might cause system crashes
 
 ## Change History ##
+## July 2017
+- Sensor/Product names are now stored in system settings and will be restored after restart
+- Pixel profiles are now loaded in a parallel process that will not block the UI (required because of python GIL.)
+
 
 ### June 2017
 - improved QGIS-TimeSeriesViewer integration
diff --git a/timeseriesviewer/main.py b/timeseriesviewer/main.py
index b5f06bc32bb282bac75b51a97fd269ef78879cb7..414793029577a5984eb07af65d169ba4033aa250 100644
--- a/timeseriesviewer/main.py
+++ b/timeseriesviewer/main.py
@@ -286,7 +286,8 @@ class TimeSeriesViewerUI(QMainWindow,
         area = Qt.BottomDockWidgetArea
         from timeseriesviewer.mapvisualization import MapViewDockUI
         self.dockMapViews = addDockWidget(MapViewDockUI(self))
-        self.dockTimeSeries = addDockWidget(docks.TimeSeriesDockUI(self))
+
+        self.dockTimeSeries = addDockWidget(TimeSeriesDockUI(self))
         from timeseriesviewer.profilevisualization import ProfileViewDockUI
         self.dockProfiles = addDockWidget(ProfileViewDockUI(self))
         self.tabifyDockWidget(self.dockTimeSeries, self.dockMapViews)
diff --git a/timeseriesviewer/timeseries.py b/timeseriesviewer/timeseries.py
index 6f10039891715c221925e40e60c39331d388dccb..3e8ce2e95b94c14a5c4840c90a144fc09f74d1a3 100644
--- a/timeseriesviewer/timeseries.py
+++ b/timeseriesviewer/timeseries.py
@@ -328,6 +328,90 @@ class TimeSeriesDatum(QObject):
         return hash((self.date,self.sensor.id()))
 
 
+class TimeSeriesTableView(QTableView):
+
+    def __init__(self, parent=None):
+        super(TimeSeriesTableView, self).__init__(parent)
+
+    def contextMenuEvent(self, event):
+
+        menu = QMenu(self)
+        menu.addAction('Check selected observation')
+        menu.addAction('Uncheck selected observation')
+
+        menu.popup(QCursor.pos())
+
+    def selectSelectedObservations(b):
+        assert isinstance(b, bool)
+
+
+from timeseriesviewer.ui.docks import TsvDockWidgetBase
+from timeseriesviewer.utils import loadUi
+class TimeSeriesDockUI(TsvDockWidgetBase, loadUi('timeseriesdock.ui')):
+    def __init__(self, parent=None):
+        super(TimeSeriesDockUI, self).__init__(parent)
+        self.setupUi(self)
+        self.btnAddTSD.setDefaultAction(parent.actionAddTSD)
+        self.btnRemoveTSD.setDefaultAction(parent.actionRemoveTSD)
+        self.btnLoadTS.setDefaultAction(parent.actionLoadTS)
+        self.btnSaveTS.setDefaultAction(parent.actionSaveTS)
+        self.btnClearTS.setDefaultAction(parent.actionClearTS)
+
+        self.progressBar.setMinimum(0)
+        self.setProgressInfo(0,100, 'Add images to fill time series')
+        self.progressBar.setValue(0)
+        self.progressInfo.setText(None)
+        self.frameFilters.setVisible(False)
+
+        self.connectTimeSeries(None)
+
+    def setStatus(self):
+        from timeseriesviewer.timeseries import TimeSeries
+        if isinstance(self.TS, TimeSeries):
+            ndates = len(self.TS)
+            nsensors = len(set([tsd.sensor for tsd in self.TS]))
+            msg = '{} scene(s) from {} sensor(s)'.format(ndates, nsensors)
+            if ndates > 1:
+                msg += ', {} to {}'.format(str(self.TS[0].date), str(self.TS[-1].date))
+            self.progressInfo.setText(msg)
+
+    def setProgressInfo(self, nDone, nMax, message=None):
+        if self.progressBar.maximum() != nMax:
+            self.progressBar.setMaximum(nMax)
+        self.progressBar.setValue(nDone)
+        self.progressInfo.setText(message)
+        QgsApplication.processEvents()
+        if nDone == nMax:
+            QTimer.singleShot(3000, lambda: self.setStatus())
+
+    def onSelectionChanged(self, *args):
+        self.btnRemoveTSD.setEnabled(self.SM is not None and len(self.SM.selectedRows()) > 0)
+
+    def selectedTimeSeriesDates(self):
+        if self.SM is not None:
+            return [self.TSM.data(idx, Qt.UserRole) for idx in self.SM.selectedRows()]
+        return []
+
+    def connectTimeSeries(self, TS):
+        from timeseriesviewer.timeseries import TimeSeries
+        self.TS = TS
+        self.TSM = None
+        self.SM = None
+        self.timeSeriesInitialized = False
+
+        if isinstance(TS, TimeSeries):
+            from timeseriesviewer.timeseries import TimeSeriesTableModel
+            self.TSM = TimeSeriesTableModel(self.TS)
+            self.tableView_TimeSeries.setModel(self.TSM)
+            self.SM = QItemSelectionModel(self.TSM)
+            self.tableView_TimeSeries.setSelectionModel(self.SM)
+            self.SM.selectionChanged.connect(self.onSelectionChanged)
+            self.tableView_TimeSeries.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
+            TS.sigLoadingProgress.connect(self.setProgressInfo)
+
+        self.onSelectionChanged()
+
+
 class TimeSeries(QObject):
 
     sigTimeSeriesDatesAdded = pyqtSignal(list)
@@ -552,6 +636,177 @@ class TimeSeries(QObject):
 
         return '\n'.join(info)
 
+
+
+class TimeSeriesTableModel(QAbstractTableModel):
+    columnames = ['date', 'sensor', 'ns', 'nl', 'nb', 'image']
+
+    def __init__(self, TS, parent=None, *args):
+
+        super(TimeSeriesTableModel, self).__init__()
+        assert isinstance(TS, TimeSeries)
+        self.TS = TS
+        self.sensors = set()
+        self.TS.sigTimeSeriesDatesRemoved.connect(self.removeTSDs)
+        self.TS.sigTimeSeriesDatesAdded.connect(self.addTSDs)
+
+        self.items = []
+        self.sortColumnIndex = 0
+        self.sortOrder = Qt.AscendingOrder
+        self.addTSDs([tsd for tsd in self.TS])
+
+    def removeTSDs(self, tsds):
+        #self.TS.removeDates(tsds)
+        for tsd in tsds:
+            if tsd in self.TS:
+                #remove from TimeSeries first.
+                self.TS.removeDates([tsd])
+            elif tsd in self.items:
+                idx = self.getIndexFromDate(tsd)
+                self.removeRows(idx.row(), 1)
+
+        #self.sort(self.sortColumnIndex, self.sortOrder)
+
+
+    def tsdChanged(self, tsd):
+        idx = self.getIndexFromDate(tsd)
+        self.dataChanged.emit(idx, idx)
+
+    def addTSDs(self, tsds):
+        self.items.extend(tsds)
+        self.sort(self.sortColumnIndex, self.sortOrder)
+
+        for tsd in tsds:
+            assert isinstance(tsd, TimeSeriesDatum)
+            tsd.sigVisibilityChanged.connect(lambda: self.tsdChanged(tsd))
+
+        for sensor in set([tsd.sensor for tsd in tsds]):
+            if sensor not in self.sensors:
+                self.sensors.add(sensor)
+                sensor.sigNameChanged.connect(lambda: self.reset())
+
+
+
+    def sort(self, col, order):
+        if self.rowCount() == 0:
+            return
+
+        self.layoutAboutToBeChanged.emit()
+        colName = self.columnames[col]
+        r = order != Qt.AscendingOrder
+
+        if colName in ['date','ns','nl','sensor']:
+            self.items.sort(key = lambda d:d.__dict__[colName], reverse=r)
+
+        self.layoutChanged.emit()
+        s = ""
+
+
+    def rowCount(self, parent = QModelIndex()):
+        return len(self.items)
+
+
+    def removeRows(self, row, count , parent=QModelIndex()):
+        self.beginRemoveRows(parent, row, row+count-1)
+        toRemove = self.items[row:row+count]
+        for tsd in toRemove:
+            self.items.remove(tsd)
+        self.endRemoveRows()
+
+    def getIndexFromDate(self, tsd):
+        return self.createIndex(self.items.index(tsd),0)
+
+    def getDateFromIndex(self, index):
+        if index.isValid():
+            return self.items[index.row()]
+        return None
+
+    def getTimeSeriesDatumFromIndex(self, index):
+        if index.isValid():
+            i = index.row()
+            if i >= 0 and i < len(self.items):
+                return self.items[i]
+
+        return None
+
+    def columnCount(self, parent = QModelIndex()):
+        return len(self.columnames)
+
+    def data(self, index, role = Qt.DisplayRole):
+        if role is None or not index.isValid():
+            return None
+
+        value = None
+        columnName = self.columnames[index.column()]
+
+        TSD = self.getTimeSeriesDatumFromIndex(index)
+        keys = list(TSD.__dict__.keys())
+
+
+        if role == Qt.DisplayRole or role == Qt.ToolTipRole:
+            if columnName == 'name':
+                value = os.path.basename(TSD.pathImg)
+            elif columnName == 'sensor':
+                if role == Qt.ToolTipRole:
+                    value = TSD.sensor.getDescription()
+                else:
+                    value = TSD.sensor.name()
+            elif columnName == 'date':
+                value = '{}'.format(TSD.date)
+            elif columnName == 'image':
+                value = TSD.pathImg
+            elif columnName in keys:
+                value = TSD.__dict__[columnName]
+            else:
+                s = ""
+        elif role == Qt.CheckStateRole:
+            if columnName == 'date':
+                value = Qt.Checked if TSD.isVisible() else Qt.Unchecked
+        elif role == Qt.BackgroundColorRole:
+            value = None
+        elif role == Qt.UserRole:
+            value = TSD
+
+        return value
+
+    def setData(self, index, value, role=None):
+        if role is None or not index.isValid():
+            return None
+
+        if role is Qt.UserRole:
+
+            s = ""
+
+        columnName = self.columnames[index.column()]
+
+        TSD = self.getTimeSeriesDatumFromIndex(index)
+        if columnName == 'date' and role == Qt.CheckStateRole:
+            TSD.setVisibility(value != Qt.Unchecked)
+            return True
+        else:
+            return False
+
+        return False
+
+    def flags(self, index):
+        if index.isValid():
+            columnName = self.columnames[index.column()]
+            flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
+            if columnName == 'date': #allow check state
+                flags = flags | Qt.ItemIsUserCheckable
+
+            return flags
+            #return item.qt_flags(index.column())
+        return None
+
+    def headerData(self, col, orientation, role):
+        if Qt is None:
+            return None
+        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
+            return self.columnames[col]
+        elif orientation == Qt.Vertical and role == Qt.DisplayRole:
+            return col
+        return None
 def getSpatialPropertiesFromDataset(ds):
     assert isinstance(ds, gdal.Dataset)
 
@@ -636,8 +891,6 @@ def parseWavelength(lyr):
 
     return wl, wlu
 
-
-
 if __name__ == '__main__':
 
 
diff --git a/timeseriesviewer/ui/docks.py b/timeseriesviewer/ui/docks.py
index c72c31ba00cfacea998b844e29cd815f78ef8728..3526bdd6345b8068d76170e2f764bf1f21e0b379 100644
--- a/timeseriesviewer/ui/docks.py
+++ b/timeseriesviewer/ui/docks.py
@@ -197,70 +197,6 @@ class RenderingDockUI(TsvDockWidgetBase, loadUi('renderingdock.ui')):
 
 
 
-class TimeSeriesDockUI(TsvDockWidgetBase, loadUi('timeseriesdock.ui')):
-    def __init__(self, parent=None):
-        super(TimeSeriesDockUI, self).__init__(parent)
-        #self.setupUi(self)
-        self.btnAddTSD.setDefaultAction(parent.actionAddTSD)
-        self.btnRemoveTSD.setDefaultAction(parent.actionRemoveTSD)
-        self.btnLoadTS.setDefaultAction(parent.actionLoadTS)
-        self.btnSaveTS.setDefaultAction(parent.actionSaveTS)
-        self.btnClearTS.setDefaultAction(parent.actionClearTS)
-
-        self.progressBar.setMinimum(0)
-        self.setProgressInfo(0,100, 'Add images to fill time series')
-        self.progressBar.setValue(0)
-        self.progressInfo.setText(None)
-        self.frameFilters.setVisible(False)
-
-        self.connectTimeSeries(None)
-
-    def setStatus(self):
-        from timeseriesviewer.timeseries import TimeSeries
-        if isinstance(self.TS, TimeSeries):
-            ndates = len(self.TS)
-            nsensors = len(set([tsd.sensor for tsd in self.TS]))
-            msg = '{} scene(s) from {} sensor(s)'.format(ndates, nsensors)
-            if ndates > 1:
-                msg += ', {} to {}'.format(str(self.TS[0].date), str(self.TS[-1].date))
-            self.progressInfo.setText(msg)
-
-    def setProgressInfo(self, nDone, nMax, message=None):
-        if self.progressBar.maximum() != nMax:
-            self.progressBar.setMaximum(nMax)
-        self.progressBar.setValue(nDone)
-        self.progressInfo.setText(message)
-        QgsApplication.processEvents()
-        if nDone == nMax:
-            QTimer.singleShot(3000, lambda: self.setStatus())
-
-    def onSelectionChanged(self, *args):
-        self.btnRemoveTSD.setEnabled(self.SM is not None and len(self.SM.selectedRows()) > 0)
-
-    def selectedTimeSeriesDates(self):
-        if self.SM is not None:
-            return [self.TSM.data(idx, Qt.UserRole) for idx in self.SM.selectedRows()]
-        return []
-
-    def connectTimeSeries(self, TS):
-        from timeseriesviewer.timeseries import TimeSeries
-        self.TS = TS
-        self.TSM = None
-        self.SM = None
-        self.timeSeriesInitialized = False
-
-        if isinstance(TS, TimeSeries):
-            from timeseriesviewer.viewmodels import TimeSeriesTableModel
-            self.TSM = TimeSeriesTableModel(self.TS)
-            self.tableView_TimeSeries.setModel(self.TSM)
-            self.SM = QItemSelectionModel(self.TSM)
-            self.tableView_TimeSeries.setSelectionModel(self.SM)
-            self.SM.selectionChanged.connect(self.onSelectionChanged)
-            self.tableView_TimeSeries.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
-            TS.sigLoadingProgress.connect(self.setProgressInfo)
-
-        self.onSelectionChanged()
-
 
 if __name__ == '__main__':
     import site, sys
diff --git a/timeseriesviewer/ui/timeseriesdock.ui b/timeseriesviewer/ui/timeseriesdock.ui
index 4786b0e98b9b2f7d56a94e32d7a88f6fbd13a10a..b98c322408b5c101607e9154113a0c9886edc685 100644
--- a/timeseriesviewer/ui/timeseriesdock.ui
+++ b/timeseriesviewer/ui/timeseriesdock.ui
@@ -234,7 +234,7 @@
          </widget>
         </item>
         <item>
-         <widget class="QTableView" name="tableView_TimeSeries">
+         <widget class="TimeSeriesTableView" name="tableView_TimeSeries">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
             <horstretch>1</horstretch>
@@ -358,6 +358,13 @@
    </layout>
   </widget>
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>TimeSeriesTableView</class>
+   <extends>QTableView</extends>
+   <header>timeseriesviewer.timeseries</header>
+  </customwidget>
+ </customwidgets>
  <resources>
   <include location="resources.qrc"/>
  </resources>
diff --git a/timeseriesviewer/viewmodels.py b/timeseriesviewer/viewmodels.py
index b516fc4146d524f2a10dd16234dea7db8f3aff7b..9ec7bcb4815aaad5b2307527fbdffbc58878f5d6 100644
--- a/timeseriesviewer/viewmodels.py
+++ b/timeseriesviewer/viewmodels.py
@@ -11,175 +11,6 @@ from timeseriesviewer.timeseries import TimeSeries, TimeSeriesDatum, SensorInstr
 
 
 
-class TimeSeriesTableModel(QAbstractTableModel):
-    columnames = ['date', 'sensor', 'ns', 'nl', 'nb', 'image']
-
-    def __init__(self, TS, parent=None, *args):
-
-        super(TimeSeriesTableModel, self).__init__()
-        assert isinstance(TS, TimeSeries)
-        self.TS = TS
-        self.sensors = set()
-        self.TS.sigTimeSeriesDatesRemoved.connect(self.removeTSDs)
-        self.TS.sigTimeSeriesDatesAdded.connect(self.addTSDs)
-
-        self.items = []
-        self.sortColumnIndex = 0
-        self.sortOrder = Qt.AscendingOrder
-        self.addTSDs([tsd for tsd in self.TS])
-
-    def removeTSDs(self, tsds):
-        #self.TS.removeDates(tsds)
-        for tsd in tsds:
-            if tsd in self.TS:
-                #remove from TimeSeries first.
-                self.TS.removeDates([tsd])
-            elif tsd in self.items:
-                idx = self.getIndexFromDate(tsd)
-                self.removeRows(idx.row(), 1)
-
-        #self.sort(self.sortColumnIndex, self.sortOrder)
-
-
-    def tsdChanged(self, tsd):
-        idx = self.getIndexFromDate(tsd)
-        self.dataChanged.emit(idx, idx)
-
-    def addTSDs(self, tsds):
-        self.items.extend(tsds)
-        self.sort(self.sortColumnIndex, self.sortOrder)
-
-        for tsd in tsds:
-            assert isinstance(tsd, TimeSeriesDatum)
-            tsd.sigVisibilityChanged.connect(lambda: self.tsdChanged(tsd))
-
-        for sensor in set([tsd.sensor for tsd in tsds]):
-            if sensor not in self.sensors:
-                self.sensors.add(sensor)
-                sensor.sigNameChanged.connect(lambda: self.reset())
-
-
-
-    def sort(self, col, order):
-        if self.rowCount() == 0:
-            return
-
-        self.layoutAboutToBeChanged.emit()
-        colName = self.columnames[col]
-        r = order != Qt.AscendingOrder
-
-        if colName in ['date','ns','nl','sensor']:
-            self.items.sort(key = lambda d:d.__dict__[colName], reverse=r)
-
-        self.layoutChanged.emit()
-        s = ""
-
-
-    def rowCount(self, parent = QModelIndex()):
-        return len(self.items)
-
-
-    def removeRows(self, row, count , parent=QModelIndex()):
-        self.beginRemoveRows(parent, row, row+count-1)
-        toRemove = self.items[row:row+count]
-        for tsd in toRemove:
-            self.items.remove(tsd)
-        self.endRemoveRows()
-
-    def getIndexFromDate(self, tsd):
-        return self.createIndex(self.items.index(tsd),0)
-
-    def getDateFromIndex(self, index):
-        if index.isValid():
-            return self.items[index.row()]
-        return None
-
-    def getTimeSeriesDatumFromIndex(self, index):
-        if index.isValid():
-            i = index.row()
-            if i >= 0 and i < len(self.items):
-                return self.items[i]
-
-        return None
-
-    def columnCount(self, parent = QModelIndex()):
-        return len(self.columnames)
-
-    def data(self, index, role = Qt.DisplayRole):
-        if role is None or not index.isValid():
-            return None
-
-        value = None
-        columnName = self.columnames[index.column()]
-
-        TSD = self.getTimeSeriesDatumFromIndex(index)
-        keys = list(TSD.__dict__.keys())
-
-
-        if role == Qt.DisplayRole or role == Qt.ToolTipRole:
-            if columnName == 'name':
-                value = os.path.basename(TSD.pathImg)
-            elif columnName == 'sensor':
-                if role == Qt.ToolTipRole:
-                    value = TSD.sensor.getDescription()
-                else:
-                    value = TSD.sensor.name()
-            elif columnName == 'date':
-                value = '{}'.format(TSD.date)
-            elif columnName == 'image':
-                value = TSD.pathImg
-            elif columnName in keys:
-                value = TSD.__dict__[columnName]
-            else:
-                s = ""
-        elif role == Qt.CheckStateRole:
-            if columnName == 'date':
-                value = Qt.Checked if TSD.isVisible() else Qt.Unchecked
-        elif role == Qt.BackgroundColorRole:
-            value = None
-        elif role == Qt.UserRole:
-            value = TSD
-
-        return value
-
-    def setData(self, index, value, role=None):
-        if role is None or not index.isValid():
-            return None
-
-        if role is Qt.UserRole:
-
-            s = ""
-
-        columnName = self.columnames[index.column()]
-
-        TSD = self.getTimeSeriesDatumFromIndex(index)
-        if columnName == 'date' and role == Qt.CheckStateRole:
-            TSD.setVisibility(value != Qt.Unchecked)
-            return True
-        else:
-            return False
-
-        return False
-
-    def flags(self, index):
-        if index.isValid():
-            columnName = self.columnames[index.column()]
-            flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
-            if columnName == 'date': #allow check state
-                flags = flags | Qt.ItemIsUserCheckable
-
-            return flags
-            #return item.qt_flags(index.column())
-        return None
-
-    def headerData(self, col, orientation, role):
-        if Qt is None:
-            return None
-        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
-            return self.columnames[col]
-        elif orientation == Qt.Vertical and role == Qt.DisplayRole:
-            return col
-        return None
 
 
 if __name__ == '__main__':