update to xmlrpc tracker, work in progress
[sface.git] / sface / sliceview.py
1 import datetime
2 import os
3 import pickle
4 from PyQt4.QtCore import *
5 from PyQt4.QtGui import *
6
7 from sfa.util.record import SfaRecord, SliceRecord, AuthorityRecord
8 from sface.config import config
9
10 NAME_COLUMN = 0
11 MEMBERSHIP_STATUS_COLUMN = 1
12
13 # maximum length of a name to display before clipping
14 NAME_MAX_LEN = 48
15
16 slice_status = { "in": "Selected",
17                 "out": "Not Selected"}
18
19 color_status = { "in": QColor.fromRgb(0, 250, 250), }
20
21 class SliceNameDelegate(QStyledItemDelegate):
22     def __init__(self, parent):
23         QStyledItemDelegate.__init__(self, parent)
24
25     def displayText(self, value, locale):
26         data = str(QStyledItemDelegate.displayText(self, value, locale))
27         if (len(data)>NAME_MAX_LEN):
28             data = data[:(NAME_MAX_LEN-3)] + "..."
29         return QString(data)
30
31     def paint(self, painter, option, index):
32         model = index.model()
33         data = str(self.displayText(index.data(), QLocale()))
34         status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
35         status_data = status_index.data().toString()
36
37         fm = QFontMetrics(option.font)
38         rect = QRect(option.rect)
39
40         rect.setHeight(rect.height() - 2)
41         rect.setWidth(fm.width(QString(data)) + 6)
42         rect.setX(rect.x() + 5)
43         rect.setY(rect.y() - 1)
44
45         textRect = QRect(option.rect)
46         textRect.setWidth(fm.width(QString(data)) + 6)
47         textRect.setX(rect.x())
48
49         x, y, h, w = rect.x(), rect.y(), rect.height(), rect.width()
50
51         path = QPainterPath()
52         path.addRoundedRect(x - 1, y + 1, w, h, 4, 4)
53
54         painter.save()
55         painter.setRenderHint(QPainter.Antialiasing)
56
57         if option.state & QStyle.State_Selected:
58             painter.fillRect(option.rect, option.palette.color(QPalette.Active, QPalette.Highlight))
59
60         color = None
61         for x in slice_status.keys():
62             if (slice_status[x] == status_data) and (x in color_status):
63                 color = color_status[x]
64
65         if color != None:
66             painter.fillPath(path, color)
67         painter.setPen(QColor.fromRgb(0, 0, 0))
68         painter.drawText(textRect, Qt.AlignVCenter, QString(data))
69
70         painter.restore()
71
72 class SliceView(QTableView):
73     def __init__(self, parent=None):
74         QTableView.__init__(self, parent)
75
76         self.setSelectionBehavior(QAbstractItemView.SelectRows)
77         self.setSelectionMode(QAbstractItemView.SingleSelection)
78         self.setAlternatingRowColors(True)
79         self.setAttribute(Qt.WA_MacShowFocusRect, 0)
80         self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
81         self.setToolTip("Double click on a row to change its status.")
82
83         self.setItemDelegateForColumn(0, SliceNameDelegate(self))
84
85     def keyPressEvent(self, event):
86         if (event.key() == Qt.Key_Space):
87             self.toggleSelection()
88         else:
89             QTableView.keyPressEvent(self, event)
90
91     def mouseDoubleClickEvent(self, event):
92         self.toggleSelection()
93
94     def toggleSelection(self):
95         index = self.currentIndex()
96         model = index.model()
97         status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
98         status_data = status_index.data().toString()
99         node_index = model.index(index.row(), NAME_COLUMN, index.parent())
100         node_data = node_index.data().toString()
101
102         if status_data == slice_status['in']:
103             model.setData(status_index, QString(slice_status['out']))
104         else:
105             model.setData(status_index, QString(slice_status['in']))
106
107         model.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), node_index, node_index)
108
109     def currentChanged(self, current, previous):
110         model = current.model()
111         node_index = model.index(current.row(), 0, current.parent())
112         node_data = node_index.data().toString()
113
114 class SliceModel(QStandardItemModel):
115     def __init__(self, rows=0, columns=4, parent=None):
116          QStandardItemModel.__init__(self, rows, columns, parent)
117
118     def updateModel(self):
119         self.clear()
120
121         slice_names = []
122
123         i=0
124         while (os.path.exists(config.getAuthorityListFile(i))):
125             rec = self.readSliceRecord(i)
126             if rec:
127                 name = str(rec.get_name())
128                 if (rec.get_type() == "slice"):
129                     slice_names.append(name)
130             i=i+1
131
132         rootItem = self.invisibleRootItem()
133
134         for name in slice_names:
135             rootItem.appendRow([self.readOnlyItem(name),
136                                 self.readOnlyItem(slice_status["out"])])
137
138         headers = QStringList() << "Slice Name" << "Status"
139         self.setHorizontalHeaderLabels(headers)
140
141     def readOnlyItem(self, x):
142         item = QStandardItem(QString(x))
143         item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
144         return item
145
146     def getSelectedSlices(self):
147         slices = []
148         item = self.invisibleRootItem()
149         children = item.rowCount()
150         for row in range(0, children):
151             childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString())
152             childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString())
153
154             if (childStatus == slice_status['in']):
155                 slices.append(childName)
156
157         return slices
158
159     def readSliceRecord(self, i):
160         rec_file = config.getAuthorityListFile(i)
161         if os.path.exists(rec_file):
162             xml = open(rec_file).read()
163             rec = SliceRecord()
164             rec.load_from_string(xml)
165             return rec
166         return None
167