3
# Copyright 2011 Shadow Robot Company Ltd.
5
# This program is free software: you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by the Free
7
# Software Foundation, either version 2 of the License, or (at your option)
10
# This program is distributed in the hope that it will be useful, but WITHOUT
11
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
# You should have received a copy of the GNU General Public License along
16
# with this program. If not, see <http://www.gnu.org/licenses/>.
2
18
import roslib; roslib.load_manifest('sr_control_gui')
17
33
QtGui.QDialog.__init__(self, parent)
18
34
self.library = library
19
35
self.treeitem = treeitem
21
37
self.setWindowTitle(title)
22
38
self.setModal(True)
24
40
dialog_frame = QtGui.QFrame(self)
25
41
dialog_layout = QtGui.QGridLayout()
27
43
label_login = QtGui.QLabel(dialog_frame)
28
44
label_login.setText("Login: ")
29
self.login_input = QtGui.QLineEdit(dialog_frame)
45
self.login_input = QtGui.QLineEdit(dialog_frame)
30
46
dialog_layout.addWidget(label_login, 0, 0)
31
dialog_layout.addWidget(self.login_input, 0, 1)
47
dialog_layout.addWidget(self.login_input, 0, 1)
33
49
dialog_frame.connect(self.login_input, QtCore.SIGNAL('textChanged(QString)'),
34
50
self.login_changed)
36
52
label_pwd = QtGui.QLabel(dialog_frame)
37
53
label_pwd.setText("Password: ")
38
54
self.pwd_input = QtGui.QLineEdit(dialog_frame)
39
55
self.pwd_input.setEchoMode(QtGui.QLineEdit.Password)
40
56
dialog_layout.addWidget(label_pwd, 1, 0)
41
57
dialog_layout.addWidget(self.pwd_input, 1, 1)
43
59
dialog_frame.connect(self.pwd_input, QtCore.SIGNAL('textChanged(QString)'),
46
62
dialog_frame.setLayout(dialog_layout)
48
btn_frame = QtGui.QFrame()
64
btn_frame = QtGui.QFrame()
49
65
self.btn_ok = QtGui.QPushButton(btn_frame)
50
66
self.btn_ok.setText("OK")
51
67
self.btn_ok.setDisabled(True)
53
69
btn_cancel = QtGui.QPushButton(btn_frame)
54
70
btn_cancel.setText("Cancel")
55
71
self.connect(btn_cancel, QtCore.SIGNAL("clicked()"), self.reject)
57
73
btn_layout = QtGui.QHBoxLayout()
58
74
btn_layout.addWidget(self.btn_ok)
59
75
btn_layout.addWidget(btn_cancel)
60
76
btn_frame.setLayout(btn_layout)
62
78
layout = QtGui.QVBoxLayout()
63
79
layout.addWidget(dialog_frame)
64
80
layout.addWidget(btn_frame)
65
81
self.setLayout(layout)
69
85
def login_changed(self, login):
71
87
if str(self.pwd_input.text()) != "":
72
88
self.btn_ok.setEnabled(True)
74
90
self.btn_ok.setDisabled(True)
76
92
def pwd_changed(self, pwd):
78
94
if str(self.login_input.text()) != "":
79
95
self.btn_ok.setEnabled(True)
81
97
self.btn_ok.setDisabled(True)
84
100
cursor = Qt.QCursor()
85
101
cursor.setShape(QtCore.Qt.WaitCursor)
86
102
self.setCursor(cursor)
88
104
login = str(self.login_input.text())
89
105
pwd = str(self.pwd_input.text())
91
107
good_pwd = self.library.test_login_pwd(login, pwd)
94
110
self.library.login = login
95
111
self.library.password = pwd
99
115
rospy.logerr("Wrong password - setting local IP")
100
116
cursor.setShape(QtCore.Qt.ArrowCursor)
101
117
self.setCursor(cursor)
105
121
cursor.setShape(QtCore.Qt.ArrowCursor)
106
122
self.setCursor(cursor)
107
123
#restarting the timer
108
124
self.treeitem.timer.start()
109
125
QtGui.QDialog.accept(self)
111
127
def reject(self):
112
128
self.library.set_local_ip()
113
129
self.treeitem.setData(3, QtCore.Qt.DisplayRole, self.library.hostname)
114
130
self.treeitem.reboot_computer_action.setDisabled(True)
115
131
self.treeitem.setIcon(0, QtGui.QIcon(self.library.icon_local_path))
117
133
QtGui.QDialog.reject(self)
119
135
class LibraryItem(QtGui.QTreeWidgetItem):
129
145
self.library = library
130
146
self.parent = parent
131
147
QtGui.QTreeWidgetItem.__init__(self, data)
133
149
self.setIcon(1, QtGui.QIcon(self.library.icon_library_path))
134
150
self.menu = QtGui.QMenu(data[0])
136
152
self.green = QtGui.QColor(153, 231, 96)
137
153
self.red = QtGui.QColor(236, 178, 178)
138
154
self.bright_red = QtGui.QColor(255, 78, 78)
139
155
self.orange = QtGui.QColor(253, 166, 15)
141
157
self.start_lib = QtGui.QAction('Start', self.menu)
142
158
self.menu.connect(self.start_lib, QtCore.SIGNAL('triggered()'), self.start_library)
144
160
self.stop_lib = QtGui.QAction('Stop', self.menu)
145
161
self.menu.connect(self.stop_lib, QtCore.SIGNAL('triggered()'), self.stop_library)
147
163
self.reboot_computer_action = QtGui.QAction('Reboot the computer', self.menu)
148
164
self.menu.connect(self.reboot_computer_action, QtCore.SIGNAL('triggered()'), self.reboot_computer)
150
166
self.edit_ip_action = QtGui.QAction('Modify the IP address', self.menu)
151
167
self.menu.connect(self.edit_ip_action, QtCore.SIGNAL('triggered()'), self.edit_ip)
153
169
if self.library.is_local:
154
170
self.reboot_computer_action.setDisabled(True)
155
171
self.setIcon(0, QtGui.QIcon(self.library.icon_local_path))
157
173
self.menu.addAction(self.start_lib)
158
174
self.menu.addAction(self.stop_lib)
159
175
self.menu.addSeparator()
160
176
self.menu.addAction(self.reboot_computer_action)
161
177
self.menu.addSeparator()
162
178
self.menu.addAction(self.edit_ip_action)
164
180
self.error_starting_stopping_status = ""
165
181
self.error_starting_stopping_timer = QtCore.QTimer(parent)
166
182
parent.connect(self.error_starting_stopping_timer, QtCore.SIGNAL('timeout()'),
167
183
self.check_error_starting_stopping)
168
184
self.error_starting_stopping_timer.setSingleShot(True)
169
185
self.error_starting_stopping_timer.setInterval(Config.library_timeout * 1000)
171
187
self.timer = QtCore.QTimer(parent)
172
188
parent.connect(self.timer, QtCore.SIGNAL('timeout()'), self.refresh_status)
173
189
self.timer.setInterval(1000 / Config.library_refresh_rate)
174
190
self.timer.start()
176
192
def edit_ip(self):
177
193
self.setFlags(self.flags() | QtCore.Qt.ItemIsEditable)
178
194
self.parent.editItem(self, 3)
180
196
def check_error_starting_stopping(self):
182
198
self.library.status = "Error"
198
214
self.start_lib.setDisabled(True)
199
215
self.stop_lib.setDisabled(True)
200
216
self.setBackgroundColor(2, QtGui.QColor(self.orange))
202
218
if current_status == "started":
203
219
if self.error_starting_stopping_timer.isActive():
204
220
if self.error_starting_stopping_status == "starting":
205
221
self.error_starting_stopping_timer.stop()
206
222
self.start_lib.setDisabled(True)
207
223
self.stop_lib.setEnabled(True)
209
225
self.setBackgroundColor(2, QtGui.QColor(self.green))
210
226
if current_status == "stopped":
211
227
if self.error_starting_stopping_timer.isActive():
262
278
self.setIcon(0, QtGui.QIcon(self.library.icon_local_path))
264
280
LoginForm(self.parent, self, self.library.hostname + " login", self.library)
266
282
cursor.setShape(QtCore.Qt.ArrowCursor)
267
283
self.parent.setCursor(cursor)
270
286
self.timer.stop()
272
288
self.library.ssh_client.close()
274
290
#the ssh client was already closed. Do nothing
277
293
class LibrariesWidget(QtGui.QWidget):
279
295
Add the correct library to the libraries dict. And contains the QTreeWidget which will display
282
298
def __init__(self, parent, backend):
283
299
QtGui.QWidget.__init__(self, parent=parent)
285
301
layout = QtGui.QHBoxLayout()
287
303
list_frame = QtGui.QFrame(self)
288
304
listframe_layout = QtGui.QVBoxLayout()
290
306
self.robot_and_libraries_backend = backend
292
308
self.robot_and_libraries_backend.add_library(Config.library_shadowhand.name,
293
309
list_of_nodes=Config.library_shadowhand.list_of_nodes,
294
310
start_cmd=Config.library_shadowhand.start_cmd,
295
311
stop_cmd=Config.library_shadowhand.stop_cmd,
296
312
status_cmd=Config.library_shadowhand.status_cmd,
297
313
root_path=self.parent().parent().rootPath)
299
315
self.robot_and_libraries_backend.add_library(Config.library_shadow_arm_hand.name,
300
316
list_of_nodes=Config.library_shadow_arm_hand.list_of_nodes,
301
317
start_cmd=Config.library_shadow_arm_hand.start_cmd,
302
318
stop_cmd=Config.library_shadow_arm_hand.stop_cmd,
303
319
status_cmd=Config.library_shadow_arm_hand.status_cmd,
304
320
root_path=self.parent().parent().rootPath)
306
322
self.robot_and_libraries_backend.add_library(Config.library_cyberglove.name,
307
323
list_of_nodes=Config.library_cyberglove.list_of_nodes,
308
324
start_cmd=Config.library_cyberglove.start_cmd,
309
325
stop_cmd=Config.library_cyberglove.stop_cmd,
310
326
status_cmd=Config.library_cyberglove.status_cmd,
311
327
root_path=self.parent().parent().rootPath)
313
329
self.robot_and_libraries_backend.add_library(Config.library_cyberglove_remapper.name,
314
330
list_of_nodes=Config.library_cyberglove_remapper.list_of_nodes,
315
331
start_cmd=Config.library_cyberglove_remapper.start_cmd,
316
332
stop_cmd=Config.library_cyberglove_remapper.stop_cmd,
317
333
status_cmd=Config.library_cyberglove_remapper.status_cmd,
318
334
root_path=self.parent().parent().rootPath)
320
336
self.robot_and_libraries_backend.add_robot(Config.robot_code.name,
321
337
root_path=self.parent().parent().rootPath)
323
339
self.tree = QtGui.QTreeWidget()
324
340
self.tree.setEditTriggers(Qt.QAbstractItemView.DoubleClicked)
326
342
self.tree.setHeaderLabels(["", "ROS Nodes / Robot Code", "Status", "Computer", "Info"])
330
346
for lib in self.robot_and_libraries_backend.libraries.values():
331
347
self.items.append(LibraryItem(lib, self.tree))
333
349
self.tree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
334
350
self.connect(self.tree,
335
351
QtCore.SIGNAL("customContextMenuRequested(const QPoint &)"),
336
self.showContextMenu)
352
self.showContextMenu)
338
354
self.connect(self.tree, QtCore.SIGNAL('itemDoubleClicked (QTreeWidgetItem *, int)'),
340
356
for item in self.items:
341
357
self.tree.addTopLevelItem(item)
342
358
listframe_layout.addWidget(self.tree)
344
360
self.tree.resizeColumnToContents(0)
345
361
self.tree.resizeColumnToContents(1)
346
362
self.tree.resizeColumnToContents(4)
347
363
#don't resize col 2 and 3 as they contain dynamic content
349
365
list_frame.setLayout(listframe_layout)
351
367
layout.addWidget(list_frame)
361
377
point.setY(point.y() + 30)
362
378
point = self.tree.mapToGlobal(point)
363
379
item.showContextMenu(point)
366
382
for item in self.items:
369
385
QtGui.QWidget.close(self)
371
387
class RobotsWidget(QtGui.QWidget):
372
388
def __init__(self, parent):
373
389
QtGui.QWidget.__init__(self, parent=parent)
374
390
layout = QtGui.QVBoxLayout()
375
391
frame = QtGui.QFrame(self)
377
393
layout.addWidget(frame)
378
394
self.setLayout(layout)