import datetime
import os
import pickle
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from sface.config import config
from sface.sfidata import SfiData
from sface.sfiprocess import SfiProcess
NAME_COLUMN = 0
MEMBERSHIP_STATUS_COLUMN = 1
# maximum length of a name to display before clipping
NAME_MAX_LEN = 48
MODE_AUTHORITY_SLICES = 0x01
MODE_USER_SLICES = 0x02
MODE_SELECT_SINGLE = 0x10
slice_status = { "in": "Selected",
"out": "Not Selected"}
color_status = { "in": QColor.fromRgb(0, 250, 250), }
class SliceNameDelegate(QStyledItemDelegate):
def __init__(self, parent):
QStyledItemDelegate.__init__(self, parent)
def displayText(self, value, locale):
data = str(QStyledItemDelegate.displayText(self, value, locale))
if (len(data)>NAME_MAX_LEN):
data = data[:(NAME_MAX_LEN-3)] + "..."
return QString(data)
def paint(self, painter, option, index):
model = index.model()
data = str(self.displayText(index.data(), QLocale()))
status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
status_data = status_index.data().toString()
fm = QFontMetrics(option.font)
rect = QRect(option.rect)
rect.setHeight(rect.height() - 2)
rect.setWidth(fm.width(QString(data)) + 6)
rect.setX(rect.x() + 5)
rect.setY(rect.y() - 1)
textRect = QRect(option.rect)
textRect.setWidth(fm.width(QString(data)) + 6)
textRect.setX(rect.x())
x, y, h, w = rect.x(), rect.y(), rect.height(), rect.width()
path = QPainterPath()
path.addRoundedRect(x - 1, y + 1, w, h, 4, 4)
painter.save()
painter.setRenderHint(QPainter.Antialiasing)
if option.state & QStyle.State_Selected:
painter.fillRect(option.rect, option.palette.color(QPalette.Active, QPalette.Highlight))
color = None
for x in slice_status.keys():
if (slice_status[x] == status_data) and (x in color_status):
color = color_status[x]
if color != None:
painter.fillPath(path, color)
painter.setPen(QColor.fromRgb(0, 0, 0))
painter.drawText(textRect, Qt.AlignVCenter, QString(data))
painter.restore()
class SliceView(QTableView):
def __init__(self, mode=0, parent=None):
QTableView.__init__(self, parent)
self.mode = mode
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection)
self.setAlternatingRowColors(True)
self.setAttribute(Qt.WA_MacShowFocusRect, 0)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.setToolTip("Double click on a row to change its status.")
self.setItemDelegateForColumn(0, SliceNameDelegate(self))
def keyPressEvent(self, event):
if (event.key() == Qt.Key_Space):
self.toggleSelection()
else:
QTableView.keyPressEvent(self, event)
def selectionChanged(self, selected, deselected):
QTableView.selectionChanged(self, selected, deselected)
if (self.mode & MODE_SELECT_SINGLE) != 0:
self.unselectAll()
self.toggleSelection()
def mouseDoubleClickEvent(self, event):
self.toggleSelection()
def unselectAll(self):
index = self.currentIndex()
model = index.model()
for row in range(0, model.rowCount()):
status_index = model.index(row, MEMBERSHIP_STATUS_COLUMN, index.parent())
model.setData(status_index, QString(slice_status['out']))
#model.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"),
# model.index(0, MEMBERSHIP_STATUS_COLUMN, index.parent()),
# model.index(model.rowCount(), MEMBERSHIP_STATUS_COLUMN, index.parent()))
def toggleSelection(self):
index = self.currentIndex()
model = index.model()
status_index = model.index(index.row(), MEMBERSHIP_STATUS_COLUMN, index.parent())
status_data = status_index.data().toString()
node_index = model.index(index.row(), NAME_COLUMN, index.parent())
node_data = node_index.data().toString()
if status_data == slice_status['in']:
model.setData(status_index, QString(slice_status['out']))
else:
model.setData(status_index, QString(slice_status['in']))
model.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), node_index, node_index)
def currentChanged(self, current, previous):
model = current.model()
node_index = model.index(current.row(), 0, current.parent())
node_data = node_index.data().toString()
class SliceModel(QStandardItemModel):
def __init__(self, rows=0, columns=4, parent=None, mode=MODE_AUTHORITY_SLICES):
QStandardItemModel.__init__(self, rows, columns, parent)
self.mode = mode
def updateModel(self):
self.clear()
if (self.mode & MODE_AUTHORITY_SLICES) != 0:
slice_names = SfiData().getAuthorityHrns(type="slice")
else: # MODE_USER_SLICES
slice_names = SfiData().getUserSliceHrns()
rootItem = self.invisibleRootItem()
for name in slice_names:
rootItem.appendRow([self.readOnlyItem(name),
self.readOnlyItem(slice_status["out"])])
headers = QStringList() << "Slice Name" << "Status"
self.setHorizontalHeaderLabels(headers)
def readOnlyItem(self, x):
item = QStandardItem(QString(x))
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
return item
def getSelectedSlices(self):
slices = []
item = self.invisibleRootItem()
children = item.rowCount()
for row in range(0, children):
childName = str(item.child(row, NAME_COLUMN).data(Qt.DisplayRole).toString())
childStatus = str(item.child(row, MEMBERSHIP_STATUS_COLUMN).data(Qt.DisplayRole).toString())
if (childStatus == slice_status['in']):
slices.append(childName)
return slices
class SlicePickerWindow(QDialog):
def __init__(self, mode=MODE_AUTHORITY_SLICES, parent=None):
super(SlicePickerWindow, self).__init__(parent)
self.mode = mode
self.slices = None
self.setWindowTitle("Slice Picker")
sliceLabel = QLabel("Slices:")
self.sliceView = SliceView(mode=self.mode)
self.status = QLabel("")
self.status.setMaximumWidth(640)
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True)
layout = QVBoxLayout()
layout.addWidget(sliceLabel)
layout.addWidget(self.sliceView)
layout.addWidget(self.status)
layout.addWidget(self.buttonBox)
self.setLayout(layout)
self.connect(self.buttonBox, SIGNAL("accepted()"), self, SLOT("accept()"))
self.connect(self.buttonBox, SIGNAL("rejected()"), self, SLOT("reject()"))
self.sliceModel = SliceModel(mode=mode)
self.refresh()
def accept(self):
self.slices = self.sliceModel.getSelectedSlices()
print self.slices
QDialog.accept(self)
def setStatus(self, x):
self.status.setText(x)
def refresh(self):
if (self.mode & MODE_AUTHORITY_SLICES) != 0:
self.refreshAuthority()
else:
self.refreshUser()
def refreshUser(self):
self.process = SfiProcess(self)
self.connect(self.process, SIGNAL('finished()'), self.getUserRecordFinished)
self.process.getRecord(hrn=config.getUser(), filename=config.getUserRecordFile())
self.setStatus("Refreshing user record. This will take a moment...")
def getUserRecordFinished(self):
self.disconnect(self.process, SIGNAL('finished()'), self.getUserRecordFinished)
faultString = self.process.getFaultString()
if not faultString:
self.setStatus("Slice list refreshed.")
self.updateSliceView()
else:
self.setStatus("User rec refresh error: %s" % (faultString))
def refreshAuthority(self):
self.process = SfiProcess(self)
self.connect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished)
self.process.listRecords(config.getAuthority(), None)
self.setStatus("Refreshing slice list. This will take a moment...")
def getAuthorityRecordFinished(self):
self.disconnect(self.process, SIGNAL('finished()'), self.getAuthorityRecordFinished)
faultString = self.process.getFaultString()
if not faultString:
self.setStatus("Slice list refreshed.")
self.updateSliceView()
else:
self.setStatus("Authority rec refresh error: %s" % (faultString))
def updateSliceView(self):
self.sliceModel.updateModel()
self.sliceView.setModel(self.sliceModel)
self.sliceView.resizeColumnToContents(0)