1# Copyright (C) 2009 Jeremy S. Sanders 2# Email: Jeremy Sanders <jeremy@jeremysanders.net> 3# 4# This program is free software; you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation; either version 2 of the License, or 7# (at your option) any later version. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License along 15# with this program; if not, write to the Free Software Foundation, Inc., 16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17############################################################################## 18 19"""Veusz data capture dialog.""" 20 21from __future__ import division 22from ..compat import citems, cstr, cstrerror 23from .. import qtall as qt 24from .. import setting 25from ..dataimport import capture, simpleread 26from .veuszdialog import VeuszDialog 27 28def _(text, disambiguation=None, context="CaptureDialog"): 29 """Translate text.""" 30 return qt.QCoreApplication.translate(context, text, disambiguation) 31 32class CaptureDialog(VeuszDialog): 33 """Capture dialog. 34 35 This allows the user to set the various capture options.""" 36 37 def __init__(self, document, mainwindow): 38 VeuszDialog.__init__(self, mainwindow, 'capture.ui') 39 self.document = document 40 41 # set values of edit controls from previous invocation (if any) 42 d = setting.settingdb 43 44 # Validate edit controls 45 validator = qt.QIntValidator(1, 65535, self) 46 self.portEdit.setValidator(validator) 47 validator = qt.QIntValidator(1, 1000000000, self) 48 self.numLinesStopEdit.setValidator(validator) 49 self.timeStopEdit.setValidator(validator) 50 self.tailEdit.setValidator(validator) 51 52 # floating point values for interval 53 self.updateIntervalsEdit.setValidator( 54 qt.QDoubleValidator(1e-2, 10000000, 2, self)) 55 56 # add completion for filenames 57 c = self.filenamecompleter = qt.QCompleter(self) 58 model = qt.QDirModel(c) 59 c.setModel(model) 60 self.filenameEdit.setCompleter(c) 61 62 # get notification of change of capture method 63 self.methodBG = qt.QButtonGroup(self) 64 self.methodBG.addButton( self.captureFileButton, 0 ) 65 self.methodBG.addButton( self.captureInternetButton, 1 ) 66 self.methodBG.addButton( self.captureProgramButton, 2 ) 67 self.methodBG.buttonClicked[int].connect(self.slotMethodChanged) 68 # restore previously clicked button 69 self.methodBG.button( d.get('CaptureDialog_method', 0) ).click() 70 71 # get notification of change of stop method 72 self.stopBG = qt.QButtonGroup(self) 73 self.stopBG.addButton( self.clickingStopButton, 0 ) 74 self.stopBG.addButton( self.numLinesStopButton, 1 ) 75 self.stopBG.addButton( self.timeStopButton, 2 ) 76 self.stopBG.buttonClicked[int].connect(self.slotStopChanged) 77 self.stopBG.button( d.get('CaptureDialog_stop', 0) ).click() 78 79 # update interval 80 self.updateIntervalsCheck.toggled.connect( 81 self.updateIntervalsEdit.setEnabled) 82 83 # tail data 84 self.tailCheck.toggled.connect(self.tailEdit.setEnabled) 85 86 # user starts capture 87 self.captureButton = self.buttonBox.addButton( 88 _("Ca&pture"), qt.QDialogButtonBox.ApplyRole ) 89 90 self.captureButton.clicked.connect(self.slotCaptureClicked) 91 92 # filename browse button clicked 93 self.browseButton.clicked.connect(self.slotBrowseClicked) 94 95 def done(self, r): 96 """Dialog is closed.""" 97 VeuszDialog.done(self, r) 98 99 # record values for next time dialog is opened 100 d = setting.settingdb 101 d['CaptureDialog_method'] = self.methodBG.checkedId() 102 d['CaptureDialog_stop'] = self.stopBG.checkedId() 103 104 def slotMethodChanged(self, buttonid): 105 """Enable/disable correct controls in methodBG.""" 106 # enable correct buttons 107 fc = buttonid==0 108 self.filenameEdit.setEnabled(fc) 109 self.browseButton.setEnabled(fc) 110 111 ic = buttonid==1 112 self.hostEdit.setEnabled(ic) 113 self.portEdit.setEnabled(ic) 114 115 xc = buttonid==2 116 self.commandLineEdit.setEnabled(xc) 117 118 def slotStopChanged(self, buttonid): 119 """Enable/disable correct controls in stopBG.""" 120 121 ns = buttonid == 1 122 self.numLinesStopEdit.setEnabled(ns) 123 124 ts = buttonid == 2 125 self.timeStopEdit.setEnabled(ts) 126 127 def slotBrowseClicked(self): 128 """Browse for a data file.""" 129 130 fd = qt.QFileDialog(self, 'Browse data file or socket') 131 fd.setFileMode( qt.QFileDialog.ExistingFile ) 132 133 # update filename if changed 134 if fd.exec_() == qt.QDialog.Accepted: 135 self.filenameEdit.replaceAndAddHistory( fd.selectedFiles()[0] ) 136 137 def slotCaptureClicked(self): 138 """User requested capture.""" 139 140 # object to interpret data from stream 141 descriptor = self.descriptorEdit.text() 142 simprd = simpleread.SimpleRead(descriptor) 143 144 maxlines = None 145 timeout = None 146 updateinterval = None 147 tail = None 148 try: 149 stop = self.stopBG.checkedId() 150 if stop == 1: 151 # number of lines to read before stopping 152 maxlines = int( self.numLinesStopEdit.text() ) 153 elif stop == 2: 154 # maximum time period before stopping 155 timeout = int( self.timeStopEdit.text() ) 156 157 # whether to do an update periodically 158 if self.updateIntervalsCheck.isChecked(): 159 updateinterval = float( self.updateIntervalsEdit.text() ) 160 161 # whether to only retain N values 162 if self.tailCheck.isChecked(): 163 tail = int( self.tailEdit.text() ) 164 165 except ValueError: 166 qt.QMessageBox.critical(self, _("Invalid number"), _("Invalid number")) 167 return 168 169 # get method of getting data 170 method = self.methodBG.checkedId() 171 try: 172 # create stream 173 if method == 0: 174 # file/socket 175 stream = capture.FileCaptureStream(self.filenameEdit.text()) 176 elif method == 1: 177 # internet socket 178 stream = capture.SocketCaptureStream( 179 self.hostEdit.text(), 180 int(self.portEdit.text()) ) 181 elif method == 2: 182 # external program 183 stream = capture.CommandCaptureStream( 184 self.commandLineEdit.text()) 185 except EnvironmentError as e: 186 # problem opening stream 187 qt.QMessageBox.critical( 188 self, _("Cannot open input"), 189 _("Cannot open input:\n %s (error %i)") % ( 190 cstrerror(e), e.errno) 191 ) 192 return 193 194 stream.maxlines = maxlines 195 stream.timeout = timeout 196 simprd.tail = tail 197 cd = CapturingDialog(self.document, simprd, stream, self, 198 updateinterval=updateinterval) 199 self.mainwindow.showDialog(cd) 200 201######################################################################## 202 203class CapturingDialog(VeuszDialog): 204 """Capturing data dialog. 205 Shows progress to user.""" 206 207 def __init__(self, document, simprd, stream, parent, 208 updateinterval = None): 209 """Initialse capture dialog: 210 document: document to send data to 211 simprd: object to interpret data 212 stream: capturestream to read data from 213 parent: parent widget 214 updateinterval: if set, interval of seconds to update data in doc 215 """ 216 217 VeuszDialog.__init__(self, parent, 'capturing.ui') 218 219 self.document = document 220 self.simpleread = simprd 221 self.stream = stream 222 223 # connect buttons 224 self.finishButton.clicked.connect(self.slotFinish) 225 self.cancelButton.clicked.connect(self.slotCancel) 226 227 # timer which governs reading from source 228 self.readtimer = qt.QTimer(self) 229 self.readtimer.timeout.connect(self.slotReadTimer) 230 231 # record time capture started 232 self.starttime = qt.QTime() 233 self.starttime.start() 234 235 # sort tree by dataset name 236 self.datasetTreeWidget.sortItems(0, qt.Qt.AscendingOrder) 237 238 # timer for updating display 239 self.displaytimer = qt.QTimer(self) 240 self.displaytimer.timeout.connect(self.slotDisplayTimer) 241 self.sourceLabel.setText( self.sourceLabel.text() % 242 stream.name ) 243 self.txt_statusLabel = self.statusLabel.text() 244 self.slotDisplayTimer() # initialise label 245 246 # timer to update document 247 self.updatetimer = qt.QTimer(self) 248 self.updateoperation = None 249 if updateinterval: 250 self.updatetimer.timeout.connect(self.slotUpdateTimer) 251 self.updatetimer.start( int(updateinterval*1000) ) 252 253 # start display and read timers 254 self.displaytimer.start(1000) 255 self.readtimer.start(10) 256 257 def slotReadTimer(self): 258 """Time to read more data.""" 259 try: 260 self.simpleread.readData(self.stream) 261 except capture.CaptureFinishException as e: 262 # stream tells us it's time to finish 263 self.streamCaptureFinished( cstr(e) ) 264 265 def slotDisplayTimer(self): 266 """Time to update information about data source.""" 267 self.statusLabel.setText( self.txt_statusLabel % 268 (self.stream.bytesread, 269 self.starttime.elapsed() // 1000) ) 270 271 tree = self.datasetTreeWidget 272 cts = self.simpleread.getDatasetCounts() 273 274 # iterate over each dataset 275 for name, length in citems(cts): 276 find = tree.findItems(name, qt.Qt.MatchExactly, 0) 277 if find: 278 # if already in tree, update number of counts 279 find[0].setText(1, str(length)) 280 else: 281 # add new item 282 tree.addTopLevelItem( qt.QTreeWidgetItem([name, str(length)])) 283 284 def slotUpdateTimer(self): 285 """Called to update document while data is being captured.""" 286 287 # undo any previous update 288 if self.updateoperation: 289 self.updateoperation.undo(self.document) 290 291 # create new one 292 self.updateoperation = capture.OperationDataCaptureSet( 293 self.simpleread) 294 295 # apply it (bypass history here - urgh) 296 self.updateoperation.do(self.document) 297 self.document.setModified() 298 299 def streamCaptureFinished(self, message): 300 """Stop timers, close stream and display message 301 about finished stream.""" 302 303 # stop reading / displaying 304 self.readtimer.stop() 305 self.displaytimer.stop() 306 self.updatetimer.stop() 307 if self.stream: 308 # update stats 309 self.slotDisplayTimer() 310 # close stream 311 self.stream.close() 312 self.stream = None 313 # show message from stream 314 self.statusLabel.setText(message) 315 316 def slotFinish(self): 317 """Finish capturing and save the results.""" 318 319 # close down timers 320 self.streamCaptureFinished('') 321 322 # undo any in-progress update 323 if self.updateoperation: 324 self.updateoperation.undo(self.document) 325 326 # apply real document operation update 327 op = capture.OperationDataCaptureSet(self.simpleread) 328 self.document.applyOperation(op) 329 330 # close dialog 331 self.close() 332 333 def slotCancel(self): 334 """Cancel capturing.""" 335 336 # close down timers 337 self.streamCaptureFinished('') 338 339 # undo any in-progress update 340 if self.updateoperation: 341 self.updateoperation.undo(self.document) 342 self.document.setModified() 343 344 # close dialog 345 self.close() 346 347 348