Example #1
0
    def __init__(self):
        super().__init__()
        self.gateway = QGateWay(self)
        self.tree = QTreeView(self)
        self.tree.setHeaderHidden(True)
        # self.tree.setSelectionMode(QTreeView.MultiSelection)
        self.model = OMEROTreeModel(self.gateway, self)
        self.thumb_grid = ThumbGrid(self.gateway, self)
        self.thumb_grid.hide()
        self.login = LoginForm(self.gateway, self)
        self.login.setWindowFlags(self.login.windowFlags() & ~Qt.Dialog)

        self.tree.setModel(self.model)
        self.tree.selectionModel().selectionChanged.connect(
            self._on_tree_selection)
        self.thumb_grid.itemSelectionChanged.connect(
            self._on_thumbnail_selected)
        layout = QVBoxLayout(self)
        self.splitter = QSplitter(Qt.Vertical, self)
        self.status = QLabel(self)
        self.status.hide()
        self.status.setAlignment(Qt.AlignCenter)
        self.status.setStyleSheet("QLabel{color: #AAA;}")
        layout.addWidget(self.status)
        layout.addWidget(self.splitter)
        self.splitter.addWidget(self.login)
        self.splitter.addWidget(self.tree)
        self.splitter.addWidget(self.thumb_grid)
        self.gateway.connected.connect(self._show_connection_label)
Example #2
0
 def mousePressEvent(self, event):
     """called when you click a result"""
     QTreeView.mousePressEvent(self, event)
     if event.button() == Qt.LeftButton:
         self.on_left_mouse_button()
     elif event.button() == Qt.RightButton:
         self.on_right_mouse_button()
Example #3
0
    def __init__(self, parent=None) -> None:
        super(ProgressView, self).__init__(parent)

        self._progress_tree_view = QTreeView(self)
        self._progress_tree_view.setHeaderHidden(True)
        self._progress_tree_view.setItemsExpandable(False)
        self._progress_tree_view.setItemDelegate(ProgressDelegate(self))
        self._progress_tree_view.setRootIsDecorated(False)
        self._progress_tree_view.setFixedHeight(30)
        self._progress_tree_view.setVerticalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)

        self._progress_bar = QProgressBar(self)
        self._progress_bar.setRange(0, 0)
        self._progress_bar.setFixedHeight(30)
        self._progress_bar.setVisible(False)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self._progress_tree_view)
        layout.addWidget(self._progress_bar)

        self.setLayout(layout)

        self.setFixedHeight(30)
Example #4
0
    def __init__(self,
                 parent,
                 init_channel=None,
                 config_name=None,
                 edit_mode=False):
        super(PyDMAlarmTree, self).__init__()

        QTreeView.__init__(self, parent)
        PyDMWritableWidget.__init__(self)

        self.setup_ui()

        self._nodes = []

        self.config_name = config_name

        self.tree_model = AlarmTreeModel(self)
        self.setModel(self.tree_model)
        self.edit_mode = edit_mode

        self.setContextMenuPolicy(Qt.CustomContextMenu)

        if not edit_mode:
            self.customContextMenuRequested.connect(self._open_menu)

        self.expandAll()
Example #5
0
    def mousePressEvent(self, position):
        QTreeView.mousePressEvent(self, position)
        indexes = self.selectedIndexes()

        # trace the tree to find the selected item
        rows = []
        for index in indexes:
            row = index.row()
            rows.append(row)
            level = 0
            while index.parent().isValid():
                index = index.parent()
                row = index.row()
                rows.append(row)
                level += 1
        rows.reverse()

        # TODO: what is this for???
        if rows != self.old_rows:
            self.old_rows = rows
        valid, keys = self.get_row()
        if not valid:
            print('invalid=%s keys=%s' % (valid, keys))
        else:
            print('valid=%s keys=%s' % (valid, keys))
Example #6
0
 def __init__(self, parent, data, choices):
     self.parent = parent
     self.old_rows = []
     self.data = data
     self.cases_deleted = set([])
     self.choices = choices
     self.single = False
     QTreeView.__init__(self)
Example #7
0
 def __init__(self, dataframe_format=None, readonly=False):
     QTreeView.__init__(self)
     self.readonly = readonly
     self.dataframe_format = dataframe_format
     from spyder.plugins.variableexplorer.widgets.collectionsdelegate \
         import ToggleColumnDelegate
     self.setItemDelegate(ToggleColumnDelegate(self))
     self.setEditTriggers(QAbstractItemView.DoubleClicked)
Example #8
0
 def __init__(self, readonly=False):
     QTreeView.__init__(self)
     self.readonly = readonly
     from spyder.plugins.variableexplorer.widgets.collectionsdelegate \
         import ToggleColumnDelegate
     self.setItemDelegate(ToggleColumnDelegate(self))
     self.setEditTriggers(QAbstractItemView.DoubleClicked)
     self.expanded.connect(self.resize_columns_to_contents)
     self.collapsed.connect(self.resize_columns_to_contents)
Example #9
0
 def keyPressEvent(self, event): #Reimplement the event here, in your case, do nothing
     #if event.key() == QtCore.Qt.Key_Escape:
         #self.close()
     #return
     key = event.key()
     if key == Qt.Key_Delete:
         self.on_delete()
     else:
         QTreeView.keyPressEvent(self, event)
Example #10
0
    def reset(self):
        """
        Reset internal state of the view and read all data afresh from model.

        This function is called whenever the model data changes drastically.
        """
        QTreeView.reset(self)
        self.resizeColumns()
        self.spanFirstColumn(0, self.model().rowCount() - 1)
 def __init__(self, parent=None):
     QTreeView.__init__(self, parent)
     self._parent = parent
     # self.formulaPane = parent.formulaPane
     self.setRootIsDecorated(False)
     self.setAlternatingRowColors(False)
     # self.doubleClicked.connect(self.openEditor)
     self.setItemDelegate(MxPropertyItemDelegate(self))
     self.setContentsMargins(0, 0, 0, 0)
Example #12
0
 def dataChanged(self, topLeft, bottomRight, roles=[]):
     """Called when data in model has changed."""
     if PYQT4:
         QTreeView.dataChanged(self, topLeft, bottomRight)
     else:
         QTreeView.dataChanged(self, topLeft, bottomRight, roles)
     self.resizeColumns()
     while topLeft.parent().isValid():
         topLeft = topLeft.parent()
     while bottomRight.parent().isValid():
         bottomRight = bottomRight.parent()
     self.spanFirstColumn(topLeft.row(), bottomRight.row())
Example #13
0
 def __init__(self, parent=None):
     """Constructor."""
     QTreeView.__init__(self, parent)
     self.header().setDefaultAlignment(Qt.AlignCenter)
     self.setItemsExpandable(True)
     self.setSortingEnabled(True)
     self.header().setSortIndicatorShown(False)
     self.header().sortIndicatorChanged.connect(self.sortByColumn)
     self.header().sortIndicatorChanged.connect(
             lambda col, order: self.header().setSortIndicatorShown(True))
     self.setExpandsOnDoubleClick(False)
     self.doubleClicked.connect(self.go_to_test_definition)
Example #14
0
 def diagTableKeyPressEvent(self, event):
     kmod = event.modifiers()
     kval = event.key()
     if kval == Qt.Key_Space:
         itlist = self.diagTable.selectedItems()
         it = itlist[0]
         itxt = it.text(0)
         if itxt[0] != '/':
             itxt = it.parent().text(0)
         self._parent.treeview.selectByPath(itxt)
     else:
         QTreeView.keyPressEvent(self.diagTable, event)
Example #15
0
 def keyPressEvent(self, event):
     """Reimplement Qt method"""
     if event.key() in (Qt.Key_Enter, Qt.Key_Return):
         self.clicked()
     elif event.key() == Qt.Key_F2:
         self.rename()
     elif event.key() == Qt.Key_Delete:
         self.delete()
     elif event.key() == Qt.Key_Backspace:
         self.go_to_parent_directory()
     else:
         QTreeView.keyPressEvent(self, event)
Example #16
0
    def __init__(self, parent, model):
        QTreeView.__init__(self, parent)
        self.setModel(model)
        self.setAlternatingRowColors(True)
        self.doubleClicked.connect(self.doubleClicked_callback)

        # Context menu
        self.contextMenu = QMenu(self)

        self.action_show_value = self.contextMenu.addAction(
            "Show Value"
        )
Example #17
0
 def keyPressEvent(self, event):
     """Reimplement Qt method"""
     if event.key() in (Qt.Key_Enter, Qt.Key_Return):
         self.clicked()
     elif event.key() == Qt.Key_F2:
         self.rename()
     elif event.key() == Qt.Key_Delete:
         self.delete()
     elif event.key() == Qt.Key_Backspace:
         self.go_to_parent_directory()
     else:
         QTreeView.keyPressEvent(self, event)
Example #18
0
class CorrelationWidget(QWidget):
    """
    Widget for viewing the correlation results.

    This could be generalized into a ComboPlotView / PlotView / ComboView ...
    """
    def __init__(self, model):
        super(CorrelationWidget, self).__init__()
        self.model = model  # type: QStandardItemModel
        self.resultsList = QTreeView(self)
        self.resultsList.setHeaderHidden(True)
        self.resultsList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.resultsList.setSelectionMode(QAbstractItemView.NoSelection)
        self.plotOpts = dict()
        self._plot = pg.PlotWidget(**self.plotOpts)
        self._legend = pg.LegendItem(offset=[-1, 1])
        self.legend.setParentItem(self._plot.getPlotItem())
        self.resultsList.setModel(self.model)
        self.selectionModel = self.resultsList.selectionModel()

        layout = QVBoxLayout()
        layout.addWidget(self.resultsList)
        layout.addWidget(self._plot)
        self.setLayout(layout)

        self.checkedItemIndexes = []
        self._curveItems = []
        # self.model.itemChanged.connect(self.updatePlot)

    def clear(self):
        raise NotImplementedError

    @property
    def plot(self):
        return self._plot

    @property
    def legend(self):
        return self._legend

    def _clearLegend(self):
        for curveItem in self._curveItems:
            self.legend.removeItem(name=curveItem.name)
        self.legend.hide()

    def results(self, dataKey):
        for index in self.checkedItemIndexes:
            yield index.data(Qt.UserRole)['data'].get(dataKey, np.array([]))

    def parentItemSet(self):
        parents = set()
        for index in self.checkedItemIndexes:
            parents.add(QPersistentModelIndex(index.parent()))
        return parents

    def updatePlot(self, item: QStandardItem):
        raise NotImplementedError
Example #19
0
    def __init__(self, parent=None):
        QTreeView.__init__(self, parent)

        self.__root = TreeItem("ERT")

        self.__tree_model = TreeModel(self.__root)

        self.setModel(self.__tree_model)

        #: :type: dict of (str, TreeItem)
        self.__groups = {}

        self.header().hide()
Example #20
0
def get_modeltree(model=None):
    """Alias to :func:`get_tree`."""
    if model is None:
        model = mx.cur_model()
    treemodel = ModelTreeModel(model._baseattrs)
    view = QTreeView()
    view.setModel(treemodel)
    view.setWindowTitle("Model %s" % model.name)
    view.setAlternatingRowColors(True)
    return view
Example #21
0
 def keyPressEvent(self, event):
     """
     Handles:
      - delete: delete result cases
      - enter/return: apply result
      - up/down/left/right: navigate the tree
     """
     #if event.key() == QtCore.Qt.Key_Escape:
     #self.close()
     #return
     key = event.key()
     if key == Qt.Key_Delete:
         self.on_delete()
     elif key in [Qt.Key_Enter, Qt.Key_Return]:
         return self.parent.parent.on_apply(event)
     elif key in [Qt.Key_Up, Qt.Key_Down]:
         QTreeView.keyPressEvent(self, event)
         self.set_rows()
     else:
         QTreeView.keyPressEvent(self, event)
Example #22
0
    def __init__(self, model):
        super(CorrelationWidget, self).__init__()
        self.model = model  # type: QStandardItemModel
        self.resultsList = QTreeView(self)
        self.resultsList.setHeaderHidden(True)
        self.resultsList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.resultsList.setSelectionMode(QAbstractItemView.NoSelection)
        self.plotOpts = dict()
        self._plot = pg.PlotWidget(**self.plotOpts)
        self._legend = pg.LegendItem(offset=[-1, 1])
        self.legend.setParentItem(self._plot.getPlotItem())
        self.resultsList.setModel(self.model)
        self.selectionModel = self.resultsList.selectionModel()

        layout = QVBoxLayout()
        layout.addWidget(self.resultsList)
        layout.addWidget(self._plot)
        self.setLayout(layout)

        self.checkedItemIndexes = []
        self._curveItems = []
Example #23
0
    def __init__(self, parent=None, channels=list(), label2width=dict(),
                 is_status=False):
        # QTableView.__init__(self, parent)
        QTreeView.__init__(self, parent)
        PyDMWidget.__init__(self)

        # setup table
        self._is_status = is_status
        self._date_fmt = ' %Y/%m/%d '
        self._time_fmt = ' %H:%M:%S '
        self.headerLabels = label2width.keys()
        self._model = QStandardItemModel()
        self._model.setHorizontalHeaderLabels(self.headerLabels)
        self.setModel(self._model)
        self.setUniformRowHeights(True)
        self.setHeader(QHeaderView(Qt.Horizontal))
        for idx, width in enumerate(label2width.values()):
            self.header().resizeSection(idx, width)
        self.header().resizeSections(QHeaderView.Fixed)
        self.header().setStretchLastSection(True)
        self.setSortingEnabled(True)
        self.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.setItemDelegateForColumn(2, LogItemDelegate(self))
        self.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.setSelectionMode(QAbstractItemView.SingleSelection)
        self.setStyleSheet("gridline-color: #ffffff;")

        # set channels
        self.address2conn = dict()
        self.address2channels = dict()
        for address in channels:
            self.address2conn[address] = False
            channel = SiriusConnectionSignal(
                address=address,
                connection_slot=self.connection_changed,
                value_slot=self.value_changed,
                severity_slot=self.alarm_severity_changed)
            channel.connect()
            self.address2channels[address] = channel
            self._channels.append(channel)
Example #24
0
    def __init__(self,
                 name=None,
                 plugin=None,
                 parent=None,
                 options=DEFAULT_OPTIONS):
        super().__init__(name, plugin, parent=parent, options=options)

        # Widgets
        self.tree = QTreeView()
        self.tree.setHeaderHidden(True)
        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.context_menu_manager)

        # TODO: simplify the navigator to get ride of 'workspace_path'
        self.project_info = ProjectNavigation('', self)

        self.toolbar = ToolBar(self.project_info, self, "ATE Plugin toolbar")

        # Layout
        layout = QVBoxLayout()
        layout.addWidget(self.tree)
        self.setLayout(layout)
Example #25
0
def get_tree(model=None):
    """Get QTreeView object containing the model tree.

    Args:
        model: :class:`Model <modelx.core.model.Model>` object.
            Defaults to the current model.
    """
    if model is None:
        model = mx.cur_model()
    treemodel = ModelTreeModel(model._baseattrs)
    view = QTreeView()
    view.setModel(treemodel)
    view.setWindowTitle("Model %s" % model.name)
    view.setAlternatingRowColors(True)
    return view
Example #26
0
    def __init__(self, parent=None):
        """ Initialization
        :param parent: parent window
        :return:
        """
        QTreeView.__init__(self, parent)
        self._myParent = parent

        # Enabled to select multiple items with shift key
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.setHorizontalScrollBar(QScrollBar())
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        self.setContextMenuPolicy(Qt.ActionsContextMenu)

        # Data structure to control the items
        self._leafDict = dict()  # dictionary for the name each leaf and its child. key is string only!
        self._mainNodeDict = dict()  # dictionary for each main node
        self._myHeaderList = list()
        self._childrenInOrder = True

        return
Example #27
0
    def viewportEvent(self, event):
        """Reimplement Qt method"""
        # Prevent Qt from crashing or showing warnings like:
        # "QSortFilterProxyModel: index from wrong model passed to
        # mapFromSource", probably due to the fact that the file system model
        # is being built. See Issue 1250.
        #
        # This workaround was inspired by the following KDE bug:
        # https://bugs.kde.org/show_bug.cgi?id=172198
        #
        # Apparently, this is a bug from Qt itself.
        self.executeDelayedItemsLayout()

        return QTreeView.viewportEvent(self, event)
Example #28
0
    def viewportEvent(self, event):
        """Reimplement Qt method"""

        # Prevent Qt from crashing or showing warnings like:
        # "QSortFilterProxyModel: index from wrong model passed to 
        # mapFromSource", probably due to the fact that the file system model 
        # is being built. See Issue 1250.
        #
        # This workaround was inspired by the following KDE bug:
        # https://bugs.kde.org/show_bug.cgi?id=172198
        #
        # Apparently, this is a bug from Qt itself.
        self.executeDelayedItemsLayout()
        
        return QTreeView.viewportEvent(self, event)        
Example #29
0
    def __init__(self, parent=None):
        """ Initialization
        :param parent: parent window
        :return:
        """
        QTreeView.__init__(self, parent)
        self._myParent = parent

        # Enabled to select multiple items with shift key
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.setHorizontalScrollBar(QScrollBar())
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        self.setContextMenuPolicy(Qt.ActionsContextMenu)

        # Data structure to control the items
        self._leafDict = dict(
        )  # dictionary for the name each leaf and its child. key is string only!
        self._mainNodeDict = dict()  # dictionary for each main node
        self._myHeaderList = list()
        self._childrenInOrder = True

        return
Example #30
0
def create_file_system_tree_dock_widget(view_menu: QMenu) -> DockWidget:
    '''
    Create file system tree dock widget

    Parameters
    ----------
    view_menu : QMenu

    Returns
    -------
    value : DockWidget
    '''
    widget = QTreeView()
    widget.setFrameShape(QFrame.NoFrame)

    m = QFileSystemModel(widget)
    m.setRootPath(QDir.currentPath())
    widget.setModel(m)

    _State.file_system_count += 1
    dock_widget = DockWidget("Filesystem {}".format(_State.file_system_count))
    dock_widget.set_widget(widget)
    view_menu.addAction(dock_widget.toggle_view_action())
    return dock_widget
Example #31
0
 def mouseDoubleClickEvent(self, event):
     """Reimplement Qt method"""
     QTreeView.mouseDoubleClickEvent(self, event)
     self.clicked()
Example #32
0
class ATEWidget(PluginMainWidget):
    """
    ATE widget.
    """

    DEFAULT_OPTIONS = {}

    # --- Signals
    # ------------------------------------------------------------------------
    sig_edit_goto_requested = Signal(str, int, str)

    database_changed = Signal(int)
    toolbar_changed = Signal(str, str, str)
    active_project_changed = Signal()
    hardware_added = Signal(str)
    hardware_activated = Signal(str)
    hardware_removed = Signal(str)
    update_target = Signal()
    select_target = Signal(str)
    select_base = Signal(str)
    select_hardware = Signal(str)
    update_settings = Signal(str, str, str)
    test_target_deleted = Signal(str, str)

    def __init__(self,
                 name=None,
                 plugin=None,
                 parent=None,
                 options=DEFAULT_OPTIONS):
        super().__init__(name, plugin, parent=parent, options=options)

        # Widgets
        self.tree = QTreeView()
        self.tree.setHeaderHidden(True)
        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.context_menu_manager)

        # TODO: simplify the navigator to get ride of 'workspace_path'
        self.project_info = ProjectNavigation('', self)

        self.toolbar = ToolBar(self.project_info, self, "ATE Plugin toolbar")

        # Layout
        layout = QVBoxLayout()
        layout.addWidget(self.tree)
        self.setLayout(layout)

        # Signals

    # --- PluginMainWidget API
    # ------------------------------------------------------------------------
    def get_title(self):
        return _('ATE')

    def get_focus_widget(self):
        return self.tree

    def setup(self, options):
        return

    def on_option_update(self, option, value):
        pass

    def update_actions(self):
        pass

    # --- PluginMainWidget API
    # ------------------------------------------------------------------------
    def run_ate_project(self):
        """For now the run of an ATE project is not integrated in the global
        run button yet"""
        pass

    def context_menu_manager(self, point):
        # https://riverbankcomputing.com/pipermail/pyqt/2009-April/022668.html
        # https://doc.qt.io/qt-5/qtreewidget-members.html
        # https://www.qtcentre.org/threads/18929-QTreeWidgetItem-have-contextMenu
        # https://cdn.materialdesignicons.com/4.9.95/
        indexes = self.tree.selectedIndexes()
        if indexes is None:
            return

        model_index = self.tree.indexAt(point)
        item = self.model.itemFromIndex(model_index)
        if item is None:
            return

        item.exec_context_menu()

    def set_tree(self):
        from ATE.spyder.widgets.actions_on.model.TreeModel import TreeModel
        self.model = TreeModel(self.project_info, parent=self)
        self.model.edit_file.connect(self.edit_test)
        self.model.delete_file.connect(self.delete_test)
        self.tree.setModel(self.model)
        self.tree.doubleClicked.connect(self.item_double_clicked)

    def item_double_clicked(self, index):
        try:
            item = self.tree.selectedIndexes()[0]
        except Exception:
            return

        model_item = item.model().itemFromIndex(index)
        from ATE.spyder.widgets.actions_on.tests.TestItem import TestItemChild
        if isinstance(model_item, TestItemChild):
            self.edit_test(model_item.path)

    def edit_test(self, path):
        """This method is called from ATE, and calls Spyder to open the file
        given by path"""
        self.sig_edit_goto_requested.emit(path, 1, "")

    def create_project(self, project_path):
        print(
            f"main_widget : Creating ATE project '{os.path.basename(project_path)}'"
        )
        status, data = NewProjectDialog(self, os.path.basename(project_path))
        if status:  # OK button pressed
            self.project_info(project_path, data['quality'])
            self.set_tree()
            #self.toolbar(self.project_info)
        else:  # Cancel button pressed
            pass

    def open_project(self, project_path):
        print(
            f"main_widget : Opening ATE project '{os.path.basename(project_path)}'"
        )
        self.project_info(project_path, self)
        self.toolbar(self.project_info)
        self.set_tree()

    def close_project(self):
        print(
            f"main_widget : Closing ATE project '{os.path.basename(self.project_info.project_directory)}'"
        )

    def delete_test(self, path):
        selected_file = os.path.basename(path)
        index = self._get_tab_index(selected_file)
        if index == -1:
            return

        self.close_tab(index)
Example #33
0
    def initUI(self):
        def selection_changed():
            # Retrieve selected items
            # selecteditems = self.tracklist.selectedItems()
            selectedindexes = self.tracklist.selectedIndexes()

            # Adding the selected items to the processing list
            self.gpxselectedlist[:] = []
            self.gpxselectednamelist[:] = []
            self.selectedpalette[:] = []
            for i in selectedindexes:
                # print str(i.text())
                self.gpxselectedlist.append(self.gpxlist[i.row()])
                self.gpxselectednamelist.append(self.gpxnamelist[i.row()])
                self.selectedpalette.append(self.palette[i.row()])

        def ClearStats():
            """
            # Some other code that could be used in the future
            index = self.treemodel.indexFromItem(parent1)
            self.tree.expand(index)
            selmod = self.tree.selectionModel()
            index2 = self.treemodel.indexFromItem(child2)
            selmod.select(index2, QtCore.QItemSelectionModel.Select|QtCore.QItemSelectionModel.Rows)
            
            root = self.treemodel.invisibleRootItem()
            (item.parent() or root).removeChild(item)
            """
            # Returns a list of indexes. In our case, for each row there are 2 indexes, cos there are 2 columns.
            for index in self.tree.selectedIndexes():
                # Consider only the first columns
                if index.column() == 0:
                    # Need to check if it's a top item (i.e. track), otherwise if a subitem (i.e. distance or time) is selected, the result might be buggy
                    parent = index.parent()
                    parent_item = self.treemodel.itemFromIndex(parent)
                    if parent_item is None:
                        self.treemodel.removeRow(index.row())

        # Application Settings
        QtCore.QCoreApplication.setOrganizationName("Ste")
        QtCore.QCoreApplication.setOrganizationDomain(
            "https://github.com/stesalati/sport/")
        QtCore.QCoreApplication.setApplicationName("TrackAnalyser")

        # Config settings
        self.settings = QtCore.QSettings(self)

        # Proxy settings
        try:
            self.use_proxy = self.settings.value('use_proxy', bool)
            self.proxy_config = self.settings.value('proxy_config', str)
        except:
            self.use_proxy = bombo.USE_PROXY
            self.proxy_config = bombo.PROXY_DATA

        # Actions
        openfile = QAction(QtGui.QIcon("icons/openfile.png"), "Open .gpx",
                           self)
        openfile.setShortcut("Ctrl+O")
        openfile.setStatusTip("Open file")
        openfile.triggered.connect(self.selectFileToOpen)

        go = QAction(QtGui.QIcon("icons/go.png"), "Go!", self)
        go.setShortcut("Ctrl+R")
        go.setStatusTip("Run analysis")
        go.triggered.connect(self.Go)

        clearstats = QAction(QtGui.QIcon("icons/clear.png"), "Clear stats",
                             self)
        clearstats.setShortcut("Ctrl+C")
        clearstats.setStatusTip("Clear stats")
        clearstats.triggered.connect(ClearStats)

        sep1 = QAction(self)
        sep1.setSeparator(True)

        showpoint = QAction(QtGui.QIcon("icons/point.png"), "Show point", self)
        showpoint.setShortcut("Ctrl+P")
        showpoint.setStatusTip("Show point")
        showpoint.triggered.connect(self.PlotSpecificAreaDialog)

        sep2 = QAction(self)
        sep2.setSeparator(True)

        quitapp = QAction(QtGui.QIcon("icons/quit.png"), "Quit", self)
        quitapp.setShortcut("Ctrl+Q")
        quitapp.setStatusTip("Quit application")
        quitapp.triggered.connect(qApp.quit)

        configs = QAction(QtGui.QIcon("icons/configs.png"), "Configs", self)
        configs.setStatusTip("Configs")
        configs.triggered.connect(self.ProxyDialog)

        # Menubar
        mainMenu = self.menuBar()
        configMenu = mainMenu.addMenu('&Config')
        configMenu.addAction(configs)

        # Toolbar
        toolbar = self.addToolBar('My tools')
        toolbar.addAction(openfile)
        toolbar.addAction(go)
        toolbar.addAction(clearstats)
        toolbar.addAction(sep1)
        toolbar.addAction(showpoint)
        toolbar.addAction(sep2)
        toolbar.addAction(quitapp)
        toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
        toolbar.setIconSize(QtCore.QSize(30, 30))

        # Status bar
        self.statusBar().show()

        # Main widget (everything that's not toolbar, statusbar or menubar must be in this widget)
        self.scatola = QWidget()

        # Main horizontal impagination
        hBox = QHBoxLayout()
        hBox.setSpacing(5)

        # Vertical left column
        vBox_left = QVBoxLayout()
        vBox_left.setSpacing(5)

        # 1st vertical box, a list
        self.tracklist = QListWidget()
        vBox_left.addWidget(self.tracklist)
        self.tracklist.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.tracklist.itemSelectionChanged.connect(selection_changed)
        self.tracklist.setMaximumHeight(120)

        # 2nd vertical box, containing several horizontal boxes, one for each setting
        vBox2 = QVBoxLayout()
        vBox2.setSpacing(5)

        # Just the group label
        labelSettings = QLabel('Settings')
        vBox2.addWidget(labelSettings)

        # Use/don't use corrected altitude
        self.checkUseSRTM = QCheckBox(
            "Use SRTM corrected elevation (needs Internet)")
        self.checkUseSRTM.setChecked(False)
        vBox2.addWidget(self.checkUseSRTM)

        # Choose processing method + use/don't use acceleration
        hBoxProcessingMethod = QHBoxLayout()
        labelProcessingMethod = QLabel('Processing method')
        hBoxProcessingMethod.addWidget(labelProcessingMethod)
        self.comboBoxProcessingMethod = QComboBox()
        self.comboBoxProcessingMethod.addItem("Just use available data")
        self.comboBoxProcessingMethod.addItem(
            "Fill all gaps at T=1s (resample)")
        self.comboBoxProcessingMethod.addItem("Fill only smaller gaps at T=1s")
        hBoxProcessingMethod.addWidget(self.comboBoxProcessingMethod)
        self.checkUseAcceleration = QCheckBox("Use acceleration")
        self.checkUseAcceleration.setChecked(False)
        hBoxProcessingMethod.addWidget(self.checkUseAcceleration)
        vBox2.addLayout(hBoxProcessingMethod)

        # Use/don't use variance smooth
        self.checkExtraSmooth = QCheckBox("Extra smooth")
        self.checkExtraSmooth.setChecked(False)
        vBox2.addWidget(self.checkExtraSmooth)

        # 2D interactive map settings
        hBox2DMap = QHBoxLayout()
        self.checkUseRDP = QCheckBox("Use RDP to reduce points")
        self.checkUseRDP.setChecked(False)
        hBox2DMap.addWidget(self.checkUseRDP)
        self.check2DMapInExternalBrowser = QCheckBox(
            "Show in external browser")
        self.check2DMapInExternalBrowser.setChecked(False)
        hBox2DMap.addWidget(self.check2DMapInExternalBrowser)
        vBox2.addLayout(hBox2DMap)

        # Settings for the 3D map
        line3DViewSettings = QFrame()
        #line3DViewSettings.setGeometry(QtCore.QRect(320, 150, 118, 3))
        line3DViewSettings.setFrameShape(QFrame.HLine)
        line3DViewSettings.setFrameShadow(QFrame.Sunken)
        vBox2.addWidget(line3DViewSettings)

        label3DViewSettings = QLabel('3D view settings')
        vBox2.addWidget(label3DViewSettings)

        hBox3DMapSelection = QHBoxLayout()
        self.check3DMapSelection = QCheckBox(
            "Select elevation tiles automatically, otherwise")
        self.check3DMapSelection.setChecked(True)
        hBox3DMapSelection.addWidget(self.check3DMapSelection)
        self.text3DMapName = QLineEdit()
        self.text3DMapName.setText("Iceland.tif")
        hBox3DMapSelection.addWidget(self.text3DMapName)
        vBox2.addLayout(hBox3DMapSelection)

        hBox3D = QHBoxLayout()
        label3DMargin = QLabel('Margin')
        hBox3D.addWidget(label3DMargin)
        self.spinbox3DMargin = QSpinBox()
        self.spinbox3DMargin.setRange(50, 1000)
        self.spinbox3DMargin.setValue(100)
        self.spinbox3DMargin.setSingleStep(10)
        hBox3D.addWidget(self.spinbox3DMargin)

        labelSpace = QLabel('  ')
        hBox3D.addWidget(labelSpace)

        label3DElevationScale = QLabel('Elev. scale')
        hBox3D.addWidget(label3DElevationScale)
        self.spinbox3DElevationScale = QDoubleSpinBox()
        self.spinbox3DElevationScale.setRange(1, 50)
        self.spinbox3DElevationScale.setSingleStep(0.1)
        hBox3D.addWidget(self.spinbox3DElevationScale)

        hBox3D.addWidget(labelSpace)

        label3DOSMZoom = QLabel('Zoom')
        hBox3D.addWidget(label3DOSMZoom)
        self.spinbox3DOSMZoom = QSpinBox()
        self.spinbox3DOSMZoom.setRange(8, 15)
        self.spinbox3DOSMZoom.setValue(13)
        self.spinbox3DOSMZoom.setSingleStep(1)
        hBox3D.addWidget(self.spinbox3DOSMZoom)

        hBox3D.addWidget(labelSpace)

        self.check3DOSMInvert = QCheckBox("Invert")
        self.check3DOSMInvert.setChecked(False)
        hBox3D.addWidget(self.check3DOSMInvert)
        vBox2.addLayout(hBox3D)

        vBox_left.addLayout(vBox2)

        # 3rd stats tree
        lineTree = QFrame()
        lineTree.setFrameShape(QFrame.HLine)
        lineTree.setFrameShadow(QFrame.Sunken)
        vBox2.addWidget(lineTree)
        labelTree = QLabel('Track stats')
        vBox2.addWidget(labelTree)

        self.tree = QTreeView()
        self.tree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treemodel = QtGui.QStandardItemModel()
        self.treemodel.setHorizontalHeaderLabels(['Name', 'Value'])
        self.tree.setModel(self.treemodel)
        self.tree.setUniformRowHeights(True)
        self.tree.setColumnWidth(0, 200)
        vBox_left.addWidget(self.tree)

        # 4th text, containing text messages/errors
        self.textWarningConsole = QTextEdit()
        self.textWarningConsole.setReadOnly(True)
        self.textWarningConsole.setFont(QtGui.QFont("Courier New", FONTSIZE))
        self.textWarningConsole.clear()
        self.textWarningConsole.setMaximumHeight(50)
        vBox_left.addWidget(self.textWarningConsole)

        # I put "vBox_left" inside a widget and then the widget inside "hBox"
        # instead of just doing "hBox.addLayout(vBox_left) so I can set its
        # maximum width.
        vBox_left_widget = QWidget()
        vBox_left_widget.setLayout(vBox_left)
        vBox_left_widget.setMinimumWidth(400)
        vBox_left_widget.setMaximumWidth(500)
        hBox.addWidget(vBox_left_widget)

        # Vertical right column
        self.tab = QTabWidget()

        # Tab 1: Summary: elevation and speed
        tab1 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Plot area
        self.plotEmbeddedElevationAndSpeed = EmbeddedPlot_ElevationSpeed(
            width=5, height=4, dpi=100)
        self.plotEmbeddedElevationAndSpeed.setMinimumWidth(800)
        # Add toolbar to the plot
        self.mpl_toolbar1 = NavigationToolbar(
            self.plotEmbeddedElevationAndSpeed, self.scatola)
        # Add widgets to the layout
        vBox_tab.addWidget(self.plotEmbeddedElevationAndSpeed)
        vBox_tab.addWidget(self.mpl_toolbar1)
        # Associate the layout to the tab
        tab1.setLayout(vBox_tab)

        # Tab 2: html 2D map
        tab2 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Area
        self.map2d = QtWebEngineWidgets.QWebEngineView()
        # Add widgets to the layout
        vBox_tab.addWidget(self.map2d)
        # Associate the layout to the tab
        tab2.setLayout(vBox_tab)

        # Tab 3: 3D plot
        tab3 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Area
        self.map3d = MayaviQWidget()
        # Add widgets to the layout
        vBox_tab.addWidget(self.map3d)
        # Associate the layout to the tab
        tab3.setLayout(vBox_tab)

        # Tab 4: Details
        tab4 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Plot area
        self.plotEmbeddedDetails = EmbeddedPlot_Details(width=5,
                                                        height=4,
                                                        dpi=100)
        self.plotEmbeddedDetails.setMinimumWidth(800)
        # Add toolbar to the plot
        self.mpl_toolbar2 = NavigationToolbar(self.plotEmbeddedDetails,
                                              self.scatola)
        # Add widgets to the layout
        vBox_tab.addWidget(self.plotEmbeddedDetails)
        vBox_tab.addWidget(self.mpl_toolbar2)
        # Associate the layout to the tab
        tab4.setLayout(vBox_tab)

        # Associate tabs
        self.tab.addTab(tab1, "Summary")
        self.tab.addTab(tab2, "2D Map")
        self.tab.addTab(tab3, "3D Map")
        self.tab.addTab(tab4, "Details")

        hBox.addWidget(self.tab)

        # Setting hBox as main box
        self.scatola.setLayout(hBox)
        self.setCentralWidget(self.scatola)

        # Application settings
        self.setWindowTitle('TrackAnalyser')
        self.setWindowIcon((QtGui.QIcon('icons/app.png')))
        self.setGeometry(100, 100, 1200, 700)
        self.show()
Example #34
0
class MainWindow(QMainWindow):
    def selectFileToOpen(self):
        def getPreProcessingChoice(self, filename, filestructure):
            items = ("Choose the longest", "Merge all")
            item, okPressed = QInputDialog.getItem(
                self, "Multiple tracks/segments", "File '" + filename +
                "' contains more than one track/segment\n\n" + infos +
                "\nWhat to do?", items, 0, False)
            if okPressed and item:
                return items.index(item)
            else:
                return 0

        # Try to recover the last used directory
        old_directory = self.settings.value("lastdirectory", str)

        # Check if the setting exists
        if old_directory is not None:
            # Check if it's not empty
            if old_directory:
                old_directory = old_directory
            else:
                old_directory = bombo.TRACKS_FOLDER
        else:
            old_directory = bombo.TRACKS_FOLDER

        # Open the dialog box
        fullfilename_list = QFileDialog.getOpenFileNames(
            self, 'Open .gpx', old_directory, "GPX files (*.gpx)")
        if os.environ['QT_API'] == 'pyqt':
            pass
        elif os.environ['QT_API'] == 'pyqt5':
            fullfilename_list = fullfilename_list[0]

        # Process every selected file
        for i, fullfilename in enumerate(fullfilename_list):
            # Process filename
            directory, filename = os.path.split(str(fullfilename))
            filename, fileextension = os.path.splitext(filename)

            # Save the new directory in the application settings (it only
            # needs to be done once)
            if i == 0:
                # print "New directory to be saved: {}\n".format(directory)
                if os.environ['QT_API'] == 'pyqt':
                    self.settings.setValue("lastdirectory", str(directory))
                elif os.environ['QT_API'] == 'pyqt5':
                    self.settings.setValue("lastdirectory",
                                           QtCore.QVariant(str(directory)))

            # Open file and inspect what's inside
            gpxraw, longest_traseg, Ntracks, Nsegments, infos = bombo.LoadGPX(
                fullfilename)

            # If there's more than one track or segment, ask how to proceed
            if (Ntracks > 1) or (Nsegments > 1):
                preprocessingchoice = getPreProcessingChoice(
                    self, filename, infos)
                if preprocessingchoice == 0:
                    preprocessedgpx = bombo.SelectOneTrackAndSegmentFromGPX(
                        gpxraw, longest_traseg[0], longest_traseg[1])
                    listname = filename + " (longest)"
                elif preprocessingchoice == 1:
                    preprocessedgpx = bombo.MergeAllTracksAndSegmentsFromGPX(
                        gpxraw)
                    listname = filename + " (merged)"
            else:
                preprocessedgpx = gpxraw
                listname = filename

            # Append the list of open GPX files using the next available color (that's the size of the list -1)
            self.gpxlist.append(preprocessedgpx)
            self.gpxnamelist.append(listname)
            newitem = QListWidgetItem(listname)
            newitem.setBackground(
                QtGui.QColor(self.palette[len(self.gpxlist) - 1]))
            self.tracklist.addItem(newitem)

        return

    def Go(self):
        if len(self.gpxselectedlist) > 0:
            # Temporarily change cursor
            QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)

            # Clear up global variables
            self.proc_coords = []
            self.proc_measurements = []
            self.proc_state_means = []
            self.proc_state_vars = []
            self.proc_new_coords = []
            self.proc_new_gpx = []
            self.proc_coords_to_plot = []
            self.proc_coords_to_plot2 = []
            self.proc_balloondata = []

            # For every GPX file that is selected
            self.textWarningConsole.clear()
            for i, currentgpx in enumerate(self.gpxselectedlist):
                # Parse the GPX file
                gpx, coords, dinfos_before, warnings = bombo.ParseGPX(
                    currentgpx,
                    track_nr=0,
                    segment_nr=0,
                    use_srtm_elevation=bool(self.checkUseSRTM.isChecked()))
                self.textWarningConsole.append(warnings)

                # Kalman processing
                coords, measurements, state_means, state_vars, dinfos_during = bombo.ApplyKalmanFilter(
                    coords,
                    gpx,
                    method=self.comboBoxProcessingMethod.currentIndex(),
                    use_acceleration=self.checkUseAcceleration.isChecked(),
                    extra_smooth=self.checkExtraSmooth.isChecked(),
                    debug_plot=False)

                # Save data in GPX structure to compute speed and elevations
                new_coords, new_gpx, dinfos_after = bombo.SaveDataToCoordsAndGPX(
                    coords, state_means)

                # Update GUI with the computed stats
                parent = QtGui.QStandardItem(self.gpxselectednamelist[i])

                parent_beforeprocessing = QtGui.QStandardItem("Raw GPX stats")
                parent_beforeprocessing.appendRow([
                    QtGui.QStandardItem("Total distance"),
                    QtGui.QStandardItem(dinfos_before['total_distance'])
                ])
                parent_beforeprocessing_moving = QtGui.QStandardItem("Moving")
                parent_beforeprocessing_moving.appendRow([
                    QtGui.QStandardItem("Time"),
                    QtGui.QStandardItem(dinfos_before['moving_time'])
                ])
                parent_beforeprocessing_moving.appendRow([
                    QtGui.QStandardItem("Distance"),
                    QtGui.QStandardItem(dinfos_before['moving_distance'])
                ])
                parent_beforeprocessing.appendRow(
                    parent_beforeprocessing_moving)
                parent_beforeprocessing_idle = QtGui.QStandardItem("Idle")
                parent_beforeprocessing_idle.appendRow([
                    QtGui.QStandardItem("Time"),
                    QtGui.QStandardItem(dinfos_before['idle_time'])
                ])
                parent_beforeprocessing_idle.appendRow([
                    QtGui.QStandardItem("Distance"),
                    QtGui.QStandardItem(dinfos_before['idle_distance'])
                ])
                parent_beforeprocessing.appendRow(parent_beforeprocessing_idle)
                parent_beforeprocessing.appendRow([
                    QtGui.QStandardItem("Elevation"),
                    QtGui.QStandardItem(dinfos_before['elevation'])
                ])
                parent_beforeprocessing.appendRow([
                    QtGui.QStandardItem("Climb"),
                    QtGui.QStandardItem(dinfos_before['climb'])
                ])
                parent.appendRow(parent_beforeprocessing)

                parent.appendRow([
                    QtGui.QStandardItem("Samples"),
                    QtGui.QStandardItem(dinfos_during['nsamples'])
                ])
                parent.appendRow([
                    QtGui.QStandardItem("Total distance"),
                    QtGui.QStandardItem(dinfos_after['total_distance'])
                ])
                parent_moving = QtGui.QStandardItem("Moving")
                parent_moving.appendRow([
                    QtGui.QStandardItem("Time"),
                    QtGui.QStandardItem(dinfos_after['moving_time'])
                ])
                parent_moving.appendRow([
                    QtGui.QStandardItem("Distance"),
                    QtGui.QStandardItem(dinfos_after['moving_distance'])
                ])
                parent.appendRow(parent_moving)
                parent_idle = QtGui.QStandardItem("Idle")
                parent_idle.appendRow([
                    QtGui.QStandardItem("Time"),
                    QtGui.QStandardItem(dinfos_after['idle_time'])
                ])
                parent_idle.appendRow([
                    QtGui.QStandardItem("Distance"),
                    QtGui.QStandardItem(dinfos_after['idle_distance'])
                ])
                parent.appendRow(parent_idle)
                parent.appendRow([
                    QtGui.QStandardItem("Elevation"),
                    QtGui.QStandardItem(dinfos_after['elevation'])
                ])
                parent.appendRow([
                    QtGui.QStandardItem("Climb"),
                    QtGui.QStandardItem(dinfos_after['climb'])
                ])
                self.treemodel.appendRow(parent)

                # Create balloondata for the html plot
                balloondata = {
                    'distance':
                    np.cumsum(
                        bombo.HaversineDistance(np.asarray(new_coords['lat']),
                                                np.asarray(
                                                    new_coords['lon']))),
                    'elevation':
                    np.asarray(new_coords['ele']),
                    'speed':
                    None
                }

                # Create extra data for the html plot (fully implemented in bombo, not here)
                """
                data = np.ones((len(lat_cleaned),2))
                data[:,0] = h_filtered / np.max(h_filtered) * 0.0004
                data[:,1] = np.hstack((np.asarray([0]), speed_h)) / np.max(np.hstack((np.asarray([0]), speed_h))) * 0.0004
                tangentdata = {'data': data,
                               'sides': (0, 1),
                               'palette': ('blue','red')}
                """

                # Save relevant output in global variables
                self.proc_coords.append(coords)
                self.proc_measurements.append(measurements)
                self.proc_state_means.append(state_means)
                self.proc_state_vars.append(state_vars)
                self.proc_new_coords.append(new_coords)
                self.proc_new_gpx.append(new_gpx)
                self.proc_coords_to_plot.append(
                    np.vstack((new_coords['lat'], new_coords['lon'])).T)
                self.proc_coords_to_plot2.append(
                    np.vstack((coords['lat'], coords['lon'])).T)
                self.proc_balloondata.append(balloondata)

            # Restore original cursor
            QApplication.restoreOverrideCursor()

            # Generate embedded plots
            if len(self.gpxselectedlist) == 1:
                self.plotEmbeddedElevationAndSpeed.update_figure(
                    measurements, state_means, new_gpx.tracks[0].segments[0])
                self.plotEmbeddedDetails.update_figure(
                    measurements, state_means, state_vars,
                    new_gpx.tracks[0].segments[0])
            else:
                # Commentato per adesso
                # self.plotEmbeddedElevationAndSpeed.update_figure_multiple_tracks(self.proc_measurements, self.proc_state_means, self.proc_new_gpx)
                self.plotEmbeddedElevationAndSpeed.clear_figure()
                self.plotEmbeddedDetails.clear_figure()

            # Generate html plot, if only one track is selected, proceed with the complete output, otherwise just plot the traces
            if len(self.gpxselectedlist) is 1:
                bombo.PlotOnMap(
                    coords_array_list=self.proc_coords_to_plot,
                    coords_array2_list=self.proc_coords_to_plot2,
                    coords_palette=self.selectedpalette,
                    tangentdata=None,
                    balloondata_list=self.proc_balloondata,
                    rdp_reduction=self.checkUseRDP.isChecked(),
                    showmap=bool(self.check2DMapInExternalBrowser.isChecked()))
            else:
                bombo.PlotOnMap(
                    coords_array_list=self.proc_coords_to_plot,
                    coords_array2_list=None,
                    coords_palette=self.selectedpalette,
                    tangentdata=None,
                    balloondata_list=self.proc_balloondata,
                    rdp_reduction=self.checkUseRDP.isChecked(),
                    showmap=bool(self.check2DMapInExternalBrowser.isChecked()))

            self.map2d.load(QtCore.QUrl(bombo.MAP_2D_FILENAME))
            self.map2d.show()

            # Generate 3D plot, only with one track for the moment
            if len(self.gpxselectedlist) == 1:
                if self.check3DMapSelection.isChecked():
                    tile_selection = 'auto'
                else:
                    tile_selection = self.text3DMapName.text()
                terrain, track, warnings = bombo.Generate3DMap(
                    new_coords['lat'],
                    new_coords['lon'],
                    tile_selection=tile_selection,
                    margin=self.spinbox3DMargin.value(),
                    elevation_scale=self.spinbox3DElevationScale.value(),
                    mapping='coords',
                    use_osm_texture=True,
                    texture_type='osm',
                    texture_zoom=self.spinbox3DOSMZoom.value(),
                    texture_invert=self.check3DOSMInvert.isChecked(),
                    use_proxy=self.use_proxy,
                    proxy_data=self.proxy_config,
                    verbose=False)

                self.textWarningConsole.append(warnings)

                if terrain is not None:
                    self.map3d.update_plot(terrain, track)

        else:
            self.textWarningConsole.setText(
                "You need to open a .gpx file before!")
        return

    def PlotSpecificAreaDialog(self):
        def PlotSpecificArea():
            # Save coordinates for the next time
            if os.environ['QT_API'] == 'pyqt':
                self.settings.setValue("last_point_coord_lat",
                                       self.spinboxLatDec.value())
                self.settings.setValue("last_point_coord_lon",
                                       self.spinboxLonDec.value())
            elif os.environ['QT_API'] == 'pyqt5':
                self.settings.setValue(
                    "last_point_coord_lat",
                    QtCore.QVariant(self.spinboxLatDec.value()))
                self.settings.setValue(
                    "last_point_coord_lon",
                    QtCore.QVariant(self.spinboxLonDec.value()))

            # Select the 3D Map tab
            self.tab.setCurrentIndex(2)

            # Plot
            if self.check3DMapSelection.isChecked():
                tile_selection = 'auto'
            else:
                tile_selection = self.text3DMapName.text()

            terrain, track, warnings = bombo.Generate3DMap(
                [self.spinboxLatDec.value()], [self.spinboxLonDec.value()],
                tile_selection=tile_selection,
                margin=self.spinbox3DMargin.value(),
                elevation_scale=self.spinbox3DElevationScale.value(),
                mapping='coords',
                use_osm_texture=True,
                texture_type='osm',
                texture_zoom=self.spinbox3DOSMZoom.value(),
                texture_invert=self.check3DOSMInvert.isChecked(),
                use_proxy=self.use_proxy,
                proxy_data=self.proxy_config,
                verbose=False)

            self.textWarningConsole.append(warnings)

            if terrain is not None:
                self.map3d.update_plot(terrain, track)
            d.done(0)

        def Convert():
            try:
                dd = bombo.parse_dms(self.textLatLonGMS.text())
                self.spinboxLatDec.setValue(dd[0])
                self.spinboxLonDec.setValue(dd[1])
            except:
                pass

        d = QDialog()
        grid = QGridLayout()

        hBox_coordsGMS = QHBoxLayout()
        hBox_coordsGMS.setSpacing(5)
        label = QLabel('Coordinates (gms)')
        grid.addWidget(label, 0, 0)
        self.textLatLonGMS = QLineEdit()
        self.textLatLonGMS.setText("")
        grid.addWidget(self.textLatLonGMS, 0, 1, 1, 2)

        button1 = QPushButton("Convert to decimal")
        button1.clicked.connect(Convert)
        grid.addWidget(button1, 0, 3)

        label = QLabel('Coordinates (decimal)')
        grid.addWidget(label, 1, 0)
        self.spinboxLatDec = QDoubleSpinBox()
        self.spinboxLatDec.setRange(-90, +90)
        self.spinboxLatDec.setSingleStep(0.0000001)
        self.spinboxLatDec.setDecimals(7)
        grid.addWidget(self.spinboxLatDec, 1, 1)
        self.spinboxLonDec = QDoubleSpinBox()
        self.spinboxLonDec.setRange(-180, +180)
        self.spinboxLonDec.setSingleStep(0.0000001)
        self.spinboxLonDec.setDecimals(7)
        grid.addWidget(self.spinboxLonDec, 1, 2)

        # Try to recover the last used points
        try:
            old_lat = self.settings.value("last_point_coord_lat", type=float)
            old_lon = self.settings.value("last_point_coord_lon", type=float)
            self.spinboxLatDec.setValue(old_lat)
            self.spinboxLonDec.setValue(old_lon)
        except:
            # Coordinates of Mt. Rinjani in Indonesia
            self.spinboxLatDec.setValue(-8.4166000)
            self.spinboxLonDec.setValue(116.4666000)

        button2 = QPushButton("Show 3D map")
        button2.clicked.connect(PlotSpecificArea)
        grid.addWidget(button2, 1, 3)

        d.setWindowTitle("Show point on 3D map")
        d.setLayout(grid)
        d.setWindowModality(QtCore.Qt.ApplicationModal)
        d.exec_()

    def ProxyDialog(self):
        def SetProxy():
            self.use_proxy = bool(self.checkUseProxy.isChecked())
            self.proxy_config = self.textProxyConfig.text()

            if os.environ['QT_API'] == 'pyqt':
                self.settings.setValue("use_proxy", self.use_proxy)
                self.settings.setValue("proxy_config", str(self.proxy_config))
            elif os.environ['QT_API'] == 'pyqt5':
                self.settings.setValue("use_proxy",
                                       QtCore.QVariant(self.use_proxy))
                self.settings.setValue("proxy_config",
                                       QtCore.QVariant(str(self.proxy_config)))

            d.done(0)

        d = QDialog()

        box = QVBoxLayout()

        hBox_proxy = QHBoxLayout()
        hBox_proxy.setSpacing(5)
        label = QLabel('Proxy')
        hBox_proxy.addWidget(label)
        self.textProxyConfig = QLineEdit()
        try:
            self.textProxyConfig.setText(
                self.settings.value('proxy_config', str))
        except:
            self.textProxyConfig.setText(bombo.PROXY_DATA)
        self.textProxyConfig.setMinimumWidth(200)
        hBox_proxy.addWidget(self.textProxyConfig)
        box.addLayout(hBox_proxy)

        self.checkUseProxy = QCheckBox("Use proxy")
        try:
            self.checkUseProxy.setChecked(
                self.settings.value('use_proxy', bool))
        except:
            self.checkUseProxy.setChecked(bool(bombo.USE_PROXY))
        box.addWidget(self.checkUseProxy)

        button = QPushButton("Save configuration")
        button.clicked.connect(SetProxy)
        box.addWidget(button)

        d.setWindowTitle("Proxy configuration")
        d.setLayout(box)
        d.setWindowModality(QtCore.Qt.ApplicationModal)
        d.exec_()

    def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.initVariables()
        self.initUI()

    def initVariables(self):
        self.gpxlist = list()
        self.gpxnamelist = list()
        self.gpxselectedlist = list()
        self.gpxselectednamelist = list()
        self.palette = bombo.GeneratePalette(N=10) * 5  # replicated 5 times
        #self.palette = ["#0000FF", "#00FF00", "#00FFFF", "#FF0000", "#FF00FF", "#FFFF00", "#FFFFFF"] # test palette
        self.selectedpalette = list()

        self.proc_coords = list()
        self.proc_measurements = list()
        self.proc_state_means = list()
        self.proc_state_vars = list()
        self.proc_new_coords = list()
        self.proc_new_gpx = list()
        self.proc_coords_to_plot = list()
        self.proc_coords_to_plot2 = list()
        self.proc_balloondata = list()

    def initUI(self):
        def selection_changed():
            # Retrieve selected items
            # selecteditems = self.tracklist.selectedItems()
            selectedindexes = self.tracklist.selectedIndexes()

            # Adding the selected items to the processing list
            self.gpxselectedlist[:] = []
            self.gpxselectednamelist[:] = []
            self.selectedpalette[:] = []
            for i in selectedindexes:
                # print str(i.text())
                self.gpxselectedlist.append(self.gpxlist[i.row()])
                self.gpxselectednamelist.append(self.gpxnamelist[i.row()])
                self.selectedpalette.append(self.palette[i.row()])

        def ClearStats():
            """
            # Some other code that could be used in the future
            index = self.treemodel.indexFromItem(parent1)
            self.tree.expand(index)
            selmod = self.tree.selectionModel()
            index2 = self.treemodel.indexFromItem(child2)
            selmod.select(index2, QtCore.QItemSelectionModel.Select|QtCore.QItemSelectionModel.Rows)
            
            root = self.treemodel.invisibleRootItem()
            (item.parent() or root).removeChild(item)
            """
            # Returns a list of indexes. In our case, for each row there are 2 indexes, cos there are 2 columns.
            for index in self.tree.selectedIndexes():
                # Consider only the first columns
                if index.column() == 0:
                    # Need to check if it's a top item (i.e. track), otherwise if a subitem (i.e. distance or time) is selected, the result might be buggy
                    parent = index.parent()
                    parent_item = self.treemodel.itemFromIndex(parent)
                    if parent_item is None:
                        self.treemodel.removeRow(index.row())

        # Application Settings
        QtCore.QCoreApplication.setOrganizationName("Ste")
        QtCore.QCoreApplication.setOrganizationDomain(
            "https://github.com/stesalati/sport/")
        QtCore.QCoreApplication.setApplicationName("TrackAnalyser")

        # Config settings
        self.settings = QtCore.QSettings(self)

        # Proxy settings
        try:
            self.use_proxy = self.settings.value('use_proxy', bool)
            self.proxy_config = self.settings.value('proxy_config', str)
        except:
            self.use_proxy = bombo.USE_PROXY
            self.proxy_config = bombo.PROXY_DATA

        # Actions
        openfile = QAction(QtGui.QIcon("icons/openfile.png"), "Open .gpx",
                           self)
        openfile.setShortcut("Ctrl+O")
        openfile.setStatusTip("Open file")
        openfile.triggered.connect(self.selectFileToOpen)

        go = QAction(QtGui.QIcon("icons/go.png"), "Go!", self)
        go.setShortcut("Ctrl+R")
        go.setStatusTip("Run analysis")
        go.triggered.connect(self.Go)

        clearstats = QAction(QtGui.QIcon("icons/clear.png"), "Clear stats",
                             self)
        clearstats.setShortcut("Ctrl+C")
        clearstats.setStatusTip("Clear stats")
        clearstats.triggered.connect(ClearStats)

        sep1 = QAction(self)
        sep1.setSeparator(True)

        showpoint = QAction(QtGui.QIcon("icons/point.png"), "Show point", self)
        showpoint.setShortcut("Ctrl+P")
        showpoint.setStatusTip("Show point")
        showpoint.triggered.connect(self.PlotSpecificAreaDialog)

        sep2 = QAction(self)
        sep2.setSeparator(True)

        quitapp = QAction(QtGui.QIcon("icons/quit.png"), "Quit", self)
        quitapp.setShortcut("Ctrl+Q")
        quitapp.setStatusTip("Quit application")
        quitapp.triggered.connect(qApp.quit)

        configs = QAction(QtGui.QIcon("icons/configs.png"), "Configs", self)
        configs.setStatusTip("Configs")
        configs.triggered.connect(self.ProxyDialog)

        # Menubar
        mainMenu = self.menuBar()
        configMenu = mainMenu.addMenu('&Config')
        configMenu.addAction(configs)

        # Toolbar
        toolbar = self.addToolBar('My tools')
        toolbar.addAction(openfile)
        toolbar.addAction(go)
        toolbar.addAction(clearstats)
        toolbar.addAction(sep1)
        toolbar.addAction(showpoint)
        toolbar.addAction(sep2)
        toolbar.addAction(quitapp)
        toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
        toolbar.setIconSize(QtCore.QSize(30, 30))

        # Status bar
        self.statusBar().show()

        # Main widget (everything that's not toolbar, statusbar or menubar must be in this widget)
        self.scatola = QWidget()

        # Main horizontal impagination
        hBox = QHBoxLayout()
        hBox.setSpacing(5)

        # Vertical left column
        vBox_left = QVBoxLayout()
        vBox_left.setSpacing(5)

        # 1st vertical box, a list
        self.tracklist = QListWidget()
        vBox_left.addWidget(self.tracklist)
        self.tracklist.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.tracklist.itemSelectionChanged.connect(selection_changed)
        self.tracklist.setMaximumHeight(120)

        # 2nd vertical box, containing several horizontal boxes, one for each setting
        vBox2 = QVBoxLayout()
        vBox2.setSpacing(5)

        # Just the group label
        labelSettings = QLabel('Settings')
        vBox2.addWidget(labelSettings)

        # Use/don't use corrected altitude
        self.checkUseSRTM = QCheckBox(
            "Use SRTM corrected elevation (needs Internet)")
        self.checkUseSRTM.setChecked(False)
        vBox2.addWidget(self.checkUseSRTM)

        # Choose processing method + use/don't use acceleration
        hBoxProcessingMethod = QHBoxLayout()
        labelProcessingMethod = QLabel('Processing method')
        hBoxProcessingMethod.addWidget(labelProcessingMethod)
        self.comboBoxProcessingMethod = QComboBox()
        self.comboBoxProcessingMethod.addItem("Just use available data")
        self.comboBoxProcessingMethod.addItem(
            "Fill all gaps at T=1s (resample)")
        self.comboBoxProcessingMethod.addItem("Fill only smaller gaps at T=1s")
        hBoxProcessingMethod.addWidget(self.comboBoxProcessingMethod)
        self.checkUseAcceleration = QCheckBox("Use acceleration")
        self.checkUseAcceleration.setChecked(False)
        hBoxProcessingMethod.addWidget(self.checkUseAcceleration)
        vBox2.addLayout(hBoxProcessingMethod)

        # Use/don't use variance smooth
        self.checkExtraSmooth = QCheckBox("Extra smooth")
        self.checkExtraSmooth.setChecked(False)
        vBox2.addWidget(self.checkExtraSmooth)

        # 2D interactive map settings
        hBox2DMap = QHBoxLayout()
        self.checkUseRDP = QCheckBox("Use RDP to reduce points")
        self.checkUseRDP.setChecked(False)
        hBox2DMap.addWidget(self.checkUseRDP)
        self.check2DMapInExternalBrowser = QCheckBox(
            "Show in external browser")
        self.check2DMapInExternalBrowser.setChecked(False)
        hBox2DMap.addWidget(self.check2DMapInExternalBrowser)
        vBox2.addLayout(hBox2DMap)

        # Settings for the 3D map
        line3DViewSettings = QFrame()
        #line3DViewSettings.setGeometry(QtCore.QRect(320, 150, 118, 3))
        line3DViewSettings.setFrameShape(QFrame.HLine)
        line3DViewSettings.setFrameShadow(QFrame.Sunken)
        vBox2.addWidget(line3DViewSettings)

        label3DViewSettings = QLabel('3D view settings')
        vBox2.addWidget(label3DViewSettings)

        hBox3DMapSelection = QHBoxLayout()
        self.check3DMapSelection = QCheckBox(
            "Select elevation tiles automatically, otherwise")
        self.check3DMapSelection.setChecked(True)
        hBox3DMapSelection.addWidget(self.check3DMapSelection)
        self.text3DMapName = QLineEdit()
        self.text3DMapName.setText("Iceland.tif")
        hBox3DMapSelection.addWidget(self.text3DMapName)
        vBox2.addLayout(hBox3DMapSelection)

        hBox3D = QHBoxLayout()
        label3DMargin = QLabel('Margin')
        hBox3D.addWidget(label3DMargin)
        self.spinbox3DMargin = QSpinBox()
        self.spinbox3DMargin.setRange(50, 1000)
        self.spinbox3DMargin.setValue(100)
        self.spinbox3DMargin.setSingleStep(10)
        hBox3D.addWidget(self.spinbox3DMargin)

        labelSpace = QLabel('  ')
        hBox3D.addWidget(labelSpace)

        label3DElevationScale = QLabel('Elev. scale')
        hBox3D.addWidget(label3DElevationScale)
        self.spinbox3DElevationScale = QDoubleSpinBox()
        self.spinbox3DElevationScale.setRange(1, 50)
        self.spinbox3DElevationScale.setSingleStep(0.1)
        hBox3D.addWidget(self.spinbox3DElevationScale)

        hBox3D.addWidget(labelSpace)

        label3DOSMZoom = QLabel('Zoom')
        hBox3D.addWidget(label3DOSMZoom)
        self.spinbox3DOSMZoom = QSpinBox()
        self.spinbox3DOSMZoom.setRange(8, 15)
        self.spinbox3DOSMZoom.setValue(13)
        self.spinbox3DOSMZoom.setSingleStep(1)
        hBox3D.addWidget(self.spinbox3DOSMZoom)

        hBox3D.addWidget(labelSpace)

        self.check3DOSMInvert = QCheckBox("Invert")
        self.check3DOSMInvert.setChecked(False)
        hBox3D.addWidget(self.check3DOSMInvert)
        vBox2.addLayout(hBox3D)

        vBox_left.addLayout(vBox2)

        # 3rd stats tree
        lineTree = QFrame()
        lineTree.setFrameShape(QFrame.HLine)
        lineTree.setFrameShadow(QFrame.Sunken)
        vBox2.addWidget(lineTree)
        labelTree = QLabel('Track stats')
        vBox2.addWidget(labelTree)

        self.tree = QTreeView()
        self.tree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treemodel = QtGui.QStandardItemModel()
        self.treemodel.setHorizontalHeaderLabels(['Name', 'Value'])
        self.tree.setModel(self.treemodel)
        self.tree.setUniformRowHeights(True)
        self.tree.setColumnWidth(0, 200)
        vBox_left.addWidget(self.tree)

        # 4th text, containing text messages/errors
        self.textWarningConsole = QTextEdit()
        self.textWarningConsole.setReadOnly(True)
        self.textWarningConsole.setFont(QtGui.QFont("Courier New", FONTSIZE))
        self.textWarningConsole.clear()
        self.textWarningConsole.setMaximumHeight(50)
        vBox_left.addWidget(self.textWarningConsole)

        # I put "vBox_left" inside a widget and then the widget inside "hBox"
        # instead of just doing "hBox.addLayout(vBox_left) so I can set its
        # maximum width.
        vBox_left_widget = QWidget()
        vBox_left_widget.setLayout(vBox_left)
        vBox_left_widget.setMinimumWidth(400)
        vBox_left_widget.setMaximumWidth(500)
        hBox.addWidget(vBox_left_widget)

        # Vertical right column
        self.tab = QTabWidget()

        # Tab 1: Summary: elevation and speed
        tab1 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Plot area
        self.plotEmbeddedElevationAndSpeed = EmbeddedPlot_ElevationSpeed(
            width=5, height=4, dpi=100)
        self.plotEmbeddedElevationAndSpeed.setMinimumWidth(800)
        # Add toolbar to the plot
        self.mpl_toolbar1 = NavigationToolbar(
            self.plotEmbeddedElevationAndSpeed, self.scatola)
        # Add widgets to the layout
        vBox_tab.addWidget(self.plotEmbeddedElevationAndSpeed)
        vBox_tab.addWidget(self.mpl_toolbar1)
        # Associate the layout to the tab
        tab1.setLayout(vBox_tab)

        # Tab 2: html 2D map
        tab2 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Area
        self.map2d = QtWebEngineWidgets.QWebEngineView()
        # Add widgets to the layout
        vBox_tab.addWidget(self.map2d)
        # Associate the layout to the tab
        tab2.setLayout(vBox_tab)

        # Tab 3: 3D plot
        tab3 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Area
        self.map3d = MayaviQWidget()
        # Add widgets to the layout
        vBox_tab.addWidget(self.map3d)
        # Associate the layout to the tab
        tab3.setLayout(vBox_tab)

        # Tab 4: Details
        tab4 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Plot area
        self.plotEmbeddedDetails = EmbeddedPlot_Details(width=5,
                                                        height=4,
                                                        dpi=100)
        self.plotEmbeddedDetails.setMinimumWidth(800)
        # Add toolbar to the plot
        self.mpl_toolbar2 = NavigationToolbar(self.plotEmbeddedDetails,
                                              self.scatola)
        # Add widgets to the layout
        vBox_tab.addWidget(self.plotEmbeddedDetails)
        vBox_tab.addWidget(self.mpl_toolbar2)
        # Associate the layout to the tab
        tab4.setLayout(vBox_tab)

        # Associate tabs
        self.tab.addTab(tab1, "Summary")
        self.tab.addTab(tab2, "2D Map")
        self.tab.addTab(tab3, "3D Map")
        self.tab.addTab(tab4, "Details")

        hBox.addWidget(self.tab)

        # Setting hBox as main box
        self.scatola.setLayout(hBox)
        self.setCentralWidget(self.scatola)

        # Application settings
        self.setWindowTitle('TrackAnalyser')
        self.setWindowIcon((QtGui.QIcon('icons/app.png')))
        self.setGeometry(100, 100, 1200, 700)
        self.show()
Example #35
0
 def rowsInserted(self, parent, firstRow, lastRow):
     """Called when rows are inserted."""
     QTreeView.rowsInserted(self, parent, firstRow, lastRow)
     self.resizeColumns()
     self.spanFirstColumn(firstRow, lastRow)