• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nens / ThreeDiToolbox / #2631

28 Nov 2025 05:48PM UTC coverage: 36.534% (-0.02%) from 36.554%
#2631

push

coveralls-python

web-flow
Merge 86de4b147 into 18c57d6c2

13 of 77 new or added lines in 22 files covered. (16.88%)

3 existing lines in 3 files now uncovered.

5262 of 14403 relevant lines covered (36.53%)

0.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

30.14
/tool_graph/graph.py
1
from qgis.PyQt.QtCore import Qt
1✔
2
from threedi_results_analysis.tool_graph.graph_view import GraphDockWidget
1✔
3
from threedi_results_analysis.threedi_plugin_model import ThreeDiResultItem, ThreeDiGridItem
1✔
4
from threedi_results_analysis.threedi_plugin_tool import ThreeDiPluginTool
1✔
5
from qgis.PyQt.QtCore import pyqtSlot
1✔
6
import qgis
1✔
7
import os
1✔
8

9

10
class ThreeDiGraph(ThreeDiPluginTool):
1✔
11

12
    def __init__(self, iface, model):
1✔
13
        super().__init__()
×
14

15
        self.iface = iface
×
16
        self.model = model
×
17

NEW
18
        self.icon_path = os.path.join(
×
19
            os.path.dirname(os.path.dirname(__file__)),
20
            "icons",
21
            "icon_time_series_plotter.svg"
22
        )
UNCOV
23
        self.menu_text = "Time series plotter"
×
24

25
        self.dock_widgets = []
×
26
        self.widget_nr = 0
×
27

28
    def on_unload(self):
1✔
29
        """
30
        on close of graph plugin
31
        """
32
        for widget in self.dock_widgets:
×
33
            widget.close()  # TODO: delete as well?
×
34

35
    def on_close_child_widget(self, widget_nr):
1✔
36
        """Cleanup necessary items here when plugin dockwidget is closed"""
37
        nr = None
×
38

39
        # find widget based on nr
40
        for i in range(0, len(self.dock_widgets)):
×
41
            widget = self.dock_widgets[i]
×
42
            if widget.nr == widget_nr:
×
43
                nr = i
×
44

45
        # close widget
46
        if nr is not None:
×
47
            widget = self.dock_widgets[nr]
×
48
            widget.closingWidget.disconnect(self.on_close_child_widget)
×
49

50
            del self.dock_widgets[nr]
×
51

52
    @pyqtSlot(ThreeDiResultItem)
1✔
53
    def result_added(self, result_item: ThreeDiResultItem):
1✔
54
        # Assign a line pattern to this result (TODO: consider keeping track of the patterns
55
        # in this plugin instead of storing in model?)
56
        if not result_item._pattern:
×
57
            result_item._pattern = ThreeDiGraph.get_line_pattern(result_item=result_item)
×
58

59
        self.action_icon.setEnabled(self.model.number_of_results() > 0)
×
60
        for dock_widget in self.dock_widgets:
×
61
            dock_widget.result_added(result_item)
×
62

63
    @pyqtSlot(ThreeDiResultItem)
1✔
64
    def result_removed(self, result_item: ThreeDiResultItem):
1✔
65
        self.action_icon.setEnabled(self.model.number_of_results() > 0)
×
66
        for dock_widget in self.dock_widgets:
×
67
            dock_widget.result_removed(result_item)
×
68

69
    @pyqtSlot(ThreeDiResultItem)
1✔
70
    def result_changed(self, result_item: ThreeDiResultItem):
1✔
71
        for dock_widget in self.dock_widgets:
×
72
            dock_widget.result_changed(result_item)
×
73

74
    @pyqtSlot(ThreeDiGridItem)
1✔
75
    def grid_changed(self, grid_item: ThreeDiGridItem):
1✔
76
        for dock_widget in self.dock_widgets:
×
77
            dock_widget.grid_changed(grid_item)
×
78

79
    def run(self):
1✔
80
        """
81
        Run method that loads and starts the plugin (docked graph widget)
82
        """
83
        # create the dockwidget
84
        self.widget_nr += 1
×
85
        new_widget = GraphDockWidget(
×
86
            iface=self.iface,
87
            nr=self.widget_nr,
88
            model=self.model,
89
        )
90
        self.dock_widgets.append(new_widget)
×
91

92
        # connect cleanup on closing of dockwidget
93
        new_widget.closingWidget.connect(self.on_close_child_widget)
×
94

95
        # show the dockwidget
96
        self.iface.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, new_widget)
×
97

98
        # make stack of graph widgets (instead of next to each other)
99
        if len(self.dock_widgets) > 1:
×
100
            window = qgis.core.QgsApplication.activeWindow()
×
101
            window.tabifyDockWidget(self.dock_widgets[0], new_widget)
×
102

103
        new_widget.show()
×
104

105
    @staticmethod
1✔
106
    def get_line_pattern(result_item: ThreeDiResultItem) -> Qt.PenStyle:
1✔
107
        """Determine (default) line pattern for this result plot
108

109
        Look at the already-used styles os sibblings and try to pick an unused one.
110

111
        :param item_field:
112
        """
113
        available_styles = [
×
114
            Qt.PenStyle.SolidLine,
115
            Qt.PenStyle.DashLine,
116
            Qt.PenStyle.DotLine,
117
            Qt.PenStyle.DashDotLine,
118
            Qt.PenStyle.DashDotDotLine,
119
        ]
120

121
        already_used_patterns = []
×
122
        grid_item = result_item.parent()
×
123
        for i in range(grid_item.rowCount()):
×
124
            if grid_item.child(i) is not result_item:
×
125
                sibling_pattern = grid_item.child(i)._pattern
×
126
                assert sibling_pattern
×
127
                already_used_patterns.append(sibling_pattern)
×
128

129
        for style in available_styles:
×
130
            if style not in already_used_patterns:
×
131
                # Hurray, an unused style.
132
                return style
×
133

134
        # No unused styles. Use the solid line style as a default.
135
        return Qt.PenStyle.SolidLine
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc