diff --git a/reflowctl/edge_widget.py b/reflowctl/edge_widget.py index 8491d45..4c88b50 100644 --- a/reflowctl/edge_widget.py +++ b/reflowctl/edge_widget.py @@ -16,6 +16,12 @@ class Edge(QtCore.QObject): (self.from_tl.temp < temp_level.temp < self.to_tl.temp) or (self.from_tl.temp > temp_level.temp > self.to_tl.temp)) + def has_from_tl(self, temp_level): + return self.from_tl == temp_level + + def has_to_tl(self, temp_level): + return self.to_tl == temp_level + def __repr__(self): return "Edge(%r, %r, %r, %r)" % (self.from_tl, self.to_tl, self.duration, self.rate) @@ -108,13 +114,13 @@ class EdgeModel(QtCore.QAbstractTableModel): def get_edge(self, ix): return self.edges[ix] -class ConstraintWidget(QtGui.QWidget): +class EdgeWidget(QtGui.QWidget): edge_changed = QtCore.pyqtSignal() def __init__(self, name): - super(ConstraintWidget, self).__init__() + super(EdgeWidget, self).__init__() self.name = name - self.edge_model = EdgeModel(self) # temp_level selection pool + self.edge_model = EdgeModel(self) self.edge_view = QtGui.QTableView(self) self.edge_view.setModel(self.edge_model) @@ -128,11 +134,9 @@ class ConstraintWidget(QtGui.QWidget): h.addWidget(self.edge_view) def edge_picked(self, ix): - print self.edge_picked self.edge_view.setCurrentIndex(self.edge_model.index(ix, 0)) def setData(self, solder): - print self.setData self.solder = solder self.edge_model.setTempLevels(solder.edges) self.edge_view.setCurrentIndex(self.edge_model.index(0,0)) @@ -143,36 +147,97 @@ class ConstraintWidget(QtGui.QWidget): self._edge_changed) def _edge_changed(self): - print self.temp_level_added self.edge_changed.emit() - def temp_level_added(self, new_tl): - print self.temp_level_added, len(self.edge_model.edges) + def make_closed(self): + first_edge = self.edge_model.edges[0] + last_edge = self.edge_model.edges[-1] + if not first_edge.from_tl == last_edge.to_tl: + self.edge_model.edges.append(Edge(last_edge.to_tl, first_edge.from_tl, None, -1)) + + def temp_level_removed(self, temp_level): + from_ix = None + to_ix = None + edges = self.edge_model.edges + end = len(edges) + + def helper(start, end): + for i in xrange(start, end): + edge = edges[i] + if edge.from_tl == temp_level: + return i + + for ix, edge in enumerate(self.edge_model.edges): + if edge.to_tl == temp_level: + from_ix = ix + to_ix = helper(ix, end) + + for i in range(to_ix, from_ix-1, -1): + self.edge_model.edges.pop(i) + + self.edge_model.reset() + + def temp_level_added(self, old_tl, new_tl): + new_edges = list() ix = 0 batch = list() - for edge in self.edge_model.edges: - if edge.contains(new_tl): - batch.append(edge) + #for edge in self.edge_model.edges: + #if edge.contains(new_tl): + #batch.append(edge) + + #if not batch: + def find_in_to(edges): + for edge in edges: + if old_tl == edge.to_tl: + yield edge + + def find_in_from(edges): + for edge in edges: + if old_tl == edge.from_tl: + yield edge + + for edge in find_in_to(self.edge_model.edges): + batch.append(edge) + for return_edge in find_in_from(self.edge_model.edges[self.edge_model.edges.index(edge):]): + batch.append(return_edge) for edge in batch: - if edge.from_tl < new_tl: - duration = None if edge.duration is None else edge.duration / 2 - new_edge = Edge(new_tl, edge.to_tl, duration, edge.rate) - edge.duration = duration - edge.to_tl = new_tl + if edge.from_tl == old_tl: + new_edge = Edge(new_tl, old_tl, None, -1) ix = self.edge_model.edges.index(edge) - self.edge_model.edges.insert(ix+1, new_edge) - else: - duration = None if edge.duration is None else edge.duration / 2 - new_edge = Edge(new_tl, edge.to_tl, duration, edge.rate) - edge.duration = duration - edge.to_tl = new_tl + self.edge_model.edges.insert(ix, new_edge) + elif edge.to_tl == old_tl: + new_edge = Edge(old_tl, new_tl, None, 1) ix = self.edge_model.edges.index(edge) self.edge_model.edges.insert(ix+1, new_edge) - #for i in new_edges: - #print repr(i) - #for edge, new_edge in new_edges: + if not batch: + self.edge_model.edges.append(Edge(old_tl, new_tl, None, 1)) + self.make_closed() self.edge_model.reset() + self.edge_changed.emit() + + + #for edge in batch: + #if edge.from_tl < new_tl: + #duration = None if edge.duration is None else edge.duration / 2 + #new_edge = Edge(new_tl, edge.to_tl, duration, edge.rate) + #edge.duration = duration + #edge.to_tl = new_tl + #ix = self.edge_model.edges.index(edge) + #self.edge_model.edges.insert(ix+1, new_edge) + #elif edge.from_tl > new_tl: + #duration = None if edge.duration is None else edge.duration / 2 + #new_edge = Edge(new_tl, edge.to_tl, duration, edge.rate) + #edge.duration = duration + #edge.to_tl = new_tl + #ix = self.edge_model.edges.index(edge) + #self.edge_model.edges.insert(ix+1, new_edge) + #else: + #raise Exception("cannot make an edge") + + #self.make_closed() + #self.edge_model.reset() + #self.edge_changed.emit() diff --git a/reflowctl/reflowctl_gui.py b/reflowctl/reflowctl_gui.py index 24f2626..5dc8976 100755 --- a/reflowctl/reflowctl_gui.py +++ b/reflowctl/reflowctl_gui.py @@ -14,7 +14,7 @@ from mpltools import annotation from solder import Solder, SolderWidget from temp_level import TempLevelWidget, TempLevel -from edge_widget import ConstraintWidget +from edge_widget import EdgeWidget progname = os.path.basename(sys.argv[0]) progversion = "0.1" @@ -79,16 +79,18 @@ class Plotter(FigureCanvas): def onpick(self, event): if isinstance(event.artist, Line2D): self.set_picked(event.ind[0]) - self.edge_picked.emit(event.ind) else: - print type(avent.artist) + raise Exception("fixme: pickme") def set_picked(self, ix): if isinstance(ix, QtCore.QModelIndex): ix = ix.row() + self.edge_picked.emit(ix) self.selected_ix = ix self.updated = True + if not self.started: + self.update_figure() def update_figure(self): if self.updated: @@ -107,8 +109,9 @@ class Plotter(FigureCanvas): self.plot_data.set_xdata(self.x) self.plot_data.set_ydata(self.y) - self.selx = numpy.array(map(float, self.x[self.selected_ix:self.selected_ix + 2])) - self.sely = numpy.array(map(float, self.y[self.selected_ix:self.selected_ix + 2])) + if self.selected_ix is not None: + self.selx = numpy.array(map(float, self.x[self.selected_ix:self.selected_ix + 2])) + self.sely = numpy.array(map(float, self.y[self.selected_ix:self.selected_ix + 2])) self.selection_data.set_xdata(self.selx) self.selection_data.set_ydata(self.sely) @@ -144,6 +147,7 @@ class Plotter(FigureCanvas): self.draw() def solder_changed(self): + self.selected_ix = None self.solder.setChanged() self.updated = True if not self.started: @@ -152,6 +156,11 @@ class Plotter(FigureCanvas): def setData(self, solder): self.solder = solder self.updated = True + self.selx = numpy.array(list()) + self.sely = numpy.array(list()) + if not self.started: + self.update_figure() + class OvenControlsWidget(QtGui.QWidget): @@ -303,7 +312,7 @@ class ApplicationWindow(QtGui.QMainWindow): self.tab_widget = QtGui.QTabWidget(self) self.temp_level_widget = TempLevelWidget(self) - self.constraint_widget = ConstraintWidget(u"Constraints") + self.constraint_widget = EdgeWidget(u"Constraints") self.tab_widget.addTab(self.temp_level_widget, u"Temperature Levels (°C)") self.tab_widget.addTab(self.constraint_widget, u"Constraints") @@ -316,7 +325,9 @@ class ApplicationWindow(QtGui.QMainWindow): QtCore.SIGNAL("solder_changed()"), self.plotter.solder_changed) + self.temp_level_widget.temp_level_added.connect(self.constraint_widget.temp_level_added) + self.temp_level_widget.temp_level_removed.connect(self.constraint_widget.temp_level_removed) self.connect( self.constraint_widget, @@ -335,6 +346,11 @@ class ApplicationWindow(QtGui.QMainWindow): QtCore.SIGNAL("clicked(QModelIndex)"), self.solder_selected) + self.connect( + self.solder_widget, + QtCore.SIGNAL("solder_selected(QModelIndex)"), + self.solder_selected) + self.connect( self.plotter, QtCore.SIGNAL("edge_picked(int)"), @@ -345,6 +361,11 @@ class ApplicationWindow(QtGui.QMainWindow): QtCore.SIGNAL("edge_picked(int)"), self.edge_picked) + self.connect( + self.temp_level_widget.temp_level_model, + QtCore.SIGNAL("status_message(QString, int)"), + self.statusBar().showMessage) + self.settings_widget = QtGui.QWidget(self) pl = QtGui.QHBoxLayout(self.settings_widget) pl.addWidget(self.solder_widget, 1) @@ -385,14 +406,10 @@ class ApplicationWindow(QtGui.QMainWindow): self.constraint_widget.setData(solder) self.plotter.setData(solder) solder.log_message.connect(self.profile_log.setPlainText) - if not self.plotter.started: - self.plotter.update_figure() def edge_picked(self, ix): if self.tab_widget.currentIndex() != 1: self.tab_widget.setCurrentIndex(1) - if not self.plotter.started: - self.plotter.update_figure() def remove_solder(self): self.solder_selected(self.solder_widget.remove_solder()) diff --git a/reflowctl/solder.py b/reflowctl/solder.py index 584f101..811c42c 100644 --- a/reflowctl/solder.py +++ b/reflowctl/solder.py @@ -17,6 +17,23 @@ from control_widgets import AddRemoveWidget def getTemperature(): return 20. +def indent(elem, level=0): + i = "\n" + level*" " + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + " " + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for child in elem: + indent(child, level+1) + if not child.tail or not child.tail.strip(): + child.tail = i + if not elem.tail or not elem.tail.strip(): + elem.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i + class Solder(QtCore.QObject): @@ -31,7 +48,6 @@ class Solder(QtCore.QObject): self.temp_levels = list() self.edges = list() - def __unicode__(self): return unicode(self.name) @@ -51,6 +67,8 @@ class Solder(QtCore.QObject): return None def calc_profile(self): + if not self.edges: + return array([]), array([]), 0, 300, 0, 300 self.log = list() x = list() y = list() @@ -72,7 +90,7 @@ class Solder(QtCore.QObject): time = calc(_edge) x.append(time) - y.append(_edge.to_tl.temp) + y.append(self.edges[-1].to_tl.temp) return array(x), array(y), min(x), max(x), min(y), max(y) @@ -116,6 +134,7 @@ class Solder(QtCore.QObject): return s def save(self): + self.changed = True if self.changed: solder_node = etree.Element("solder_type", {"name" : self.name, "description" : self.description}) for temp_level in self.temp_levels: @@ -134,7 +153,7 @@ class Solder(QtCore.QObject): root.append(solder_node) if self.filename is None: self.filename = os.path.join(dirname, self.name + ".xml") - etree.ElementTree(root).write(self.filename, "UTF-8", True) + etree.ElementTree(root).write(self.filename, "UTF-8") self.changed = False def setChanged(self): @@ -146,6 +165,7 @@ class SolderListModel(QtCore.QAbstractListModel): """ datain: a list where each item is a row """ super(SolderListModel, self).__init__(parent, *args) + self.solder_list = [] self._load_solder_list() def rowCount(self, parent=QtCore.QModelIndex()): @@ -153,10 +173,11 @@ class SolderListModel(QtCore.QAbstractListModel): def _load_solder_list(self): dirname = self.dirname() - dirlisting = filter(lambda x: os.path.splitext(x)[1] == ".xml", os.listdir(dirname)) - self.solder_list = [] + dirlisting = filter( + lambda x: os.path.splitext(x)[1] == ".xml", os.listdir(dirname)) for p in dirlisting: - self.solder_list.append(Solder.unpack(os.path.join(dirname, p), self)) + self.solder_list.append( + Solder.unpack(os.path.join(dirname, p), self)) self.solder_list.sort(key=lambda x: x.name) self.reset() @@ -179,19 +200,24 @@ class SolderListModel(QtCore.QAbstractListModel): def setData(self, index, variant, role): if index.isValid() and role == QtCore.Qt.EditRole: new_name = str(variant.toString()) - if new_name and new_name != "": - self.solder_list[index.row()].name = new_name - self.solder_list[index.row()].changed = True + if (new_name is not None and new_name != "" and + self.check_name(new_name)): + solder = self.solder_list[index.row()] + solder.name = new_name + solder.changed = True return True return False def flags(self, index): if not index.isValid(): return 0 - return QtCore.Qt.ItemFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable) + return QtCore.Qt.ItemFlags( + QtCore.Qt.ItemIsEnabled | + QtCore.Qt.ItemIsSelectable | + QtCore.Qt.ItemIsEditable) def create_solder(self): - solder = Solder(None, datetime.now().strftime("%Y-%M-%D %H:%m:%s"), "") + solder = Solder(None, "new %d" % len(self.solder_list), "") tl = solder.add_temp_level("environment temp", getTemperature(), True) tl.color = QtGui.QColor(0, 0, 0) @@ -210,6 +236,8 @@ class SolderListModel(QtCore.QAbstractListModel): class SolderWidget(QtGui.QWidget): + solder_selected = QtCore.pyqtSignal(QtCore.QModelIndex) + def __init__(self, parent, readonly=False): super(SolderWidget, self).__init__(parent) self.solder_model = SolderListModel(self) @@ -224,7 +252,7 @@ class SolderWidget(QtGui.QWidget): self.connect( self.solder_controls.add_button, QtCore.SIGNAL("clicked()"), - self.solder_model.create_solder) + self.create_solder) self.connect( self.solder_controls.remove_button, @@ -233,12 +261,18 @@ class SolderWidget(QtGui.QWidget): self.solder_view.setCurrentIndex(self.solder_model.index(0,0)) + def create_solder(self): + self.solder_model.create_solder() + ix = self.solder_model.index(self.solder_model.rowCount(None) - 1, 0) + self.solder_view.setCurrentIndex(ix) + self.solder_selected.emit(ix) + def remove_solder(self): index = self.solder_view.currentIndex() solder = self.solder_model.solder_list[index.row()] try: os.remove(solder.filename) - except OSError: + except (OSError, TypeError): pass del self.solder_model.solder_list[index.row()] self.solder_model.reset() diff --git a/reflowctl/temp_level.py b/reflowctl/temp_level.py index 79f84c3..4ff0b21 100644 --- a/reflowctl/temp_level.py +++ b/reflowctl/temp_level.py @@ -79,6 +79,7 @@ class TempLevel(QtCore.QObject): class TempLevelModel(QtCore.QAbstractTableModel): solder_changed = QtCore.pyqtSignal() + status_message = QtCore.pyqtSignal(QtCore.QString, int) def __init__(self, parent): super(TempLevelModel, self).__init__(parent) @@ -147,12 +148,14 @@ class TempLevelModel(QtCore.QAbstractTableModel): try: tl0 = self.temp_levels[index.row() - 1] if tl0.temp >= temp: + self.status_message.emit(QtCore.QString(u"Error: TempLevel %r cannot be moved across TempLevel %r!" % (tl.name, tl0.name)), 10000) return False except Exception, e: pass try: tl1 = self.temp_levels[index.row() + 1] if tl1.temp <= temp: + self.status_message.emit(QtCore.QString(u"Error: TempLevel %r cannot be moved across TempLevel %r!" % (tl.name, tl1.name)), 10000) return False except Exception, e: pass @@ -178,6 +181,13 @@ class TempLevelModel(QtCore.QAbstractTableModel): self.solder_changed.emit() + def append_temp_level(self, temp_level): + self.temp_levels.append(temp_level) + set_colors(self.temp_levels) + self.reset() + self.solder_changed.emit() + + def setTempLevels(self, temp_levels): assert isinstance(temp_levels, list) self.temp_levels = temp_levels @@ -195,8 +205,7 @@ class TempLevelModel(QtCore.QAbstractTableModel): class TempLevelWidget(QtGui.QWidget): temp_level_removed = QtCore.pyqtSignal(TempLevel) - temp_level_added = QtCore.pyqtSignal(TempLevel) - temp_levels_changed = QtCore.pyqtSignal() + temp_level_added = QtCore.pyqtSignal(TempLevel, TempLevel) solder_changed = QtCore.pyqtSignal() def __init__(self, parent, readonly=False): @@ -227,7 +236,7 @@ class TempLevelWidget(QtGui.QWidget): self.connect( self.controls.add_button, QtCore.SIGNAL("clicked()"), - self.add_temp_level) + self.append_temp_level) self.connect( self.controls.remove_button, @@ -248,27 +257,26 @@ class TempLevelWidget(QtGui.QWidget): self.temp_level_view.resizeColumnsToContents() self.temp_level_view.setCurrentIndex(self.temp_level_model.index(0, 0)) - def add_temp_level(self): - index = self.temp_level_view.currentIndex() - old_tl = self.temp_level_model.temp_levels[index.row()] - print "next temp", self.temp_level_model.temp_levels[index.row() + 1].temp - new_temp = old_tl.temp + (self.temp_level_model.temp_levels[index.row() + 1].temp - old_tl.temp) / 2 - print "new_temp", new_temp - new_tl = TempLevel("new " + str(self.temp_level_model.rowCount(None)), new_temp) - self.temp_level_model.add_temp_level(index, new_tl) - self.temp_level_view.setCurrentIndex(self.temp_level_model.index(index.row() + 1, 0)) - self.temp_levels_changed.emit() - print "TempLevelWidget.add_temp_level 1", old_tl, new_tl - self.temp_level_added.emit(new_tl) - print "TempLevelWidget.add_temp_level 2" + pass + #new_temp = old_tl.temp + (self.temp_level_model.temp_levels[index.row() + 1].temp - old_tl.temp) / 2 + def append_temp_level(self): + old_tl = self.temp_level_model.temp_levels[-1] + new_temp = old_tl.temp + 20 + ix = self.temp_level_model.rowCount(None) + new_tl = TempLevel("new " + str(ix), new_temp) + self.temp_level_model.append_temp_level(new_tl) + self.temp_level_view.setCurrentIndex(self.temp_level_model.index(ix, 0)) + self.temp_level_added.emit(old_tl, new_tl) + def remove_temp_level(self): self.temp_level_removed.emit( self.temp_level_model.remove_temp_level( - self.temp_level_view.currentIndex().row())) + self.temp_level_model.rowCount(None) - 1)) self.solder_changed.emit() + self.temp_level_view.setCurrentIndex(self.temp_level_model.index(self.temp_level_model.rowCount(None) - 1, 0)) def temp_level_selected(self, index):