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