Exemple #1
0
	def __init__(self, szprefix, no_warn=False, parent=None):
		"""Filler 2 class constructor."""
		QWidget.__init__(self, parent)
		self.ui = Ui_MainWindow()
		self.ui.setupUi(self)

		# check single instance
		try:
			self.single_instance = SingleInstance(LOCKFILE)
		except IOError:
			logger.error('another instance of Filler 2 is running, exiting...')
			self.criticalError(_translate("MainWindow",
				"Cannot acquire a single instance lock. There is "
				"another Filler 2 program running on the system."))

		# parse local SZARP configuration
		try:
			self.parser = IPKParser(szprefix)
		except IOError as err:
			logger.error("cannot read SZARP configuration")
			logger.error(str(err))
			self.criticalError(_translate("MainWindow",
						"Cannot read SZARP configuration")
						+ " (%s)." % err.bad_path)
			sys.exit(1)
		except ValueError as err:
			logger.error(str(err))
			self.criticalError(_translate("MainWindow",
						"Non-valid SZARP database prefix."))
			sys.exit(1)

		logger.info("editing database of prefix '%s'", self.parser.ipk_prefix)

		# verify SZARP prefix versus hostname
		if no_warn == False:
			try:
				process = subprocess.Popen(
						["/bin/hostname", "-s"], stdout=subprocess.PIPE)
				out, err = process.communicate()
				if err == None:
					hostname = out[:-1]

				if hostname != self.parser.ipk_prefix:
					self.warningBox(_translate("MainWindow",
						"Warning! Database prefix differs from hostname, "
						"you are probably modifying non-local database."))
			except OSError:
				pass

		### initialize Qt4 widgets ##

		# name of the local configuration
		self.ui.titleLabel.setText(self.parser.getTitle())

		# list of parameter sets
		self.ui.listOfSets.addItem(
				_translate("MainWindow", "--- Choose a set of parameters ---"))
		self.ui.listOfSets.addItems(self.parser.getSets())
		self.ui.listOfSets.model().setData(
				self.ui.listOfSets.model().index(0,0),
				QVariant(0), Qt.UserRole-1)
		self.ui.listOfSets.setEnabled(True)

		# parameter's type combobox
		self.dialog_factory = ValueDialogFactory()

		for name, icon, desc in self.dialog_factory.get_dialogs():
			self.ui.valueType.addItem(icon, desc, QVariant((name, desc)))

		self.ui.valueType.model().setData(
				self.ui.valueType.model().index(0,0),
				QVariant(0), Qt.UserRole-1)

		# date interval variables
		self.fromDate = None
		self.toDate = None

		# table of changes
		base = 64
		self.ui.changesTable.setColumnCount(6)
		self.ui.changesTable.setColumnWidth(0, 6*base-24) # param's draw_name
		self.ui.changesTable.setColumnWidth(1, 3*base)    # "from" date
		self.ui.changesTable.setColumnWidth(2, 3*base)    # "to" date
		self.ui.changesTable.setColumnWidth(3, 3*base)    # param's value type
		self.ui.changesTable.setColumnWidth(4, base-20)   # remove entry button
		self.ui.changesTable.setColumnHidden(5, True)     # param's full name

		self.ui.changesTable.horizontalHeader().setVisible(False)
		self.ui.changesTable.setRowCount(0)
Exemple #2
0
class Filler2(QMainWindow):
	"""SZARP Filler 2 application's main window (pyQt4)."""

	def __init__(self, szprefix, no_warn=False, parent=None):
		"""Filler 2 class constructor."""
		QWidget.__init__(self, parent)
		self.ui = Ui_MainWindow()
		self.ui.setupUi(self)

		# check single instance
		try:
			self.single_instance = SingleInstance(LOCKFILE)
		except IOError:
			logger.error('another instance of Filler 2 is running, exiting...')
			self.criticalError(_translate("MainWindow",
				"Cannot acquire a single instance lock. There is "
				"another Filler 2 program running on the system."))

		# parse local SZARP configuration
		try:
			self.parser = IPKParser(szprefix)
		except IOError as err:
			logger.error("cannot read SZARP configuration")
			logger.error(str(err))
			self.criticalError(_translate("MainWindow",
						"Cannot read SZARP configuration")
						+ " (%s)." % err.bad_path)
			sys.exit(1)
		except ValueError as err:
			logger.error(str(err))
			self.criticalError(_translate("MainWindow",
						"Non-valid SZARP database prefix."))
			sys.exit(1)

		logger.info("editing database of prefix '%s'", self.parser.ipk_prefix)

		# verify SZARP prefix versus hostname
		if no_warn == False:
			try:
				process = subprocess.Popen(
						["/bin/hostname", "-s"], stdout=subprocess.PIPE)
				out, err = process.communicate()
				if err == None:
					hostname = out[:-1]

				if hostname != self.parser.ipk_prefix:
					self.warningBox(_translate("MainWindow",
						"Warning! Database prefix differs from hostname, "
						"you are probably modifying non-local database."))
			except OSError:
				pass

		### initialize Qt4 widgets ##

		# name of the local configuration
		self.ui.titleLabel.setText(self.parser.getTitle())

		# list of parameter sets
		self.ui.listOfSets.addItem(
				_translate("MainWindow", "--- Choose a set of parameters ---"))
		self.ui.listOfSets.addItems(self.parser.getSets())
		self.ui.listOfSets.model().setData(
				self.ui.listOfSets.model().index(0,0),
				QVariant(0), Qt.UserRole-1)
		self.ui.listOfSets.setEnabled(True)

		# parameter's type combobox
		self.dialog_factory = ValueDialogFactory()

		for name, icon, desc in self.dialog_factory.get_dialogs():
			self.ui.valueType.addItem(icon, desc, QVariant((name, desc)))

		self.ui.valueType.model().setData(
				self.ui.valueType.model().index(0,0),
				QVariant(0), Qt.UserRole-1)

		# date interval variables
		self.fromDate = None
		self.toDate = None

		# table of changes
		base = 64
		self.ui.changesTable.setColumnCount(6)
		self.ui.changesTable.setColumnWidth(0, 6*base-24) # param's draw_name
		self.ui.changesTable.setColumnWidth(1, 3*base)    # "from" date
		self.ui.changesTable.setColumnWidth(2, 3*base)    # "to" date
		self.ui.changesTable.setColumnWidth(3, 3*base)    # param's value type
		self.ui.changesTable.setColumnWidth(4, base-20)   # remove entry button
		self.ui.changesTable.setColumnHidden(5, True)     # param's full name

		self.ui.changesTable.horizontalHeader().setVisible(False)
		self.ui.changesTable.setRowCount(0)

	# end of __init__()

	def criticalError(self, msg, title = None):
		"""Display critical error dialog and terminate.

		Arguments:
			msg - text message to be displayed.
			title - optional dialog title.
		"""
		if title is None:
			title = "SZARP Filler 2 - " + \
				_translate("MainWindow", "Critical Error")
		QMessageBox.critical(self, title, msg)
		sys.exit(1)

	# end of criticalError()

	def warningBox(self, msg, title = None):
		"""Display warning dialog.

		Arguments:
			msg - text message to be displayed.
			title - optional dialog title.
		"""
		if title is None:
			title = "SZARP Filler 2 - " + _translate("MainWindow", "Warning")
		QMessageBox.warning(self, title, msg)

	# end of warningBox()

	def infoBox(self, msg, title = None):
		"""Display information dialog.

		Arguments:
			msg - text message to be displayed.
			title - optional dialog title.
		"""
		if title is None:
			title = "SZARP Filler 2 - " + _translate("MainWindow", "Information")
		QMessageBox.information(self, title, msg)

	# end of infoBox()

	def questionBox(self, msg, title = None):
		"""Display question dialog.

		Arguments:
			msg - text message to be displayed.
			title - optional dialog title.

		Returns:
			QMessageBox.Yes | QMessageBox.No - user's answer.
		"""
		if title is None:
			title = "SZARP Filler 2 - " + _translate("MainWindow", "Question")
		return QMessageBox.question(self, title, msg,
				QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

	# end of questionBox()

	def onSetChosen(self, text):
		"""Slot for signal activated(QString) from 'listOfSets' (QComboBox).

		Arguments:
			text - name of the chosen set.
		"""
		self.ui.paramList.clear()
		self.ui.paramList.addItem(
				_translate("MainWindow", "--- Choose a parameter ---"))
		self.ui.paramList.model().setData(
				self.ui.paramList.model().index(0,0),
				QVariant(0), Qt.UserRole-1)

		# insert a list of parameters from given set
		for p in self.parser.getParams(unicode(text)):
			self.ui.paramList.addItem(p.draw_name, p)

		# activate/reset other ui elements
		self.ui.paramList.setEnabled(True)
		self.ui.paramList.setFocus()
		self.ui.valueType.setCurrentIndex(0)
		self.ui.valueType.setEnabled(False)
		self.ui.addButton.setEnabled(False)

	# end of onSetChosen()

	def onParamChosen(self, index):
		"""Slot for signal activated(QString) from 'paramList' (QComboBox).

		Arguments:
			text - name of chosen parameter (not used).
		"""
		# activate other ui elements
		self.ui.fromDate.setEnabled(True)
		self.ui.toDate.setEnabled(True)
		self.ui.valueType.setEnabled(True)
		self.type_dialog = None
		self.validateInput()

	# end of onParamChosen()

	def onFromDate(self):
		"""Slot for signal clicked() from 'fromDate' (QPushButton). Displays dialog
		for choosing date and time.
		"""
		if self.fromDate is None:
			if self.toDate is None:
				dlg = DatetimeDialog_impl()
			else:
				dlg = DatetimeDialog_impl(start_date=
						(self.toDate - datetime.timedelta(minutes=10)))
		else:
			if self.toDate is None or self.fromDate < self.toDate:
				dlg = DatetimeDialog_impl(start_date=self.fromDate)
			else:
				dlg = DatetimeDialog_impl(start_date=
						(self.toDate - datetime.timedelta(minutes=10)))

		# execute DatetimeDialog
		if dlg.exec_():
			self.fromDate = dlg.getValue()
			self.ui.fromDate.setText(_translate("MainWindow", "From:") + " " +
					self.fromDate.strftime('%Y-%m-%d %H:%M'))
			self.validateInput()

	# end of onFromDate()

	def onToDate(self):
		"""Slot for signal clicked() from 'toDate' (QPushButton). Displays dialog
		for choosing date and time.
		"""
		if self.toDate is None:
			if self.fromDate is None:
				dlg = DatetimeDialog_impl()
			else:
				dlg = DatetimeDialog_impl(start_date=
						(self.fromDate + datetime.timedelta(minutes=10)))
		else:
			if self.fromDate is None or self.toDate > self.fromDate:
				dlg = DatetimeDialog_impl(start_date=self.toDate)
			else:
				dlg = DatetimeDialog_impl(start_date=
						(self.fromDate + datetime.timedelta(minutes=10)))

		# execute DatetimeDialog
		if dlg.exec_():
			self.toDate = dlg.getValue()
			self.ui.toDate.setText(_translate("MainWindow", "To:") + " " +
					self.toDate.strftime('%Y-%m-%d %H:%M'))
			self.validateInput()

	# end of onToDate()

	def onTypeChosen(self, index):
		"""Slot for signal activated() from 'valueType' (QComboBox). Constructs
		appropriate dialog from factory and collects chosen plot parameters.
		"""
		# fetch dialog and parameter data
		dlg_name = self.ui.valueType.itemData(index).toPyObject()[0]
		param_info = self.ui.paramList.itemData(self.ui.paramList.currentIndex()).toPyObject()

		dlg = self.dialog_factory.construct(str(dlg_name),
				param_info.prec, param_info.lswmsw,
				parent = self)

		# reset type items' texts
		for i in range(self.ui.valueType.count()):
			desc = self.ui.valueType.itemData(i).toPyObject()[1]
			self.ui.valueType.setItemText(i, desc)

		if dlg.exec_():
			self.type_dialog = dlg
			self.ui.valueType.setItemText(index, dlg.get_value_desc())
		else:
			self.ui.valueType.setCurrentIndex(0)
			self.type_dialog = None
		self.validateInput()

	# end of onTypeChosen()

	def validateInput(self):
		"""Check whether all needed data is filled and valid. If do, "Add"
		button is activated.
		"""
		if  self.ui.paramList.currentIndex() != 0 and \
			self.fromDate is not None and \
			self.toDate is not None and \
			self.ui.valueType.currentIndex() != 0:
				self.ui.addButton.setEnabled(True)
		else:
				self.ui.addButton.setEnabled(False)

	# end of validateInput()

	def aboutQt(self):
		"""Display about Qt4 dialog."""
		QMessageBox.aboutQt(self)

	def about(self):
		"""Display about Filler 2 dialog."""
		AboutDialog_impl().exec_()

	def addChange(self):
		"""Slot for signal clicked() from addButton (QPushButton). Adds
		change-entry to changesTable (QTableWidget)."""
		if self.fromDate >= self.toDate:
			self.warningBox(_translate("MainWindow",
				"\"To\" date is earlier (or equals) \"From\" date.\nAdding change aborted."))
			return

		if self.toDate >= datetime.datetime.now():
			if QMessageBox.Yes != \
					self.questionBox(_translate("MainWindow",
						"You are trying to modify future data - "
						"it will block SZARP from writing actual data in this period.\n\n"
						"Are you sure that's what you really want to do?")):
				return

		param_info = self.ui.paramList.itemData(
				self.ui.paramList.currentIndex()).toPyObject()

		self.ui.changesTable.setRowCount(self.ui.changesTable.rowCount()+1)
		self.addRow(self.ui.changesTable.rowCount() - 1,
					param_info.name,
					self.ui.paramList.currentText(),
					self.fromDate,
					self.toDate,
					self.type_dialog,
					param_info.lswmsw)

		# reset type items' texts
		for i in range(self.ui.valueType.count()):
			desc = self.ui.valueType.itemData(i).toPyObject()[1]
			self.ui.valueType.setItemText(i, desc)
		self.ui.valueType.setCurrentIndex(0)

	# end of addChange()

	def addRow(self, row, fname, pname, from_date, to_date, typedlg, lswmsw):
		"""Add row to changesTable (QTableWidget).

		Arguments:
			row - number of row to be set.
			fname - full parameter name
			pname - parameter's draw name
			from_date - beginning of time period
			to_date - end of time period
			value - parameter's value
			typedlg - object of input value dialog
			lswmsw - whether parametr is a combined lsw/msw
		"""
		# visible columns
		item_pname = QTableWidgetItem(unicode(pname))
		item_pname.setFlags(Qt.ItemIsEnabled)

		item_from_date = QTableWidgetItem(from_date.strftime('%Y-%m-%d %H:%M'))
		item_from_date.setFlags(Qt.ItemIsEnabled)
		item_from_date.setTextAlignment(Qt.AlignCenter)

		item_to_date = QTableWidgetItem(to_date.strftime('%Y-%m-%d %H:%M'))
		item_to_date.setFlags(Qt.ItemIsEnabled)
		item_to_date.setTextAlignment(Qt.AlignCenter)

		item_value = QTableWidgetItem(typedlg.get_value_desc())
		item_value.setFlags(Qt.ItemIsEnabled)
		item_value.setIcon(QIcon(typedlg.qicon_path))
		item_value.setTextAlignment(Qt.AlignCenter)

		# hidden column
		item_fname = QTableWidgetItem(unicode(fname))
		item_fname.setData(Qt.UserRole, QVariant((lswmsw, typedlg)))
		item_fname.setFlags(Qt.ItemIsEnabled)

		self.ui.changesTable.setItem(row, 0, item_pname)
		self.ui.changesTable.setItem(row, 1, item_from_date)
		self.ui.changesTable.setItem(row, 2, item_to_date)
		self.ui.changesTable.setItem(row, 3, item_value)
		self.ui.changesTable.setItem(row, 5, item_fname)

		# "remove" button widget
		rm_button = QPushButton(QIcon.fromTheme("window-close"), "")
		rm_button.setToolTip(_translate("MainWindow", "Remove entry"))
		rm_button.row_id = row
		QObject.connect(rm_button, SIGNAL("clicked()"), self.removeChange)
		self.ui.changesTable.setCellWidget(row, 4, rm_button)

	# end of addRow()

	def removeChange(self):
		"""Slot for signal clicked() from rm_button (QPushButton). Removes
		entry from changesTable (QTableWidget).
		"""
		if QMessageBox.Yes != \
				self.questionBox(_translate("MainWindow", "Remove change?")):
			return

		row = self.sender().row_id
		self.ui.changesTable.removeRow(row)

		# update row_id for every row
		for i in range(row, self.ui.changesTable.rowCount()):
			self.ui.changesTable.cellWidget(i, 4).row_id -= 1

	# end of removeChange()

	def clearChanges(self):
		"""Slot for action 'actionClear'. Removes all entries from
		changesTable (QTableWidget).
		"""
		txt = _translate("MainWindow",
				"Are you sure you want to clear all changes?")

		if QMessageBox.Yes == self.questionBox(txt):
			self.ui.changesTable.setRowCount(0)

	# end of clearChanges()

	def commitChanges(self):
		"""Slot for action 'actionSaveData'. Commits all scheduled changes
		to local szbase.
		"""
		if self.ui.changesTable.rowCount() == 0:
			self.warningBox(_translate("MainWindow", "No changes to commit."))
			return

		# list and confirm
		txt = _translate("MainWindow",
				"Following parameters will be modified:") + "\n\n"

		for i in range(0, self.ui.changesTable.rowCount()):
			txt.append("   * %s\n\n" \
					% (self.ui.changesTable.item(i,0).text()))

		txt.append(_translate("MainWindow", "Commit changes?"))

		if QMessageBox.Yes == self.questionBox(txt):
			# construct list of changes to be committed
			logger.info("committing scheduled changes...")
			changes_list = []

			for i in range(0, self.ui.changesTable.rowCount()):

				start_date = datetime.datetime.strptime(
					str(self.ui.changesTable.item(i,1).text()),
					'%Y-%m-%d %H:%M')

				end_date = datetime.datetime.strptime(
					str(self.ui.changesTable.item(i,2).text()),
					'%Y-%m-%d %H:%M')

				lswmsw, typedlg = \
					self.ui.changesTable.item(i,5).data(Qt.UserRole).toPyObject()

				# generate list of 10-minute probes in given interval
				dsec = int((end_date-start_date).total_seconds())
				dts = [start_date + datetime.timedelta(minutes=x) \
						for x in range(0, dsec / 60 + 1, 10)]
				# generate probes' values
				dvals = typedlg.generate(dts)

				rmrk = typedlg.get_remark()

				changes_list.append(SzChangeInfo(
						draw_name = unicode(self.ui.changesTable.item(i,0).text()),
						name = unicode(self.ui.changesTable.item(i,5).text()),
						dvalues = dvals,
						lswmsw = lswmsw,
						remark = rmrk
						))

			# do the job (in a new thread)
			szbw = SzbWriter(changes_list, self.parser)
			szbp = SzbProgressWin(szbw, parent = self)

			# reset all GUI elements
			self.ui.changesTable.setRowCount(0)
			self.fromDate = None
			self.toDate = None
			self.ui.listOfSets.setCurrentIndex(0)
			self.ui.paramList.clear()
			self.ui.paramList.setEnabled(False)
			self.ui.fromDate.setText(_translate("MainWindow", "From:"))
			self.ui.fromDate.setEnabled(False)
			self.ui.toDate.setText(_translate("MainWindow", "To:"))
			self.ui.toDate.setEnabled(False)
			self.ui.valueType.setCurrentIndex(0)
			self.ui.valueType.setEnabled(False)
			self.ui.addButton.setEnabled(False)

			# disable main window until job is finished
			self.setEnabled(False)

	# end of commitChanges()

	def contextHelp(self):
		"""Slot for action 'actionContextHelp'. Activates "What is that?" mode."""
		QWhatsThis.enterWhatsThisMode()

	def onViewHistory(self):
		"""Slot for action 'actionViewHistory'. Shows history of committed changes."""
		HistoryDialog_impl(self.parser, parent=self).exec_()