show selected nodes in slice.
[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")])
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
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         self.nodeView = NodeView(self)
150         self.nodeModel = NodeModel(self)
151         self.nodeView.setModel(self.nodeModel)
152
153         refresh = QLabel("<a href='refresh'>Refresh</a>", self)
154         refresh.setScaledContents(False)
155         slicename = QLabel ("Slice : %s"%(config.getSlice() or "None"),self)
156         slicename.setScaledContents(False)
157
158         hlayout = QHBoxLayout()
159         hlayout.addWidget(slicename)
160         hlayout.addStretch()
161         hlayout.addWidget(refresh)
162
163         layout = QVBoxLayout()
164         layout.addLayout(hlayout)
165         layout.addWidget(self.nodeView)
166         self.setLayout(layout)
167         self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
168
169         self.connect(refresh, SIGNAL('linkActivated(QString)'), self.refresh)
170
171         rspec_file = os.path.expanduser("~/.sfi/%s.rspec" % config.getSlice())
172         if os.path.exists(rspec_file):
173             self.updateView()
174         
175     def readSliceRSpec(self):
176         rspec_file = os.path.expanduser("~/.sfi/%s.rspec" % config.getSlice())
177         xml = open(rspec_file).read()
178         return xml
179
180     def refresh(self, link=None):
181         if not config.getSlice():
182             self.parent().setStatus("<font color='red'>Slice not set yet!</font>")
183             return
184
185         self.process = SfiProcess()
186         outfile = self.process.getRSpecFromSM()
187         self.parent().setStatus("Updating slice data. This may take some time...")
188         
189         self.connect(self.process, SIGNAL('finished()'), self.refreshFinished)
190
191     def refreshFinished(self):
192         del self.process
193         self.parent().setStatus("<font color='green'>Slice data updated.</font>")
194         self.updateView()
195
196     def updateView(self):
197         self.nodeModel.clear()
198         rspec_string = self.readSliceRSpec()
199         networks = rspec_get_networks(rspec_string)
200
201         for network in networks:
202             networkItem = TreeItem([QString(network), QString("")], self.nodeModel.rootItem)
203
204             all_nodes = rspec_get_nodes_from_network(rspec_string, network)
205             sliver_nodes = rspec_get_sliver_nodes_from_network(rspec_string, network)
206             available_nodes = filter(lambda x:x not in sliver_nodes, all_nodes)
207
208             for node in sliver_nodes:
209                 nodeItem = TreeItem([QString(""), QString("%s (selected)" % node)], networkItem)
210                 networkItem.appendChild(nodeItem)
211
212             for node in available_nodes:
213                 nodeItem = TreeItem([QString(""), QString(node)], networkItem)
214                 networkItem.appendChild(nodeItem)
215
216             self.nodeModel.rootItem.appendChild(networkItem)
217
218         self.nodeView.expandAll()
219
220
221 class MainScreen(SfaScreen):
222     def __init__(self, parent):
223         SfaScreen.__init__(self, parent)
224
225         slice = SliceWidget(self)
226         self.init(slice, "Main Window", "PlanetLab Federation GUI")