c3908e1b52711c69cb085b6d412cf1d73b4a348f
[sface.git] / sface / screens / mainscreen.py
1
2 import os
3 from PyQt4.QtCore import *
4 from PyQt4.QtGui import *
5
6 from sfa.util.rspecHelper import RSpec
7 from sface.sfahelper import *
8 from sface.config import config
9 from sface.sfiprocess import SfiProcess
10 from sface.screens.sfascreen import SfaScreen
11
12 class NodeView(QTreeView):
13     def __init__(self, parent):
14         QTreeView.__init__(self, parent)
15
16         self.setItemsExpandable(True)
17         self.setRootIsDecorated(True)
18         self.setAlternatingRowColors(True)
19         self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
20         self.setAttribute(Qt.WA_MacShowFocusRect, 0)
21
22 class ItemDelegate(QStyledItemDelegate):
23     def __init__(self, parent):
24         QStyledItemDelegate.__init__(self)
25
26     def paint(self, painter, option, index):
27         data = "%s" % index.data().toString()
28
29         if data.startswith("*"): # already in the sliver
30             data = " %s " % data[1:]
31
32             fm = QFontMetrics(option.font)
33             rect = option.rect
34             rect.setWidth(fm.width(QString(data)))
35             rect.setHeight(rect.height() - 2)
36             rect.setX(rect.x() + 1)
37             x, y, h, w = rect.x(), rect.y(), rect.height(), rect.width()
38
39             path = QPainterPath()
40             path.addRoundedRect(x, y, w, h, 4, 4)
41
42             painter.save()
43             painter.setRenderHint(QPainter.Antialiasing)
44             painter.drawRoundedRect(rect, 4, 4)
45             painter.fillPath(path, QColor.fromRgb(0, 250, 0))
46             painter.setPen(QColor.fromRgb(0, 0, 0))
47             painter.drawText(option.rect, 0, QString(data))
48             painter.restore()
49         else: # others, fall back to default view
50             QStyledItemDelegate.paint(self, painter, option, index)
51
52 class TreeItem:
53     def __init__(self, data, parent=None):
54         self.parentItem = parent
55         self.itemData = data
56         self.childItems = []
57
58     def clear(self):
59         for child in self.childItems:
60             child.clear()
61             del child
62         del self.childItems
63         self.childItems = []
64
65     def appendChild(self, child):
66         self.childItems.append(child)
67
68     def child(self, row):
69         return self.childItems[row]
70     
71     def childCount(self):
72         return len(self.childItems)
73
74     def columnCount(self):
75         return len(self.itemData)
76
77     def data(self, column):
78         return self.itemData[column]
79
80     def row(self):
81         if (self.parentItem):
82             try:
83                 return self.parentItem.childItems.index(self)
84             except ValueError:
85                 return 0
86         return 0
87     
88     def parent(self):
89         return self.parentItem
90
91
92
93 class NodeModel(QAbstractItemModel):
94     def __init__(self, parent):
95         QAbstractItemModel.__init__(self, parent)
96         self.__initRoot()
97
98     def clear(self):
99         self.rootItem.clear()
100         self.__initRoot()
101
102     def __initRoot(self):
103         self.rootItem = TreeItem([QString("Testbed"), QString("Hostname"), QString("Selected")])
104
105     def columnCount(self, parent):
106         if parent.isValid():
107             return parent.internalPointer().columnCount()
108         else:
109             return self.rootItem.columnCount()
110
111     def data(self, index, role):
112         if not index.isValid():
113             return QVariant()
114
115         if role != Qt.DisplayRole:
116             return QVariant()
117
118         item = index.internalPointer()
119         return item.data(index.column())
120
121     def headerData(self, section, orientation, role):
122         if orientation == Qt.Horizontal and role == Qt.DisplayRole:
123             return self.rootItem.data(section)
124         return QVariant()
125
126     def flags(self, index):
127         if not index.isValid():
128             return 0
129         return Qt.ItemIsEnabled | Qt.ItemIsSelectable # | Qt.ItemIsEditable
130
131     def index(self, row, column, parent):
132         if not self.hasIndex(row, column, parent):
133             return QModelIndex()
134
135         parentItem = None
136         if not parent.isValid():
137             parentItem = self.rootItem
138         else:
139             parentItem = parent.internalPointer()
140             
141         childItem = parentItem.child(row)
142         if childItem:
143             return self.createIndex(row, column, childItem)
144         else:
145             return QModelIndex()
146
147     def parent(self, index):
148         if not index.isValid():
149             return QModelIndex()
150
151         childItem = index.internalPointer()
152         parentItem = childItem.parent()
153
154         if not parentItem:
155             return QModelIndex()
156
157         if parentItem is self.rootItem:
158             return QModelIndex()
159
160         return self.createIndex(parentItem.row(), 0, parentItem)
161
162     def rowCount(self, parent):
163         if parent.column() > 0:
164             return 0
165
166         parentItem = None
167         if not parent.isValid():
168             parentItem = self.rootItem
169         else:
170             parentItem = parent.internalPointer()
171
172         return parentItem.childCount()
173
174
175 class SliceWidget(QWidget):
176     def __init__(self, parent):
177         QWidget.__init__(self, parent)
178
179         slicename = QLabel ("Slice : %s"%(config.getSlice() or "None"),self)
180         slicename.setScaledContents(False)
181
182         self.nodeView = NodeView(self)
183         self.nodeModel = NodeModel(self)
184         self.nodeView.setModel(self.nodeModel)
185
186         refresh = QPushButton("Update Slice Data", self)
187         refresh.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
188         submit = QPushButton("Submit", self)
189         submit.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
190
191         hlayout = QHBoxLayout()
192         hlayout.addWidget(refresh, 0, Qt.AlignLeft)
193         hlayout.addStretch()
194         hlayout.addWidget(submit, 0, Qt.AlignRight)
195
196         layout = QVBoxLayout()
197         layout.addWidget(slicename)
198         layout.addWidget(self.nodeView)
199         layout.addLayout(hlayout)
200
201         self.setLayout(layout)
202         self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
203
204         self.connect(refresh, SIGNAL('clicked()'), self.refresh)
205         self.connect(submit, SIGNAL('clicked()'), self.submit)
206
207         rspec_file = os.path.expanduser("~/.sfi/%s.rspec" % config.getSlice())
208         if os.path.exists(rspec_file):
209             self.updateView()
210
211     def submit(self):
212         self.parent().setStatus("TODO: Submit not implemented yet!", 3000)
213         
214     def readSliceRSpec(self):
215         rspec_file = config.getSliceRSpecFile()
216         xml = open(rspec_file).read()
217         return xml
218
219     def refresh(self):
220         if not config.getSlice():
221             self.parent().setStatus("<font color='red'>Slice not set yet!</font>", timeout=None)
222             return
223
224         self.process = SfiProcess()
225         outfile = self.process.getRSpecFromSM()
226         self.parent().setStatus("Updating slice data. This may take some time...", timeout=None)
227         
228         self.connect(self.process, SIGNAL('finished()'), self.refreshFinished)
229
230     def refreshFinished(self):
231         del self.process
232         self.parent().setStatus("<font color='green'>Slice data updated.</font>", timeout=5000)
233         self.updateView()
234
235     def updateView(self):
236         self.nodeModel.clear()
237         rspec_string = self.readSliceRSpec()
238         networks = rspec_get_networks(rspec_string)
239
240         for network in networks:
241             networkItem = TreeItem([QString(network), QString(""), QString("")], self.nodeModel.rootItem)
242
243             all_nodes = rspec_get_nodes_from_network(rspec_string, network)
244             sliver_nodes = rspec_get_sliver_nodes_from_network(rspec_string, network)
245             available_nodes = filter(lambda x:x not in sliver_nodes, all_nodes)
246
247             for node in sliver_nodes:
248                 nodeItem = TreeItem([QString(""), QString("*%s" % node), QString("Implement Checkbox")], networkItem)
249                 networkItem.appendChild(nodeItem)
250
251             for node in available_nodes:
252                 nodeItem = TreeItem([QString(""), QString(node), QString("Implement Checkbox")], networkItem)
253                 networkItem.appendChild(nodeItem)
254
255             self.nodeModel.rootItem.appendChild(networkItem)
256
257         self.nodeView.expandAll()
258         self.nodeView.resizeColumnToContents(1)
259
260         self.delegate = ItemDelegate(self)
261         self.nodeView.setItemDelegateForColumn(1, self.delegate)
262
263
264 class MainScreen(SfaScreen):
265     def __init__(self, parent):
266         SfaScreen.__init__(self, parent)
267
268         slice = SliceWidget(self)
269         self.init(slice, "Main Window", "OneLab Federation GUI")