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, parent=None): |
31 def __init__(self, project, 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 parent reference to the parent widget |
37 @param parent reference to the parent widget |
34 @type QWidget |
38 @type QWidget |
35 """ |
39 """ |
36 super().__init__(parent) |
40 super().__init__(parent) |
37 self.setupUi(self) |
41 self.setupUi(self) |
38 |
42 |
39 self.__refreshButton = self.buttonBox.addButton( |
43 self.__refreshButton = self.buttonBox.addButton( |
40 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole) |
44 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole |
|
45 ) |
41 self.__refreshButton.clicked.connect(self.showSummary) |
46 self.__refreshButton.clicked.connect(self.showSummary) |
42 |
47 |
43 self.__project = project |
48 self.__project = project |
44 |
49 |
45 self.__process = None |
50 self.__process = None |
46 self.__currentItemIndex = 1000000 |
51 self.__currentItemIndex = 1000000 |
47 self.__currentRevision = "" |
52 self.__currentRevision = "" |
48 |
53 |
49 def showSummary(self): |
54 def showSummary(self): |
50 """ |
55 """ |
51 Public method to show the migrations summary. |
56 Public method to show the migrations summary. |
52 """ |
57 """ |
53 projectPath = self.__project.projectPath() |
58 projectPath = self.__project.projectPath() |
54 |
59 |
55 self.show() |
60 self.show() |
56 self.raise_() |
61 self.raise_() |
57 |
62 |
58 self.buttonBox.button( |
63 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False) |
59 QDialogButtonBox.StandardButton.Close).setEnabled(False) |
64 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True) |
60 self.buttonBox.button( |
65 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True) |
61 QDialogButtonBox.StandardButton.Cancel).setDefault(True) |
66 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setFocus( |
62 self.buttonBox.button( |
67 Qt.FocusReason.OtherFocusReason |
63 QDialogButtonBox.StandardButton.Cancel).setEnabled(True) |
68 ) |
64 self.buttonBox.button( |
|
65 QDialogButtonBox.StandardButton.Cancel).setFocus( |
|
66 Qt.FocusReason.OtherFocusReason) |
|
67 QGuiApplication.processEvents( |
69 QGuiApplication.processEvents( |
68 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) |
70 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents |
69 |
71 ) |
|
72 |
70 command = self.__project.getAlembicCommand() |
73 command = self.__project.getAlembicCommand() |
71 |
74 |
72 self.__process = QProcess() |
75 self.__process = QProcess() |
73 self.__process.setWorkingDirectory(projectPath) |
76 self.__process.setWorkingDirectory(projectPath) |
74 |
77 |
75 args = ["-c", "development.ini", "history", "--indicate-current"] |
78 args = ["-c", "development.ini", "history", "--indicate-current"] |
76 |
79 |
77 with EricOverrideCursor(): |
80 with EricOverrideCursor(): |
78 self.__process.start(command, args) |
81 self.__process.start(command, args) |
79 ok = self.__process.waitForStarted(10000) |
82 ok = self.__process.waitForStarted(10000) |
80 if ok: |
83 if ok: |
81 ok = self.__process.waitForFinished(10000) |
84 ok = self.__process.waitForFinished(10000) |
82 if ok: |
85 if ok: |
83 out = str(self.__process.readAllStandardOutput(), |
86 out = str(self.__process.readAllStandardOutput(), "utf-8") |
84 "utf-8") |
|
85 self.__processOutput(out) |
87 self.__processOutput(out) |
86 self.__selectItem(self.__currentRevision) |
88 self.__selectItem(self.__currentRevision) |
87 else: |
89 else: |
88 with EricOverridenCursor(): |
90 with EricOverridenCursor(): |
89 EricMessageBox.critical( |
91 EricMessageBox.critical( |
90 None, |
92 None, |
91 self.tr("Migrations Summary"), |
93 self.tr("Migrations Summary"), |
92 self.tr("""The 'alembic' process did not finish""" |
94 self.tr( |
93 """ within 10 seconds.""")) |
95 """The 'alembic' process did not finish""" |
|
96 """ within 10 seconds.""" |
|
97 ), |
|
98 ) |
94 else: |
99 else: |
95 with EricOverridenCursor(): |
100 with EricOverridenCursor(): |
96 EricMessageBox.critical( |
101 EricMessageBox.critical( |
97 None, |
102 None, |
98 self.tr("Migrations Summary"), |
103 self.tr("Migrations Summary"), |
99 self.tr("""The 'alembic' process could not be""" |
104 self.tr( |
100 """ started.""")) |
105 """The 'alembic' process could not be""" """ started.""" |
|
106 ), |
|
107 ) |
101 for column in range(self.summaryWidget.columnCount()): |
108 for column in range(self.summaryWidget.columnCount()): |
102 self.summaryWidget.resizeColumnToContents(column) |
109 self.summaryWidget.resizeColumnToContents(column) |
103 |
110 |
104 self.buttonBox.button( |
111 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) |
105 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) |
112 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) |
106 self.buttonBox.button( |
113 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) |
107 QDialogButtonBox.StandardButton.Close).setEnabled(True) |
114 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus( |
108 self.buttonBox.button( |
115 Qt.FocusReason.OtherFocusReason |
109 QDialogButtonBox.StandardButton.Close).setDefault(True) |
116 ) |
110 self.buttonBox.button( |
117 |
111 QDialogButtonBox.StandardButton.Close).setFocus( |
|
112 Qt.FocusReason.OtherFocusReason) |
|
113 |
|
114 def __processOutput(self, output): |
118 def __processOutput(self, output): |
115 """ |
119 """ |
116 Private method to process the flask output and populate the summary |
120 Private method to process the flask output and populate the summary |
117 list. |
121 list. |
118 |
122 |
119 @param output output of the flask process |
123 @param output output of the flask process |
120 @type str |
124 @type str |
121 """ |
125 """ |
122 self.summaryWidget.clear() |
126 self.summaryWidget.clear() |
123 self.upDownButton.setEnabled(False) |
127 self.upDownButton.setEnabled(False) |
124 self.__currentItemIndex = 1000000 |
128 self.__currentItemIndex = 1000000 |
125 self.__currentRevision = "" |
129 self.__currentRevision = "" |
126 |
130 |
127 lines = output.splitlines() |
131 lines = output.splitlines() |
128 for line in lines: |
132 for line in lines: |
129 isCurrent = False |
133 isCurrent = False |
130 oldRev, rest = line.split("->") |
134 oldRev, rest = line.split("->") |
131 rest, message = rest.split(",", 1) |
135 rest, message = rest.split(",", 1) |
132 newRev, *labels = rest.split() |
136 newRev, *labels = rest.split() |
133 if labels: |
137 if labels: |
134 labelList = [ |
138 labelList = [ |
135 label.replace("(", "").replace(")", "") |
139 label.replace("(", "").replace(")", "") for label in labels |
136 for label in labels |
|
137 ] |
140 ] |
138 labelsStr = ", ".join(labelList) |
141 labelsStr = ", ".join(labelList) |
139 if "current" in labelList: |
142 if "current" in labelList: |
140 isCurrent = True |
143 isCurrent = True |
141 else: |
144 else: |
142 labelsStr = "" |
145 labelsStr = "" |
143 |
146 |
144 itm = QTreeWidgetItem(self.summaryWidget, [ |
147 itm = QTreeWidgetItem( |
145 oldRev.strip(), |
148 self.summaryWidget, |
146 newRev.strip(), |
149 [ |
147 message.strip(), |
150 oldRev.strip(), |
148 labelsStr, |
151 newRev.strip(), |
149 ]) |
152 message.strip(), |
|
153 labelsStr, |
|
154 ], |
|
155 ) |
150 if isCurrent: |
156 if isCurrent: |
151 font = itm.font(0) |
157 font = itm.font(0) |
152 font.setBold(True) |
158 font.setBold(True) |
153 for column in range(self.summaryWidget.columnCount()): |
159 for column in range(self.summaryWidget.columnCount()): |
154 itm.setFont(column, font) |
160 itm.setFont(column, font) |
155 |
161 |
156 self.__currentItemIndex = ( |
162 self.__currentItemIndex = self.summaryWidget.indexOfTopLevelItem(itm) |
157 self.summaryWidget.indexOfTopLevelItem(itm) |
|
158 ) |
|
159 self.__currentRevision = newRev.strip() |
163 self.__currentRevision = newRev.strip() |
160 |
164 |
161 @pyqtSlot() |
165 @pyqtSlot() |
162 def on_summaryWidget_itemSelectionChanged(self): |
166 def on_summaryWidget_itemSelectionChanged(self): |
163 """ |
167 """ |
164 Private slot to handle the selection of an entry. |
168 Private slot to handle the selection of an entry. |
165 """ |
169 """ |
184 if self.upDownButton.text() == self.tr("Upgrade"): |
188 if self.upDownButton.text() == self.tr("Upgrade"): |
185 self.__project.upgradeDatabase(revision=rev) |
189 self.__project.upgradeDatabase(revision=rev) |
186 else: |
190 else: |
187 self.__project.downgradeDatabase(revision=rev) |
191 self.__project.downgradeDatabase(revision=rev) |
188 self.showSummary() |
192 self.showSummary() |
189 |
193 |
190 @pyqtSlot(QAbstractButton) |
194 @pyqtSlot(QAbstractButton) |
191 def on_buttonBox_clicked(self, button): |
195 def on_buttonBox_clicked(self, button): |
192 """ |
196 """ |
193 Private slot handling a button press of the button box. |
197 Private slot handling a button press of the button box. |
194 |
198 |
195 @param button reference to the pressed button |
199 @param button reference to the pressed button |
196 @type QAbstractButton |
200 @type QAbstractButton |
197 """ |
201 """ |
198 if button is self.buttonBox.button( |
202 if button is self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): |
199 QDialogButtonBox.StandardButton.Cancel |
|
200 ): |
|
201 self.__cancelProcess() |
203 self.__cancelProcess() |
202 |
204 |
203 @pyqtSlot() |
205 @pyqtSlot() |
204 def __cancelProcess(self): |
206 def __cancelProcess(self): |
205 """ |
207 """ |
206 Private slot to terminate the current process. |
208 Private slot to terminate the current process. |
207 """ |
209 """ |
208 if ( |
210 if ( |
209 self.__process is not None and |
211 self.__process is not None |
210 self.__process.state() != QProcess.ProcessState.NotRunning |
212 and self.__process.state() != QProcess.ProcessState.NotRunning |
211 ): |
213 ): |
212 self.__process.terminate() |
214 self.__process.terminate() |
213 QTimer.singleShot(2000, self.__process.kill) |
215 QTimer.singleShot(2000, self.__process.kill) |
214 self.__process.waitForFinished(3000) |
216 self.__process.waitForFinished(3000) |
215 |
217 |
216 self.__process = None |
218 self.__process = None |
217 |
219 |
218 def __selectItem(self, revision): |
220 def __selectItem(self, revision): |
219 """ |
221 """ |
220 Private method to select an item given its revision. |
222 Private method to select an item given its revision. |
221 |
223 |
222 @param revision revision of the item to select |
224 @param revision revision of the item to select |
223 @type str |
225 @type str |
224 """ |
226 """ |
225 if revision: |
227 if revision: |
226 items = self.summaryWidget.findItems( |
228 items = self.summaryWidget.findItems(revision, Qt.MatchFlag.MatchExactly, 1) |
227 revision, Qt.MatchFlag.MatchExactly, 1) |
|
228 if items: |
229 if items: |
229 # select the first item |
230 # select the first item |
230 items[0].setSelected(True) |
231 items[0].setSelected(True) |
231 self.summaryWidget.scrollToItem( |
232 self.summaryWidget.scrollToItem( |
232 items[0], QAbstractItemView.ScrollHint.PositionAtCenter) |
233 items[0], QAbstractItemView.ScrollHint.PositionAtCenter |
|
234 ) |