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