ProjectFlask/FlaskMigrateExtension/MigrateSummaryDialog.py

branch
eric7
changeset 70
22e1d0f69668
parent 66
0d3168d0e310
child 72
4557829a4acf
equal deleted inserted replaced
69:c31a4f756a04 70:22e1d0f69668
8 """ 8 """
9 9
10 from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QEventLoop, QTimer 10 from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QEventLoop, QTimer
11 from PyQt6.QtGui import QGuiApplication 11 from PyQt6.QtGui import QGuiApplication
12 from PyQt6.QtWidgets import ( 12 from PyQt6.QtWidgets import (
13 QDialog, QDialogButtonBox, QAbstractButton, QTreeWidgetItem, 13 QDialog,
14 QAbstractItemView 14 QDialogButtonBox,
15 QAbstractButton,
16 QTreeWidgetItem,
17 QAbstractItemView,
15 ) 18 )
16 19
17 from EricGui.EricOverrideCursor import EricOverrideCursor, EricOverridenCursor 20 from EricGui.EricOverrideCursor import EricOverrideCursor, EricOverridenCursor
18 from EricWidgets import EricMessageBox 21 from EricWidgets import EricMessageBox
19 22
22 25
23 class MigrateSummaryDialog(QDialog, Ui_MigrateSummaryDialog): 26 class MigrateSummaryDialog(QDialog, Ui_MigrateSummaryDialog):
24 """ 27 """
25 Class implementing a dialog showing a summary of all created.migrations. 28 Class implementing a dialog showing a summary of all created.migrations.
26 """ 29 """
30
27 def __init__(self, project, migrateProject, migrations="", parent=None): 31 def __init__(self, project, migrateProject, migrations="", parent=None):
28 """ 32 """
29 Constructor 33 Constructor
30 34
31 @param project reference to the project object 35 @param project reference to the project object
32 @type Project 36 @type Project
33 @param migrateProject reference to the migrate project extension 37 @param migrateProject reference to the migrate project extension
34 @type MigrateProject 38 @type MigrateProject
35 @param migrations directory path containing the migrations 39 @param migrations directory path containing the migrations
37 @param parent reference to the parent widget 41 @param parent reference to the parent widget
38 @type QWidget 42 @type QWidget
39 """ 43 """
40 super().__init__(parent) 44 super().__init__(parent)
41 self.setupUi(self) 45 self.setupUi(self)
42 46
43 self.__refreshButton = self.buttonBox.addButton( 47 self.__refreshButton = self.buttonBox.addButton(
44 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole) 48 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole
49 )
45 self.__refreshButton.clicked.connect(self.showSummary) 50 self.__refreshButton.clicked.connect(self.showSummary)
46 51
47 self.__project = project 52 self.__project = project
48 self.__migrateProject = migrateProject 53 self.__migrateProject = migrateProject
49 self.__migrations = migrations 54 self.__migrations = migrations
50 55
51 self.__process = None 56 self.__process = None
52 self.__currentItemIndex = 1000000 57 self.__currentItemIndex = 1000000
53 self.__currentRevision = "" 58 self.__currentRevision = ""
54 59
55 def showSummary(self): 60 def showSummary(self):
56 """ 61 """
57 Public method to show the migrations summary. 62 Public method to show the migrations summary.
58 """ 63 """
59 workdir, env = self.__project.prepareRuntimeEnvironment() 64 workdir, env = self.__project.prepareRuntimeEnvironment()
60 if env is not None: 65 if env is not None:
61 self.show() 66 self.show()
62 self.raise_() 67 self.raise_()
63 68
64 self.buttonBox.button( 69 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(
65 QDialogButtonBox.StandardButton.Close).setEnabled(False) 70 False
66 self.buttonBox.button( 71 )
67 QDialogButtonBox.StandardButton.Cancel).setDefault(True) 72 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(
68 self.buttonBox.button( 73 True
69 QDialogButtonBox.StandardButton.Cancel).setEnabled(True) 74 )
70 self.buttonBox.button( 75 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(
71 QDialogButtonBox.StandardButton.Cancel).setFocus( 76 True
72 Qt.FocusReason.OtherFocusReason) 77 )
78 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setFocus(
79 Qt.FocusReason.OtherFocusReason
80 )
73 QGuiApplication.processEvents( 81 QGuiApplication.processEvents(
74 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) 82 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents
75 83 )
84
76 command = self.__project.getFlaskCommand() 85 command = self.__project.getFlaskCommand()
77 86
78 self.__process = QProcess() 87 self.__process = QProcess()
79 self.__process.setProcessEnvironment(env) 88 self.__process.setProcessEnvironment(env)
80 self.__process.setWorkingDirectory(workdir) 89 self.__process.setWorkingDirectory(workdir)
81 90
82 args = ["db", "history", "--indicate-current"] 91 args = ["db", "history", "--indicate-current"]
83 if self.__migrations: 92 if self.__migrations:
84 args += ["--directory", self.__migrations] 93 args += ["--directory", self.__migrations]
85 94
86 with EricOverrideCursor(): 95 with EricOverrideCursor():
87 self.__process.start(command, args) 96 self.__process.start(command, args)
88 ok = self.__process.waitForStarted(10000) 97 ok = self.__process.waitForStarted(10000)
89 if ok: 98 if ok:
90 ok = self.__process.waitForFinished(10000) 99 ok = self.__process.waitForFinished(10000)
91 if ok: 100 if ok:
92 out = str(self.__process.readAllStandardOutput(), 101 out = str(self.__process.readAllStandardOutput(), "utf-8")
93 "utf-8")
94 self.__processOutput(out) 102 self.__processOutput(out)
95 self.__selectItem(self.__currentRevision) 103 self.__selectItem(self.__currentRevision)
96 else: 104 else:
97 with EricOverridenCursor(): 105 with EricOverridenCursor():
98 EricMessageBox.critical( 106 EricMessageBox.critical(
99 None, 107 None,
100 self.tr("Migrations Summary"), 108 self.tr("Migrations Summary"),
101 self.tr("""The Flask process did not finish""" 109 self.tr(
102 """ within 10 seconds.""")) 110 """The Flask process did not finish"""
111 """ within 10 seconds."""
112 ),
113 )
103 else: 114 else:
104 with EricOverridenCursor(): 115 with EricOverridenCursor():
105 EricMessageBox.critical( 116 EricMessageBox.critical(
106 None, 117 None,
107 self.tr("Migrations Summary"), 118 self.tr("Migrations Summary"),
108 self.tr("""The Flask process could not be""" 119 self.tr(
109 """ started.""")) 120 """The Flask process could not be""" """ started."""
121 ),
122 )
110 for column in range(self.summaryWidget.columnCount()): 123 for column in range(self.summaryWidget.columnCount()):
111 self.summaryWidget.resizeColumnToContents(column) 124 self.summaryWidget.resizeColumnToContents(column)
112 125
113 self.buttonBox.button( 126 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(
114 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 127 False
115 self.buttonBox.button( 128 )
116 QDialogButtonBox.StandardButton.Close).setEnabled(True) 129 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(
117 self.buttonBox.button( 130 True
118 QDialogButtonBox.StandardButton.Close).setDefault(True) 131 )
119 self.buttonBox.button( 132 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(
120 QDialogButtonBox.StandardButton.Close).setFocus( 133 True
121 Qt.FocusReason.OtherFocusReason) 134 )
122 135 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus(
136 Qt.FocusReason.OtherFocusReason
137 )
138
123 def __processOutput(self, output): 139 def __processOutput(self, output):
124 """ 140 """
125 Private method to process the flask output and populate the summary 141 Private method to process the flask output and populate the summary
126 list. 142 list.
127 143
128 @param output output of the flask process 144 @param output output of the flask process
129 @type str 145 @type str
130 """ 146 """
131 self.summaryWidget.clear() 147 self.summaryWidget.clear()
132 self.upDownButton.setEnabled(False) 148 self.upDownButton.setEnabled(False)
133 self.__currentItemIndex = 1000000 149 self.__currentItemIndex = 1000000
134 self.__currentRevision = "" 150 self.__currentRevision = ""
135 151
136 lines = output.splitlines() 152 lines = output.splitlines()
137 for line in lines: 153 for line in lines:
138 isCurrent = False 154 isCurrent = False
139 oldRev, rest = line.split("->") 155 oldRev, rest = line.split("->")
140 rest, message = rest.split(",", 1) 156 rest, message = rest.split(",", 1)
141 newRev, *labels = rest.split() 157 newRev, *labels = rest.split()
142 if labels: 158 if labels:
143 labelList = [ 159 labelList = [
144 label.replace("(", "").replace(")", "") 160 label.replace("(", "").replace(")", "") for label in labels
145 for label in labels
146 ] 161 ]
147 labelsStr = ", ".join(labelList) 162 labelsStr = ", ".join(labelList)
148 if "current" in labelList: 163 if "current" in labelList:
149 isCurrent = True 164 isCurrent = True
150 else: 165 else:
151 labelsStr = "" 166 labelsStr = ""
152 167
153 itm = QTreeWidgetItem(self.summaryWidget, [ 168 itm = QTreeWidgetItem(
154 oldRev.strip(), 169 self.summaryWidget,
155 newRev.strip(), 170 [
156 message.strip(), 171 oldRev.strip(),
157 labelsStr, 172 newRev.strip(),
158 ]) 173 message.strip(),
174 labelsStr,
175 ],
176 )
159 if isCurrent: 177 if isCurrent:
160 font = itm.font(0) 178 font = itm.font(0)
161 font.setBold(True) 179 font.setBold(True)
162 for column in range(self.summaryWidget.columnCount()): 180 for column in range(self.summaryWidget.columnCount()):
163 itm.setFont(column, font) 181 itm.setFont(column, font)
164 182
165 self.__currentItemIndex = ( 183 self.__currentItemIndex = self.summaryWidget.indexOfTopLevelItem(itm)
166 self.summaryWidget.indexOfTopLevelItem(itm)
167 )
168 self.__currentRevision = newRev.strip() 184 self.__currentRevision = newRev.strip()
169 185
170 @pyqtSlot() 186 @pyqtSlot()
171 def on_summaryWidget_itemSelectionChanged(self): 187 def on_summaryWidget_itemSelectionChanged(self):
172 """ 188 """
173 Private slot to handle the selection of an entry. 189 Private slot to handle the selection of an entry.
174 """ 190 """
180 elif index > self.__currentItemIndex: 196 elif index > self.__currentItemIndex:
181 self.upDownButton.setText(self.tr("Downgrade")) 197 self.upDownButton.setText(self.tr("Downgrade"))
182 self.upDownButton.setEnabled(index != self.__currentItemIndex) 198 self.upDownButton.setEnabled(index != self.__currentItemIndex)
183 else: 199 else:
184 self.upDownButton.setEnabled(False) 200 self.upDownButton.setEnabled(False)
185 201
186 @pyqtSlot() 202 @pyqtSlot()
187 def on_upDownButton_clicked(self): 203 def on_upDownButton_clicked(self):
188 """ 204 """
189 Private slot to upgrade/downgrade to the selected revision. 205 Private slot to upgrade/downgrade to the selected revision.
190 """ 206 """
193 if self.upDownButton.text() == self.tr("Upgrade"): 209 if self.upDownButton.text() == self.tr("Upgrade"):
194 self.__migrateProject.upgradeDatabase(revision=rev) 210 self.__migrateProject.upgradeDatabase(revision=rev)
195 else: 211 else:
196 self.__migrateProject.downgradeDatabase(revision=rev) 212 self.__migrateProject.downgradeDatabase(revision=rev)
197 self.showSummary() 213 self.showSummary()
198 214
199 @pyqtSlot(QAbstractButton) 215 @pyqtSlot(QAbstractButton)
200 def on_buttonBox_clicked(self, button): 216 def on_buttonBox_clicked(self, button):
201 """ 217 """
202 Private slot handling a button press of the button box. 218 Private slot handling a button press of the button box.
203 219
204 @param button reference to the pressed button 220 @param button reference to the pressed button
205 @type QAbstractButton 221 @type QAbstractButton
206 """ 222 """
207 if button is self.buttonBox.button( 223 if button is self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
208 QDialogButtonBox.StandardButton.Cancel
209 ):
210 self.__cancelProcess() 224 self.__cancelProcess()
211 225
212 @pyqtSlot() 226 @pyqtSlot()
213 def __cancelProcess(self): 227 def __cancelProcess(self):
214 """ 228 """
215 Private slot to terminate the current process. 229 Private slot to terminate the current process.
216 """ 230 """
217 if ( 231 if (
218 self.__process is not None and 232 self.__process is not None
219 self.__process.state() != QProcess.ProcessState.NotRunning 233 and self.__process.state() != QProcess.ProcessState.NotRunning
220 ): 234 ):
221 self.__process.terminate() 235 self.__process.terminate()
222 QTimer.singleShot(2000, self.__process.kill) 236 QTimer.singleShot(2000, self.__process.kill)
223 self.__process.waitForFinished(3000) 237 self.__process.waitForFinished(3000)
224 238
225 self.__process = None 239 self.__process = None
226 240
227 def __selectItem(self, revision): 241 def __selectItem(self, revision):
228 """ 242 """
229 Private method to select an item given its revision. 243 Private method to select an item given its revision.
230 244
231 @param revision revision of the item to select 245 @param revision revision of the item to select
232 @type str 246 @type str
233 """ 247 """
234 if revision: 248 if revision:
235 items = self.summaryWidget.findItems( 249 items = self.summaryWidget.findItems(revision, Qt.MatchFlag.MatchExactly, 1)
236 revision, Qt.MatchFlag.MatchExactly, 1)
237 if items: 250 if items:
238 # select the first item 251 # select the first item
239 items[0].setSelected(True) 252 items[0].setSelected(True)
240 self.summaryWidget.scrollToItem( 253 self.summaryWidget.scrollToItem(
241 items[0], QAbstractItemView.ScrollHint.PositionAtCenter) 254 items[0], QAbstractItemView.ScrollHint.PositionAtCenter
255 )

eric ide

mercurial