/
mdihistory_widget.py
225 lines (183 loc) · 7.5 KB
/
mdihistory_widget.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# -*- coding: utf-8 -*-
"""QtPyVCP MDI History Widget
This widget implements the following key elements:
[1] A history display of MDI commands issued with the latest
command at the top of the list and the oldest at the bottom
of the list.
[2] A queue system of commands that have been entered
but have not yet been executed. This allows the rapid entry
of MDI commands to be executed without having to wait for any
running commands to complete.
ToDo:
* add/test for styling based on the class queue codes
* be able to select and remove unwanted commands from the history
* be able to select a row and run commands from that point upwards
"""
from qtpy.QtCore import Qt, Slot, Property, QTimer
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import QListWidget
from qtpy.QtWidgets import QListWidgetItem
import qtpyvcp
from qtpyvcp.plugins import getPlugin
from qtpyvcp.utilities.info import Info
from qtpyvcp.actions.machine_actions import issue_mdi
from qtpyvcp.widgets.base_widgets.base_widget import CMDWidget
import linuxcnc
STATUS = getPlugin('status')
STAT = STATUS.stat
INFO = Info()
class MDIHistory(QListWidget, CMDWidget):
"""MDI History and Queuing Widget.
This widget implements a visual view of the MDI command
history. It also implements a command queuing startegy
so that commands can be entered and queued up for execution.
Visual style is used to identify items that have been completed,
are running and are yet to run.
"""
# MDI Queue status constants
MDIQ_DONE = 0
MDIQ_RUNNING = 1
MDIQ_TODO = 2
MDQQ_ROLE = 256
def __init__(self, parent=None):
super(MDIHistory, self).__init__(parent)
# name and widget handle for MDI cmd entry widget
self.mdi_entryline_name = None
self.mdi_entry_widget = None
self.heart_beat_timer = None
self.icon_run_name = 'media-playback-start'
self.icon_run = QIcon.fromTheme(self.icon_run_name)
self.icon_waiting_name = 'media-playback-pause'
self.icon_waiting = QIcon.fromTheme(self.icon_waiting_name)
#self.returnPressed.connect(self.submit)
@Property(str)
def mdi_entryline_name(self):
"""Return name of entry object to Designer"""
return self._mdi_entryline_name
@mdi_entryline_name.setter
def mdi_entryline_name(self, object_name):
"""Set the name for Designer"""
self._mdi_entryline_name = object_name
@Slot(bool)
def toggle_queue(self, toggle):
"""Toggle queue pause.
Starting point is the queue is active.
"""
if toggle:
self.heart_beat_timer.stop()
else:
self.heart_beat_timer.start()
@Slot()
def clear_queue(self):
"""Clear queue items yet to be run."""
list_length = self.count()-1
while list_length >= 0:
row_item = self.item(list_length)
row_item_data = row_item.data(MDIHistory.MDQQ_ROLE)
if row_item_data == MDIHistory.MDIQ_TODO:
row_item.setData(MDIHistory.MDQQ_ROLE, MDIHistory.MDIQ_DONE)
row_item.setIcon(QIcon())
list_length -= 1
@Slot()
def run_from_selection(self):
"""Start running MDI from the selected row back to top."""
row = self.currentRow()
# from selected row loop back to top and set ready for run
while row >= 0:
row_item = self.item(row)
row_item.setData(MDIHistory.MDQQ_ROLE, MDIHistory.MDIQ_TODO)
row_item.setIcon(self.icon_waiting)
row -= 1
@Slot()
def submit(self):
"""Put a new command on the queue for later execution.
"""
# put the new command on the queue
cmd = str(self.mdi_entry_widget.text()).strip()
row_item = QListWidgetItem()
row_item.setText(cmd)
row_item.setData(MDIHistory.MDQQ_ROLE, MDIHistory.MDIQ_TODO)
row_item.setIcon(self.icon_waiting)
self.insertItem(0, row_item)
# put the command onto the status channel mdi history
STATUS.mdi_history.setValue(cmd)
# now clear down the mdi entry text ready for new input
self.mdi_entry_widget.clear()
def row_clicked(self):
"""Item row clicked."""
pass
def key_press_event(self, event):
"""Key movement processing.
Arrow keys move the selected list item up/down
Return key generates a submit situation by making the item as
the next available command to processes.
"""
row = self.currentRow()
if event.key() == Qt.Key_Up:
if row > 0:
row -= 1
elif event.key() == Qt.Key_Down:
if row < self.count()-1:
row += 1
else:
super(MDIHistory, self).keyPressEvent(event)
self.setCurrentRow(row)
#def focusInEvent(self, event):
# super(MDIHistory, self).focusInEvent(event)
# pass
def set_history(self, items_list):
"""Clear and reset the history in the list.
item_list is a list of strings."""
print 'Clear and load history to list'
self.clear()
for item in items_list:
row_item = QListWidgetItem()
row_item.setText(item)
row_item.setData(MDIHistory.MDQQ_ROLE, MDIHistory.MDIQ_DONE)
row_item.setIcon(QIcon())
self.addItem(row_item)
def heart_beat(self):
"""Supports heart beat on the MDI History execution queue.
Issue the next command from the queue.
Double check machine is in ok state to accept next command.
Issue the command and if success mark command as being active.
Mark last command as done.
"""
# check if machine is idle and ready to run another command
if STAT.interp_state != linuxcnc.INTERP_IDLE:
# RS274NGC interpreter not in a state to execute, bail
return
# scan for the next command to execute from bottom up.
list_length = self.count()-1
while list_length >= 0:
row_item = self.item(list_length)
row_item_data = row_item.data(MDIHistory.MDQQ_ROLE)
if row_item_data == MDIHistory.MDIQ_RUNNING:
# machine is in idle state so the running command is done
row_item.setData(MDIHistory.MDQQ_ROLE, MDIHistory.MDIQ_DONE)
row_item.setIcon(QIcon())
elif row_item_data == MDIHistory.MDIQ_TODO:
cmd = str(row_item.text()).strip()
row_item.setData(MDIHistory.MDQQ_ROLE, MDIHistory.MDIQ_RUNNING)
row_item.setIcon(self.icon_run)
issue_mdi(cmd)
break
list_length -= 1
def initialize(self):
"""Load up starting data and set signal connections."""
history = STATUS.mdi_history.value
self.set_history(history)
self.clicked.connect(self.row_clicked)
# Get handle to windows list and seach through them
# for the widget referenced in mdi_entryline_name
for win_name, obj in qtpyvcp.WINDOWS.items():
if hasattr(obj, self.mdi_entryline_name):
self.mdi_entry_widget = getattr(obj, self.mdi_entryline_name)
# Setup the basic timer system as a heart beat on the queue
self.heart_beat_timer = QTimer(self)
# use a 1 second timer
self.heart_beat_timer.start(1000)
self.heart_beat_timer.timeout.connect(self.heart_beat)
def terminate(self):
"""Teardown processing."""
self.heart_beat_timer.stop()