add event for notifying mainscreen of server-side slice changes
[sface.git] / sface / sficreate.py
1 import calendar
2 import datetime
3 import os
4 import re
5 import sys
6 import time
7
8 from PyQt4.QtCore import *
9 from PyQt4.QtGui import *
10 from sface.config import config
11 from sface.sfiprocess import SfiProcess
12 from sface.screens.userscreen import UserView, UserModel
13
14 class CreateWindow(QDialog):
15     def __init__(self, parent=None):
16         super(CreateWindow, self).__init__(parent)
17         self.setWindowTitle("Create new Slice")
18
19         self.renewProcess = None
20
21         self.sliceWasCreated = False
22
23         hrnLabel = QLabel("Slice HRN:")
24         self.hrnEdit = QLineEdit()
25         urlLabel = QLabel("Project URL:")
26         self.urlEdit = QLineEdit()
27         descLabel = QLabel("Description:")
28         self.descEdit = QTextEdit()
29         self.descEdit.setMinimumWidth(400)
30         self.descEdit.setMaximumHeight(100)
31
32         self.userLabel = QLabel("Researchers:")
33         self.userView = UserView()
34
35         self.status = QLabel("")
36         self.status.setMaximumWidth(640)
37
38         self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
39         self.buttonBox.addButton("refresh", QDialogButtonBox.ActionRole)
40         self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True)
41
42         layout = QVBoxLayout()
43         layout.addWidget(hrnLabel)
44         layout.addWidget(self.hrnEdit)
45         layout.addWidget(urlLabel)
46         layout.addWidget(self.urlEdit)
47         layout.addWidget(descLabel)
48         layout.addWidget(self.descEdit)
49         layout.addWidget(self.userLabel)
50         layout.addWidget(self.userView)
51         layout.addWidget(self.status)
52         layout.addWidget(self.buttonBox)
53         self.setLayout(layout)
54
55         self.userModel = UserModel(parent=self)
56
57         self.connect(self.buttonBox, SIGNAL("accepted()"), self, SLOT("accept()"))
58         self.connect(self.buttonBox, SIGNAL("rejected()"), self, SLOT("reject()"))
59         self.connect(self.buttonBox, SIGNAL("clicked(QAbstractButton *)"), self.clicked)
60
61         self.updateView()
62
63         if (self.userModel.rowCount() == 0):
64             self.refreshAuthority()
65
66     def clicked(self, button):
67         if button.text() == "refresh":
68             self.refreshAuthority()
69
70     def refreshAuthority(self):
71         self.refreshProcess = SfiProcess(self)
72         self.connect(self.refreshProcess, SIGNAL('finished()'), self.getAuthorityRecordFinished)
73
74         self.refreshProcess.listRecords(config.getAuthority(), "user", config.getAuthorityListFile())
75         self.setStatus("Refreshing user list...")
76
77     def accept(self):
78         auth = config.getAuthority()
79         desc = str(self.descEdit.toPlainText())
80         hrn = str(self.hrnEdit.text())
81         type = "slice"
82         url = str(self.urlEdit.text())
83
84         researchers = self.userModel.getResearchers()
85
86         if not hrn.startswith(auth):
87             QMessageBox.warning(self, "Invalid HRN", "HRN must be within your current authority (%s)" % auth)
88             return
89
90         if not (url.startswith("http://") or url.startswith("https://")):
91             QMessageBox.warning(self, "Invalid URL", "URL must start with http:// or https://")
92             return
93
94         if not desc:
95             QMessageBox.warning(self, "Invalid Description", "Description is too short")
96             return
97
98         if not researchers:
99             QMessageBox.warning(self, "Invalid Researchers", "Please add at least one researcher by double-clicking on a researcher name")
100             return
101
102         self.setStatus("Registering Slice...")
103
104         self.createProcess = SfiProcess(self)
105         self.connect(self.createProcess, SIGNAL('finished()'), self.createFinished)
106
107         self.buttonBox.setEnabled(False)
108
109         researcherXml = "<researcher>" + "</researcher><researcher>".join(researchers) + "</researcher>"
110
111         newSliceRecord = os.path.expanduser("~/.sfi/newslice.record")
112         file(newSliceRecord, "w").write('<record authority="%s" description="%s" hrn="%s" type="%s" url="%s">%s</record>' % (auth, desc, hrn, type, url, researcherXml))
113         self.createProcess.addRecord(newSliceRecord)
114
115     def getAuthorityRecordFinished(self):
116         self.setStatus("<font color='green'>User list refreshed.</font>")
117         self.updateView()
118
119     def setStatus(self, x):
120         self.status.setText(x)
121
122     def createFinished(self):
123         faultString = self.createProcess.getFaultString()
124         if not faultString:
125             self.setStatus("<font color='green'>Slice created.</font>")
126             self.sliceWasCreated = True
127             self.buttonBox.setEnabled(True)
128             self.buttonBox.clear()
129             self.buttonBox.addButton(QDialogButtonBox.Close)
130         else:
131             self.setStatus("<font color='red'>Slice creation failed: %s</font>" % (faultString))
132             self.sliceWasCreated = False
133             self.buttonBox.setEnabled(True)
134
135         self.disconnect(self.createProcess, SIGNAL('finished()'), self.createFinished)
136         self.createProcess = None
137
138     def getHrn(self):
139         return self.hrnEdit.text()
140
141     def updateView(self):
142         self.userModel.updateModel(None)
143
144         self.userView.setModel(self.userModel)
145         self.userView.hideUnusableColumns()
146         self.userView.resizeColumnToContents(0)
147
148 class RemoveWindow(QDialog):
149     def __init__(self, hrn, parent=None):
150         super(RemoveWindow, self).__init__(parent)
151         self.setWindowTitle("Remove Slice")
152
153         hrnLabel = QLabel("Slice HRN:")
154         self.hrnEdit = QLineEdit()
155         self.status = QLabel("")
156         self.status.setMaximumWidth(640)
157
158         if hrn:
159             self.hrnEdit.setText(hrn)
160
161         self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
162         self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True)
163
164         layout = QVBoxLayout()
165         layout.addWidget(hrnLabel)
166         layout.addWidget(self.hrnEdit)
167         layout.addWidget(self.status)
168         layout.addWidget(self.buttonBox)
169         self.setLayout(layout)
170
171         self.userModel = UserModel(parent=self)
172
173         self.connect(self.buttonBox, SIGNAL("accepted()"), self, SLOT("accept()"))
174         self.connect(self.buttonBox, SIGNAL("rejected()"), self, SLOT("reject()"))
175
176     def accept(self):
177         hrn = self.hrnEdit.text()
178
179         box = QMessageBox(parent=self)
180         box.setText("Confirm deletion of slice %s ?" % hrn)
181         box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
182         ret = box.exec_()
183         if (ret != QMessageBox.Yes):
184             return
185
186         self.setStatus("Removing Slice...")
187
188         self.removeProcess = SfiProcess(self)
189         self.connect(self.removeProcess, SIGNAL('finished()'), self.removeFinished)
190
191         self.buttonBox.setEnabled(False)
192
193         self.removeProcess.removeRecord(hrn)
194
195     def setStatus(self, x):
196         self.status.setText(x)
197
198     def removeFinished(self):
199         faultString = self.removeProcess.getFaultString()
200         if not faultString:
201             self.setStatus("<font color='green'>Slice removed.</font>")
202             self.sliceWasCreated = True
203             self.buttonBox.setEnabled(True)
204             self.buttonBox.clear()
205             self.buttonBox.addButton(QDialogButtonBox.Close)
206         else:
207             self.setStatus("<font color='red'>Slice removal failed: %s</font>" % (faultString))
208             self.buttonBox.setEnabled(True)
209
210         self.disconnect(self.removeProcess, SIGNAL('finished()'), self.removeFinished)
211         self.removeProcess = None
212
213