Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6f97e50
Implement cross-platform application state with QSettings.
bradyzp Aug 7, 2018
b01d5e8
Rename splash.py, enhance project loading function.
bradyzp Aug 8, 2018
855b5a2
Refactor application settings module, add splash screen.
bradyzp Aug 8, 2018
e03b574
Enhance MainWindow loading logic, support for recent projects.
bradyzp Aug 8, 2018
6acd186
Add new Icon resources, cleanup old resources.
bradyzp Aug 14, 2018
60c0554
Refactor Icon usage/creation with Enum.icon() method
bradyzp Aug 14, 2018
bc115c2
Rewrite channel control widget
bradyzp Aug 16, 2018
7dc2f94
Merge branch 'feature/app-settings' into feature/ui-improvements
bradyzp Aug 16, 2018
d192d8d
Rewrite workspace tab logic
bradyzp Aug 16, 2018
3c56fa3
Add documentation launcher and 'About' dialog.
bradyzp Aug 16, 2018
6961779
Add sensor linkage to data-set controllers.
bradyzp Aug 17, 2018
f3ee074
Implement basic state restoration for segment selection tab.
bradyzp Aug 21, 2018
c0a33a8
Refactor workspace tab bases. Add tab persistent state handling
bradyzp Aug 21, 2018
ca3ae11
Refactor ChannelController, thread loading of dataset tab.
bradyzp Aug 21, 2018
140de7e
Add segment visibility toggle to LineSelectPlot
bradyzp Aug 21, 2018
725cd82
Cleanup: Remove unused code, add docstrings, cleanup imports
bradyzp Aug 24, 2018
c99d18c
Fix error updating binary channel state when plot clear triggered.
bradyzp Aug 24, 2018
8a4e600
Fix splash screen visibility when loading.
bradyzp Aug 26, 2018
8550d7d
Fix attribute error in datafile controller. Fix invalid Path construc…
bradyzp Aug 26, 2018
6d0853e
Fix project dock visibility when main window is minimized/restored.
bradyzp Aug 26, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions dgp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
__version__ = "0.1.0"

__about__ = f"""
DGP version {__version__}

DGP (Dynamic Gravity Processor) is an open source project licensed under the Apache v2 license.

The source for DGP is available at https://github.com/DynamicGravitySystems/DGP

DGP is written in Python, utilizing the Qt framework with the PyQt5 Python bindings.

"""
28 changes: 18 additions & 10 deletions dgp/__main__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# coding: utf-8

import os
# -*- coding: utf-8 -*-
import sys
import time
import traceback

sys.path.append(os.path.dirname(__file__))

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication
from dgp.gui.splash import SplashScreen
from PyQt5.QtWidgets import QApplication, QSplashScreen

from dgp.gui.main import MainWindow


def excepthook(type_, value, traceback_):
def excepthook(type_, value, traceback_): # pragma: no cover
"""This allows IDE to properly display unhandled exceptions which are
otherwise silently ignored as the application is terminated.
Override default excepthook with
Expand All @@ -24,13 +24,21 @@ def excepthook(type_, value, traceback_):


app = None
_align = Qt.AlignBottom | Qt.AlignHCenter


def main():
def main(): # pragma: no cover
global app
sys.excepthook = excepthook
app = QApplication(sys.argv)
form = SplashScreen()
splash = QSplashScreen(QPixmap(":/icons/dgp_large"))
splash.showMessage("Loading Dynamic Gravity Processor", _align)
splash.show()
time.sleep(.5)
window = MainWindow()
splash.finish(window)
window.sigStatusMessage.connect(lambda msg: splash.showMessage(msg, _align))
window.load()
sys.exit(app.exec_())


Expand Down
7 changes: 3 additions & 4 deletions dgp/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-

__all__ = ['OID', 'Reference', 'StateAction']

from .oid import OID
from .types.reference import Reference
from .types.enumerations import *
from .types.enumerations import DataType, StateAction, Icon

__all__ = ['OID', 'Reference', 'DataType', 'StateAction', 'Icon']
11 changes: 7 additions & 4 deletions dgp/core/controllers/datafile_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ def __init__(self, datafile: DataFile, dataset=None):

self._bindings = [
('addAction', ('Properties', self._properties_dlg)),
('addAction', (QIcon(Icon.OPEN_FOLDER.value), 'Show in Explorer',
('addAction', (Icon.OPEN_FOLDER.icon(), 'Show in Explorer',
self._launch_explorer))
]

@property
def uid(self) -> OID:
return self._datafile.uid
try:
return self._datafile.uid
except AttributeError:
return None

@property
def dataset(self) -> IDataSetController:
Expand Down Expand Up @@ -58,9 +61,9 @@ def set_datafile(self, datafile: DataFile):
self.setToolTip("Source path: {!s}".format(datafile.source_path))
self.setData(datafile, role=Qt.UserRole)
if self._datafile.group is DataType.GRAVITY:
self.setIcon(QIcon(Icon.GRAVITY.value))
self.setIcon(Icon.GRAVITY.icon())
elif self._datafile.group is DataType.TRAJECTORY:
self.setIcon(QIcon(Icon.TRAJECTORY.value))
self.setIcon(Icon.TRAJECTORY.icon())

def _properties_dlg(self):
if self._datafile is None:
Expand Down
62 changes: 45 additions & 17 deletions dgp/core/controllers/dataset_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@
from pathlib import Path
from typing import List, Union, Generator, Set

from PyQt5.QtWidgets import QInputDialog
from pandas import DataFrame, Timestamp, concat
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor, QBrush, QIcon, QStandardItemModel, QStandardItem
from PyQt5.QtGui import QColor, QBrush, QStandardItemModel, QStandardItem

from dgp.core.oid import OID
from dgp.core.types.enumerations import Icon
from dgp.core import OID, Icon
from dgp.core.hdf5_manager import HDF5Manager
from dgp.core.controllers import controller_helpers
from dgp.core.models.datafile import DataFile
from dgp.core.models.dataset import DataSet, DataSegment
from dgp.core.types.enumerations import DataType, StateColor
from dgp.gui.plotting.helpers import LinearSegmentGroup
from dgp.lib.etc import align_frames

from .controller_interfaces import IFlightController, IDataSetController, IBaseController
from . import controller_helpers
from .gravimeter_controller import GravimeterController
from .controller_interfaces import (IFlightController, IDataSetController,
IBaseController, IAirborneController)
from .project_containers import ProjectFolder
from .datafile_controller import DataFileController

Expand Down Expand Up @@ -83,20 +85,19 @@ def __init__(self, dataset: DataSet, flight: IFlightController):
super().__init__()
self._dataset = dataset
self._flight: IFlightController = flight
self._project = self._flight.project
self._active = False
self.log = logging.getLogger(__name__)

self.setEditable(False)
self.setText(self._dataset.name)
self.setIcon(QIcon(Icon.OPEN_FOLDER.value))
self.setIcon(Icon.PLOT_LINE.icon())
self.setBackground(QBrush(QColor(StateColor.INACTIVE.value)))
self._grav_file = DataFileController(self._dataset.gravity, self)
self._traj_file = DataFileController(self._dataset.trajectory, self)
self._child_map = {DataType.GRAVITY: self._grav_file,
DataType.TRAJECTORY: self._traj_file}

self._segments = ProjectFolder("Segments")
self._segments = ProjectFolder("Segments", Icon.LINE_MODE.icon())
for segment in dataset.segments:
seg_ctrl = DataSegmentController(segment, parent=self)
self._segments.appendRow(seg_ctrl)
Expand All @@ -105,6 +106,13 @@ def __init__(self, dataset: DataSet, flight: IFlightController):
self.appendRow(self._traj_file)
self.appendRow(self._segments)

self._sensor = None
if dataset.sensor is not None:
ctrl = self.project.get_child(dataset.sensor.uid)
if ctrl is not None:
self._sensor = ctrl.clone()
self.appendRow(self._sensor)

self._gravity: DataFrame = DataFrame()
self._trajectory: DataFrame = DataFrame()
self._dataframe: DataFrame = DataFrame()
Expand All @@ -114,13 +122,13 @@ def __init__(self, dataset: DataSet, flight: IFlightController):
self._menu_bindings = [ # pragma: no cover
('addAction', ('Set Name', self._set_name)),
('addAction', ('Set Active', lambda: self.get_parent().activate_child(self.uid))),
('addAction', (QIcon(Icon.METER.value), 'Set Sensor',
self._set_sensor_dlg)),
('addAction', (Icon.METER.icon(), 'Set Sensor',
self._action_set_sensor_dlg)),
('addSeparator', ()),
('addAction', (QIcon(Icon.GRAVITY.value), 'Import Gravity',
lambda: self._project.load_file_dlg(DataType.GRAVITY, dataset=self))),
('addAction', (QIcon(Icon.TRAJECTORY.value), 'Import Trajectory',
lambda: self._project.load_file_dlg(DataType.TRAJECTORY, dataset=self))),
('addAction', (Icon.GRAVITY.icon(), 'Import Gravity',
lambda: self.project.load_file_dlg(DataType.GRAVITY, dataset=self))),
('addAction', (Icon.TRAJECTORY.icon(), 'Import Trajectory',
lambda: self.project.load_file_dlg(DataType.TRAJECTORY, dataset=self))),
('addAction', ('Align Data', self.align)),
('addSeparator', ()),
('addAction', ('Delete', lambda: self.get_parent().remove_child(self.uid))),
Expand All @@ -134,6 +142,10 @@ def clone(self):
def uid(self) -> OID:
return self._dataset.uid

@property
def project(self) -> IAirborneController:
return self._flight.get_parent()

@property
def hdfpath(self) -> Path:
return self._flight.get_parent().hdfpath
Expand Down Expand Up @@ -307,6 +319,22 @@ def _set_name(self):
if name:
self.set_attr('name', name)

def _set_sensor_dlg(self):
# TODO: Dialog to enable selection of sensor assoc with the dataset
pass
def _action_set_sensor_dlg(self):
sensors = {}
for i in range(self.project.meter_model.rowCount()):
sensor = self.project.meter_model.item(i)
sensors[sensor.text()] = sensor

item, ok = QInputDialog.getItem(self.parent_widget, "Select Gravimeter",
"Sensor", sensors.keys(), editable=False)
if ok:
if self._sensor is not None:
self.removeRow(self._sensor.row())

sensor: GravimeterController = sensors[item]
self.set_attr('sensor', sensor)
self._sensor: GravimeterController = sensor.clone()
self.appendRow(self._sensor)

def _action_delete(self, confirm: bool = True):
self.get_parent().remove_child(self.uid, confirm)
5 changes: 3 additions & 2 deletions dgp/core/controllers/flight_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
import logging
from _weakrefset import WeakSet
from weakref import WeakSet
from typing import Union

from PyQt5.QtCore import Qt
Expand All @@ -12,7 +12,7 @@
from dgp.core.controllers.controller_interfaces import IAirborneController, IFlightController
from dgp.core.models.dataset import DataSet
from dgp.core.models.flight import Flight
from dgp.core.types.enumerations import DataType, StateColor
from dgp.core.types.enumerations import DataType, StateColor, Icon
from dgp.gui.dialogs.add_flight_dialog import AddFlightDialog


Expand Down Expand Up @@ -54,6 +54,7 @@ def __init__(self, flight: Flight, project: IAirborneController):
self._parent = project
self._active: bool = False
self.setData(flight, Qt.UserRole)
self.setIcon(Icon.AIRBORNE.icon())
self.setEditable(False)
self.setBackground(QColor(StateColor.INACTIVE.value))

Expand Down
2 changes: 2 additions & 0 deletions dgp/core/controllers/gravimeter_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from PyQt5.QtCore import Qt

from dgp.core import Icon
from dgp.core.oid import OID
from dgp.core.controllers.controller_interfaces import IAirborneController, IMeterController
from dgp.core.controllers.controller_helpers import get_input
Expand All @@ -13,6 +14,7 @@ def __init__(self, meter: Gravimeter, parent: IAirborneController = None):
super().__init__(meter.name)
self.setEditable(False)
self.setData(meter, role=Qt.UserRole)
self.setIcon(Icon.METER.icon())

self._meter = meter # type: Gravimeter
self._parent = parent
Expand Down
11 changes: 6 additions & 5 deletions dgp/core/controllers/project_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

from PyQt5.QtGui import QStandardItem, QStandardItemModel, QIcon

from dgp.core import Icon


class ProjectFolder(QStandardItem):
"""Displayable StandardItem used for grouping sub-elements.
Expand All @@ -17,14 +19,13 @@ class ProjectFolder(QStandardItem):
-----
Overriding object methods like __getitem__ __iter__ etc seems to break
"""
inherit_context = False

def __init__(self, label: str, icon: str=None, inherit=False, **kwargs):
def __init__(self, label: str, icon: QIcon = None, **kwargs):
super().__init__(label)
if icon is not None:
self.setIcon(QIcon(icon))
if icon is None:
icon = Icon.OPEN_FOLDER.icon()
self.setIcon(icon)
self._model = QStandardItemModel()
self.inherit_context = inherit
self.setEditable(False)
self._attributes = kwargs

Expand Down
22 changes: 13 additions & 9 deletions dgp/core/controllers/project_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Union, List, Generator, cast

from PyQt5.QtCore import Qt, QRegExp
from PyQt5.QtGui import QColor, QStandardItemModel, QIcon, QRegExpValidator
from PyQt5.QtGui import QColor, QStandardItemModel, QRegExpValidator
from pandas import DataFrame

from .project_treemodel import ProjectTreeModel
Expand Down Expand Up @@ -54,27 +54,29 @@ def __init__(self, project: AirborneProject, path: Path = None):
self._parent = None
self._active = None

self.setIcon(QIcon(Icon.DGS.value))
self.setIcon(Icon.DGP_NOTEXT.icon())
self.setToolTip(str(self._project.path.resolve()))
self.setData(project, Qt.UserRole)
self.setBackground(QColor(StateColor.INACTIVE.value))

self.flights = ProjectFolder("Flights", Icon.AIRBORNE.value)
self.flights = ProjectFolder("Flights")
self.appendRow(self.flights)
self.meters = ProjectFolder("Gravimeters", Icon.METER.value)
self.meters = ProjectFolder("Gravimeters")
self.appendRow(self.meters)

self._child_map = {Flight: self.flights,
Gravimeter: self.meters}

for flight in self.project.flights:
controller = FlightController(flight, project=self)
self.flights.appendRow(controller)

# It is important that GravimeterControllers are defined before Flights
# Flights may create references to a Gravimeter object, but not vice versa
for meter in self.project.gravimeters:
controller = GravimeterController(meter, parent=self)
self.meters.appendRow(controller)

for flight in self.project.flights:
controller = FlightController(flight, project=self)
self.flights.appendRow(controller)

self._bindings = [
('addAction', ('Set Project Name', self.set_name)),
('addAction', ('Show in Explorer',
Expand Down Expand Up @@ -291,7 +293,9 @@ def _on_load(datafile: DataFile, params: dict, parent: IDataSetController):
else:
self.log.error("Unrecognized data group: " + datafile.group)
return
progress_event = ProgressEvent(self.uid, f"Loading {datafile.group.value}", stop=0)
progress_event = ProgressEvent(self.uid, f"Loading "
f"{datafile.group.value}",
stop=0)
self.get_parent().progressNotificationRequested.emit(progress_event)
loader = FileLoader(datafile.source_path, method,
parent=self.parent_widget, **params)
Expand Down
Loading