00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 __facility__ = "Online"
00011 __abstract__ = "GLAST LAT Message Logger GUI"
00012 __author__ = """A. Kavelaars <AliciaK@SLAC.Stanford.edu>
00013 SLAC - GLAST LAT I&T/Online"""
00014 __date__ = "2005/07/23 00:08:27"
00015 __updated__ = "$Date: 2006/04/26 20:46:39 $"
00016 __version__ = "$Revision: 1.6 $"
00017 __release__ = "$Name: HEAD $"
00018 __credits__ = "SLAC"
00019
00020 import LICOS.copyright_SLAC
00021
00022
00023 from qt import *
00024 from MSGLogGUI import MSGLogGUI
00025 from select import select
00026 import sys, string, struct, types, cPickle, socket
00027 import logging, logging.handlers, logging.config
00028 logging.raiseExceptions = 1
00029 import threading
00030 import atexit
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 imageInfo_data = [
00047 "20 18 3 1",
00048 "# c #000080",
00049 "a c #808080",
00050 ". c #ffffff",
00051 ".......######.......",
00052 ".....##########.....",
00053 "....############....",
00054 "...######..######...",
00055 "..#######..#######..",
00056 "..################..",
00057 ".##################.",
00058 ".########..########.",
00059 ".########..########.",
00060 ".########..########.",
00061 ".########..########.",
00062 "..#######..#######a.",
00063 "..#######..#######..",
00064 "..a######..######a..",
00065 "...a############a...",
00066 "....a##########a....",
00067 ".....aa######aa.....",
00068 ".......aaaaaa......."
00069 ]
00070
00071 imageFatal_data = [
00072 "20 18 19 1",
00073 "p c #004040",
00074 "b c #484242",
00075 "d c #5e4f4f",
00076 "j c #675656",
00077 "m c #685151",
00078 "g c #695555",
00079 "a c #808080",
00080 "h c #cddcdc",
00081 "e c #cedcdc",
00082 "k c #d4e1e1",
00083 "n c #e1eded",
00084 "q c #ebefef",
00085 "i c #ecf6f6",
00086 "f c #edf7f7",
00087 "l c #f1fafa",
00088 "o c #f2f6f6",
00089 "c c #f3fcfc",
00090 "# c #ff0000",
00091 ". c #ffffff",
00092 "......########......",
00093 ".....##########.....",
00094 "....############....",
00095 "...#####....#####...",
00096 "..#####......#####..",
00097 ".#####........#####.",
00098 ".####..aa..aa..####.",
00099 ".####...a..a...####.",
00100 ".####..........####.",
00101 ".#####...aa...#####.",
00102 ".######......######.",
00103 ".a######.aa.######a.",
00104 ".ba#####....#####aa.",
00105 ".cda####....####aae.",
00106 "..fga##########aah..",
00107 "...ija########aak...",
00108 "....lmaaaaaaaaan....",
00109 ".....oppppppppq....."
00110 ]
00111
00112 imageWarn_data = [
00113 "20 18 4 1",
00114 "a c #004040",
00115 "b c #808080",
00116 "# c #ffff00",
00117 ". c #ffffff",
00118 ".........##.........",
00119 "........####........",
00120 "........####........",
00121 ".......######.......",
00122 ".......##aa##.......",
00123 "......###aa###......",
00124 "......###aa###......",
00125 ".....####aa####.....",
00126 ".....####aa####.....",
00127 "....#####aa#####....",
00128 "....#####aa#####....",
00129 "...######aa######...",
00130 "...##############...",
00131 "..################..",
00132 "..#######aa#######..",
00133 ".########aa########.",
00134 ".##################.",
00135 "..bbbbbbbbbbbbbbbbb."
00136 ]
00137
00138 imageError_data = [
00139 "20 18 3 1",
00140 "a c #808080",
00141 "# c #ff0000",
00142 ". c #ffffff",
00143 ".......######.......",
00144 ".....##########.....",
00145 "....############....",
00146 "...##############...",
00147 "..###..#####..####..",
00148 "..###...###...####..",
00149 ".#####...#...######.",
00150 ".######.....#######.",
00151 ".#######...########.",
00152 ".######.....#######.",
00153 ".#####...#...######.",
00154 ".a###...###...####a.",
00155 "..###..#####..####..",
00156 "..a##############a..",
00157 "...a############a...",
00158 "....a##########a....",
00159 ".....aa######aa.....",
00160 ".......aaaaaa......."
00161 ]
00162
00163 imageNotset_data = [
00164 "20 18 19 1",
00165 "p c #004040",
00166 "# c #008000",
00167 "b c #484242",
00168 "d c #5e4f4f",
00169 "j c #675656",
00170 "m c #685151",
00171 "g c #695555",
00172 "a c #808080",
00173 "h c #cddcdc",
00174 "e c #cedcdc",
00175 "k c #d4e1e1",
00176 "n c #e1eded",
00177 "q c #ebefef",
00178 "i c #ecf6f6",
00179 "f c #edf7f7",
00180 "l c #f1fafa",
00181 "o c #f2f6f6",
00182 "c c #f3fcfc",
00183 ". c #ffffff",
00184 "......########......",
00185 ".....##########.....",
00186 "....#####..#####....",
00187 "...######..######...",
00188 "..#######..#######..",
00189 ".########..########.",
00190 ".########..########.",
00191 ".########..########.",
00192 ".########..########.",
00193 ".########..########.",
00194 ".##################.",
00195 ".a################a.",
00196 ".ba######..######aa.",
00197 ".cda#####..#####aae.",
00198 "..fga##########aah..",
00199 "...ija########aak...",
00200 "....lmaaaaaaaaan....",
00201 ".....oppppppppq....."
00202 ]
00203
00204 imageDebug_data = [
00205 "20 18 19 1",
00206 "p c #004040",
00207 "b c #484242",
00208 "d c #5e4f4f",
00209 "j c #675656",
00210 "m c #685151",
00211 "g c #695555",
00212 "a c #808080",
00213 "# c #c0c0c0",
00214 "h c #cddcdc",
00215 "e c #cedcdc",
00216 "k c #d4e1e1",
00217 "n c #e1eded",
00218 "q c #ebefef",
00219 "i c #ecf6f6",
00220 "f c #edf7f7",
00221 "l c #f1fafa",
00222 "o c #f2f6f6",
00223 "c c #f3fcfc",
00224 ". c #ffffff",
00225 "......########......",
00226 ".....##########.....",
00227 "....#####..#####....",
00228 "...######..######...",
00229 "..################..",
00230 ".##################.",
00231 ".########..########.",
00232 ".########..########.",
00233 ".########..########.",
00234 ".########..########.",
00235 ".########..########.",
00236 ".a#######..#######a.",
00237 ".ba######..######aa.",
00238 ".cda#####..#####aae.",
00239 "..fga##########aah..",
00240 "...ija########aak...",
00241 "....lmaaaaaaaaan....",
00242 ".....oppppppppq....."
00243 ]
00244
00245
00246 from SocketServer import ThreadingTCPServer, StreamRequestHandler
00247 import errno
00248 import select
00249
00250
00251 MAX_ENTRIES = 9000
00252 DELETE_ENTRIES = 100
00253
00254 class LogRecordStreamHandler(StreamRequestHandler):
00255 """!\brief Handler for a streaming logging request.
00256
00257 It basically logs the record
00258 using whatever logging policy is configured locally.
00259
00260 """
00261
00262 def handle(self):
00263 """!\brief Handle multiple requests.
00264
00265 Handle multiple requests - each expected to be a 4-byte length,
00266 followed by the LogRecord in pickle format. Logs the record
00267 according to whatever policy is configured locally.
00268
00269 """
00270 while 1:
00271 try:
00272 chunk = self.connection.recv(4)
00273 if len(chunk) < 4:
00274 break
00275 slen = struct.unpack(">L", chunk)[0]
00276
00277 chunk = self.connection.recv(slen)
00278 while len(chunk) < slen:
00279 chunk = chunk + self.connection.recv(slen - len(chunk))
00280 obj = self.unPickle(chunk)
00281 record = logging.makeLogRecord(obj)
00282
00283
00284 self.handleLogRecord(record)
00285 except socket.error, e:
00286 if type(e.args) != types.TupleType:
00287 raise e
00288 else:
00289 errcode = e.args[0]
00290 if errcode != errno.ECONNRESET:
00291 raise e
00292 break
00293
00294 def unPickle(self, data):
00295 """!\brief Unpickle incoming log packet
00296
00297 \param data Log packet
00298
00299 \return Unpickled log packet
00300 """
00301 return cPickle.loads(data)
00302
00303 def handleLogRecord(self, record):
00304 """!\brief Process the log record.
00305
00306 Send the log record to the GUI class for processing.
00307
00308 \param record Log record
00309
00310 """
00311
00312
00313
00314
00315 if self.server.logname is not None:
00316 name = self.server.logname
00317 else:
00318 name = record.name
00319 logger = logging.getLogger(name)
00320
00321
00322
00323
00324
00325 self.server.gui.appendLogData(logger.handlers[0].format(record))
00326
00327
00328 class MSGLogSocketReceiver(ThreadingTCPServer):
00329 """!\brief Socket server class for receiving log packets.
00330
00331 """
00332 allow_reuse_address = 1
00333
00334 def __init__(self, gui, host='', port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
00335 handler=LogRecordStreamHandler):
00336 """!\brief MSGLogSocketReceiver constructor.
00337
00338 \param gui Message logger GUI
00339 \param host Host to listen to (If blank it receives data from any host)
00340 \param port Logging port
00341 \param handler Handler class
00342 """
00343 ThreadingTCPServer.__init__(self, (host, port), handler)
00344 self.__abort = 0
00345 self.timeout = 1
00346 self.logname = None
00347 self.gui = gui
00348 self.handler = handler
00349
00350 def abort(self):
00351 """!\brief Stop listening for logs
00352
00353 """
00354 self.__abort = 1
00355
00356 def serve_until_stopped(self):
00357 """!\brief Main listen loop
00358
00359 """
00360 while not self.__abort:
00361 rd, wr, ex = select.select([self.socket.fileno()],
00362 [], [],
00363 self.timeout)
00364 if rd:
00365 self.handle_request()
00366
00367 class MSGLogGUIImpl(MSGLogGUI):
00368 """!\brief Message Logger GUI
00369
00370 """
00371 def __init__(self, port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
00372 updateInterval=100, parent = None,name = None,fl = 0):
00373 """!\brief MSGLogGUIImpl constructor
00374
00375 \param port Logging port
00376 \param updateInterval The interval the the GUI will check for new log entries
00377 \param parent Parent GUI
00378 \param name Name
00379 \param fl Flags
00380
00381 """
00382 MSGLogGUI.__init__(self,parent,name,fl)
00383
00384 self.__secure = 0
00385 self.__timer = QTimer(self)
00386 QObject.connect(self.__timer, SIGNAL("timeout()"), self.addLogDataToView)
00387 self.__updateInterval = updateInterval
00388 self.__timer.start(self.__updateInterval)
00389 self.__port = port
00390 self.__level = 0
00391 self.__filename = None
00392 self.printer = QPrinter()
00393 self.filename = QString.null
00394 self.tcpserver = None
00395 self.__logname = "MSGLogger"
00396 self.__logData = []
00397 self.__logList = []
00398 self.__count = 0
00399 self.__previousMSG = ["","","",""]
00400 self.__previousMSGcut = ["",""]
00401
00402 self.imageFatal = QPixmap(imageFatal_data)
00403 self.imageError = QPixmap(imageError_data)
00404 self.imageWarn = QPixmap(imageWarn_data)
00405 self.imageInfo = QPixmap(imageInfo_data)
00406 self.imageDebug = QPixmap(imageDebug_data)
00407 self.imageNotset = QPixmap(imageNotset_data)
00408
00409 self.connect(self.filterbyCritical,SIGNAL("activated()"),self.levelCritical)
00410 self.connect(self.filterbyFatal,SIGNAL("activated()"),self.levelFatal)
00411 self.connect(self.filterbyError,SIGNAL("activated()"),self.levelError)
00412 self.connect(self.filterbyWarn,SIGNAL("activated()"),self.levelWarn)
00413 self.connect(self.filterbyInfo,SIGNAL("activated()"),self.levelInfo)
00414 self.connect(self.filterbyDebug,SIGNAL("activated()"),self.levelDebug)
00415 self.connect(self.filterbyNotset,SIGNAL("activated()"),self.levelNotset)
00416 self.connect(self.noFilter,SIGNAL("activated()"),self.levelNoFilter)
00417
00418
00419 self.connect(self.Logger,SIGNAL("currentChanged(QListViewItem*)"),self.showEntries)
00420
00421 self.connect(self.RunningLogButton,SIGNAL("clicked()"),self.switchToRunningLog)
00422 self.connect(self.FileLogButton,SIGNAL("clicked()"),self.fileOpen)
00423
00424 self.contextMenu = QPopupMenu( self )
00425 self.contextMenu.insertItem( "&Copy", self.copyToClipboard, Qt.CTRL+Qt.Key_C)
00426 self.contextMenu.insertItem( "Copy Whole &Row", self.copyRowToClipboard, Qt.CTRL+Qt.Key_R)
00427 self.clip = QApplication.clipboard()
00428
00429 QObject.connect(self.Logger,
00430 SIGNAL("contextMenuRequested(QListViewItem*,const QPoint&,int)"),
00431 self.contextMenuShow
00432 )
00433
00434
00435 atexit.register(self.__shutdown)
00436
00437 self.__hdlr = logging.StreamHandler()
00438 fmt = logging.Formatter("%(asctime)s %(filename)s:%(lineno)d %(levelname)-5s - %(message)s")
00439 self.__hdlr.setFormatter(fmt)
00440 logger = logging.getLogger(self.__logname)
00441 logger.addHandler(self.__hdlr)
00442
00443
00444 self.Logger.setColumnAlignment(0, Qt.AlignLeft | Qt.AlignVCenter)
00445 self.Logger.header().setMovingEnabled(0)
00446
00447 self.Logger.setSorting(-1,1)
00448
00449
00450
00451
00452
00453
00454
00455
00456 logging.addLevelName(60, 'ALERT')
00457 logging.ALERT = 60
00458
00459 def preventSaturation(self):
00460 """!\brief Make sure we don't exceed MAX_ENTRIES.
00461
00462 """
00463 if self.Logger.childCount() >= MAX_ENTRIES:
00464
00465 self.__timer.stop()
00466 item = self.Logger.firstChild()
00467 count = 0
00468 while (count < DELETE_ENTRIES):
00469 if QString.compare(item.text(0),'CRITICAL') != 0 and QString.compare(item.text(0),'FATAL') != 0 :
00470 count += 1
00471 if count >= self.Logger.childCount(): break
00472 saveItem = item.nextSibling()
00473 self.Logger.takeItem(item)
00474 item = saveItem
00475 else:
00476 item = item.nextSibling()
00477
00478
00479 self.__timer.start(self.__updateInterval)
00480
00481 def showEntries(self):
00482 """!\brief Show number of entries in status bar.
00483
00484 """
00485 self.statusBar().message('Number of entries: ' + str(self.Logger.childCount()))
00486
00487 def preventCheck(self):
00488 """!\brief Ask user for acknowledgment for critical and fatal log entries.
00489
00490 """
00491 item = self.Logger.currentItem()
00492 if item is not None:
00493 if item.isOn():
00494 if QString.compare(item.text(0),'CRITICAL') == 0 or QString.compare(item.text(0),'FATAL') == 0 :
00495 self.statusBar().message('CRITICAL or FATAL error: Uncheck to Acknowledge',2000)
00496 else:
00497 self.statusBar().message('CRITICAL and FATAL errors check boxes ONLY are enabled to be acknowledged',2500)
00498 item.setOn(0)
00499
00500 def appendLogData(self, data):
00501 """!\brief Append the log to the buffer.
00502
00503 \param data Log data
00504
00505 """
00506 self.__logData.append(data)
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 def switchToRunningLog(self):
00520 """!\brief Switch from a file based or static view to running log view.
00521
00522 """
00523 self.LogType.setText("Active Run Control Log")
00524 self.Logger.clear()
00525
00526 self.addLogDataToView()
00527 if not self.runTCPThread.isAlive():
00528 self.startListenerThread()
00529
00530
00531
00532
00533 def abortListenerThread(self):
00534 """!\brief Abort the listener thread before loading a file
00535
00536 """
00537 if self.runTCPThread.isAlive():
00538 self.tcpserver.abort()
00539 self.runTCPThread.join()
00540
00541
00542 def startListenerThread(self):
00543 """!\brief Start the listener thread.
00544
00545 """
00546 self.Logger.clear()
00547 self.LogType.setText("Active Run Control Log")
00548 self.LogType.setAlignment(QLineEdit.AlignLeft)
00549
00550 self.tcpserver = MSGLogSocketReceiver(self, host='', port=self.__port)
00551 self.tcpserver.logname = self.__logname
00552 self.runTCPThread = threading.Thread(target=self.runTCP, name=self.__logname, args=(self.tcpserver,))
00553 self.runTCPThread.start()
00554
00555
00556 def runTCP(self, tcpserver):
00557 """!\brief Start the main listen loop.
00558
00559 \param tcpserver MSGLogSocketReceiver instance
00560
00561 """
00562 try:
00563 tcpserver.serve_until_stopped()
00564 finally:
00565 tcpserver.server_close()
00566
00567
00568 def clearLevels(self):
00569 """!\brief Clear filter levels.
00570
00571 """
00572 self.filterbyCritical.setOn(0)
00573 self.filterbyError.setOn(0)
00574 self.filterbyInfo.setOn(0)
00575 self.filterbyDebug.setOn(0)
00576 self.filterbyNotset.setOn(0)
00577 self.filterbyFatal.setOn(0)
00578 self.filterbyWarn.setOn(0)
00579 self.noFilter.setOn(0)
00580
00581 def levelCritical(self):
00582 """!\brief Filter by critical level
00583
00584 """
00585 self.clearLevels()
00586 self.filterbyCritical.setOn(1)
00587 self.__level = logging.CRITICAL
00588
00589 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00590 self.switchToRunningLog()
00591 else:
00592 self.load( )
00593
00594 def levelFatal(self):
00595 """!\brief Filter by fatal level
00596
00597 """
00598 self.clearLevels()
00599 self.filterbyFatal.setOn(1)
00600 self.__level = logging.CRITICAL
00601 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00602 self.switchToRunningLog()
00603 else:
00604 self.load( )
00605
00606 def levelError(self):
00607 """!\brief Filter by error level
00608
00609 """
00610 self.clearLevels()
00611 self.filterbyError.setOn(1)
00612 self.__level = logging.ERROR
00613 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00614 self.switchToRunningLog()
00615 else:
00616 self.load( )
00617
00618 def levelWarn(self):
00619 """!\brief Filter by warning level
00620
00621 """
00622 self.clearLevels()
00623 self.filterbyWarn.setOn(1)
00624 self.__level = logging.WARN
00625 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00626 self.switchToRunningLog()
00627 else:
00628 self.load( )
00629
00630 def levelInfo(self):
00631 """!\brief Filter by info level
00632
00633 """
00634 self.clearLevels()
00635 self.filterbyInfo.setOn(1)
00636 self.__level = logging.INFO
00637 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00638 self.switchToRunningLog()
00639 else:
00640 self.load( )
00641
00642 def levelDebug(self):
00643 """!\brief Filter by debug level
00644
00645 """
00646 self.clearLevels()
00647 self.filterbyDebug.setOn(1)
00648 self.__level = logging.DEBUG
00649 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00650 self.switchToRunningLog()
00651 else:
00652 self.load( )
00653
00654 def levelNotset(self):
00655 """!\brief Filter by notset level
00656
00657 """
00658 self.clearLevels()
00659 self.filterbyNotset.setOn(1)
00660 self.__level = logging.NOTSET
00661 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00662 self.switchToRunningLog()
00663 else:
00664 self.load( )
00665
00666 def levelNoFilter(self):
00667 """!\brief Clear filter
00668
00669 """
00670 self.clearLevels()
00671 self.noFilter.setOn(1)
00672 self.__level = logging.NOTSET
00673 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00674
00675 self.switchToRunningLog()
00676 else:
00677 self.load( )
00678
00679 def setListViewItem(self, data):
00680 """!\brief Parse and convert the message log data to a listview item
00681
00682 \param data Message log data
00683 """
00684
00685
00686
00687
00688
00689
00690
00691 level = self.__level
00692
00693 p = data.rstrip()
00694
00695 s = string.splitfields(p)
00696 temps = string.splitfields(p)
00697 r = string.splitfields(p, ' - ',3)
00698
00699
00700
00701
00702 if temps[3] == 'FATAL':
00703 temps[3] = 'CRITICAL'
00704
00705 if logging._levelNames[temps[3]] >= level:
00706 if s[2] == self.__previousMSG[2] and s[3] == self.__previousMSG[3] \
00707 and r[1] == self.__previousMSGcut:
00708
00709 self.__count += 1
00710
00711 else:
00712 if self.__count >= 3:
00713 messageItem = QListViewItem( self.Logger,self.Logger.lastItem())
00714
00715 messageItem.setText( 0, self.__previousMSG[3])
00716 messageItem.setText( 2, self.__previousMSG[0])
00717 messageItem.setText( 3, self.__previousMSG[1])
00718 messageItem.setText( 4, self.__previousMSG[2])
00719
00720
00721 self.__countMSG = "The previous message was repeated " + str(self.__count) + " time(s)."
00722 messageItem.setText(1, self.__countMSG)
00723
00724 if self.__previousMSG[3] == 'CRITICAL' or \
00725 self.__previousMSG[3] == 'FATAL' or \
00726 self.__previousMSG[3] == 'ALERT':
00727 messageItem.setPixmap(0, self.imageFatal)
00728 messageItem.setOn(1)
00729
00730 elif self.__previousMSG[3] == 'ERROR':
00731 messageItem.setPixmap(0, self.imageError)
00732
00733 elif self.__previousMSG[3] == 'WARNING':
00734 messageItem.setPixmap(0, self.imageWarn)
00735
00736 elif self.__previousMSG[3] == 'INFO':
00737 messageItem.setPixmap(0, self.imageInfo)
00738
00739 elif self.__previousMSG[3] == 'DEBUG':
00740 messageItem.setPixmap(0, self.imageDebug)
00741
00742 elif self.__previousMSG[3] == 'NOTSET':
00743 messageItem.setPixmap(0, self.imageNotset)
00744 self.__count = 0
00745
00746 item = QListViewItem( self.Logger, self.Logger.lastItem())
00747
00748 item.setText( 0, s[3])
00749 item.setText( 2, s[0])
00750 item.setText( 3, s[1])
00751 item.setText( 4, s[2])
00752
00753
00754
00755 item.setText(1, r[1])
00756 if r[1].find('\n') != -1:
00757 item.setMultiLinesEnabled(1)
00758
00759 if s[3] == 'ALERT':
00760 item.setPixmap(0, self.imageFatal)
00761 item.setOn(1)
00762 self.handleAlert(s)
00763
00764 elif s[3] == 'CRITICAL' or s[3] == 'FATAL':
00765 item.setPixmap(0, self.imageFatal)
00766 item.setOn(1)
00767
00768 elif s[3] == 'ERROR':
00769 item.setPixmap(0, self.imageError)
00770
00771 elif s[3] == 'WARNING':
00772 item.setPixmap(0, self.imageWarn)
00773
00774 elif s[3] == 'INFO':
00775 item.setPixmap(0, self.imageInfo)
00776
00777 elif s[3] == 'DEBUG':
00778 item.setPixmap(0, self.imageDebug)
00779
00780 elif s[3] == 'NOTSET':
00781 item.setPixmap(1, self.imageNotset)
00782
00783 self.__previousMSG = s
00784 self.__previousMSGcut = r[1]
00785
00786 self.preventSaturation()
00787
00788 def handleAlert(self, s):
00789 """!\brief handleAlert
00790
00791 \param s
00792 """
00793 pass
00794
00795
00796 def addLogDataToView(self):
00797 """!\brief Add the log to the listview
00798
00799 """
00800
00801
00802 self.Logger.blockSignals(1)
00803 while len(self.__logData) > 0:
00804 data = self.__logData.pop(0)
00805 self.setListViewItem(data)
00806
00807 vScroll = self.Logger.verticalScrollBar()
00808
00809 if not self.PauseLogButton.isOn() and not vScroll.draggingSlider() :
00810 vScroll.setValue(vScroll.maxValue())
00811
00812 self.Logger.blockSignals(0)
00813 self.showEntries()
00814
00815
00816
00817
00818
00819
00820 def load( self ):
00821 """!\brief Load a message log file into the logger
00822
00823 """
00824 if self.tcpserver is not None:
00825 self.abortListenerThread()
00826 self.Logger.clear()
00827
00828 f = file( str(self.__filename), 'r' )
00829
00830
00831
00832
00833
00834
00835
00836
00837 multi_line = 0
00838 while 1:
00839 data = f.readline()
00840 data = data[:len(data)-1]
00841 if data == "":
00842 break
00843 if multi_line == 0:
00844 (data1, data2) = data.split(" - ",1)
00845 if data2.startswith("<//") > 0 and multi_line == 0:
00846 datax = data1 + " - " + data2[3:]
00847 multi_line = 1
00848 continue
00849 if multi_line:
00850 if data.endswith("//>"):
00851 datax += "\n" + data[:-3]
00852 multi_line = 0
00853 else:
00854 datax += "\n" + data
00855 continue
00856 else:
00857 datax = data
00858 self.setListViewItem(datax)
00859
00860 f.close()
00861
00862 def filePrint(self):
00863 """!\brief Print the message log to the printer
00864
00865 """
00866 Margin = 50
00867 pageNo = 1
00868 column = [0, 50, 110, 180, 260, 400]
00869
00870
00871 if not self.Logger.firstChild():
00872 return
00873
00874 if self.printer.setup(self):
00875 self.statusBar().message('Printing...')
00876
00877 p = QPainter()
00878 p.begin(self.printer)
00879 p.setFont(self.Logger.font())
00880 yPos = 0
00881 fm = p.fontMetrics()
00882 metrics = QPaintDeviceMetrics(self.printer)
00883
00884 if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00885 header = "Message Logger Source: Active Run Control Log"
00886 else:
00887 header = "Message Logger Source: " + str(self.__filename)
00888
00889 page = "Page: 1"
00890 p.drawText(Margin,Margin + yPos,metrics.width(),fm.lineSpacing(),Qt.ExpandTabs | Qt.DontClip, header)
00891 yPos = yPos + fm.lineSpacing()
00892 p.drawText(Margin,Margin + yPos,metrics.width(),fm.lineSpacing(),Qt.ExpandTabs | Qt.DontClip, page)
00893 yPos = yPos + 2*fm.lineSpacing()
00894
00895 columnHeader = ['Severity','Message','Date','Time','Source']
00896
00897 for i in range (0,6):
00898 p.drawText(column[i],Margin + yPos,metrics.width(),fm.lineSpacing(),
00899 Qt.ExpandTabs | Qt.DontClip, columnHeader[i])
00900 yPos = yPos + fm.lineSpacing()
00901
00902 item = self.Logger.firstChild()
00903 for j in range(self.Logger.childCount()):
00904 if Margin + yPos > metrics.height() - Margin:
00905 pageNo = pageNo + 1
00906 page = "Page: " + str(pageNo)
00907 self.statusBar().message('Printing (page %d)...' % (pageNo))
00908 self.printer.newPage()
00909 yPos = 0
00910 p.drawText(Margin,Margin + yPos,metrics.width(),fm.lineSpacing(),Qt.ExpandTabs | Qt.DontClip, header)
00911 yPos = yPos + fm.lineSpacing()
00912 p.drawText(Margin,Margin + yPos,metrics.width(),fm.lineSpacing(),Qt.ExpandTabs | Qt.DontClip, page)
00913 yPos = yPos + 2*fm.lineSpacing()
00914
00915 for i in range (0,6):
00916 p.drawText(column[i],Margin + yPos,metrics.width(),fm.lineSpacing(),
00917 Qt.ExpandTabs | Qt.DontClip, columnHeader[i])
00918 yPos = yPos + fm.lineSpacing()
00919
00920 for i in range (0,6):
00921 p.drawText(column[i],Margin + yPos,metrics.width(),fm.lineSpacing(),
00922 Qt.ExpandTabs | Qt.DontClip,item.text(i))
00923 yPos = yPos + fm.lineSpacing()
00924 item = item.nextSibling()
00925
00926 p.end()
00927 self.statusBar().message('Printing completed',2000)
00928 else:
00929 self.statusBar().message('Printing aborted',2000)
00930
00931 def Help(self):
00932 """!\brief Help
00933
00934 """
00935 pass
00936
00937 def fileNew(self):
00938 """!\brief fileNew
00939
00940 """
00941 print "MSGLogGUIImpl.fileNew(): Not implemented yet"
00942
00943 def fileOpen(self):
00944 """!\brief Bring up a file open dialog for log file selection
00945
00946 """
00947 fn = QFileDialog.getOpenFileName( QString.null, "(*.log)", self, "Log file dialog",
00948 "Choose a Log File" )
00949 if not fn.isEmpty():
00950 self.__filename = fn
00951 self.LogType.setText(str(self.__filename))
00952 self.LogType.setAlignment(QLineEdit.AlignRight)
00953 self.load( )
00954
00955 def fileSave(self):
00956 """!\brief Save log file
00957
00958 """
00959 if self.__filename.isEmpty():
00960 self.fileSaveAs()
00961 return
00962
00963 self.Logger.save( self.__filename )
00964
00965 def fileSaveAs(self):
00966 """!\brief Save log file under a name
00967
00968 """
00969 fn = QFileDialog.getSaveFileName( QString.null, QString.null, self )
00970 if not fn.isEmpty():
00971 self.__filename = fn
00972 self.fileSave()
00973
00974 def fileExit(self):
00975 """!\brief Close the GUI
00976
00977 """
00978 self.close()
00979
00980 def closeEvent(self, e):
00981 """!\brief Handle exit
00982
00983 """
00984 if self.__secure:
00985 e.ignore()
00986 return
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003 e.accept()
01004
01005 def __shutdown(self):
01006 """!\brief Shutdown the listener thread
01007
01008 """
01009 self.abortListenerThread()
01010
01011 def setSecure(self, secure):
01012 """!\brief Set the secure flag
01013
01014 \param secure Secure flag
01015 """
01016 self.__secure = secure
01017
01018 def contextMenuShow(self, item, point, column):
01019 """!\brief Bring up the context menu on right mouse click.
01020
01021 \param item Listview item
01022 \param point Position where the mouse was clicked
01023 \param column Listview column
01024 """
01025 self.selectedItem = item
01026 self.contextMenu.exec_loop(point)
01027
01028 def copyToClipboard(self):
01029 """!\brief Copy the item value to the clipboard.
01030
01031 """
01032 if self.Logger.selectedItem() is not None:
01033 self.clip.setText(self.Logger.selectedItem().text(1))
01034
01035 def copyRowToClipboard(self):
01036 """!\brief Copy the item value to the clipboard.
01037
01038 """
01039 if self.Logger.selectedItem() is not None:
01040 selItem = self.Logger.selectedItem()
01041 text = str(selItem.text(0)) + ' ' + str(selItem.text(1)) + ' ' + \
01042 str(selItem.text(2)) + ' ' + str(selItem.text(3)) + ' ' + \
01043 str(selItem.text(4))
01044 self.clip.setText(text)
01045
01046 if __name__ == "__main__":
01047 import logging.handlers
01048 from LICOS.util.gOptions import Options
01049 def usage(msg):
01050 print """
01051 Error %s
01052 Usage: python MSGLogGUIImpl.py [--port <portno>] (default: %d)
01053 """ % (msg, logging.handlers.DEFAULT_TCP_LOGGING_PORT)
01054
01055 options = Options([],['port'],[])
01056 try:
01057 options.parse()
01058 except Exception, msg:
01059 usage(msg)
01060 sys.exit()
01061
01062 a = QApplication(sys.argv)
01063 QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()"))
01064 if options.port is None:
01065 port = logging.handlers.DEFAULT_TCP_LOGGING_PORT
01066 else:
01067 port = int(options.port)
01068 w = MSGLogGUIImpl(port)
01069 w.startListenerThread()
01070 a.setMainWidget(w)
01071 w.show()
01072 a.exec_loop()