/ lib / python / qtvcp / lib / message.py
message.py
  1  from PyQt5.QtWidgets import *
  2  from PyQt5.QtCore import Qt
  3  from PyQt5.QtGui import QColor
  4  from qtvcp.core import Status, Info
  5  import hal
  6  
  7  # Set up logging
  8  from qtvcp import logger
  9  log = logger.getLogger(__name__)
 10  
 11  # Instantiate the libraries with global reference
 12  # STATUS gives us status messages from linuxcnc
 13  STATUS = Status()
 14  INFO = Info()
 15  
 16  class Message:
 17      def __init__(self):
 18          self.OK_TYPE = 1
 19          self.YN_TYPE = 0
 20          self.QUESTION = QMessageBox.Question
 21          self.INFO = QMessageBox.Information
 22          self.WARNING = QMessageBox.Warning
 23          self.CRITICAL = QMessageBox.Critical
 24          self._color = QColor(0, 0, 0, 150)
 25          self.focus_text =' '
 26          self.play_sounds = True
 27          self.alert_sound = 'READY'
 28          self.use_focus_overlay = True
 29  
 30      def showDialog(self, message, more_info=None, details=None, display_type=1,
 31                       icon=QMessageBox.Information, pinname=None):
 32          msg = QMessageBox()
 33          msg.setWindowModality(Qt.ApplicationModal)
 34          msg.setIcon(icon)
 35          msg.setWindowTitle("User MessageBox")
 36          msg.setTextFormat(Qt.RichText)
 37          msg.setText('<b>%s</b>'% message)
 38          if more_info:
 39              msg.setInformativeText(more_info)
 40          if details:
 41              msg.setDetailedText(details)
 42          if display_type == self.OK_TYPE:
 43              msg.setStandardButtons(QMessageBox.Ok)
 44          else:
 45              msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
 46          msg.buttonClicked.connect(self.msgbtn)
 47          # block on answer
 48          retval = msg.exec_()
 49          log.debug('value of pressed message box button: {}'.format(retval))
 50          self.dialog_return(None,retval==QMessageBox.Yes,display_type,pinname)
 51  
 52      def msgbtn(self, i):
 53          pass
 54          #print "Button pressed is:",i.text()
 55  
 56      # This is part of the user message system
 57      # There is status that prints to the status bar
 58      # There is Okdialog that prints a dialog that the user must acknoledge
 59      # there is yes/no dialog where the user must choose between yes or no
 60      # you can combine status and dialog messages so they print to the status bar 
 61      # and pop a dialog
 62      def on_printmessage(self, pin, pinname, boldtext, text, details, type, icon):
 63          if not pin.get(): return
 64          if self.play_sounds:
 65              STATUS.emit('play-sound',self.alert_sound)
 66          if boldtext == "NONE": boldtext = ''
 67          if "status" in type:
 68              if boldtext:
 69                  statustext = boldtext
 70              else:
 71                  statustext = text
 72              if self.NOTIFY:
 73                  self.NOTIFY.notify(_("INFO:"),statustext)
 74          if "dialog" in type or "okdialog" in type:
 75              if self.use_focus_overlay:
 76                  STATUS.emit('focus-overlay-changed', True, self.focus_text, self._color)
 77              if pin.get():
 78                  self.HAL_GCOMP_[pinname + "-waiting"] = True
 79              if "okdialog" in type:
 80                  self.showDialog(boldtext,text,details,self.OK_TYPE,icon,pinname)
 81              else:
 82                  if pin.get():
 83                      self.HAL_GCOMP_[pinname + "-response"] = 0
 84                  self.showDialog(boldtext,text,details,self.YN_TYPE,icon,pinname)
 85  
 86      # search for and set up user requested message system.
 87      # status displays on the statusbat and requires no acknowledge.
 88      # dialog displays a  Messagebox with yes or no buttons
 89      # okdialog displays a Messagebox with an ok button
 90      # dialogs require an answer before focus is sent back to main screen
 91      def message_setup(self, hal_comp):
 92          self.HAL_GCOMP_ = hal_comp
 93          icon = QMessageBox.Question
 94          if INFO.ZIPPED_USRMESS:
 95              for bt,t,d,style,name in (INFO.ZIPPED_USRMESS):
 96                  if not ("status" in style) and not ("dialog" in style) and not ("okdialog" in style):
 97                      log.debug('invalid message type {} in INI File [DISPLAY] section'.format(C))
 98                      continue
 99                  if not name == None:
100                      # this is how we make a pin that can be connected to a callback 
101                      self[name] = self.HAL_GCOMP_.newpin(name, hal.HAL_BIT, hal.HAL_IO)
102                      self[name].value_changed.connect(self.dummy(self[name],name,bt,t,d,style,icon))
103                      if ("dialog" in style):
104                          self.HAL_GCOMP_.newpin(name+"-waiting", hal.HAL_BIT, hal.HAL_OUT)
105                          if not ("ok" in style):
106                              self.HAL_GCOMP_.newpin(name+"-response", hal.HAL_BIT, hal.HAL_OUT)
107  
108      # a hacky way to adjust future options
109      # using it to adjust runtime options from a preference file in screenoptions (presently)
110      # 'with great power comes ....'
111      def message_option(self, option, data):
112          try:
113              self[option] = data
114          except:
115              pass
116  
117      # This weird code is so we can get access to proper variables.
118      # using clicked.connect( self.on_printmessage(pin,name,bt,t,c) ) apparently doesn't easily
119      # add user data - it seems you only get the last set added
120      # found this closure technique hack on the web
121      # truely weird black magic
122      def dummy(self,pin,name,bt,t,d,c,i):
123          def calluser():
124              self.on_printmessage(pin,name,bt,t,d,c,i)
125          return calluser
126  
127      # message dialog returns a response here
128      # update any hand shaking pins
129      def dialog_return(self,widget,result,dialogtype,pinname):
130          if not dialogtype: # yes/no dialog
131              if pinname:
132                  self.HAL_GCOMP_[pinname + "-response"] = result
133          if pinname:
134              self.HAL_GCOMP_[pinname + "-waiting"] = False
135          # reset the HAL IO pin so it can fire again
136          self.HAL_GCOMP_[pinname] = False
137          if self.use_focus_overlay:
138              STATUS.emit('focus-overlay-changed',False,None,None)
139  
140      ##############################
141      # required class boiler code #
142      ##############################
143  
144      def __getitem__(self, item):
145          return getattr(self, item)
146      def __setitem__(self, item, value):
147          return setattr(self, item, value)
148  
149  if __name__ == '__main__':
150      import sys
151      from PyQt5.QtCore import *
152      m = Message()
153      app = QApplication(sys.argv)
154      w = QWidget()
155      b = QPushButton(w)
156      b.setText("Show Y/N\n message!")
157      b.move(10,0)
158      b.clicked.connect(lambda data: m.showdialog('This is a question message',
159           more_info='Pick yes or no', icon=m.QUESTION, display_type=m.YN_TYPE))
160  
161      c = QPushButton(w)
162      c.setText("Show OK\n message!")
163      c.move(10,40)
164      c.clicked.connect(lambda data: m.showdialog('This is an OK message', display_type=1))
165  
166      d = QPushButton(w)
167      d.setText("Show critical\n message!")
168      d.move(10,80)
169      d.clicked.connect(lambda data: m.showdialog('This is an Critical message',
170              details='There seems to be something wrong', icon=m.CRITICAL, display_type=1))
171  
172      w.setWindowTitle("PyQt Dialog demo")
173      w.setGeometry(300, 300, 300, 150)
174      w.show()
175      sys.exit(app.exec_())